Gio*_*uri 9 wcf soa servicecontract
我们god object在我们的系统中遇到了一个.该系统包括public service暴露给我们的客户,middle office service和back office service.
流程如下:用户注册一些交易public service,然后经理middle office service检查交易并批准或拒绝交易,最后管理者back office service完成或拒绝交易.
使用我'这个词transaction,但实际上这些都是不同的类型,如操作的CRUD on entity1,CRUD on entiny2......不仅CRUD操作,但其他许多操作,例如approve/send/decline entity1,make entity1 parent/child of entity2等等...
现在WCF服务合同只是根据系统的那些部分分开.所以我们有3个服务合同:
PublicService.cs
MiddleOfficeService.cs
BackOfficeService.cs
Run Code Online (Sandbox Code Playgroud)
每个都有大量的运营合同:
public interface IBackOfficeService
{
[OperationContract]
void AddEntity1(Entity1 item);
[OperationContract]
void DeleteEntity1(Entity1 item);
....
[OperationContract]
void SendEntity2(Entity2 item);
....
}
Run Code Online (Sandbox Code Playgroud)
所有3项服务的运营合同数量已经达到2000个,每个服务合同约为600个.它不仅打破了最佳实践,而且只需更新服务引用就会非常痛苦,因为它需要很长时间.并且系统每天都在增长,并且在每次迭代中将越来越多的操作添加到这些服务中.
现在我们面临两难困境,因为我们如何将这些神服务分解为逻辑部分.有人说服务不应包含超过12~20次操作.其他人说一些不同的事情.我意识到没有黄金法则,但我希望听到一些关于此的建议.
例如,如果我只是按实体类型拆分这些服务,那么我可以在项目中获得大约50个服务端点和50个服务引用.在这种情况下,可维护性是什么?
还有一件事需要考虑.假设我选择了按实体拆分这些服务的方法.例如:
public interface IEntity1Service
{
[OperationContract]
void AddEntity1(Entity1 item);
[OperationContract]
void ApproveEntity1(Entity1 item);
[OperationContract]
void SendEntity1(Entity1 item);
[OperationContract]
void DeleteEntity1(Entity1 item);
....
[OperationContract]
void FinalizeEntity1(Entity1 item);
[OperationContract]
void DeclineEntity1(Entity1 item);
}
Run Code Online (Sandbox Code Playgroud)
现在发生的事情是我应该在public client和中添加对此服务的引用back office client.但back office只需要FinalizeEntity1和DeclineEntity1操作.因此,这里是一个典型的侵犯Interface segregation principle在SOLID.所以,我必须拆分进一步的可能是3级不同的服务IEntity1FrontService,IEntity1MiddleService,IEntity1BackService.
这里的挑战是重构代码而不改变代码的大部分以避免潜在的回归.
避免使用数千行的大型业务代码的一种解决方案是将接口/实现拆分为多个部分,每个部分代表给定的业务域.
例如,您的IPublicService接口可以编写如下(使用接口继承,每个业务域一个接口):
IPublicService.cs:
[ServiceContract]
public interface IPublicService : IPublicServiceDomain1, IPublicServiceDomain2
{
}
Run Code Online (Sandbox Code Playgroud)
IPublicServiceDomain1.cs:
[ServiceContract]
public interface IPublicServiceDomain1
{
[OperationContract]
string GetEntity1(int value);
}
Run Code Online (Sandbox Code Playgroud)
IPublicServiceDomain2.cs:
[ServiceContract]
public interface IPublicServiceDomain2
{
[OperationContract]
string GetEntity2(int value);
}
Run Code Online (Sandbox Code Playgroud)
现在,对于服务实现,您可以使用部分类(每个业务域一个部分类)将其拆分为多个部分:
Service.cs:
public partial class Service : IPublicService
{
}
Run Code Online (Sandbox Code Playgroud)
Service.Domain1.cs:
public partial class Service : IPublicServiceDomain1
{
public string GetEntity1(int value)
{
// Some implementation
}
}
Run Code Online (Sandbox Code Playgroud)
Service.Domain2.cs:
public partial class Service : IPublicServiceDomain2
{
public string GetEntity2(int value)
{
// Some implementation
}
}
Run Code Online (Sandbox Code Playgroud)
对于服务器配置,仍然只有一个端点:
<system.serviceModel>
<services>
<service name="WcfServiceLibrary2.Service">
<endpoint address="" binding="basicHttpBinding" contract="WcfServiceLibrary2.IPublicService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/Design_Time_Addresses/WcfServiceLibrary2/Service1/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Run Code Online (Sandbox Code Playgroud)
对于客户端也是如此:仍然是一个服务引用:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IPublicService" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8733/Design_Time_Addresses/WcfServiceLibrary2/Service1/"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IPublicService"
contract="ServiceReference1.IPublicService" name="BasicHttpBinding_IPublicService" />
</client>
</system.serviceModel>
Run Code Online (Sandbox Code Playgroud)
这允许通过将大型服务拆分为多个逻辑部分(与给定业务域相关联的每个部分)来重构服务器端.
这并不会改变您的3个服务中的每个服务仍然有600个操作的事实,因此客户端代理生成仍然需要很长时间.至少你的代码将更好地组织在服务器端,并且重构将是便宜的并且没有那么危险.
这里没有银弹,这只是代码重组,以提高可读性/维护性.
200个服务,每个服务10个操作,20个服务,每个服务100个操作,这是另一个主题,但可以肯定的是,重构需要更多的时间,你仍然可以进行2000次操作.除非您重构整个应用程序并减少此数量(例如,通过提供更"高级"(并非总是可能)的服务).
| 归档时间: |
|
| 查看次数: |
321 次 |
| 最近记录: |