我目前正在重新编写.NET 6 WebAPI。在重构时,我转而使用Autofac作为我的DI框架。
为了让我的控制器不返回null值,我使用了带有以下选项的newtonsoft-json:
builder.Services.AddControllers().AddDefaultJsonOptions();
public static IMvcBuilder AddDefaultJsonOptions(this IMvcBuilder builder)
{
return builder.AddNewtonsoftJson(options =>
{
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
}
使用autofac,我将控制器的注册更改为:
builder.Host.ConfigureContainer<Autofac.ContainerBuilder>(builder =>
{
...
var executingAssembly = Assembly.GetExecutingAssembly();
builder.RegisterApiControllers(executingAssembly);
...
});
但是我现在如何更改默认的json序列化选项呢?
ASP.NET Core完全开源的美妙之处在于,您可以自己访问repo,进行一些深入研究,了解这些方法的作用,然后跟踪如何解决此类问题。
在这种情况下,让我们看看AddControllers
实际上做了什么:
public static IMvcBuilder AddControllers(this IServiceCollection services)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
var builder = AddControllersCore(services);
return new MvcBuilder(builder.Services, builder.PartManager);
}
看起来AddControllersCore
中隐藏了很多内容,所以我们可以向下滚动到:
private static IMvcCoreBuilder AddControllersCore(IServiceCollection services)
{
// This method excludes all of the view-related services by default.
var builder = services
.AddMvcCore()
.AddApiExplorer()
.AddAuthorization()
.AddCors()
.AddDataAnnotations()
.AddFormatterMappings();
if (MetadataUpdater.IsSupported)
{
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IActionDescriptorChangeProvider, HotReloadService>());
}
return builder;
}
有趣。因此,AddControllers
实际上并没有将字面控制器添加到服务集,而是添加了执行控制器所需的东西。为什么?
我会快进一点——这是因为控制器默认情况下不会被解析为服务惊喜!实际情况是,控制器参数被解析,但控制器本身是通过反射创建的,解析的参数被传递给构造函数。如果您确实希望控制器被解析(例如,支持属性注入或其他(,则需要使用AddControllersAsServices
(这也在Autofac文档中(
事实上,您使用的RegisterApiControllers
方法甚至不适用于ASP.NET Core,而是适用于ASP.NET Web API,后者不在.NET 6中。您真的需要检查ASP.NET核心集成,并且在重构中绝对不要使用任何经典的ASP.NET和Web API。这不是混搭。这都是.NET核心/ASP.NET核心。
那么,为了回答这个问题,您如何注册控制器和获得JSON选项?
继续做你正在做的事情
builder.Services
.AddControllers()
.AddControllersAsServices()
.AddDefaultJsonOptions();
如果你真的想用Autofac手动注册控制器,你可以重新注册它们(在之后你调用AddControllersAsServices
(,但你会将它们注册为自己。
builder.Host
.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Services
.AddControllers()
.AddControllersAsServices()
.AddDefaultJsonOptions();
builder.Host
.ConfigureContainer<ContainerBuilder>(b => {
b.RegisterType<MyController>().PropertiesAutowired();
});
但是,同样,除非你特别要做一些事情来覆盖控制器的注册方式,比如需要设置lambda或属性注入之类的,否则AddControllersAsServices
会覆盖它
如果您希望Autofac作为您的容器,您确实需要UseServiceProviderFactory
调用否则,即使调用ConfigureContainer<T>
,也会得到默认的Microsoft容器。