Dependency Injection design pattern is widely used in modern applications. It decouples objects to the extent that no client code needs to be changed simply because an object it depends changes to a different one. It brings you a lot of benefits, like reduced dependency, more reusable code, more testable code, etc. in the past, it was very difficult to use Dependency Injection in WebForms application before. Starting from .NET 4.7.2, it is now easy for developers to use Dependency Injection in WebForms applications. With the UnityAdapter, you can add it to your existing WebForms application in 4 simple steps.
How to enable Dependency Injection in your existing WebForms application
Suppose you have a movie website which lists most popular movies in history. You use repository pattern to separate the logic that retrieves the data and maps it to the business entity. Currently you are creating business logic object and repository object in default.aspx page. The code looks like bellow.
Now simply follow 4 steps below, you will be able to adopt Dependency Injection to decouple the MovieManager from default.aspx page. The sample web application is on this Github repo. And you can use tag to retrieve the code change in each step.
1. Retarget the project to .NET Framework 4.7.2. (Git Tag: step-1)
Open project property and change the targetFramework of the project to .NET Framework 4.7.2. You would also need to change targetFramework in httpRuntime section in web.config file as illustrated below.
2. Install AspNet.WebFormsDependencyInjection.Unity NuGet package. (Git Tag: step-2)
3. Register types in Global.asax. (Git Tag: step-3)
4. Refactor Default.aspx.cs. (Git Tag: step-4)
Areas that Dependency Injection can be used
There are many areas you can use Dependency Injection in WebForms applications now. Here is a complete list.
- Pages and controls
- WebForms page
- User control
- Custom control
- IHttpHandler and IHttpHandlerFactory
- IHttpModule
- Providers
- BuildProvider
- ResourceProviderFactory
- Health monitoring provider
- Any ProviderBase based provider created by System.Web.Configuration.ProvidersHelper.InstantiateProvider. e.g. custom sessionstate provider
Summary
Using Microsoft.AspNet.WebFormsDependencyInjection.Unity NuGet package on .net framework 4.7.2, Dependency Injection can be easily added into your existing WebForms application. Please give it a try and let us know your feedback.
Here, you can find the NuGet package PosInformatique.AspNet.WebForms.DependencyInjection implementation which use the Microsoft.Extensions.DependencyInjection:
https://www.nuget.org/packages/PosInformatique.AspNet.WebForms.DependencyInjection/
How can we have dependencies with a per-request lifetime? Scoped?
How can we have dependencies with a per-request lifetime? As far as I can tell from looking at the source-code and disassembly of the NuGet packages this only supports a single container - effectively allowing only for Singleton and Transient dependencies - whereas almost every non-trivial web-application will need dependencies scoped a HTTP request's lifetime. Using per-thread lifetime is not a solution because threads outlive requests (due to thread-pooling) and can serve multiple requests.
An interesting blog post about this feature that discusses lifetimes: https://www.natmarchand.fr/aspnet-dependency-injection-net472/
How do we get HttpModules to be resolved using WebObjectActivator ?? Modules added both via web.config or by calling HttpApplication.RegisterModule are instantiated BEFORE Application_Start in global.asax and therefor before we have had the chance to set our WebObjectActivator.
Seems like a catch 22?
Would you expect this to work with User Controls loaded via Page.LoadControl()? At the moment I see an exception saying that the control has no parameterless constructor.
Same here. Report filed: https://developercommunity.visualstudio.com/content/problem/668468/user-control-fake-error-with-dependency-injection.html
https://github.com/aspnet/AspNetWebFormsDependencyInjection/issues/13
It would be great for Global class to support DI too. HttpRuntime.WebObjectActivator can be configured inside method designated by PreApplicationStartMethodAttribute and then used to resolve Global instances.