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

时间:2014-10-08 09:49:03

标签: c# .net web-services wcf soa

我们将核心Web应用程序重构为3层SOA架构:

  • 演示文稿(asp mvc)
  • 服务层(wcf,net.tcp)
  • persistence(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

我们最终得到了大量的获取方法,其中实际的逻辑方法正在丢失。 是否有更好的命名约定,甚至是完全不同的方法?(不暴露域/持久性) Web /服务层是物理隔离的,因此必须使用WCF。

2 个答案:

答案 0 :(得分:1)

我喜欢将过滤器传递给一般的get问题,就像那样

IEnumerable<stuff> GetTheStuff(params Func<stuff, bool> filters)
{
    IQueryable<stuff> resultList = DAL.Stuff.Queryable;
    foreach (var filter in filters)
    {
        resultList = resultList.Where(filter);
    }
}

(语法是近似的,我没有IDE方便)

优势在于,您可以在调用中组合任何过滤器,以使其满足您的需求:查询保持明确,您不会因Get*签名过载而导致

GetStuff(stuff => stuff.Name.Contains("great stuff"), stuff => stuff.CreationDate.Year == 1900 );

如果您需要明确调用

,您甚至可以将过滤器表达为参数
var NamedGreat = stuff => stuff.Name.Contains("great stuff");
var CreatedIn1900 = stuff => stuff.CreationDate.Year == 1900;

GetStuff(NamedGreat, CreatedIn1900);

在此基础上有很多变化,但它应该可以帮助您避免过度显式的方法重载。


这会暴露部分域,但您可以创建能够针对DTO表示的过滤器(例如)。注意虽然没有将过滤器应用于已恢复的对象列表(例如DTO本身),但是这意味着您将查询整个数据库而不是在其中进行过滤

答案 1 :(得分:0)

samy提议的变体如下:

您可以像这样表达GetCompany操作:

CompanyDTO GetCompany(CompanyQueryBase query)

其中,CompanyQueryBase是一个抽象类,其中包含以下数据协定:

CompanyNameQuery
CompanyNameAndCityQuery
CompanyNameOrCityQuery
CompanyStartsWithNameOrStartsWithCityQuery
CompanyNameOrStartsWithCityQuery
CompanyNameOrStartsWithCityAndAtLeastOneUserQuery

如果您愿意,可以将逻辑附加到查询类,但我更喜欢使用某种查询处理程序工厂,它将为您提供可以处理和执行此类查询的类。这意味着基本上所有当前与公司相关的操作都将转变为“处理程序”类,剩下的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,这将导致在服务端的异常中无法实例化抽象类(因为服务知道它的抽象)。