How can I implement Ninject or DI on asp.net Web Forms?

nellbryant picture nellbryant · Feb 8, 2011 · Viewed 27.2k times · Source

There are plenty of examples for having it worked on an MVC application. How is it done on Web Forms?

Answer

Joe Ratzer picture Joe Ratzer · May 25, 2011

Here are the steps to use Ninject with WebForms.

Step1 - Downloads

There are two downloads required - Ninject-2.0.0.0-release-net-3.5 and the WebForm extensions Ninject.Web_1.0.0.0_With.log4net (there is an NLog alternative).

The following files need to be referenced in the web application: Ninject.dll, Ninject.Web.dll, Ninject.Extensions.Logging.dll and Ninject.Extensions.Logging.Log4net.dll.

Step 2 - Global.asax

The Global class needs to derive from Ninject.Web.NinjectHttpApplication and implement CreateKernel(), which creates the container:

using Ninject; using Ninject.Web;

namespace Company.Web {
    public class Global : NinjectHttpApplication


        protected override IKernel CreateKernel()
        {
            IKernel kernel = new StandardKernel(new YourWebModule());
            return kernel;
        }

The StandardKernel constructor takes a Module.

Step 3 - Module

The Module, in this case YourWebModule, defines all the bindings the web application will need:

using Ninject;
using Ninject.Web;

namespace Company.Web
{
    public class YourWebModule : Ninject.Modules.NinjectModule
    {

        public override void Load()
        {
            Bind<ICustomerRepository>().To<CustomerRepository>();
        }   

In this example, wherever the ICustomerRepository interface is referenced the concrete CustomerRepository will be used.

Step 4 - Pages

Once that's done each page needs to inherit from Ninject.Web.PageBase:

  using Ninject;
    using Ninject.Web;
    namespace Company.Web
    {
        public partial class Default : PageBase
        {
            [Inject]
            public ICustomerRepository CustomerRepo { get; set; }

            protected void Page_Load(object sender, EventArgs e)
            {
                Customer customer = CustomerRepo.GetCustomerFor(int customerID);
            }

The InjectAttribute -[Inject] - tells Ninject to inject ICustomerRepository into the CustomerRepo Property.

If you already have a base page you just need to get your base page to derive from the Ninject.Web.PageBase.

Step 5 - Master Pages

Inevitably, you'll have master pages, and to allow a MasterPage to access injected objects you'll need to derive your master page from Ninject.Web.MasterPageBase:

using Ninject;
using Ninject.Web;

namespace Company.Web
{
    public partial class Site : MasterPageBase
    {

        #region Properties

        [Inject]
        public IInventoryRepository InventoryRepo { get; set; }     

Step 6 - Static Web Service Methods

The next problem was not being able to inject into static methods. We had a few Ajax PageMethods, which are obviously static, so I had to move the methods into a standard web service. Again, the web service needs to derive from a Ninject class - Ninject.Web.WebServiceBase:

using Ninject;
using Ninject.Web;    
namespace Company.Web.Services
{

    [WebService(Namespace = "//tempuri.org/">http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]    
    [System.Web.Script.Services.ScriptService]
    public class YourWebService : WebServiceBase
    {

        #region Properties

        [Inject]
        public ICountbackRepository CountbackRepo { get; set; }

        #endregion

        [WebMethod]
        public Productivity GetProductivity(int userID)
        {
            CountbackService _countbackService =
                new CountbackService(CountbackRepo, ListRepo, LoggerRepo);

In your JavaScript you'll need to reference the standard service - Company.Web.Services.YourWebService.GetProductivity(user, onSuccess), rather than PageMethods.GetProductivity(user, onSuccess).

The only other problem I found was injecting objects into User Controls. While it's possible to create your own base UserControl with Ninject capabilities, I found it quicker to add a Property to the user control for the required object and setting the Property in the container page. I think supporting UserControls out of the box is on the Ninject "to-do" list.

Adding Ninject is quite simple and it is an eloquent IoC solution. Many people like it because there is no Xml configuration. It has other useful "tricks" such as turning objects into Singletons with just the Ninject syntax - Bind<ILogger>().To<WebLogger>().InSingletonScope(). There is no need to change WebLogger into an actual Singleton implmentation, I like this.