在这种情况下,我如何不使用DependencyResolver.Current.GetService(…)?

本文关键字:GetService Current DependencyResolver 这种情况下 何不使 | 更新日期: 2023-09-27 18:04:11

根据我在这个线程中给出的建议[Ninject UOW模式,用户经过身份验证后的新ConnectionString,我现在明白我不应该使用以下行…

    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作为我的依赖注入框架。欢迎提出建议。

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

在这种情况下,我如何不使用DependencyResolver.Current.GetService(…)?

你不能阻止在Application_PostAuthenticateRequest中调用DI容器或抽象,但这应该不是问题,因为这个Application_PostAuthenticateRequest可以被认为是你的组合根的一部分。或者换句话说:你必须在某个地方解决它。

在您的例子中,问题是这个方法包含了大量的代码,原因是您缺少一个抽象。要解决这个问题,可以将该方法的所有逻辑提取到一个新类中,并将其隐藏在抽象之后。剩下的代码如下:

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()
    {
        // ...
    }
}

根据Steven的建议,最后的代码是:

一个新的接口"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);
    }
.
.
}