繁体   English   中英

在迁移到 .Net Core 3.1 时,.Net Core 2.2 中使用的 Services.AddMvc() 和 SuperJsonOutputFormatter 的替代方法是什么

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM