質問

I wonder if any one can point me in the right direction?

I am using the UOW repository pattern and have my dependencies injected via Ninject. I have a UnitOfWorkMapping class which inherits from NinjectModule, which I use to bind my IUnitOfWork to a concrete implementation of Dbcontext, see below

public class UnitOfWorkMapping : NinjectModule
{
    public override void Load()
    {
        Bind<IUnitOfWork>()
            .To<WebsiteDbContext>()
            .InRequestScope()
            .WithConstructorArgument(
                "connectionString",
                ConfigurationManager.ConnectionStrings[ConnectionStringKeys.UnauthorisedUser]
                    .ConnectionString);

        // Objects that explicitly need a DB context for the life of the request
        Bind<IUnitOfWorkInRequestScope>()
            .To<WebsiteDbContext>()
            .InRequestScope()
            .WithConstructorArgument(
                "connectionString",
                ConfigurationManager.ConnectionStrings[ConnectionStringKeys.UnauthorisedUser]
                    .ConnectionString);

        // Objects that specificall need a DB context for the life of the application
        Bind<IUnitOfWorkInApplicationScope>()
            .To<WebsiteDbContext>()
            .InSingletonScope()
            .WithConstructorArgument(
                "connectionString",
                ConfigurationManager.ConnectionStrings[ConnectionStringKeys.UnauthorisedUser]
                    .ConnectionString);
    }
}

So this gets called when the application starts and provides my site user with a context for an unauthorised user. This context has a database connection which connects to a database User which has limited access to the database objects.

Once the user has logged in to site I would like to switch to another connection which will give the context access to a Database user with wider access to the database objects.

So by the time the code execution reaches the true condition block for "if (Request.IsAuthenticated)" it is already using the "authorised" database connection for the context.

    /// <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)
        {
            var roleRepository =
                (IRoleRepository)DependencyResolver.Current.GetService(typeof(IRoleRepository));
            roles = roleRepository.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;
    }

I haven't been able to find a code example on the net that is close enough to my code to adapt and implement. Please can any one advise? Thank you in advance.

A link to the complete code can be provided if required.

Solution: Ok, so with the tireless help of Erik we have got there. The solution I am using is as so..

public class UnitOfWorkMapping : NinjectModule
{
    public override void Load()
    {
        // Bind the IUnitOfWork for a user that is not logged in.
        Bind<IUnitOfWork>()
            .To<WebsiteDbContext>()
            .When(request => IsUserAuthenticated(request))
            .WithConstructorArgument(
                "connectionString", ConfigurationManager.ConnectionStrings[ConnectionStringKeys.MainUserConnectionString]
                    .ConnectionString);

        // Bind the IUnitOfWork for a user that is not logged in.
        Bind<IUnitOfWork>()
            .To<WebsiteDbContext>()
            .When(request => !IsUserAuthenticated(request))
            .WithConstructorArgument(
                "connectionString", ConfigurationManager.ConnectionStrings[ConnectionStringKeys.UnauthorisedUser]
                    .ConnectionString);

    }

    /// <summary>
    /// Determines if the user authenticated.
    /// </summary>
    /// <param name="request">The Ninject Activation request.</param>
    /// <returns>
    /// returns <c>true</c> if the user exists and is authenticated
    /// </returns>
    public Boolean IsUserAuthenticated(IRequest request)
    {
        return (
            (HttpContext.Current.User != null) &&
            HttpContext.Current.User.Identity.IsAuthenticated);
    }
}

I hope that helps someone not spend days trying to get to the bottom of this issue.

役に立ちましたか?

解決

If you want to use different bindings for whether a user is logged in or out, it's very simple.

Bind<IUnitOfWork>()
   .To<WebsiteDbContext>()
   .When(x => !HttpContext.Current.Request.IsAuthenticated)
   .InRequestScope()
   .WithConstructorArgument(
       "connectionString",
        ConfigurationManager.ConnectionStrings[ConnectionStringKeys.UnauthorisedUser]
           .ConnectionString);

Bind<IUnitOfWork>()
    .To<WebsiteDbContext>()
    .When(x => HttpContext.Current.Request.IsAuthenticated)
    .InRequestScope()
    .WithConstructorArgument(
        "connectionString",
        ConfigurationManager.ConnectionStrings[ConnectionStringKeys.AuthorisedUser]
           .ConnectionString);

Note that these both have the same IUnitOfWork binding, it will simply return the correct one based on whether the user is logged in or not.

I would also do this:

Bind<IIdentity>()
    .To<WebIdentity>()
     ...

Bind<IIdentity>()
    .ToMethod(x => HttpContext.Current.User.Identity)
    .WhenInjectedInto(typeof(WebIdentity))
    ...

Bind<IPrincipal>()
    .To<WebsitePrincipal>()
    ...

Then, configure your WebsitePrincipal's constructor to take IIdentity and IApplicationConfiguration parameters, make WebIdentity's constructor take IIdentity and IRoleRepository as parameters (note the .WhenInjectedInto uses the existing Identity). Have your constructors do the work.

Then you need only write the following (DI takes care of the rest):

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
    HttpContext.Current.User = DependencyResolver.Current.GetService(typeof(IPrincipal));
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top