在一个类中使用 Unity.BuildUp 会破坏其他类中的注入

发布于 2024-11-25 22:38:05 字数 7715 浏览 0 评论 0原文

我有一个会员资格提供商,它造成了依赖注入的问题。 我想了解为什么会发生

这是基本控制器的一些部分。 (它的工作原理应该如此。)

namespace Our.Web.Controllers
{
    public abstract partial class OurBaseController : VABController
    {
        //--------------------------------------
        //  EVENT DECLARATIONS
        //--------------------------------------

        //--------------------------------------
        //  CLASS CONSTANTS
        //--------------------------------------

        //--------------------------------------
        //  PRIVATE VARIABLES
        //--------------------------------------

        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        private UserInfo m_info;

        //--------------------------------------
        //  PROTECTED VARIABLES
        //--------------------------------------

        //--------------------------------------
        //  CONSTRUCTOR & INITIALIZATION
        //--------------------------------------

        protected override void Initialize(System.Web.Routing.RequestContext requestContext)
        {
            base.Initialize(requestContext);

            logger.Debug("Initializing OurBaseController.");

            m_info = UserInfoAccessor.GetCurrent();
        }

        //--------------------------------------
        //  GETTER/SETTERS
        //--------------------------------------

        [Dependency]
        public UserInfoAccessor UserInfoAccessor { get; set; }

        <snip>

    }
}

这是 Global.asax.cs 中统一注册的相关部分:

namespace OurWeb
{

    public class MvcApplication : System.Web.HttpApplication, IContainerAccessor
    {
        <snip>

        //--------------------------------------
        //  GETTER/SETTERS
        //--------------------------------------

        IUnityContainer IContainerAccessor.Container
        {
            get { return MvcUnityContainer.Container ; }
        }

        //--------------------------------------
        //  EVENT HANDLERS
        //--------------------------------------

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterRoutes(RouteTable.Routes);

            ConfigureUnity();

            <snip>
        }

        <snip>

        //--------------------------------------
        //  STATIC METHODS
        //--------------------------------------

        <snip>

        //--------------------------------------
        //  PRIVATE & PROTECTED INSTANCE METHODS
        //--------------------------------------

        private void ConfigureUnity()
        {
            //Create UnityContainer          
            IUnityContainer container = new UnityContainer()
                <snip>
                .RegisterType<UserInfoAccessor>()
                <snip>

            //Set container for Controller Factory
            MvcUnityContainer.Container = container;

            <snip>

            //Set Controller Factory as UnityControllerFactory
            ControllerBuilder.Current.SetControllerFactory(
                                typeof(UnityControllerFactory));
        }

        <snip>
    }
}

现在,当我添加自定义成员资格提供程序时,我无法注入它,因此我在构造函数中使用了 BuildUp。

namespace System.Web.Security
{
    public class OurMembershipProvider : SqlMembershipProvider
    {
        //--------------------------------------
        //  EVENT DECLARATIONS
        //--------------------------------------

        //--------------------------------------
        //  CLASS CONSTANTS
        //--------------------------------------

        //--------------------------------------
        //  PRIVATE VARIABLES
        //--------------------------------------

        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        //--------------------------------------
        //  PROTECTED VARIABLES
        //--------------------------------------

        //--------------------------------------
        //  CONSTRUCTOR & INITIALIZATION
        //--------------------------------------

        public OurMembershipProvider()
            : base()
        {
            // Can't inject so we'll ask the container to build the instance.
            IUnityContainer container = GetUnityContainer();
            container.BuildUp(this);
        }

        //--------------------------------------
        //  GETTER/SETTERS
        //--------------------------------------

        [Dependency]
        public UserInfoAccessor UserInfoAccessor { get; set; }

        //--------------------------------------
        //  PUBLIC METHODS
        //--------------------------------------

        public override bool ValidateUser(string username, string password)
        {
            //Sufficient for the question. In reality it contains account mapping validation logic.
            return base.ValidateUser(username, password);
        }

        //--------------------------------------
        //  EVENT HANDLERS
        //--------------------------------------

        //--------------------------------------
        //  STATIC METHODS
        //--------------------------------------

