添加Mvc服务后分别添加Mvc选项

时间:2019-02-25 08:24:17

标签: c# asp.net-core asp.net-core-mvc asp.net-core-2.1

一个非常特定于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,查看源代码并提出一些解决方案。但。是否有实现此结果的通用方法?也许微软已经想到了这一点,所以我正在尝试重新实现方向盘?

非常欢迎任何建议或代码示例。

2 个答案:

答案 0 :(得分:2)

对于应用程序部分,您也可以使用Kirk Larkin建议的Microsoft.Extensions.DependencyInjection包在单独的库中创建自定义扩展类。

  1. 在单独的库中添加“ Microsoft.Extensions.DependencyInjection”包。
Install-Package Microsoft.Extensions.DependencyInjection
  1. 在单独的库中创建一个新类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;
        }
    }
}
  1. 更新您的Startup.cs
services.AddMvc()
        .ConfigureExternalControllers();

答案 1 :(得分:1)

在社区的帮助下,我能够完成修改。他们正在关注:

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核心源代码,才能将控制器作为服务添加。否则一切都会顺利进行。谢谢大家!

P.S。在属性配置的情况下-可以使用其他类型的扩展名,如下所示:

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

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