简体   繁体   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

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.

相关问题 从 .NET Core 2.2 迁移到 3.1 后,不会在 ASP.NET Core 自定义 AuthenticationHandler 中忽略 AllowAnonymous - AllowAnonymous is not ignored in ASP.NET Core custom AuthenticationHandler after migrating from .NET Core 2.2 to 3.1 从.Net Core 3.1 迁移到 .NET 5 - Migrating from .Net Core 3.1 to .NET 5 Net Core 2.2 到 Net Core 3.1 迁移错误 - Net Core 2.2 to Net Core 3.1 migration error 从 .NET core 2.2 迁移到 3.1 api 后,将 newtonsoft 添加到项目时,结果中间件中断 - After migrating to from .NET core 2.2 to 3.1 api result middleware breaks when adding newtonsoft to project .net core 3.1 中 RequestCookieCollection 和 ResponseCookies 的替代方案是什么? - what's the alternative of RequestCookieCollection and ResponseCookies in .net core 3.1? 将 .NET 内核从 2.2 迁移到 3.1 - Migrate .NET Core from 2.2 to 3.1 将 .net 核心 2.2 迁移到 3.1 问题 - migrate .net core 2.2 to 3.1 issue asp.net核心2.2项目迁移到3.1版本后分析器异常 - Analyzer exceptions after migrating asp.net core 2.2 project to version 3.1 services.AddControllersWithViews() 与 services.AddMvc() - services.AddControllersWithViews() vs services.AddMvc() ASP.NET Core http post [FromBody] 在 3.1 中损坏,在 2.2 中使用 - ASP.NET Core http post [FromBody] broken in 3.1, used to work in 2.2
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM