views:

830

answers:

6

With regular ASP.NET MVC pages, the repository is passed in to the constructor of the control. Then the tests can instantiate the controller passing in a mock repository.

How can I do this with web services? The problem I see is that we don't have the equivalent of ControllerBuilder.SetControllerFactory.

What are the best practices to get my IoC framework (Castle) to instantiate my web service with the correct repository implementation?

I thought there might be a way to extend HttpHandler and change the way the web service is actually instantiated. I believe this is how the MVC framework does it.

+1  A: 

This is a good question. I have the same problem. I think that if you are creating web services using .asmx files, it is impossible to use constructor injection. If you were using WCF to implement the web service instead, then I think that it is possible.

In my .asmx web service I let the DI container set the dependencies by setting properties. As my application is also a web form asp.net application, than is how I have to do it, because I cannot use constructor injection on web forms either. But I'm using StructureMap, and it has a BuildUp function that can set properties of an already created object. Not as clean as constructor injection, but a good compromise.

But the web services differentiate themselves from the web forms, becuase I can place the buildup outside of the web form, in the Application_PostMapRequestHandler event. But I have not found out an event that is triggered after the web service class is created. Thus in the constructor of my web service, I have the following code

ObjectFactory.BuildUp(this);

And that is an anti pattern. A class that is initialized by a DI container should not know of the DI container itself. But I have not yet found a better solution.

Pete
A: 

Define a base class and use property injection in there. Pete already said it, but you would do: ObjectFactory.BuildUp(this);

The difference is that I would put it on a base class for the web services, so its "automatic" for the specific implementations.

That way its one line, so I wouldn't care about it unless you have the explicit need to switch DI containers at runtime (unlikely). If you still need that, just move the call to a separate class that would use the specific DI container.

eglasius
A: 

Is there any reason you can't create a custom class with the desired constructor, then instantiate an object of that class in your asmx, then delegate all action to that object?

I usually create those kinds of objects like this:

var o = CustomClass.Create();

public class CustomClass
{
  public static CustomClass Create()
  {
    return IoC.Resolve<CustomClass>();
  }
}

public static class IoC
{
  public T Resolve<T>()
  {
    return yourStaticReferenceToPreferredContainer.Resolve<T>();
  }
}
Thomas Eyde
A: 

What type of services are you creating? If your using WCF I wrote this:

http://davidkiff.co.uk/post/2009/08/28/WCF-Inversion-of-Control-e2809cService-Constructore2809d-and-better-Unit-Testing!.aspx

David Kiff
+1  A: 

I believe you are looking for the Castle Windsor WCF Integration Facility. It provides a ServiceHost implementation that takes over the construction process of your service implementations, utilizing the Windsor IOC. You can inject dependencies like any other IoC app using this facility, and conveniently enough, its part of the Castle project:

http://www.castleproject.org/container/facilities/trunk/wcf/index.html

If the Castle Project version does not do what you need it to do, I have my own facility that I created to do the same thing for Windsor before I found the Castle project's version. They both generally do the same thing, but both also approach the problem a little differently.

jrista
I guess the answer is "you can't use constructor injection with ASP.NET web services", so either use BuildUp(this) or use WCF with castle.
Brandon
Actually, you should be able to use Castle Windsor with ASMX style services (if that is what you mean). I thought you were asking about WCF, but I don't see why you couldn't integrate Windsor into the ASMX pipeline as well. It is probably not quite as easy as with WCF, but it shouldn't be impossible.
jrista
+1  A: 

MS actually have a solution to this: http://msdn.microsoft.com/en-us/library/ff664461(PandP.50).aspx

Liza