c# - 迁移到 .Net Core 3.1 时,.Net Core 2.2 中使用的 Services.AddMvc() 和 SuperJsonOutputFormatter 的替代方法是什么
问题描述
我正在迁移一个 .Net Core 2.2 Web API 应用程序,它只有 API 控制器,没有视图。我在我的项目中使用 SuperJsonOutputFormatter 设置了自定义 API 响应。现在,我使用 NewtonsoftJsonOutputFormatter 为 API 创建自定义响应。但根据 microsoft 文档 services.AddMvc() 在 .Net Core 3.1 中已过时。那么,如何在 startup.cs 中调用 customformatter。我正在使用下面的代码
services.AddControllers().AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
options.SerializerSettings.Formatting = Formatting.Indented;
});
services.AddScoped<SuperJsonOutputFormatterFilter>();
services.AddMvc(opts =>
{
opts.EnableEndpointRouting = false;
var oldFormatter = opts.OutputFormatters.OfType<CustomOutputFormatter>().Single();
opts.OutputFormatters.Remove(oldFormatter);
var replacementJsonOutputFormatter =
new CustomOutputFormatter(oldFormatter.serializerSettings, ArrayPool<char>.Shared);
opts.OutputFormatters.Add(replacementJsonOutputFormatter);
}).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
配置服务如下
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseRouting();
app.UseExceptionHandler("/Error");
app.UseAuthentication();
app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseMvc();
}
上面的代码给出了一些服务无法构建的运行时错误,验证服务描述符时出错。如何在不使用 Services.AppMvc() 的情况下调用 customformatter
我的 Error_Helper 如下
错误描述类
public class ErrorDescription
{
public ErrorDescription(HttpStatusCode statusCode)
{
this.Code = (int)statusCode;
this.Description = GetDescription((int)statusCode);
}
string GetDescription(int statusCode)
{
return statusCode switch
{
404 => "Employee ID not found",
500 => "Internal server error",
400 => "Device token already registered",
406 => "No data found in table",
_ => "",
};
}
[JsonProperty("errorCode")]
public int Code { get; set; }
[JsonProperty("errorDescription")]
public string Description { get; set; }
}
FormatterFilter 类
public class CustomJsonOutputFormatterFilter : IAsyncActionFilter
{
private readonly CustomOutputFormatter _formatter;
// inject SuperJsonOutputFormatter service
public CustomJsonOutputFormatterFilter(CustomOutputFormatter formatter)
{
this._formatter = formatter;
}
// a helper method that provides an ObjectResult wrapper over the raw object
private ObjectResult WrapObjectResult(ActionExecutedContext context, object obj)
{
var wrapper = new ObjectResult(obj);
wrapper.Formatters.Add(this._formatter);
context.Result = wrapper;
return wrapper;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
ActionExecutedContext resultContext = await next();
// in case we get a 500
if (resultContext.Exception != null && !resultContext.ExceptionHandled)
{
var ewrapper = this.WrapObjectResult(resultContext, new { });
ewrapper.StatusCode = (int)HttpStatusCode.InternalServerError;
resultContext.ExceptionHandled = true;
return;
}
else
{
switch (resultContext.Result)
{
case BadRequestObjectResult b: // 400 with an object
var bwrapper = this.WrapObjectResult(resultContext, b.Value);
bwrapper.StatusCode = b.StatusCode;
break;
case NotFoundObjectResult n: // 404 with an object
var nwrapper = this.WrapObjectResult(resultContext, n.Value);
nwrapper.StatusCode = n.StatusCode;
break;
case ObjectResult o: // plain object
this.WrapObjectResult(resultContext, o.Value);
break;
case JsonResult j: // plain json
this.WrapObjectResult(resultContext, j.Value);
break;
case StatusCodeResult s: // other statusCodeResult(including NotFound,NoContent,...), you might want to custom this case
var swrapper = this.WrapObjectResult(resultContext, new { result="" });
swrapper.StatusCode = s.StatusCode;
break;
}
}
}
}
自定义Outputformatter类,该类调用customformatterfilter
public class CustomOutputFormatter : NewtonsoftJsonOutputFormatter
{
public CustomOutputFormatter(JsonSerializerSettings serializerSettings,
ArrayPool<char> charPool) : base (serializerSettings, charPool)
{
}
public JsonSerializerSettings serializerSettings { get; private set; }
public override async Task WriteResponseBodyAsync(
OutputFormatterWriteContext context,
Encoding selectedEncoding)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (selectedEncoding == null)
if (selectedEncoding == null)
throw new ArgumentNullException(nameof(selectedEncoding));
using TextWriter writer = context.WriterFactory(context.HttpContext.Response.Body, selectedEncoding);
var statusCode = context.HttpContext.Response.StatusCode;
var rewrittenValue = new
{
status = IsSucceeded(statusCode),
error = IsSucceeded(statusCode) ? null : new ErrorDescription((HttpStatusCode)statusCode),
data = context.Object,
};
writer.Write(rewrittenValue);
this.CreateJsonWriter(writer);
await writer.FlushAsync();
}
private bool IsSucceeded(int statusCode)
{
// 204 is not an error but handled
if (statusCode >= 400 || statusCode == 204) { return false; }
return true;
}
}
解决方案
我没有详细查看您的实现(看起来很复杂,您要实现什么目标?),但您可以使用与之前配置实例UseControllers()
相同的方式。例如:UseMvc()
MvcOptions
services.AddControllers(options =>
{
options.InputFormatters.Insert(0, new VcardInputFormatter());
options.OutputFormatters.Insert(0, new VcardOutputFormatter());
})
这可能会解决您的问题 - 无需致电AddMvc
.
但是,错误“无法构建某些服务”表明您缺少服务依赖项。错误信息会告诉你是哪一个。这是 .NET Core 3.1 中的一项新功能,即服务提供者验证,您可以在这篇博文中了解它。
推荐阅读
- c# - LINQ在C#中使用多个键值选择查询嵌套字典
- cygwin - 为什么我无法修复 cygwin1.dll 不匹配问题?
- version-control - 具有所需域的 gitlab 安装(http://gitlab.
.com) - azure - 如何使用存储的继续令牌从 blob 恢复数据复制?
- java - 如何格式化单个字符串
- github - 有什么可以进入 .github “dot github” 目录的概述吗?
- flutter - 将 Uint8List 转换为文件
- python - 创建 python Zeep 客户端时如何发送 POST 正文
- angular - Angular Material Table 不显示从本地服务器获取的数据
- python - Python:从天才那里获取歌曲歌词 - 错误