I am in the process of introducing a Dependency Injection framework into an existing WebForms application (using Castle Windsor).
I have pretty deep experience with DI, and tend to very strongly favor constructor injection over setter injection. If you are familiar with Webforms, you know that the ASP.Net framework handles the construction of page and control objects, making true constructor injection impossible.
My current solution is to register the container in the Application_Start event of the Global.asax, and keep the container as a public static variable in Global as well. I then simply resolve each service that I need directly in the page or control when I need them. So at the top of each page, I end up with code like this:
private readonly IMyService _exposureManager = Global.IoC.Resolve<IMyService>();
private readonly IMyOtherService _tenCustomersExposureManager = Global.IoC.Resolve<IMyOtherService>();
Obviously, I don't like having all these references to the container scattered about my application or having my page/control dependencies be non-explicit, but I have not been able to find a better way.
Is there a more elegant solution for using DI with Webforms?
ASP.NET Web Forms remains a popular framework for creating web apps. Even so, innovations in software development aren't slowing. All software developers need to stay abreast of new technologies and trends.
Web Forms is NOT deprecated, the framework support is limited to critical updates, but all ASP.NET full . NET Framework projects are fully supported. While we are not investing in the Web Forms framework, we still need to ensure that Web Forms developers can successfully develop their apps in Visual Studio.
ASP.NET Web Forms is a part of the ASP.NET web application framework and is included with Visual Studio. It is one of the four programming models you can use to create ASP.NET web applications, the others are ASP.NET MVC, ASP.NET Web Pages, and ASP.NET Single Page Applications.
NET 5, Microsoft's new direction has been on . NET Core, not . NET Framework, of which Web Forms is a part. It is impossible to run your ASP.NET Web Forms applications using .
I agree with @DarinDimitrov that MVP is an interesting option. However, when working with a legacy application, rewriting an existing page to the MVP pattern is a hell of a job. In that case it might be better to start with the Service Locator pattern (but only in your UI classes) as you are already doing. However, do change one thing. Do not expose the chosen DI container to the application, as I expect you are doing with the Global.IoC
property.
Instead, create a static Resolve<T>
method on the Global
class. This hides the container completely and allows you to swap implementations without having to change anything in your web pages. When you do this, there is no advantage in using the Common Service Locator as @Wiktor proposes. The Common Service Locator is just another abstraction for something that doesn't have to be abstracted (since you've already abstracted away the container using the Global.Resolve<T>
).
Unfortunately with Web forms, there is not really any good way to do this. For Simple Injector, I wrote an integration guide for Web Forms that basically describes the use of the Global.Resolve<T>
method, but also shows a way to tests if Page classes can be created. The guide can be used for other DI containers as well.
BTW, please keep in mind that with Castle Windsor, everything you request must be released explicitly (the Register Resolve Release pattern). This is a bit nasty (IMO) and differs from how other containers work and can be a source of memory leaks when you do not do this correctly.
Last note. It is possible to do constructor injection with Web Forms. Well... sort of, since this will call the overloaded constructor using reflection after the Form
has been created using the default constructor, so this causes Temporal Coupling.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With