3

I am adding IoC to an already existing web forms project, and I am having a little trouble with getting the dependencies of user controls injected, especially dynamic user controls in a master page.

On the master page, I load some user controls:

protected override void OnLoad(EventArgs e)
    {
        bool processComplete = false;
        var page = Page as BasePage;
        if (page != null && HttpContext.Current.User.Identity.IsAuthenticated)
            processComplete = page.processComplete ;

        var segments = this.Request.Url.Segments;
        Control bodyheader = null;
        if (processComplete )
        {
            if (segments.Count() > 1 && segments[1].StartsWith("evaluation", true, System.Globalization.CultureInfo.CurrentCulture))
                bodyheader = Page.LoadControl("~/Themes/HWP/HeaderNoSearch.ascx");
            else
                bodyheader = Page.LoadControl("~/Themes/HWP/Header.ascx");
        }
        else if (segments.Count() > 1 && segments[1].StartsWith("welcome", true, System.Globalization.CultureInfo.CurrentCulture))
        {
            bodyheader = Page.LoadControl("~/Themes/HWP/plainHeaderAuth.ascx");
        }
        else
        {
            bodyheader = Page.LoadControl("~/Themes/HWP/plainHeaderAuth.ascx");
        }
        plcBodyHeader.Controls.Add(bodyheader);

        Control bodyfooter = Page.LoadControl("~/Themes/HWP/Footer.ascx");
        plcBodyFooter.Controls.Add(bodyfooter);

        base.OnLoad(e);
    }

Each of these user controls has some dependencies. I can manually inject the dependencies in each user control:

protected override void OnInit(EventArgs e)
{
    var cpa = (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance;
    var cp = cpa.ContainerProvider;
    cp.RequestLifetime.InjectProperties(this);
    base.OnInit(e);
}

But that seems like it defeats the purpose of using an IoC. How should the MasterPage -> Page -> UserControls be structured to allow for DI? And how do I inject properties in a dynamic user control? Should I be using constructor injection?

I am using Autofac, but I think this question id IoC agnostic.

Ethan Schofer
  • 1,718
  • 5
  • 26
  • 55

1 Answers1

3

You are on the right track. I normally create a BaseUserControl class which inherits from UserControl. Then inherit all UserControls from this BaseUserControl class.

Place all required dependencies inside that BaseUserControl class.

public class BaseUserControl : UserControl
{
    public ISomeService SomeService { get; set; }
    public IOtherService OtherService { get; set; }

    public BaseUserControl()
    {
        var cpa = (IContainerProviderAccessor)
            HttpContext.Current.ApplicationInstance;
        var cp = cpa.ContainerProvider;
        cp.RequestLifetime.InjectProperties(this);
    }
}

You might think that it is a bit wasted, because not all user controls use all dependencies.

Mark Seemann stated in Dependency Injection in .NET book that dependency injection is quite fast and never been an issue. If you think your application is slow, it will be from other places of your code (not from dependency injection).

If you want to use constructor injection, look at this answer.

Community
  • 1
  • 1
Win
  • 61,100
  • 13
  • 102
  • 181
  • OK. So in this case, the IoC will do the instantiating, but I still have to manually tell it to get started? I'll try that... – Ethan Schofer Dec 16 '14 at 15:29
  • `manually tell it to get started` No. BaseUserControl constructor will inject the dependencies to those properties automatically. – Win Dec 16 '14 at 16:33
  • It's not necessary to put the properties into the base class. You can create only required properties in derived controls. The injection will work fine. – Der_Meister Jan 02 '16 at 18:13
  • God bless you for this response. I was looking for a solution for 3 days now. It's working perfect. I added all the properties used in controls in the BaseControl class. It's easier this way. I only have 8 properties. Thanks again. I forgot to tell something: this solution is based on Autofac IOC. I used the same idea with unity. **var container = HttpContext.Current.Application.GetContainer(); container.BuildUp(this);** – sebastian.roibu Jul 22 '17 at 15:20