使用程序集扫描注册 ASP.NET 个核心 JsonConverter 实现
Register ASP.NET Core JsonConverter implementations using assembly scan
我有很多 json 转换器,它们源自 JsonConverter<T>
。它们在各种程序集中,而不仅仅是执行程序集。
我是这样注册的:
services
.AddControllers()
.AddJsonOptions(o => {
o.JsonSerializerOptions.Converters.Add(new FooJsonConverter());
o.JsonSerializerOptions.Converters.Add(new BarJsonConverter());
o.JsonSerializerOptions.Converters.Add(new BazJsonConverter());
o.JsonSerializerOptions.Converters.Add(new QuxJsonConverter());
// lots more...
});
我宁愿使用程序集扫描动态地添加它们——就像 AutoMapper、FluentValidation、Autofac 等一样。我查看了他们的秘密酱汁回购协议,但找不到。
所以我尝试了一些基本的反思:
services
.AddControllers()
.AddJsonOptions(o => {
var jsonConverters =
AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(x => x.ExportedTypes)
.Where(x => x.BaseType != null && x.IsAssignableFrom(typeof(JsonConverter<>)));
foreach (var jsonConverter in jsonConverters)
o.JsonSerializerOptions.Converters.Add(Activator.CreateInstance(jsonConverter) as JsonConverter);
});
但是无法启动,并抛出:
FTL | Microsoft.AspNetCore.Hosting.Diagnostics | Application startup exception
Autofac.Core.DependencyResolutionException: An exception was thrown while activating Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionEndpointDataSourceFactory -> Microsoft.AspNetCore
.Mvc.Infrastructure.DefaultActionDescriptorCollectionProvider -> λ:Microsoft.AspNetCore.Mvc.Abstractions.IActionDescriptorProvider[] -> Microsoft.AspNetCore.Mvc.ApplicationModels.ControllerA
ctionDescriptorProvider -> Microsoft.AspNetCore.Mvc.ApplicationModels.ApplicationModelFactory -> λ:Microsoft.AspNetCore.Mvc.ApplicationModels.IApplicationModelProvider[] -> Microsoft.AspNetC
ore.Mvc.ApplicationModels.DefaultApplicationModelProvider -> Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.DefaultModelMetadataProvider -> λ:Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.I
CompositeMetadataDetailsProvider.
---> System.MissingMethodException: Cannot create an abstract class.
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean wrapExceptions, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& hasNoDefaultCtor
)
注意 Cannot create an abstract class
。基础 class 是抽象的,但我正在尝试激活子 classes.
正确的做法是什么?另外,引用 AppDomain 是否合适,因为我记得在某处读到该行为在 aspnet 中发生了变化。
只需更改为:
var jsonConverters =
AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(x => x.ExportedTypes)
.Where(x => x.BaseType != null && x.IsAssignableTo(typeof(JsonConverter)));
JsonConverter<> 满足您的条件 x => x.BaseType != null && x.IsAssignableFrom(typeof(JsonConverter<>)
。
它具有基本类型并且是可分配的。抱歉 ;)
你可以随时检查是否输入 .IsAbstract
然后忽略它们。
另一种解决方案是按惯例注册 类(在本例中按名称)。我使用 Autofac,但方法相同
builder
.RegisterAssemblyTypes(serviceAssembly)
.Where(t => t.Name.EndsWith("Service"))
.AsSelf();
这对我有用:
services.AddControllers().AddJsonOptions(o => {
var jsonConverters =
AppDomain.CurrentDomain
.GetAssemblies()
.Where(x => !x.IsDynamic)
.SelectMany(x => x.ExportedTypes)
.Where(x => x.BaseType != null) // is not Object, or an interface
.Where(x => x.BaseType.IsGenericType) // must derive from JsonConverter<T>
.Where(x => x.BaseType.BaseType == typeof(JsonConverter)) // exclude framework types
foreach (var jsonConverter in jsonConverters) {
var instance = Activator.CreateInstance(jsonConverter) as JsonConverter;
o.JsonSerializerOptions.Converters.Add(instance);
}
});
我不确定是使用 AppDomain.CurrentDomain
还是 AssemblyLoadContext.Default
,但这种方式似乎可行。
我有很多 json 转换器,它们源自 JsonConverter<T>
。它们在各种程序集中,而不仅仅是执行程序集。
我是这样注册的:
services
.AddControllers()
.AddJsonOptions(o => {
o.JsonSerializerOptions.Converters.Add(new FooJsonConverter());
o.JsonSerializerOptions.Converters.Add(new BarJsonConverter());
o.JsonSerializerOptions.Converters.Add(new BazJsonConverter());
o.JsonSerializerOptions.Converters.Add(new QuxJsonConverter());
// lots more...
});
我宁愿使用程序集扫描动态地添加它们——就像 AutoMapper、FluentValidation、Autofac 等一样。我查看了他们的秘密酱汁回购协议,但找不到。
所以我尝试了一些基本的反思:
services
.AddControllers()
.AddJsonOptions(o => {
var jsonConverters =
AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(x => x.ExportedTypes)
.Where(x => x.BaseType != null && x.IsAssignableFrom(typeof(JsonConverter<>)));
foreach (var jsonConverter in jsonConverters)
o.JsonSerializerOptions.Converters.Add(Activator.CreateInstance(jsonConverter) as JsonConverter);
});
但是无法启动,并抛出:
FTL | Microsoft.AspNetCore.Hosting.Diagnostics | Application startup exception
Autofac.Core.DependencyResolutionException: An exception was thrown while activating Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionEndpointDataSourceFactory -> Microsoft.AspNetCore .Mvc.Infrastructure.DefaultActionDescriptorCollectionProvider -> λ:Microsoft.AspNetCore.Mvc.Abstractions.IActionDescriptorProvider[] -> Microsoft.AspNetCore.Mvc.ApplicationModels.ControllerA ctionDescriptorProvider -> Microsoft.AspNetCore.Mvc.ApplicationModels.ApplicationModelFactory -> λ:Microsoft.AspNetCore.Mvc.ApplicationModels.IApplicationModelProvider[] -> Microsoft.AspNetC ore.Mvc.ApplicationModels.DefaultApplicationModelProvider -> Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.DefaultModelMetadataProvider -> λ:Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.I CompositeMetadataDetailsProvider.
---> System.MissingMethodException: Cannot create an abstract class.
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean wrapExceptions, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& hasNoDefaultCtor )
注意 Cannot create an abstract class
。基础 class 是抽象的,但我正在尝试激活子 classes.
正确的做法是什么?另外,引用 AppDomain 是否合适,因为我记得在某处读到该行为在 aspnet 中发生了变化。
只需更改为:
var jsonConverters =
AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(x => x.ExportedTypes)
.Where(x => x.BaseType != null && x.IsAssignableTo(typeof(JsonConverter)));
JsonConverter<> 满足您的条件 x => x.BaseType != null && x.IsAssignableFrom(typeof(JsonConverter<>)
。
它具有基本类型并且是可分配的。抱歉 ;)
你可以随时检查是否输入 .IsAbstract
然后忽略它们。
另一种解决方案是按惯例注册 类(在本例中按名称)。我使用 Autofac,但方法相同
builder
.RegisterAssemblyTypes(serviceAssembly)
.Where(t => t.Name.EndsWith("Service"))
.AsSelf();
这对我有用:
services.AddControllers().AddJsonOptions(o => {
var jsonConverters =
AppDomain.CurrentDomain
.GetAssemblies()
.Where(x => !x.IsDynamic)
.SelectMany(x => x.ExportedTypes)
.Where(x => x.BaseType != null) // is not Object, or an interface
.Where(x => x.BaseType.IsGenericType) // must derive from JsonConverter<T>
.Where(x => x.BaseType.BaseType == typeof(JsonConverter)) // exclude framework types
foreach (var jsonConverter in jsonConverters) {
var instance = Activator.CreateInstance(jsonConverter) as JsonConverter;
o.JsonSerializerOptions.Converters.Add(instance);
}
});
我不确定是使用 AppDomain.CurrentDomain
还是 AssemblyLoadContext.Default
,但这种方式似乎可行。