首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用ASP.NET WebForms动态加载WebUserControls的IoC

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

Stack Overflow用户
提问于 2014-06-13 16:27:17
回答 1查看 787关注 0票数 3

我正在尝试使用IoC加载web用户控件。我用的是统一性,我按照书中的例子来设置。到目前为止,还不错,但是当我注入外观单个控件本身的接口时,我遇到了一个问题。我试图使用LoadControl(类型、参数),但是没有加载web用户控件。

我环顾网络,找不到任何东西来帮助我使用IoC动态加载web用户控件。

你们中有谁有其他策略来装载它吗?你需要更多关于我的尝试的信息吗?

问候

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-06-13 21:55:00

让您的DI容器连接您的页面、HttpHandler和UserControls是绝对有可能的,但是没有任何内置的东西,所以您必须自己做。有两种方法可以做到这一点。您可以创建自定义PageHandlerFactory,也可以创建自定义HttpModule。由于连接PageHandlerFactory的唯一方法是通过web.config,所以我的首选是使用HttpModule。使用HttpModule时,可以使用System.Web.PreApplicationStartMethodAttribute (System.Web程序集)和Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility (Microsoft.Web.Infrastructure程序集)注册它。看起来是这样的:

代码语言:javascript
复制
[assembly: System.Web.PreApplicationStartMethod(typeof(ModuleInitializer), "Init")]

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

使用自定义HttpModule的诀窍是连接到应用程序的PreRequestHandlerExecute事件。这允许您在执行页面之前遍历页面层次结构并注入任何依赖项。

代码语言:javascript
复制
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 { ... }
}

这个模块只是确保在页面生活方式中很早就调用了Unity的BuildUp方法来构建PageIHttpHandler实例。这允许您将依赖项注入到Page类中,但不会在任何已使用的UserControl实例中注入任何依赖项。为此,模块调用特殊的PageInitializer.HookEventsForUserControlInitialization方法。这里的PageInitializer类是:

代码语言:javascript
复制
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);
        }
    }
}

PageInitializer类将进一步处理该过程,并将连接到页面的PreInitPreLoad事件,从而允许将依赖项注入母版页,并通过完整的控件层次结构将依赖项注入到任何UserControl中。它甚至链接到控件层次结构中任何DataBoundDataBoundControl事件,以确保由DataBoundControl加载的任何UserControl都被初始化。

我认为这应该是个好办法:-)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24209905

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档