1

This question may be more appropriate for the Programmers stack. If so, I will move it. However I think I may get more answers here.

So far, all interface dependencies in my domain are resolved using DI from the executing assembly, which for now, is a .NET MVC3 project (+ Unity IoC container). However I've run across a scenario where I think service locator may be a better choice.

There is an entity in the domain that stores (caches) content from a URL. Specifically, it stores SAML2 EntityDescriptor XML from a metadata URL. I have an interface IConsumeHttp with a single method:

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

The current implementation uses the static WebRequest class in System.Net:

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;
    }
}

The entity which caches the XML content exists as a non-root in a much larger entity aggregate. For the rest of the aggregate, I am implementing a somewhat large Facade pattern, which is the public endpoint for the MVC controllers. I could inject the IConsumeHttp dependency in the facade constructor like so:

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

The issue I see with this is that only one method in the facade has a dependency on this interface, so it seems silly to inject it for the whole facade. Object creation of the WebRequestHttpConsumer class shouldn't add a lot of overhead, but the domain is unaware of this.

I am instead considering moving all of the caching logic for the entity out into a separate static factory class. Still, the code will depend on IConsumeHttp. So I'm thinking of using a static service locator within the static factory method to resolve IConsumeHttp, but only when the cached XML needs to be initialized or refreshed.

My question: Is this a bad idea? It does seem to me that it should be the domain's responsibility to make sure the XML metadata is appropriately cached. The domain does this periodically as part of other related operations (such as getting metadata for SAML Authn requests & responses, updating the SAML EntityID or Metadata URL, etc). Or am I just worrying about it too much?

Shankar Narayana Damodaran
  • 68,075
  • 43
  • 96
  • 126
danludwig
  • 46,965
  • 25
  • 159
  • 237
  • 1
    related: http://stackoverflow.com/questions/4835046/why-not-use-an-ioc-container-to-resolve-dependencies-for-entities-business-objec – Steven Mar 21 '12 at 15:11
  • IMO this is a valid question for SO. – Steven Mar 21 '12 at 15:11
  • @Steven thanks for the link, the vote of confidence, and your blogs on how you roll with the query + command sides of your architecture. Very interesting stuff. – danludwig Mar 21 '12 at 16:31

2 Answers2

0

It does seem to me that it should be the domain's responsibility to make sure the XML metadata is appropriately cached

I'm not sure about that, unless your domain is really about metadata manipulation, http requests and so on. For a "normal" application with a non-technical domain, I'd rather deal with caching concerns in the Infrastructure/Technical Services layer.

The issue I see with this is that only one method in the facade has a dependency on this interface, so it seems silly to inject it for the whole facade

Obviously, Facades usually don't lend themselves very well to constructor injection since they naturally tend to point to many dependencies. You could consider other types of injection or, as you pointed out, using a locator. But what I'd personnaly do is ask myself if a Facade is really appropriate and consider using finer-grained objects instead of the same large interface in all of my controllers. This would allow for more modularity and ad-hoc injection rather than inflating a massive object upfront.

But that may just be because I'm not a big Facade fan ;)

guillaume31
  • 13,738
  • 1
  • 32
  • 51
  • Thanks for your input. The domain is not about HTTP, and does not reference System.Web, MVC, or any dlls like that, which is why I wrapped the HttpConsumer in an interface. This is the only case where it is used in the domain. The controller deals with SAML http things and uses the metadata for ops such as sending Authn requests. It seems like making the controller ensure the domain has the correct XML is too granular, giving the client too much responsibility. The domain already knows the URL, and can do this itself. You do have a point though and I am looking into other patterns. – danludwig Mar 22 '12 at 14:41
0

In your comment to @ian31, you mention "It seems like making the controller ensure the domain has the correct XML is too granular, giving the client too much responsibility". For this reason, I'd prefer the controller asks its service/repository (which can implement the caching layer) for the correct & current XML. To me, this responsibility is a lot to ask of the domain entity.

However, if you're OK with the responsibilities you've outlined, and you mention the object creation isn't much overhead, I think leaving the IConsumeHttp in the entity is fine.
Sticking with this responsibility, another approach could be to move this interface down into a child entity. If this was possible for your case, at least the dependency is confined to the scenario that requires it.

Chris Melinn
  • 2,046
  • 1
  • 17
  • 18
  • thanks for the answer and sorry for the late reply. In this project, there is no service layer. The MVC project accesses the domain surface directly, using factory & facade patterns. The IConsumeHttp dependency is not on a domain entity, it is on another domain class. Ultimately the metadata is stored on a domain entity property, but it is not an entity that performs the HTTP lookup. Also, when I say "cache", I don't mean using in-memory caching. I mean that the XML content is stored on an entity, and periodically refreshed using the metadata URL. – danludwig Apr 02 '12 at 20:17