添加 Mvc 服务后单独添加 Mvc 选项
Adding Mvc options separately after adding Mvc services
一个非常针对 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.Extensions.DependencyInjection 包在单独的库中创建自定义扩展 class,正如 Kirk Larkin 所建议的那样。
- 在您的单独库中添加 "Microsoft.Extensions.DependencyInjection" 包。
Install-Package Microsoft.Extensions.DependencyInjection
- 在您的单独库中创建一个新的 class ExternalConfigurationExtensions.cs 并更新 class 命名空间,如下所述。
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();
在社区的帮助下,我能够完成修改。他们正在关注:
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());
}
一个非常针对 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.Extensions.DependencyInjection 包在单独的库中创建自定义扩展 class,正如 Kirk Larkin 所建议的那样。
- 在您的单独库中添加 "Microsoft.Extensions.DependencyInjection" 包。
Install-Package Microsoft.Extensions.DependencyInjection
- 在您的单独库中创建一个新的 class ExternalConfigurationExtensions.cs 并更新 class 命名空间,如下所述。
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();
在社区的帮助下,我能够完成修改。他们正在关注:
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());
}