在这种情况下,我怎么不使用DependencyResolver.Current.GetService(...)

时间:2014-05-19 05:19:29

标签: c# dependency-injection ninject anti-patterns service-locator

按照我在这个帖子中给出的建议[Ninject UOW pattern, new ConnectionString after user is authenticated我现在明白我不应该使用以下行......

    var applicationConfiguration =
            (IApplicationConfiguration)
                DependencyResolver.Current.GetService(typeof(IApplicationConfiguration));

...作为服务定位器是一种反模式。

但是在以下过程的情况下,我如何实例化实现“ IApplicationConfiguration ”的具体对象,以便我可以使用该对象获取未知用户角色名称,或者使用它来分配到我原则的“ ApplicationConfiguration ”属性?

Global.asax中

public class MvcApplication : NinjectHttpApplication
{
    /// <summary>
    /// Handles the PostAuthenticateRequest event of the Application control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
    protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        String[] roles;
        var applicationConfiguration =
            (IApplicationConfiguration)
                DependencyResolver.Current.GetService(typeof(IApplicationConfiguration));
        var identity = HttpContext.Current.User.Identity;
        if (Request.IsAuthenticated)
        {
            roles = Roles.GetRolesForUser(identity.Name);
        }
        else
        {
            roles = new[] { applicationConfiguration.UnknownUserRoleName };
        }
        var webIdentity = new WebIdentity(identity, roles);
        var principal = new WebsitePrincipal(webIdentity)
        {
            ApplicationConfiguration = applicationConfiguration
        };

        HttpContext.Current.User = principal;
    }
    .
    .
    .
}

分辨率映射代码

    public class ApplicationConfigurationContractMapping : NinjectModule
{
    public override void Load()
    {
        Bind<IApplicationConfiguration>()
            .To<ApplicationConfiguration>();
    }
}

ApplicationConfiguration

public class ApplicationConfiguration : IApplicationConfiguration
{
    .
    .
    .
    .
}

我使用Ninject作为我的依赖注入框架。任何建议表示赞赏。

编辑:完整代码可以在这里看到: https://github.com/dibley1973/Dibware.Template.Presentation.Web

2 个答案:

答案 0 :(得分:14)

您无法阻止在Application_PostAuthenticateRequest中调用DI容器或对其进行抽象,但这不应该是一个问题,因为此Application_PostAuthenticateRequest可以被认为是其中的一部分你的Composition Root。换句话说:你必须在某个地方解决它。

然而,在您的情况下,问题是此方法包含大量代码,而真正的问题是您缺少抽象。要解决此问题,请将此方法的所有逻辑提取到新类中,并将其隐藏在抽象之后。剩下的是以下代码:

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
   var provider = (IPostAuthenticateRequestProvider)
       DependencyResolver.Current.GetService(typeof(IPostAuthenticateRequestProvider));

   provider.ApplyPrincipleToCurrentRequest();
}

代码可以由您的DI容器构建,并具有以下签名:

public class MvcPostAuthenticateRequestProvider : IPostAuthenticateRequestProvider
{
    private readonly IApplicationConfiguration configuration;

    public MvcPostAuthenticateRequestProvider(IApplicationConfiguration configuration)
    {
        this.configuration = configuration;
    }

    public void ApplyPrincipleToCurrentRequest()
    {
        // ...
    }
}

答案 1 :(得分:3)

根据史蒂文的建议,最终的代码是:

新界面“IPostAuthenticateRequestProvider”

/// <summary>
/// Defines the expected members of a PostAuthenticateRequestProvider
/// </summary>
internal interface IPostAuthenticateRequestProvider
{
    /// <summary>
    /// Applies a correctly setup principle to the Http request
    /// </summary>
    /// <param name="httpContext"></param>
    void ApplyPrincipleToHttpRequest(HttpContext httpContext);
}

实现“IPostAuthenticateRequestProvider”的具体类

/// <summary>
/// Provides PostAuthenticateRequest functionality
/// </summary>
public class MvcPostAuthenticateRequestProvider : IPostAuthenticateRequestProvider
{
    #region Declarations

    private readonly IApplicationConfiguration _configuration;

    #endregion

    #region Constructors

    public MvcPostAuthenticateRequestProvider(IApplicationConfiguration configuration)
    {
        _configuration = configuration;
    }

    #endregion

    #region IPostAuthenticateRequestProvider Members

    /// <summary>
    /// Applies a correctly setup principle to the Http request
    /// </summary>
    /// <param name="httpContext"></param>
    public void ApplyPrincipleToHttpRequest(HttpContext httpContext)
    {
        // declare a collection to hold roles for the current user
        String[] roles;

        // Get the current identity
        var identity = HttpContext.Current.User.Identity;

        // Check if the request is authenticated...
        if (httpContext.Request.IsAuthenticated)
        {
            // ...it is so load the roles collection for the user
            roles = Roles.GetRolesForUser(identity.Name);
        }
        else
        { 
            // ...it isn't so load the collection with the unknown role
            roles = new[] { _configuration.UnknownUserRoleName };
        }

        // Create a new WebIdenty from the current identity 
        // and using the roles collection just populated
        var webIdentity = new WebIdentity(identity, roles);

        // Create a principal using the web identity and load it
        // with the app configuration
        var principal = new WebsitePrincipal(webIdentity)
        {
            ApplicationConfiguration = _configuration
        };

        // Set the user for the specified Http context
        httpContext.User = principal;
    }

    #endregion
}

在global.asax中......

public class MvcApplication : NinjectHttpApplication
{
    /// <summary>
    /// Handles the PostAuthenticateRequest event of the Application control.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
    protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
        // Get a PostAuthenticateRequestProvider and use this to apply a 
        // correctly configured principal to the current http request
        var provider = (IPostAuthenticateRequestProvider)
            DependencyResolver.Current.GetService(typeof(IPostAuthenticateRequestProvider));
        provider.ApplyPrincipleToHttpRequest(HttpContext.Current);
    }
.
.
}