尝试配置多个.NET Core管道,HttpContext最终为空

时间:2019-02-02 00:24:39

标签: .net-core asp.net-core-mvc

我试图按照本指南在我的MVC应用中在API部分和MVC部分之间创建逻辑分隔:

https://www.strathweb.com/2017/04/running-multiple-independent-asp-net-core-pipelines-side-by-side-in-the-same-application/

这是我正在使用的扩展方法的实现:

    public static IApplicationBuilder UseBranchWithServices(this IApplicationBuilder app,
        PathString path, Action<IServiceCollection> servicesConfiguration,
        Action<IApplicationBuilder> appBuilderConfiguration)
    {
        var webhost = new WebHostBuilder()
            .UseKestrel()
            .ConfigureServices(servicesConfiguration)
            .UseStartup<StartupHarness>()
            .Build()
  /* ojO */ .CreateOrMigrateDatabase(); /* Ojo */

        var serviceProvider = webhost.Services;
        var featureCollection = webhost.ServerFeatures;
        var appFactory = serviceProvider.GetRequiredService<IApplicationBuilderFactory>();
        var branchBuilder = appFactory.CreateBuilder(featureCollection);
        var factory = serviceProvider.GetRequiredService<IServiceScopeFactory>();

        branchBuilder.Use(async (context, next) => {
            using (var scope = factory.CreateScope()) {
                context.RequestServices = scope.ServiceProvider;
                await next();
            }
        });

        appBuilderConfiguration(branchBuilder);

        var branchDelegate = branchBuilder.Build();

        return app.Map(path, builder => { builder.Use(async (context, next) => {
            await branchDelegate(context);
          });
        });
    }

当我尝试将其与SignInManager一起使用时,HttpContext始终为空。

这是我的AccountController的一个荒谬的简化版本:

    public AccountController(SignInManager<AppUser> mgr) {
        _mgr = mgr;
    }

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (ModelState.IsValid)
        {
            var result = await _mgr.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, lockoutOnFailure: false);
        }
    }

我是calling app.UseAuthentication(),在ApplicationBuilder中;为了简洁起见,我将该设置作为扩展方法。这有效:

    public void ConfigureServices(IServiceCollection services)
    {
        services.ConfigureMvcServices(Configuration);
    }

    public void Configure(IApplicationBuilder builder, IHostingEnvironment env)
    {
        builder.ConfigureMvcBuilder(env);
    }

这不是:

    public void Configure(IApplicationBuilder builder, IHostingEnvironment env)
    {
        builder.UseBranchWithServices(StaticConfiguration.RootPath,
            services =>
            {
                services.ConfigureMvcServices(Configuration); 
            },
            app => { app.ConfigureMvcBuilder(env); }
        );
        builder
            .Run(async c =>
                await c.Response.WriteAsync("This should work"));
    }

在后一个示例中,services对象以Count结尾,包含335个描述符,在前一个(有效)示例中,它具有356个描述符。

我尝试查看this blog以查看是否可以查明发生了什么,但是我看不出方法中的内容与Gordon所描述的内容之间有很强的相关性。所以我完全迷路了。任何帮助,将不胜感激。如果有办法拆分扩展方法并为每个管道传递服务,那对我来说很好。

是的,我知道您在这里只能看到一个管道。关键是要添加更多。

1 个答案:

答案 0 :(得分:0)

这就是我最终得到的:

这是解决此问题的错误方法。我需要一个配置正确的管道。我将我的API和Web项目组合到一个项目中(尽管这并不重要,只要所有内容都已注册)。

(出于其他原因,我添加了异步。与此无关。)

Program.cs:

        public static async Task Main(string[] args)
        {
            IWebHost webhost = CreateWebHostBuilder(args).Build();

            await webhost.CreateOrMigrateDatabase();

            await webhost.RunAsync();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            new WebHostBuilder()
                .ConfigureAppConfiguration((host, config) =>
                {
                    config.SetBasePath(Directory.GetCurrentDirectory());
                    config.AddJsonFile("appsettings.json");

                    if (host.HostingEnvironment.IsDevelopment())
                        config.AddUserSecrets<Startup>();
                    else
                        config.AddEnvironmentVariables(prefix: "MYAPP_");
                })
                .UseKestrel()
                .ConfigureLogging((app, logging) =>
                {
//snip
                })
                .UseStartup<Startup>()
                .UseUrls("http://*:4213");
    }

Startup.cs:

        public void ConfigureServices(IServiceCollection services)
        {
            var connString = Configuration.GetConnectionString("default");

            services.ConfigureJwt(_signingKey, Configuration);

            // https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-2.2#configure-localization
            services.AddLocalization(options => options.ResourcesPath = StartupConfiguration.ResourcesFolder);

            services.AddDbContext<AppDbContext>(builder =>
            {
                builder.UseLazyLoadingProxies()
                       .UseSqlServer(connString, with => with.MigrationsAssembly("App.Data"));
            });

            services.ConfigureAuthentication(Configuration);

            var mapperConfig = new MapperConfiguration(maps =>
            {
                maps.ConfigureMvc();
                maps.ConfigureApi();
            });
            var mapper = mapperConfig.CreateMapper();
            services.AddSingleton(mapper);

            // https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-2.2#configure-localization
            services.AddMvc() // (config => { config.Filters.Add(new AuthorizeFilter()); }) // <~ for JWT auth
                .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
                .AddDataAnnotationsLocalization()
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddSpaStaticFiles(angularApp =>
            {
                angularApp.RootPath = "dist"; // TODO
            }); 
//snip           
}

我拆分了地图(IMapper,不相关;它们只是为两个名称空间配置ViewModel的扩展方法),但我没有拆分管道。一个正确配置的管道,其中静态网站位于{folder} / dist。同时运行API和MVC项目。而且管理起来要少得多。

感兴趣的完整代码是here