是否有时可以在域类中使用服务定位器模式?

时间:2012-03-21 14:38:20

标签: caching dependency-injection httpwebrequest domain-driven-design service-locator

这个问题可能更适合程序员堆栈。如果是这样,我会移动它。不过我想我可能会在这里得到更多答案。

到目前为止,我的域中的所有接口依赖项都是使用执行程序集中的DI解决的,目前这是一个.NET MVC3项目(+ Unity IoC容器)。但是,我遇到了一个场景,我认为服务定位器可能是更好的选择。

域中有一个实体存储(缓存)来自URL的内容。具体来说,它从元数据URL存储SAML2 EntityDescriptor XML。我有一个接口IConsumeHttp与一个方法:

public interface IConsumeHttp
{
    string Get(string url);
}

当前实现使用System.Net中的静态WebRequest类:

public class WebRequestHttpConsumer : IConsumeHttp
{
    public string Get(string url)
    {
        string content = null;
        var request = WebRequest.Create(url);
        var response = request.GetResponse();
        var stream = response.GetResponseStream();
        if (stream != null)
        {
            var reader = new StreamReader(stream);
            content = reader.ReadToEnd();
            reader.Close();
            stream.Close();
        }
        response.Close();
        return content;
    }
}

缓存XML内容的实体作为非root用户存在于更大的实体聚合中。对于聚合的其余部分,我实现了一个稍大的Facade模式,它是MVC控制器的公共端点。我可以在Facade构造函数中注入IConsumeHttp依赖项,如下所示:

public AnAggregateFacade(IDataContext dataContext, IConsumeHttp httpClient)
{
    ...

我看到的问题是,Facade中只有一个方法依赖于这个接口,因此为整个外观注入它似乎很愚蠢。 WebRequestHttpConsumer类的对象创建不应该增加很多开销,但域不知道这一点。

我正在考虑将实体的所有缓存逻辑移到一个单独的静态工厂类中。不过,代码仍将取决于IConsumeHttp。所以我想在静态工厂方法中使用静态服务定位器来解析IConsumeHttp,但是只有在需要初始化或刷新缓存的XML时才这样。

我的问题:这是个坏主意吗?在我看来,确保XML元数据被适当缓存应该是域的责任。域定期执行此操作作为其他相关操作的一部分(例如获取SAML Authn请求和响应的元数据,更新SAML EntityID或元数据URL等)。或者我只是担心它太多了?

2 个答案:

答案 0 :(得分:0)

  

在我看来,它应该是域名的责任   确保适当缓存XML元数据

我不确定,除非您的域名真的是关于元数据操作,http请求等等。对于具有非技术领域的“普通”应用程序,我宁愿处理基础架构/技术服务层中的缓存问题。

  

我看到的问题是,门面中只有一种方法有   依赖于这个接口,因此为它注入它似乎很愚蠢   整个门面

显然,Facades通常不适合构造函数注入,因为它们自然倾向于指向许多依赖项。您可以考虑其他类型的注射,或者正如您所指出的,使用定位器。但我个人所做的就是问自己,Facade是否真的合适,并考虑在我的所有控制器中使用更细粒度的对象而不是相同的大接口。这将允许更多的模块化和临时注入,而不是预先膨胀大型对象。

但这可能只是因为我不是门面的大粉丝;)

答案 1 :(得分:0)

在你对@ ian31的评论中,你提到“似乎让控制器确保域中有正确的XML过于细化,给客户太多的责任”。出于这个原因,我更喜欢控制器询问其服务/存储库(可以实现缓存层)以获得正确的&当前的XML。对我而言,这个责任对域实体要求很多。

但是,如果您对已经概述的职责感到满意,并且您提到对象创建的开销并不大,我认为将IConsumeHttp留在实体中就可以了。
坚持这一责任,另一种方法可能是将此界面移动到子实体中。如果您的情况可能,那么至少依赖性仅限于需要它的场景。