简体   繁体   English

ASP.NET WebForms使用IoC动态加载WebUserControls

[英]ASP.NET WebForms dynamic load WebUserControls using IoC

I'm trying to load web user controls using IoC. 我正在尝试使用IoC加载Web用户控件。 I'm using unity, I setup following the examples in the book. 我正在使用统一,我按照书中的例子设置。 So far so good, but when I inject the interface that looks the individual controls itself I've a problem. 到目前为止一切都那么好,但是当我注入看起来单独控件本身的界面时,我遇到了问题。 I'm trying to use LoadControl(type, arguments) but the web user control is not loaded. 我正在尝试使用LoadControl(类型,参数),但未加载Web用户控件。

I look around the web and I cannot find anything to help me dynamic load web user controls using IoC. 我环顾网络,找不到任何东西来帮助我使用IoC动态加载Web用户控件。

Any of you have other strategy to load it? 你们中的任何人都有其他加载策略吗? Do you need more info about my attempt? 您是否需要有关我的尝试的更多信息?

Regards 问候

Letting your DI container wire up your Page, HttpHandler and UserControls is absolutely possible with Web Forms, but there isn't anything built-in, so you'll have to do it yourself. 让你的DI容器连接你的Page,HttpHandler和UserControls绝对可以使用Web Forms,但是没有内置任何东西,所以你必须自己做。 There are two ways of doing this. 有两种方法可以做到这一点。 Either you create a custom PageHandlerFactory or you create a custom HttpModule . 您可以创建自定义PageHandlerFactory也可以创建自定义HttpModule Since the only way to hook in a PageHandlerFactory is through the web.config, my preference is using a HttpModule . 由于挂钩PageHandlerFactory的唯一方法是通过web.config,我的偏好是使用HttpModule When using an HttpModule , you can register it using the System.Web.PreApplicationStartMethodAttribute (System.Web assembly) and the Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility (Microsoft.Web.Infrastructure assembly). 使用HttpModule ,可以使用System.Web.PreApplicationStartMethodAttribute (System.Web程序集)和Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility (Microsoft.Web.Infrastructure程序集)注册它。 That would look like this: 这看起来像这样:

[assembly: System.Web.PreApplicationStartMethod(typeof(ModuleInitializer), "Init")]

public static class ModuleInitializer
{
    public static void Init()
    {
        DynamicModuleUtility.RegisterModule(
            typeof(WebFormsDependencyInjectionHttpModule));
    }
}

The trick with your custom HttpModule is to hook onto the application's PreRequestHandlerExecute event. 使用自定义HttpModule的技巧是挂钩应用程序的PreRequestHandlerExecute事件。 This allows you to go through the page hierarchy and inject any dependencies before the page is being executed. 这允许您在页面执行之前浏览页面层次结构并注入任何依赖项。

public class WebFormsDependencyInjectionHttpModule : IHttpModule {
    public static UnityContainer Container;
    private HttpApplication application;

    public void Init(HttpApplication context) {
        this.application = context;
        context.PreRequestHandlerExecute += this.PreRequestHandlerExecute;
    }

    public void Dispose() { }

    internal static void InitializeInstance(object instance) {
        Container.BuildUp(instance);
    }

    private void PreRequestHandlerExecute(object sender, EventArgs e) {
        if (Container == null) 
            throw new InvalidOperationException("Set Container first.");

        var handler = this.application.Context.CurrentHandler;
        if (handler != null) {
            InitializeHttpHandler(handler);
        }
    }

    private void InitializeHttpHandler(IHttpHandler handler) {
        InitializeInstance(handler);
        if (handler is Page) {
            PageInitializer.HookEventsForUserControlInitialization((Page)handler);
        }
    }
    private sealed class PageInitializer { ... }
}

This module just makes sure that Unity's BuildUp method is called very early in the page lifestyle to build up the Page or IHttpHandler instance. 这个模块只是确保在页面生活方式的早期调用Unity的BuildUp方法来构建PageIHttpHandler实例。 This allows you to inject dependencies into your Page classes, but won't inject any dependencies in any used UserControl instances. 这允许您将依赖项注入到Page类中,但不会在任何使用过的UserControl实例中注入任何依赖项。 To enable this, the module calls the special PageInitializer.HookEventsForUserControlInitialization method. 要启用此功能,模块将调用特殊的PageInitializer.HookEventsForUserControlInitialization方法。 Here the PageInitializer class is: 这里的PageInitializer类是:

internal sealed class PageInitializer {
    private HashSet<Control> alreadyInitializedControls = new HashSet<Control>();
    private Page page;

    internal PageInitializer(Page page) {
        this.page = page;
    }

    internal static void HookEventsForUserControlInitialization(Page page) {
        var initializer = new PageInitializer(page);
        page.PreInit += initializer.PreInit;
        page.PreLoad += initializer.PreLoad;
    }

    private void PreInit(object sender, EventArgs e) {
        this.RecursivelyInitializeMasterPages();
    }

    private void RecursivelyInitializeMasterPages() {
        foreach (var masterPage in this.GetMasterPages())
            this.InitializeUserControl(masterPage);
    }

    private IEnumerable<MasterPage> GetMasterPages() {
        MasterPage master = this.page.Master;

        while (master != null) {
            yield return master;
            master = master.Master;
        }
    }

    private void PreLoad(object sender, EventArgs e) {
        this.InitializeControlHierarchy(this.page);
    }

    private void InitializeControlHierarchy(Control control) {
        var dataBoundControl = control as DataBoundControl;

        if (dataBoundControl != null) {
            dataBoundControl.DataBound += this.InitializeDataBoundControl;
        } else {
            var userControl = control as UserControl;

            if (userControl != null)
                this.InitializeUserControl(userControl);

            foreach (var childControl in control.Controls.Cast<Control>()) {
                this.InitializeControlHierarchy(childControl);
            }
        }
    }

    private void InitializeDataBoundControl(object sender, EventArgs e) {
        var control = (DataBoundControl)sender;
        if (control != null) {
            control.DataBound -= this.InitializeDataBoundControl;
            this.InitializeControlHierarchy(control);
        }
    }

    private void InitializeUserControl(UserControl instance)
    {
        if (!this.alreadyInitializedControls.Contains(instance)) {
            WebFormsDependencyInjectionHttpModule.InitializeInstance(instance);
            // Ensure every user control is only initialized once.
            this.alreadyInitializedControls.Add(instance);
        }
    }
}

The PageInitializer class will take the process a step further and will hook onto the Page's PreInit and PreLoad events to allow dependencies to be injected into master pages and to go through the complete control hierarchy to inject dependencies into any UserControl . PageInitializer类将采取工艺更进了一步,将钩挂在页面的PreInitPreLoad的事件,让依赖注入到母版页和经过完全控制层次结构,以依赖注入任何UserControl It even hooks onto the DataBound event of any DataBoundControl in the control hierarchy, to make sure that any UserControl that is loaded by a DataBoundControl gets initialized. 它甚至挂钩到控件层次结构中任何DataBoundControlDataBound事件,以确保DataBoundControl加载的任何UserControl都被初始化。

I think this should do the trick :-) 我认为这应该做的伎俩:-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM