【问题标题】:Adding Mvc options separately after adding Mvc services添加 Mvc 服务后单独添加 Mvc 选项
【发布时间】:2019-02-25 08:24:16
【问题描述】:

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

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

【问题讨论】:

  • 你看到答案here了吗?它解释了如何使用选项模式来实现这些东西。在您的情况下,您可以在扩展方法中添加一个委托(使用services.Configure(...)),这将允许您的库代码在入口应用程序的代码之后运行。
  • 不完全清楚。 AddMvc() 也来自“外部”库。当您要将 ConfigureExternalControllers() 放在其库中时,请在名称中添加“默认”一词。否则,它只是 Startup 类的一个方法。
  • @KirkLarkin 我听从了您的建议,并完成了为验证属性创建扩展方法。见更新。对“应用部分”有什么建议吗?
  • 为此,您可以为IMvcBuilder 创建自己的扩展方法,该方法从AddMvc() 返回。
  • @KirkLarkin 听从了您的建议。很棒的输入!现在都解决了:)(您可以查看下面的答案)

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


【解决方案1】:

对于应用程序部分,您可以按照 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();

【讨论】:

  • 有没有办法从IServiceCollection获取一个之前配置的IMvcBuilder,以便在上面调用AddApplicationPart
【解决方案2】:

在社区的帮助下,我得以完成修改。他们如下:

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 核心源代码以将控制器添加为服务。否则一切顺利。谢谢大家!

附:在属性配置的情况下 - 可以使用不同类型的扩展,如下所示:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-10
    • 1970-01-01
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    • 2013-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多