Добавление параметров Mvc отдельно после добавления сервисов Mvc - PullRequest
0 голосов
/ 25 февраля 2019

Вопрос, очень специфичный для Net Core.Я хотел бы написать метод расширения для IServiceCollection, который будет выполнять настройку в приложении.

Причина тому, что в настоящее время некоторые компоненты, такие как атрибут и контроллер, расположены в отдельных библиотеках.Итак, я хотел бы написать метод расширения, который позаботится о конфигурации для каждой из этих библиотек. Конфигурация должна быть независимой от конфигурации основного приложения.

Вот текущий код (который мне не нравится по вышеуказанной причине):

public void ConfigureServices(IServiceCollection services)
{
    //..
    services.AddMvc(options => {
            // is needed for the library "filters". 
            options.Filters.Add(typeof(ExternalValidationActionFilterAttribute));
        })
        // is needed for the library "controllers"
        .AddApplicationPart(typeof(ExternalController).Assembly)
        .AddControllersAsServices();

    //..
    services.AddSingleton<ExternalControllerConfiguration>(new ExternalControllerConfiguration());
    services.AddSingleton<ExternalValidationAttributeConfiguration>(new ExternalValidationAttributeConfiguration());
}

Единственный метод из основного приложения - AddMvc().Остальная часть кода специфична для внешних библиотек .Я хотел бы избежать смешивания логики, специфичной для внешней библиотеки, с логикой основного приложения.В идеале рефакторинг кода должен выглядеть следующим образом:

public void ConfigureServices(IServiceCollection services)
{
    //..
    services.AddMvc();
    services.ConfigureExternalAttributes();
    services.ConfigureExternalControllers();
    //..
}

и

public static class ServiceCollectionExtensions
{
    public static void ConfigureExternalAttributes(this IServiceCollection services)
    {
        // TBD: check if Mvc services added
        //      if not - add new, with options
        //      if yes - add options to existing
        //          options.Filters.Add(typeof(ExternalValidationActionFilterAttribute));

        services.AddSingleton<ExternalValidationAttributeConfiguration>(new ExternalValidationAttributeConfiguration());
    }

    public static void ConfigureExternalControllers(this IServiceCollection services)
    {
        // TBD: check if Mvc services added
        //      if not - add new, with options
        //      if yes - add options to existing
        //          1. If 'part' not present already: .AddApplicationPart(typeof(ExternalController).Assembly)
        //          2. If 'AddControllersAsServices' not present already: .AddControllersAsServices();
        //             Else: skip

        services.AddSingleton<ExternalControllerConfiguration>(new ExternalControllerConfiguration());
    }
}

Моя последняя идея состояла в том, чтобы перейти на git-hub, посмотреть исходный код и придуматькакое-то решение.НО.Существуют ли общие способы достижения этого результата?Возможно, Microsoft уже думала об этом, поэтому я пытаюсь заново внедрить колесо?

Любые советы или примеры кода приветствуются.

Ответы [ 2 ]

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

С помощью сообщества я смог доработать модификации.Они следующие:

public static partial class MvcBuilderExtensions
{
    public static IMvcBuilder ConfigureExternalAttributes(this IMvcBuilder builder, ExternalValidationAttributeConfiguration attributeConfiguration = null)
    {
        if (builder == null)
            throw new ArgumentNullException(nameof(builder));

        builder.Services.Configure<MvcOptions>(o => {
            o.Filters.Add(typeof(ExternalValidationActionFilterAttribute));
        });

        // add default configuration
        if (attributeConfiguration == null)
            attributeConfiguration = new ExternalValidationAttributeConfiguration();

        builder.Services.AddSingleton<ExternalValidationAttributeConfiguration>(attributeConfiguration);

        return builder;
    }
}

и

    public static IMvcBuilder ConfigureExternalControllers(this IMvcBuilder builder, ExternalControllerConfiguration controllerConfiguration = null)
    {
        if (builder == null)
            throw new ArgumentNullException(nameof(builder));

        var externalControllerAssembly = typeof(ExternalController).Assembly;
        builder.AddApplicationPart(externalControllerAssembly);

        // Next part is optional. Is used to add controller as a service.
        // see: https://github.com/aspnet/AspNetCore
        // /Mvc/Mvc.Core/src/DependencyInjection/MvcCoreMvcBuilderExtensions.cs
        var feature = new ControllerFeature();
        builder.PartManager.PopulateFeature(feature);
        foreach (var controller in feature.Controllers
            .Where(w => w.Assembly == externalControllerAssembly)
            .Select(c => c.AsType()))
        {
            builder.Services.TryAddTransient(controller, controller);
        }

        // builder.Services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());

        // add default configuration
        if (controllerConfiguration == null)
            controllerConfiguration = new ExternalControllerConfiguration();

        builder.Services.AddSingleton<ExternalControllerConfiguration>(controllerConfiguration);

        return builder;
    }

Мне пришлось копаться в исходном коде ядра dotnet, чтобы добавить контроллер в качестве службы. В противном случае все прошло гладко.Спасибо всем!

PS в случае настройки атрибута - возможно использовать расширение другого типа, например:

public static void ConfigureExternalAttributes(this IServiceCollection services)
{
    services.Configure<MvcOptions>(o => {
        o.Filters.Add(typeof(ExternalValidationActionFilterAttribute));
    });

    services.AddSingleton<ExternalValidationAttributeConfiguration>(new ExternalValidationAttributeConfiguration());
}
0 голосов
/ 25 февраля 2019

Для части приложения вы можете создать пользовательский класс расширения в отдельной библиотеке, используя пакет Microsoft.Extensions.DependencyInjection, как также предложено Кирком Ларкиным.

  1. Добавить пакет «Microsoft.Extensions.DependencyInjection» вваша отдельная библиотека.
Install-Package Microsoft.Extensions.DependencyInjection
Создайте новый класс ExternalConfigurationExtensions.cs в отдельной библиотеке и обновите пространство имен класса, как описано ниже.
namespace Microsoft.Extensions.DependencyInjection
{
    public static class ExternalConfigurationExtensions
    {
        public static IMvcBuilder ConfigureExternalControllers(this IMvcBuilder builder)
        {
            if (builder == null)
                throw new ArgumentNullException(nameof(builder));

            builder.AddApplicationPart(typeof(ExternalController).Assembly);

            return builder;
        }
    }
}
Обновите свой Startup.cs
services.AddMvc()
        .ConfigureExternalControllers();
...