簡體   English   中英

有什么方法可以將owin startup.cs配置為在全局asax應用程序啟動之前運行?

[英]Is there any way to configure owin startup.cs to be run before global asax application start?

我正在嘗試在MVC 5中實現每個請求的容器和每個請求的事務模式。我已經利用全局asax編寫了大部分代碼。 我在創建多個上下文時遇到了麻煩,因為owin正在創建新的DbContext類作為startup.cs的一部分。 有什么辦法可以在全局asax應用程序啟動事件之前運行owin,以便可以檢索在那里創建的現有上下文? 我是這些模式的新手,因此,如果這個問題聽起來不正確,我歡迎您提出替代建議。

public IContainer Container
{
    get
    {
        return (IContainer)HttpContext.Current.Items["_Container"];
    }
    set
    {
        HttpContext.Current.Items["_Container"] = value;
    }
}

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    ////Database.SetInitializer(new MigrateDatabaseToLatestVersion<ApplicationDbContext, Configuration>());


    DependencyResolver.SetResolver(
        new StructureMapDependencyResolver(() => Container ?? IoC.Container));

    IoC.Container.Configure(cfg =>
    {
        cfg.AddRegistry(new StandardRegistry());
        cfg.AddRegistry(new ControllerRegistry());
        cfg.AddRegistry(new ActionFilterRegistry(
            () => Container ?? IoC.Container));
        cfg.AddRegistry(new MvcRegistry());
        cfg.AddRegistry(new TaskRegistry());
        cfg.AddRegistry(new ModelMetadataRegistry());
    });

    using (var container = IoC.Container.GetNestedContainer())
    {

        foreach (var task in container.GetAllInstances<IRunAtInit>())
        {
            task.Execute();
        }

        foreach (var task in container.GetAllInstances<IRunAtStartup>())
        {
            task.Execute();
        }
    }
}

public void Application_BeginRequest()
{
    Container = IoC.Container.GetNestedContainer();

    foreach (var task in Container.GetAllInstances<IRunOnEachRequest>())
    {
        task.Execute();
    }
}

public void Application_Error()
{
    foreach (var task in Container.GetAllInstances<IRunOnError>())
    {
        task.Execute();
    }
}

public void Application_EndRequest()
{
    try
    {
        foreach (var task in
            Container.GetAllInstances<IRunAfterEachRequest>())
        {
            task.Execute();
        }
    }
    finally
    {
        Container.Dispose();
        Container = null;
    }
}

結構圖類

public class StructureMapDependencyResolver : IDependencyResolver
{
    private readonly Func<IContainer> _factory;

    public StructureMapDependencyResolver(Func<IContainer> factory)
    {
        _factory = factory;
    }

    public object GetService(Type serviceType)
    {
        if (serviceType == null)
        {
            return null;
        }

        var factory = _factory();

        return serviceType.IsAbstract || serviceType.IsInterface
            ? factory.TryGetInstance(serviceType)
            : factory.GetInstance(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return _factory().GetAllInstances(serviceType).Cast<object>();
    }

Owin的啟動-在啟動和每個請求時在Global ASAX之后執行,但在全局ASAX代碼之后執行。 我希望能夠將OWIN上下文設置為現有的上下文實例,或者先執行此代碼並獲取在啟動時創建的上下文。

    // For more information on configuring authentication, please visit https://go.microsoft.com/fwlink/?LinkId=301864
    public void ConfigureAuth(IAppBuilder app)
    {

        // Configure the db context, user manager and signin manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        // Configure the sign in cookie
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                // Enables the application to validate the security stamp when the user logs in.
                // This is a security feature which is used when you change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            }
        });            
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        // Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
        app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));

        // Enables the application to remember the second login verification factor such as phone or email.
        // Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
        // This is similar to the RememberMe option when you log in.
        app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);

        // Uncomment the following lines to enable logging in with third party login providers
        //app.UseMicrosoftAccountAuthentication(
        //    clientId: "",
        //    clientSecret: "");

        //app.UseTwitterAuthentication(
        //   consumerKey: "",
        //   consumerSecret: "");

        //app.UseFacebookAuthentication(
        //   appId: "",
        //   appSecret: "");

        //app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
        //{
        //    ClientId = "",
        //    ClientSecret = ""
        //});
    }
}

使用MVC 5,OWIN將始終在global.asax Application_Start()之后運行。 這是因為MVC應用程序托管OWIN。 僅使用MVC注冊的App_Start,讓OWIN處理配置和啟動要容易得多。 因此,我建議將您的容器注冊和Startup移動到Startup 像這樣:

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        DependencyResolver.SetResolver(
            new StructureMapDependencyResolver(IoC.Container));

        IoC.Container.Configure(cfg =>
        {
           ...
        });

        using (var container = IoC.Container.GetNestedContainer())
        {
            foreach (var task in container.GetAllInstances<IRunAtInit>())
            {
                task.Execute();
            }

            foreach (var task in container.GetAllInstances<IRunAtStartup>())
            {
                task.Execute();
            }
        }
    }
}

然后,在Application_BeginRequestApplication_EndRequestApplication_Error ,您可以通過DependencyResolver訪問容器。 例如:

public void Application_BeginRequest()
{
    foreach (var task in DependencyResolver.Current.GetServices<IRunOnEachRequest>())
    {
        task.Execute();
    }
}

請注意,這里沒有更多的Container屬性,並且隨后沒有嵌套的容器(啟動時除外)。 那是因為您的問題比管道計時更細微。 容器和按請求的事務模式實際上是關於生命周期 (特別是瞬態生命周期)的,在ASP.NET中,容器已經知道要解決每個請求。 因此,您無需重復這項工作。 StructureMap文檔比我能更好地解釋它。

旁注 :您可以在程序集中放置一個PreApplicationStart屬性,該屬性指示在Application_start之前要運行哪種方法,但是由於它是靜態方法,因此它實際上僅對靜態配置有用-IoC容器不是。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM