![](/img/trans.png)
[英]AllowAnonymous is not ignored in ASP.NET Core custom AuthenticationHandler after migrating from .NET Core 2.2 to 3.1
[英]what is the alternative for Services.AddMvc() and SuperJsonOutputFormatter used in .Net Core 2.2 while migrating to .Net Core 3.1
我正在迁移 a.Net Core 2.2 web API 应用程序只有 API 控制器没有视图。 我使用 SuperJsonOutputFormatter 在我的项目中设置了自定义 API 响应。 现在,我正在使用 NewtonsoftJsonOutputFormatter 为 API 创建自定义响应。 但根据微软文档 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 如下
错误描述 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; }
}
格式化过滤器 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,这个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;
}
}
我没有详细查看您的实现(它看起来很复杂,您想要实现什么?),但是您可以像之前使用UseControllers()
UseMvc()
配置MvcOptions
实例一样使用 UseControllers()。 例如:
services.AddControllers(options =>
{
options.InputFormatters.Insert(0, new VcardInputFormatter());
options.OutputFormatters.Insert(0, new VcardOutputFormatter());
})
这可能会解决您的问题 - 无需调用AddMvc
。
但是,错误“无法构建某些服务”表明您缺少服务依赖项。 错误消息会告诉您是哪一个。 这是 .NET Core 3.1 中的一项新功能,即服务提供商验证,您可以在这篇博文中了解相关信息。
我正在迁移 a.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 如下
错误描述 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
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 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.