        //--------------------------------------
        //  PRIVATE & PROTECTED INSTANCE METHODS
        //--------------------------------------

        private IUnityContainer GetUnityContainer()
        {
            var context = HttpContext.Current;

            if (context == null)
                throw new Exception("No HttpContext");

            var accessor = context.ApplicationInstance as IContainerAccessor;

            if (accessor == null)
                throw new Exception("The global HttpApplication instance needs to implement " + typeof(IContainerAccessor).FullName);

            if (accessor.Container == null)
                throw new Exception("HttpApplication has no container initialized");

            return accessor.Container;
        }
    }
}

该类驻留在 MVC Web 项目中,因此我刚刚更改了 web.config,如下所示:

<!--<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression="" applicationName="/"/>-->
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.OurMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression="" applicationName="/"/>  

现在,当我完成此操作后,我在该行的 OurBaseController 构造函数中收到空引用异常: m_info = UserInfoAccessor.GetCurrent();

为什么当我注册此自定义会员资格提供程序时 Unity 不注入 UserInfoAccessor,但当我返回到标准会员资格提供程序时它却工作正常?
BuildUp 会干扰注射吗?

我在调试器或 elmah 中没有遇到任何其他异常。

解决方案 20110726

设置 UnityContainer 时创建了自定义成员资格对象。这使得容器不可用,并且初始化期间的异常使 UnityContainer 保持未初始化状态,这就是容器不可用的原因。

我从中学到了什么?
使用unity容器作为资源定位器是一个装满蠕虫的罐子。

为什么我在配置过程中错过了错误?
当我启动该网站时,我的网络浏览器打开了一个新选项卡。我放弃了它并刷新了较早的窗口。因此,我正在查看第二个请求的结果,其中该网站已经启动。

I've got a membership provider that creates a problem with dependency injection. I would like to understand why it happens.

This is some parts of a base controller. (It works like it should.)

namespace Our.Web.Controllers
{
    public abstract partial class OurBaseController : VABController
    {
        //--------------------------------------
        //  EVENT DECLARATIONS
        //--------------------------------------

        //--------------------------------------
        //  CLASS CONSTANTS
        //--------------------------------------

        //--------------------------------------
        //  PRIVATE VARIABLES
        //--------------------------------------

        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        private UserInfo m_info;

        //--------------------------------------
        //  PROTECTED VARIABLES
        //--------------------------------------

        //--------------------------------------
        //  CONSTRUCTOR & INITIALIZATION
        //--------------------------------------

        protected override void Initialize(System.Web.Routing.RequestContext requestContext)
        {
            base.Initialize(requestContext);

            logger.Debug("Initializing OurBaseController.");

            m_info = UserInfoAccessor.GetCurrent();
        }

        //--------------------------------------
        //  GETTER/SETTERS
        //--------------------------------------

        [Dependency]
        public UserInfoAccessor UserInfoAccessor { get; set; }

        <snip>

    }
}

Here's the relevant parts of the unity registration from Global.asax.cs:

namespace OurWeb
{

    public class MvcApplication : System.Web.HttpApplication, IContainerAccessor
    {
        <snip>

        //--------------------------------------
        //  GETTER/SETTERS
        //--------------------------------------

        IUnityContainer IContainerAccessor.Container
        {
            get { return MvcUnityContainer.Container ; }
        }

        //--------------------------------------
        //  EVENT HANDLERS
        //--------------------------------------

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterRoutes(RouteTable.Routes);

            ConfigureUnity();

            <snip>
        }

        <snip>

        //--------------------------------------
        //  STATIC METHODS
        //--------------------------------------

        <snip>

        //--------------------------------------
        //  PRIVATE & PROTECTED INSTANCE METHODS
        //--------------------------------------

        private void ConfigureUnity()
        {
            //Create UnityContainer          
            IUnityContainer container = new UnityContainer()
                <snip>
                .RegisterType<UserInfoAccessor>()
                <snip>

            //Set container for Controller Factory
            MvcUnityContainer.Container = container;

            <snip>

            //Set Controller Factory as UnityControllerFactory
            ControllerBuilder.Current.SetControllerFactory(
                                typeof(UnityControllerFactory));
        }

