Following the advice I have been given in this thread [Ninject UOW pattern, new ConnectionString after user is authenticated I now understand that I should not use the following line...
var applicationConfiguration =
(IApplicationConfiguration)
DependencyResolver.Current.GetService(typeof(IApplicationConfiguration));
...as a Service Locator is an anti-pattern.
But in the case of the following procedure how can I instantiate my concrete object that implements "IApplicationConfiguration" so that I can use that object to get the unknown user role name, or use it to assign to the "ApplicationConfiguration" property of my principle?
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;
}
.
.
.
}
Resolution Mapping Code
public class ApplicationConfigurationContractMapping : NinjectModule
{
public override void Load()
{
Bind<IApplicationConfiguration>()
.To<ApplicationConfiguration>();
}
}
ApplicationConfiguration
public class ApplicationConfiguration : IApplicationConfiguration
{
.
.
.
.
}
I am using Ninject as my Dependency Injection framework. Any suggestions appreciated.
EDIT: Full code can be seen here: https://github.com/dibley1973/Dibware.Template.Presentation.Web
You can't prevent having to call either the DI Container or an abstraction over it in your Application_PostAuthenticateRequest
, but that shouldn't be a problem, since this Application_PostAuthenticateRequest
can be considered to be part of your Composition Root. Or in other words: you have to resolve it somewhere.
The problem in your case, however, is that this method contains an awful lot of code, and the real problem is that you are missing an abstraction. To resolve this, extract all logic of this method into a new class and hide it behind an abstraction. What will be left is the following code:
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
var provider = (IPostAuthenticateRequestProvider)
DependencyResolver.Current.GetService(typeof(IPostAuthenticateRequestProvider));
provider.ApplyPrincipleToCurrentRequest();
}
The code can be built up by your DI Container, and will have the following signature:
public class MvcPostAuthenticateRequestProvider : IPostAuthenticateRequestProvider
{
private readonly IApplicationConfiguration configuration;
public MvcPostAuthenticateRequestProvider(IApplicationConfiguration configuration)
{
this.configuration = configuration;
}
public void ApplyPrincipleToCurrentRequest()
{
// ...
}
}
Following Steven's suggestion, the final code was:
A new interface "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);
}
A concrete class that implements "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
}
And in 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);
}
.
.
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With