какая альтернатива для Services.Add Mvc () и SuperJsonOutputFormatter, используемых в. Net Core 2.2 при переходе на. Net Core 3.1 - PullRequest
0 голосов
/ 22 апреля 2020

Я выполняю миграцию. Net Core 2.2 приложения веб-API, имеющего только контроллеры API без представлений. У меня есть собственный ответ API, установленный в моем проекте с использованием SuperJsonOutputFormatter. Теперь я использую NewtonsoftJsonOutputFormatter для создания пользовательского ответа для API. Но в соответствии с сервисами документов Microsoft. Add Mvc () устарел в. Net Core 3.1. Итак, как вызвать customformatter в файле startup.cs. Я использую приведенный ниже код

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();
}

Приведенный выше код дает ошибку во время выполнения, что некоторые службы не могут быть построены, Ошибка при проверка дескриптора службы. Как вызвать customformatter без использования Services.App Mvc ()

Мой Error_Helper такой, как показано ниже

ErrorDescription 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, этот класс вызывает 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;
        }
    }

Ответы [ 2 ]

1 голос
/ 26 апреля 2020

Я не подробно рассмотрел вашу реализацию (кажется, что она довольно запутанная, чего вы пытаетесь достичь?), Но вы можете использовать UseControllers() так же, как вы использовали UseMvc() ранее для настройки MvcOptions экземпляр. Например:

services.AddControllers(options =>
{
    options.InputFormatters.Insert(0, new VcardInputFormatter());
    options.OutputFormatters.Insert(0, new VcardOutputFormatter());
})

Это может решить вашу проблему - вам не нужно звонить AddMvc.

Однако ошибка «Некоторые службы не могут быть построены» указывает на то, что вам не хватает зависимости службы. Сообщение об ошибке скажет вам, какой. Это новая функция в NET Core 3.1, проверка поставщика услуг, о которой вы можете прочитать в этом посте .

0 голосов
/ 22 апреля 2020

Вы можете использовать рекомендации по миграции, предоставленные Microsoft:

Миграция с ASP. NET Ядро от 2,2 до 3,0

Миграция с ASP. NET Ядро от 3,0 до 3,1

...