[英]what is the alternative for Services.AddMvc() and SuperJsonOutputFormatter used in .Net Core 2.2 while migrating to .Net Core 3.1
I'm migrating a.Net Core 2.2 web API application having API Controllers only with no views.我正在迁移 a.Net Core 2.2 web API 应用程序只有 API 控制器没有视图。 I have a custom API response set in my project using SuperJsonOutputFormatter.
我使用 SuperJsonOutputFormatter 在我的项目中设置了自定义 API 响应。 Now, I'm using NewtonsoftJsonOutputFormatter for creating custom response for the APIs.
现在,我正在使用 NewtonsoftJsonOutputFormatter 为 API 创建自定义响应。 But as per microsoft document services.AddMvc() is obsolete in.Net Core 3.1.
但根据微软文档 services.AddMvc() 在.Net Core 3.1 中已过时。 So, how to call the customformatter in startup.cs.
那么,如何调用startup.cs中的customformatter。 I'm using the below code
我正在使用下面的代码
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);
The configure services is as below配置服务如下
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();
}
The above code gives a runtime error that Some services are not able to be constructed, Error while validating the service descriptor.上面的代码给出了一些服务无法构建的运行时错误,验证服务描述符时出错。 How to call customformatter without using Services.AppMvc()
如何在不使用 Services.AppMvc() 的情况下调用 customformatter
My Error_Helper is as below我的 Error_Helper 如下
ErrorDescription Class错误描述 Class
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 Class格式化过滤器 Class
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;
}
}
}
}
Custom Outputformatter Class, this class calls the customformatterfilter Custom Outputformatter Class,这个class调用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;
}
}
I haven't looked in detail at your implementation (it seems quite convoluted, what are you trying to achieve?), but you can use UseControllers()
in the same way as you were using UseMvc()
previously to configure the MvcOptions
instance.我没有详细查看您的实现(它看起来很复杂,您想要实现什么?),但是您可以像之前使用
UseControllers()
UseMvc()
配置MvcOptions
实例一样使用 UseControllers()。 eg:例如:
services.AddControllers(options =>
{
options.InputFormatters.Insert(0, new VcardInputFormatter());
options.OutputFormatters.Insert(0, new VcardOutputFormatter());
})
That might solve your problem - there's no need to call AddMvc
.这可能会解决您的问题 - 无需调用
AddMvc
。
However, the error "Some services are not able to be constructed" suggests you are missing a service dependency.但是,错误“无法构建某些服务”表明您缺少服务依赖项。 The error message will tell you which one.
错误消息会告诉您是哪一个。 This is a new feature in .NET Core 3.1, service provider validation, that you can read about in this blog post .
这是 .NET Core 3.1 中的一项新功能,即服务提供商验证,您可以在这篇博文中了解相关信息。
I'm migrating a.Net Core 2.2 web API application having API Controllers only with no views.我正在迁移 a.Net Core 2.2 web API 应用程序,该应用程序只有 API 控制器,没有视图。 I have a custom API response set in my project using SuperJsonOutputFormatter.
我使用 SuperJsonOutputFormatter 在我的项目中设置了自定义 API 响应。 Now, I'm using NewtonsoftJsonOutputFormatter for creating custom response for the APIs.
现在,我使用 NewtonsoftJsonOutputFormatter 为 API 创建自定义响应。 But as per microsoft document services.AddMvc() is obsolete in.Net Core 3.1.
但根据 microsoft 文档 services.AddMvc() 在.Net Core 3.1 中已过时。 So, how to call the customformatter in startup.cs.
那么,如何在 startup.cs 中调用 customformatter。 I'm using the below code
我正在使用下面的代码
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);
The configure services is as below配置服务如下
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();
}
The above code gives a runtime error that Some services are not able to be constructed, Error while validating the service descriptor.上面的代码给出了一些服务无法构建的运行时错误,验证服务描述符时出错。 How to call customformatter without using Services.AppMvc()
如何在不使用 Services.AppMvc() 的情况下调用 customformatter
My Error_Helper is as below我的 Error_Helper 如下
ErrorDescription Class错误描述 Class
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 Class FormatterFilter Class
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;
}
}
}
}
Custom Outputformatter Class, this class calls the customformatterfilter自定义Outputformatter Class,这个class调用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;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.