Пытаясь настроить несколько конвейеров .NET Core, HttpContext заканчивается нулевым - PullRequest
0 голосов
/ 02 февраля 2019

Я пытаюсь следовать этому руководству, чтобы создать логическое разделение в моем приложении 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 всегда имеет значение null.

Вот нелепо упрощенная версия моего 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);
        }
    }

Я звоню 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.

Я попытался просмотреть этот блог , чтобы посмотреть, смогу ли я выяснить, что происходит, но я не вижу сильной корреляции между тем, что вметод и то, что Гордон описывает.Так что я полностью потерян.Любая помощь будет оценена.Если есть способ разделить метод расширения и передать службы для каждого конвейера, это будет хорошо для меня.

Да, я знаю, что вы видите здесь только один конвейер.Дело в том, чтобы добавить больше.

1 Ответ

0 голосов
/ 02 февраля 2019

Вот что у меня получилось:

Это был неправильный способ решения этой проблемы.Мне нужен был один правильно настроенный конвейер.Я объединил свои API и веб-проекты в один проект (хотя это, вероятно, не имеет значения, если все зарегистрировано).

(По другим причинам я добавил асинхронный. Ничего общего с этим.)

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, не связанные; они являются просто методами расширения для настройки ViewModelsдля двух пространств имен) но я не разделил конвейеры.Один правильно настроенный конвейер со статическим веб-сайтом в {folder} / dist.Запускает как API, так и проект MVC.И управлять им намного меньше.

Полный код для заинтересованных: здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...