C# 使用getter方法膨胀服务的解决方案?

C# 使用getter方法膨胀服务的解决方案?,c#,.net,web-services,wcf,soa,C#,.net,Web Services,Wcf,Soa,我们正在将核心web应用程序重构为三层SOA体系结构: 演示文稿(asp mvc) 服务层(wcf,net.tcp) 持久性(sql) 大约有5个内部网站,每个网站都有自己的服务层。 服务和UI通过DTO彼此共享信息。 问题是,大多数服务方法都是专门为UI设计的,因此一些服务变得非常庞大,例如: // CompanyService: CompanyDTO GetByName(String) CompanyDTO GetByNameAndCity(String, String) Compa

我们正在将核心web应用程序重构为三层SOA体系结构:

  • 演示文稿(asp mvc)
  • 服务层(wcf,net.tcp)
  • 持久性(sql)
大约有5个内部网站,每个网站都有自己的服务层。 服务和UI通过DTO彼此共享信息。 问题是,大多数服务方法都是专门为UI设计的,因此一些服务变得非常庞大,例如:

// CompanyService:
CompanyDTO GetByName(String)  
CompanyDTO GetByNameAndCity(String, String)
CompanyDTO GetByNameOrCity(String, String)
CompanyDTO GetByStartsWithNameOrStartsWithCity (String, String)
CompanyDTO GetByNameOrStartsWithCity(String, String)
CompanyDTO GetByNameOrStartsWithCityAndHavingAtLeastOneUser(String, String)
...
CompanyPeopleDTO GetByNameWithPeople(String)
CompanyPeopleDTO GetByNameAndCityWithPeople(String,String)
CompanyPeopleActivityDTO GetByNameWithPeopleAndActivites(String)
...
有时会有一些非常具体的查询,比如:

CompanyAdmin1DTO GetComplexForAdmins1(String, String, String, String, Boolean, Boolean, int) // name,city,country,email, is deleted, is active, founded
CompanyAdmin2DTO GetComplexForAdmins2(String, String, String, Boolean) // name starts with, city starts with, have users
CompanyAdmin3DTO GetComplexForAdmins3(String, String, String, int) // name OR city AND have users
我们最终得到了大量的fetch方法,而实际的逻辑方法正在丢失。 是否有更好的命名约定或完全不同的方法?(不公开域/持久性)
web/服务层在物理上是分开的,所以WCF是必须的。

我喜欢将过滤器传递给一般的get问题,类似这样的问题

IEnumerable<stuff> GetTheStuff(params Func<stuff, bool> filters)
{
    IQueryable<stuff> resultList = DAL.Stuff.Queryable;
    foreach (var filter in filters)
    {
        resultList = resultList.Where(filter);
    }
}
如果在调用中需要显式,甚至可以将过滤器表示为参数

var NamedGreat = stuff => stuff.Name.Contains("great stuff");
var CreatedIn1900 = stuff => stuff.CreationDate.Year == 1900;

GetStuff(NamedGreat, CreatedIn1900);
在此基础上,您有很多变体,但它应该可以帮助您避免方法的过度显式重载



这将公开部分域,但您可以创建能够针对DTO表示的筛选器(例如)。注意不要将过滤器应用于对象的解析列表(如DTO本身),因为这意味着您正在查询整个数据库,而不是在其中进行过滤

您可以这样表示GetCompany操作:

CompanyDTO GetCompany(CompanyQueryBase query)
其中CompanyQueryBase是一个抽象类,并从中派生以下数据协定:

CompanyNameQuery
CompanyNameAndCityQuery
CompanyNameOrCityQuery
CompanyStartsWithNameOrStartsWithCityQuery
CompanyNameOrStartsWithCityQuery
CompanyNameOrStartsWithCityAndAtLeastOneUserQuery
如果愿意,可以将逻辑附加到查询类,但我更喜欢使用某种查询处理程序工厂,它将为您提供一个可以处理和执行此类查询的类。这意味着,基本上当前所有与公司相关的操作都将变成“Handler”类,剩下的GetCompany操作将只调用工厂并执行查询,例如:

CompanyDTO GetCompany(CompanyQueryBase query)
{
   // _queryHandlerFactory is a member of the service class
   // it is best to use DI for injecting the specific query handler factory
   // as a dependency to the class
   var queryHandler = _queryHandlerFactory.GetHander(query);
   return queryHandler.Execute();
}
这将允许您保持当前逻辑基本不变,只公开一个Get方法(对于公司),并且易于扩展以支持将来需要支持的查询


然而,这个解决方案有一个令人讨厌的小问题。您的客户机将不知道CompanyQueryBase是一个抽象类(这是因为DataContractSerializer不支持xsd抽象复杂类型声明,而XmlSerializer则不支持),这意味着您的客户机将能够意外地向您发送CompanyQueryBase,这将导致服务端出现异常,无法实例化抽象类(因为服务知道其抽象)

可能有其他选择,但我知道这些都是表面的方法,可能看起来一团糟。。但归根结底,façades试图在使用底层域时解决复杂性问题。服务中的域是隔离的,因此不暴露于UI。这在服务层中非常有效。您可以将过滤器表示为参数,请参见编辑
CompanyDTO GetCompany(CompanyQueryBase query)
{
   // _queryHandlerFactory is a member of the service class
   // it is best to use DI for injecting the specific query handler factory
   // as a dependency to the class
   var queryHandler = _queryHandlerFactory.GetHander(query);
   return queryHandler.Execute();
}