简体   繁体   English

wcf决定:一个服务多个合同或许多服务

[英]wcf decision: one service multiple contracts or many services

I am using .NET 4 to create a small client server application for a customer. 我使用.NET 4为客户创建一个小型客户端服务器应用程序。 Should I create one giant service that implements many contracts (IInvoice, IPurchase, ISalesOrder, etc) or should I create many services running one contract each on many ports? 我应该创建一个实现许多合同的巨型服务(IInvoice,IPurchase,ISalesOrder等),还是应该创建许多服务,在许多端口上运行一个合同? My questions specifically is interested in the pros/cons of either choice. 我的问题特别感兴趣的是两种选择的优缺点。 Also, what is the common way of answering this question? 另外,回答这个问题的常用方法是什么?

My true dilemma is that I have no experience making this decision, and I have little enough experience with wcf that I need help understanding the technical implications of such a decision. 我真正的困境是我没有做出这个决定的经验,而且我对wcf的经验不足以至于我需要帮助理解这个决定的技术含义。

Don't create one large service that implements n-number of service contracts. 不要创建一个实现n个服务契约的大型服务。 These types of services are easy to create, but will eventually become a maintenance headache and will not scale well. 这些类型的服务很容易创建,但最终会成为一种维护问题,并且不能很好地扩展。 Plus, you'll get all sorts of code merging conflicts if there's a development group competing for check-ins/check-outs. 另外,如果有一个开发小组竞争签到/签出,你会得到各种代码合并冲突。

Don't create too many services either. 也不要创建太多服务。 Avoid the trap of making your services too fine-grained. 避免使您的服务过于细化的陷阱。 Try to create services based on a functionality. 尝试基于功能创建服务。 The methods exposed by these services shouldn't be fine-grained either. 这些服务所暴露的方法也不应该是细粒度的。 You're better off having fewer methods that do more. 你做的更少的方法更少。 Avoid creating similar functions like GetUserByID(int ID), GetUserByName(string Name) by creating a GetUser(userObject user). 通过创建GetUser(userObject用户),避免创建类似GetUserByID(int ID),GetUserByName(string Name)的函数。 You'll have less code, easier maintenance and better discoverability. 您将拥有更少的代码,更轻松的维护和更好的可发现性。

Finally, you're probably only going to need one port no matter what you do. 最后,无论你做什么,你可能只需要一个端口。

UPDATE 12/2018 Funny how things have changed since I wrote this. 更新12/2018自从我写这篇文章以来,事情发生了变化。 Now with the micro-services pattern, I'm creating a lot of services with chatty APIs :) 现在有了微服务模式,我用繁琐的API创建了很多服务:)

In real time applications you have one service contract for each entity like Invoice, Purchase and SalesOrder will have separate ServiceContract 在实时应用程序中,您为每个实体(例如Invoice,Purchase和SalesOrder)提供了一个服务合同,它们将具有单独的ServiceContract

However for each service contract there will be heterogeneous clients like Invoice will be called by backoffice through windows application using netNamedPipeBinding or netTcpBinding and same time client application needs to call the service using basicHttpBinding or wsHttpBindings. 但是,对于每个服务合同,将使用netNamedPipeBinding或netTcpBinding通过Windows应用程序通过后台调用Invoice等异构客户端,同时客户端应用程序需要使用basicHttpBinding或wsHttpBindings来调用服务。 Basically you need to create multiple endpoints for each service. 基本上,您需要为每个服务创建多个端点。

You would typically create different services for each main entity like IInvoice, IPurchase, ISalesOrder. 您通常会为每个主要实体创建不同的服务,如IInvoice,IPurchase,ISalesOrder。

Another option is to seperate queries from commands. 另一种选择是从命令中分离查询。 You could have a command service for each main entity and implement business operations accepting only the data they need in order to perform the operation (avoid CRUD-like operations); 您可以为每个主实体提供命令服务,并实现业务操作,仅接受他们执行操作所需的数据(避免类似CRUD的操作); and one query service that returns the data in the format required by the client. 和一个查询服务,以客户端所需的格式返回数据。 This means that the command part uses the underlying domain model/business layer; 这意味着命令部分使用底层域模型/业务层; while the query service directly operates on the database (bypassing the business, which is not needed for querying). 而查询服务直接在数据库上运行(绕过业务,查询不需要)。 This simplifies your querying a lot and makes it more flexible (return only what the client needs). 这简化了您的查询并使其更加灵活(仅返回客户端需要的内容)。

