Как устранить повторяющиеся проверки на ноль и обработку исключений в методах контроллера? - PullRequest
1 голос
/ 05 апреля 2019

Я хочу избежать использования повторяющихся блоков try / catch, повторяющихся команд ведения журнала и учета кодов ответов HTTP, таких как 404, 200, 204 и т. Д., И минимизировать строки кода метода API в каком-либо интерфейсе или службе. Другими словами, сделайте мой код более СУХИМ.

Учитывая этот код:

    [HttpGet()]
    [Route("Contracts/{id}")]
    public async Task<IActionResult> Get(int id)
    {
        try
        { 
            var results = await _service.GetContractByIdAsync(id);
            if (results == null) { return NotFound(); }             
            return Ok(results);
        }
        catch(Exception ex)
        {
            _log(ex);
            return StatusCode(500); 
        }
    }

Если у меня несколько похожих методов, каждая строка кода, кроме

var results = await _service.GetContractByIdAsync(id);

будет повторяться. Как мне избежать этого дублирования? Возможно, я захочу позже изменить способ обработки ошибок, и мне не нужно менять его во многих местах.

Ответы [ 2 ]

1 голос
/ 05 апреля 2019

ВЫЗОВ 1: попытаться / поймать

Вы можете добавить промежуточное ПО перед MVC, которое выполнит следующее промежуточное ПО (включая MVC) в попытке / пойматьblock:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    //...

    app.UseMyExceptionHandler();
    // ...
    app.UseMvc();
}

Промежуточное программное обеспечение может выглядеть следующим образом:

public class ExceptionHandlerMiddleware
{
    readonly RequestDelegate _next;
    readonly ILogger logger;

    public ExceptionHandlerMiddleware(RequestDelegate next, ILogger<ExceptionHandlerMiddleware> logger)
    {
        _next = next;
        this.logger = logger;
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception e)
        {
            await HandleExceptionAsync(context, e);
        }
    }

    private Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        // Log the exceptions
        string result = ... cretate the response if you need it
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = 500;
        return context.Response.WriteAsync(result);
    }
}

И я использовал метод расширения, чтобы добавить его в конструктор приложений:

public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseMyExceptionHandler(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<ExceptionHandlerMiddleware>();
    }
}

Теперь вы можете удалить try/catch из всех ваших действий контроллера, потому что все необработанные исключения будут перехвачены промежуточным программным обеспечением.

Есть также некоторые встроенные способы выполнения этого, которыеможет помочь вам.

ВЫЗОВ 2: нулевые проверки для NotFound

Вы можете создать некоторый базовый контроллер, от которого будут наследоваться все ваши контроллеры, и обработать проверку nullв нем:

public class BaseController : ControllerBase
{
    protected IActionResult CreateResponse(object result)
    {
        if (results == null)
            return NotFound();
        return Ok(results);
    }
}

и затем вы заставляете все свои контроллеры наследовать от него:

[ApiController]
public class YourController : BaseController
// ...

И теперь ваш метод действия может выглядеть так:

[HttpGet()]
[Route("Contracts/{id}")]
public async Task<IActionResult> Get(int id)
{
    var results = await _service.GetContractByIdAsync(id);
    return CreateResponse(results);
}
1 голос
/ 05 апреля 2019

Вы можете определить ResultFilterAttribute, который заменит все ObjectResult с нулевым значением на NotFoundResult. Вы можете комментировать методы вашего контроллера, где бы они ни применялись, или даже зарегистрировать фильтр глобально. См. Также статью Преобразование значений NULL в 404 в asp.net-core mvc , чтобы узнать, как и почему.

Атрибут будет выглядеть так (код из указанной статьи)

public class NotFoundResultFilterAttribute : ResultFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext context)
    {
        if (context.Result is ObjectResult objectResult && objectResult.Value == null)
        {
            context.Result = new NotFoundResult();
        }
    }
}

Примените его к вашему методу контроллера и просто верните результат.

[HttpGet()]
[Route("Contracts/{id}")]
[NotFoundResult]
public async Task<IActionResult> Get(int id) {
    var results = await _service.GetContractByIdAsync(id);
    return results;
}

Убедитесь, что ваш контроллер имеет атрибут ApiController. Я пропустил блок try-catch, потому что вы также можете разрешить конвейеру обрабатывать исключения для вас. В вашем методе Startup.Configure зарегистрируйте лямбду для app.UseExceptionHandler(...).

Ознакомьтесь с документацией по Microsoft ASP.NET Core - раздел обработки ошибок для получения дополнительной информации.

...