Как НЕ использовать DependencyResolver.Current.GetService () в этой ситуации

Следуя совету, который я получил в этой ветке [Ninject UOW шаблон, новая строка ConnectionString после аутентификации пользователя Теперь я понимаю, что мне не следует использовать следующую строку ...

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

... как Service Locator - это антипаттерн.

Но в случае следующей процедуры, как я могу создать экземпляр своего конкретного объекта, реализующего "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>();
    }
}

Конфигурация приложения

public class ApplicationConfiguration : IApplicationConfiguration
{
    .
    .
    .
    .
}

Я использую Ninject в качестве своей структуры внедрения зависимостей. Любые предложения приветствуются.

РЕДАКТИРОВАТЬ: Полный код можно увидеть здесь: https://github.com/dibley1973/Dibware.Template.Presentation.Web


person Dib    schedule 19.05.2014    source источник


Ответы (2)


Вы не можете предотвратить необходимость вызова контейнера DI или абстракции над ним в вашем Application_PostAuthenticateRequest, но это не должно быть проблемой, поскольку этот 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()
    {
        // ...
    }
}
person Steven    schedule 19.05.2014
comment
Ооо, это выглядит довольно мило, спасибо. Я попробую и обратную связь. - person Dib; 19.05.2014
comment
Это работает и выглядит красиво и аккуратно. Спасибо - person Dib; 19.05.2014

Следуя предложению Стивена, окончательный код был:

Новый интерфейс «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);
    }
.
.
}
person Dib    schedule 19.05.2014