Обработка исключений для проверки запросов DTO Postsharp и широкой проверки контроллера

#c# #aop #webapi #postsharp

Вопрос:

Я пытаюсь использовать PostSharp в проекте WebAPI. Я не могу сосредоточиться на этой задаче. Я хотел бы использовать контракты PostSharp для проверки входящих DTO и централизованной обработки исключений в случае ошибки проверки. Но я не знаю, как применить аспект исключения на уровне класса, и, что еще хуже, как вернуть ответ на ошибку JSON, когда это произойдет.

Комментарии:

1. Над какой платформой вы работаете? ASP.NET Ядро? У вас есть примеры кода, от которых вы пытаетесь избавиться (как выглядит ваш текущий подход?)? Вы просмотрели документацию и примеры перехвата вызовов методов ?

2. Платформа-.NET 5.0. У меня есть контроллер, для которого я хочу проверить входные данные. Для этого я использовал контракты PostSharp, и создаются исключения для недопустимых запросов. Просто, похоже, не удается поймать ни одного, потому что фактическое исключение создается в установщике класса DTO запроса, который создается в методе контроллера атрибутом [FromBody].

3. Обработка исключения в методе контроллера не работает, так как исключение создается до того, как будет создан метод контроллера. Найдите «исключение привязки модели дескриптора .net core», чтобы найти способ подключиться к этому процессу.

Ответ №1:

Без примеров кода немного неясно, для чего вы пытаетесь использовать PostSharp. Похоже, вы ищете какую-то типичную проверку модели в ASP.NET Ядро (.NET 5) и возврат пользовательского ответа JSON (при условии, что вы работаете с ASP.NET веб-API).

Я знаю, что вы спрашиваете о PostSharp, но я считаю, что для этого требуется некоторый пользовательский код, чтобы он работал и возвращал пользовательские ответы в ASP.NET, в то время как вы получаете большую часть этого бесплатно с помощью самого ASP в пространстве имен DataAnnotations.

Пример:

 // CredentialsRequest.cs
using System.ComponentModel.DataAnnotations;
public class Credentials
{
    [Required]
    [EmailAddress]
    public string Email { get; set; }

    [Required]
    public string Password { get; set; }
}


// AuthenticationController.cs
[ApiController]
public class AuthenticationController : ControllerBase
{
    [HttpPost]
    public Task<IActionResult> Login([FromBody] Credentials credentials)
    {
        var result = // check `credentials` for valid login
        return result.Success
            ? Ok(result)
            : StatusCode(StatusCodes.Status401Unauthorized, result);
    }
}
 

Чтобы отловить все ошибки проверки модели, вы можете добавить следующую фабрику ответов Startup.ConfigureServices (настройте ее по своему усмотрению).:

 services.Configure<ApiBehaviorOptions>(config =>
{
    // Override default response when input model is invalid
    config.InvalidModelStateResponseFactory =
        ctx => new BadRequestObjectResult(new BaseResponse(
            success: ctx.ModelState.IsValid,
            errors: ctx.ModelState.Values
                .Where(v => v.ValidationState == ModelValidationState.Invalid)
                .SelectMany(v => v.Errors)
                .Select(e => new ErrorDetails
                {
                    Code = "ModelError",
                    Description = e.ErrorMessage
                })
                .ToList()
            ));
});
 

Вот BaseResponse и ErrorDetails некоторые простые модели данных/классы, которые я использую в качестве основы для всех моих моделей данных ответов:

 public class BaseResponse
{
    public bool Success { get; }
    public List<ErrorDetails> Errors { get; }

    public BaseResponse(bool success, ErrorDetails error)
        : this(success, new List<ErrorDetails> { error })
    { }

    public BaseResponse(bool success, List<ErrorDetails> errors = null)
    {
        Success = success;
        Errors = errors;
    }
}
 

Если вы не настроили свой API для возврата данных в другом формате, по умолчанию это должен быть JSON.

Комментарии:

1. Спасибо @Xerillio за этот подробный пример. Я знаю о датааннотациях, и это именно то, что мне нужно, я просто попытался использовать PostSharp. Шаблоны. Вместо этого заключаются контракты.