So i have gotten stuck while trying to get my asmx webservice to use dependency injection and using an IoC to do it. I want my webservice to be able to use my internal business layer services. The webservice is to be used by an external client from a different domain and will mainly be used to send and recieve information about entities such as Orders and Customers.
An example would be:
public class MyService : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return new MyBusinessService().MyMethod();
}
}
public class MyBusinessService : IMyBusinessService
{
public string MyMethod()
{
return "hello";
}
}
I want to use dependency injection to eliminate the need for "newing" up my service but i cant figure out a way to do this. I can get it to work using poor mans DI, or at least i think it's called "poor mans".
like this:
public class MyService : System.Web.Services.WebService
{
private IMyBusinessService _myService;
public MyService(IMyBusinessService myService)
{
_myService = myService;
}
public MyService() : this(new MyBusinessServie()) { }
[WebMethod]
public string HelloWorld()
{
return _myService.MyMethod();
}
}
But I simply cant get my head around how to use a IoC container to inject my dependencies because i cant get the service to run without a parameterless constructor. Please be kind, i am not an experienced programmer and have just started to test dependency injection and got it to work fine on my windows forms application with structuremap but got stuck on this one.
Unfortunately there isn't any way for one to perform constructor injection with web services in ASP.NET. It is a requirement of ASP.NET that you provide a default constructor. The constructor of MyService is about as close to the composition root that you can get with this type of web service, without using a DI container.
With ASP.NET it is not unusual to have multiple composition roots. Which can be the constructors of the individual web services and web pages. If you are using ASP.NET MVC it is the ControllerFactory, which is more DI friendly.
With your implementation the important part isn't to move the construction of the object graph from the web service, as this is your composition root. The main thing to do, is to keep the web service as thin as possible, keep most of the logic in the dependency so it can be tested, or reused. Pulling information out of the HTTP headers is an example of a task that the web service could to then pass off that information to the dependency.
A good book to refer to for DI patterns and techniques is Dependency Injection in .NET by Mark Seemann.
If your web service implemented System.Web.IHttpHandler
instead of deriving from System.Web.Services.WebService
you could implement your DI like so:
Global.ashx.cs
public class Global : HttpApplication
{
protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
var needsMyBusinessService = context.Handler as INeedMyBusinessService;
if (needsMyBusinessService != null)
needsMyBusinessService.MyBusinessService = new MyBusinessService();
}
}
MyService.ashx.cs
public class MyService : IHttpHandler, INeedMyBusinessService
{
public IMyBusinessService MyBusinessService { get; set; }
public bool IsReusable { get { return true; } }
public void ProcessRequest(HttpContext context)
{
// uses my dependency
}
}
INeedMyBusinessService.cs
public interface INeedMyBusinessService
{
IMyBusinessService MyBusinessService { get; set; }
}
However the catch with this implementation is that is does not work with web services that implement System.Web.Services.WebService
as the web service object is not initialized until after the PreRequestHandlerExecute
event is call, which is the last event before ProcessRequest
is called.
The above example works if you want to have a unique instance for each web service. If you wanted to have the same instance (Singleton lifecycle) of MyBusinessService
for each web service request you could implement the Global.ashx.cs file like so:
public class Global : HttpApplication
{
private static IMyBusinessService businessService;
protected void Application_Start(object sender, EventArgs e)
{
Global.businessService = new MyBusinessService();
}
protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
var needsMyBusinessService = context.Handler as INeedMyBusinessService;
if (needsMyBusinessService != null)
needsMyBusinessService.MyBusinessService = Global.businessService;
}
}