        <snip>
    }
}

Now when I add a custom membership provider, I couldn't inject into it, so I have used BuildUp in the constructor.

namespace System.Web.Security
{
    public class OurMembershipProvider : SqlMembershipProvider
    {
        //--------------------------------------
        //  EVENT DECLARATIONS
        //--------------------------------------

        //--------------------------------------
        //  CLASS CONSTANTS
        //--------------------------------------

        //--------------------------------------
        //  PRIVATE VARIABLES
        //--------------------------------------

        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        //--------------------------------------
        //  PROTECTED VARIABLES
        //--------------------------------------

        //--------------------------------------
        //  CONSTRUCTOR & INITIALIZATION
        //--------------------------------------

        public OurMembershipProvider()
            : base()
        {
            // Can't inject so we'll ask the container to build the instance.
            IUnityContainer container = GetUnityContainer();
            container.BuildUp(this);
        }

        //--------------------------------------
        //  GETTER/SETTERS
        //--------------------------------------

        [Dependency]
        public UserInfoAccessor UserInfoAccessor { get; set; }

        //--------------------------------------
        //  PUBLIC METHODS
        //--------------------------------------

        public override bool ValidateUser(string username, string password)
        {
            //Sufficient for the question. In reality it contains account mapping validation logic.
            return base.ValidateUser(username, password);
        }

        //--------------------------------------
        //  EVENT HANDLERS
        //--------------------------------------

        //--------------------------------------
        //  STATIC METHODS
        //--------------------------------------

        //--------------------------------------
        //  PRIVATE & PROTECTED INSTANCE METHODS
        //--------------------------------------

        private IUnityContainer GetUnityContainer()
        {
            var context = HttpContext.Current;

            if (context == null)
                throw new Exception("No HttpContext");

            var accessor = context.ApplicationInstance as IContainerAccessor;

            if (accessor == null)
                throw new Exception("The global HttpApplication instance needs to implement " + typeof(IContainerAccessor).FullName);

            if (accessor.Container == null)
                throw new Exception("HttpApplication has no container initialized");

            return accessor.Container;
        }
    }
}

The class resides in the MVC web project so I've just changed the web.config like this:

<!--<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression="" applicationName="/"/>-->
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.OurMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" passwordStrengthRegularExpression="" applicationName="/"/>  

Now when I have done this, I get a null reference exception in the constructor of OurBaseController on this row: m_info = UserInfoAccessor.GetCurrent();

How come Unity doesn't inject UserInfoAccessor when I register this custom membership provider, but it works fine when I go back to the standard one?
Does BuildUp disturb the injection?

I don't get any other exceptions in the debugger or in elmah.

RESOLUTION 20110726

The custom membership object got created when the UnityContainer was being set up. That made the container not being available and the exception during initialization made the UnityContainer stay uninitializad which was why the container it wasn't available.

What have I learned from this?
Using the unity container as a resource locator is a can full of worms.

Why did I miss the error during configuration?
When I started the site, my web browser opened a new tab. I discarded that and refreshed an earlier window. So I was looking at the result from the second request in which the site already had been started.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

行至春深 2024-12-02 22:38:05

自定义成员资格对象是在设置 UnityContainer 时创建的。这使得容器不可用,并且初始化期间的异常使 UnityContainer 保持未初始化状态,这就是容器不可用的原因。

我从中学到了什么?
使用unity容器作为资源定位器是一个装满蠕虫的罐子。

为什么我在配置过程中错过了错误?
当我启动该网站时,我的网络浏览器打开了一个新选项卡。我放弃了它并刷新了较早的窗口。因此,我正在查看第二个请求的结果,其中该网站已经启动。

The custom membership object got created when the UnityContainer was being set up. That made the container not being available and the exception during initialization made the UnityContainer stay uninitializad which was why the container it wasn't available.

What have I learned from this?
Using the unity container as a resource locator is a can full of worms.

Why did I miss the error during configuration?
When I started the site, my web browser opened a new tab. I discarded that and refreshed an earlier window. So I was looking at the result from the second request in which the site already had been started.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文