Its seems that you are mixing between DataContract(s) and ServiceContract(s). 它似乎是在DataContract和ServiceContract之间混合。 You can have one ServiceContract and many DataContract(s) and that would perfectly suit your needs. 您可以拥有一个ServiceContract和许多DataContract,这将完全满足您的需求。

The truth is that splitting up WCF services - or any services is a balancing act. 事实是,拆分WCF服务 - 或任何服务是一种平衡行为。 The principle is that you want to to keep downward pressure on complexity while still considering performance. 原则是您希望在仍然考虑性能的同时保持复杂性的下行压力。

The more services you create, the more configuration you will have to write. 您创建的服务越多,您需要编写的配置就越多。 Also, you will increase the number of proxy classes you need to create and maintain on the client side. 此外,您将增加在客户端创建和维护所需的代理类的数量。

Putting too many ServiceContracts on one service will increase the time it takes to generate and use a proxy. 在一个服务上放置太多ServiceContracts将增加生成和使用代理所需的时间。 But, if you only end up with one or two Operations on a contract, you will have added complexity to the system with very little to gain. 但是,如果您最终只能在合同上执行一个或两个操作,那么您将增加系统的复杂性而几乎没有收获。 This is not a scientific prescription, but a good rule of thumb could be say about 10-20 OperationContracts per ServiceContract. 这不是一个科学的处方,但一个好的经验法则可以说是每个ServiceContract大约10-20个OperationContracts。

Class coupling is of course a consideration, but are you really dealing with separate concerns? 类耦合当然是一个考虑因素,但你真的在处理不同的问题吗? It depends on what your system does, but most systems deal with only a few areas of concern, so splitting things up may not actually decrease class coupling that much anyway. 这取决于你的系统做什么,但大多数系统只涉及一些关注的领域,所以拆分事实上可能实际上并没有减少那么多的类耦合。

Another thing to remember, and this is ultra important is to always make your methods as generic as possible. 要记住的另一件事是,最重要的是始终使您的方法尽可能通用。 WCF deals in DataContracts for a reason. 出于某种原因,WCF在DataContracts中处理。 DataContracts mean that you can send any object to and from the server so long as the DataContracts are known. DataContracts意味着只要已知DataContracts,您就可以向服务器发送任何对象。

So, for example, you might have 3 OperationContracts: 因此,例如,您可能有3个OperationContracts:

[OperationContract]
Person GetPerson(string id);

[OperationContract]
Dog GetDog(string id);

[OperationContract]
Cat GetCat(string id);

But, so long as these are all known types, you could merge these in to one operation like: 但是,只要这些都是已知类型,您可以将它们合并到一个操作中,如:

[OperationContract]
IDatabaseRecord GetDatabaseRecord(string recordTypeName, string id);

Ultimately, this is the most important thing to consider when designing service contracts. 最终,这是设计服务合同时最重要的考虑因素。 This applies for REST if you are using a DataContract serialization like serialization method. 如果您使用像序列化方法一样的DataContract序列化,这适用于REST。

Lastly, go back over your ServiceContracts every few months and delete operations that are not getting used by the clients. 最后,每隔几个月返回一次ServiceContracts并删除客户未使用的操作。 This is another big one! 这是另一个大问题!

You should take the decision based the load expected, extensibility needed and future perspective. 您应该根据预期的负载,所需的可扩展性和未来的视角来做出决策。 As you wrote " small client server application for a customer" it is not giving clear idea of intended use of the development in hand. 当您为客户编写“小客户端服务器应用程序”时,它并没有明确了解手头开发的预期用途。 Mr. Big's answer must be considered too. 必须考虑Big先生的答案。

You are most welcome to put forward further question backed with specific data or particulars about the situation in hand. 我们非常欢迎您提出进一步的问题,并提供有关手头情况的具体数据或详情。 Thanks. 谢谢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM