Перехват ошибок внедрения зависимостей в контроллерах в .NET Web Api - PullRequest
1 голос
/ 05 ноября 2019

У меня есть простой проект C # Web Api, который предоставляет несколько спокойных конечных точек.

Обработка / ведение журнала неустранимых ошибок сервера, как правило, хорошо описывается с помощью:

  1. Реализация /переопределение метода Application_Error в Global.asax.cs
protected override void Application_Error(object sender, EventArgs e)
   {
       var ex = Server.GetLastError();
       _logger.Error("Unexpected error while initializing application", ex);
   }
Или добавив фильтр обработчика исключений:

config.Filters.Add(new ExceptionHandlingAttribute());

ИЛИ

GlobalConfiguration.Configuration.Filters.Add(new ExceptionHandlingAttribute());

public class ExceptionHandlingAttribute : ExceptionFilterAttribute
    {
        private static readonly ILog _logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public override void OnException(HttpActionExecutedContext actionExecutedContext)
        {
            _logger.Error("Unexpected error in API.", actionExecutedContext.Exception);

            throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError)
            {
                Content = new StringContent("An error occurred, please try again or contact the administrator."),
                ReasonPhrase = "Critical Exception"
            });
        }
    }

Однако,когда во время создания экземпляра контроллера возникает ошибка из-за ошибки внедрения зависимостей в конструкторе этого кода:

    public class DataController : ApiController
    {
        private readonly IDataService _dataService;

        public DataController(IDataService dataService)
        {
            _dataService = dataService;
        }

        [AllowAnonymous]
        [HttpGet]
        public IHttpActionResult GetSomeStuff()
        {
            return Ok(new AjaxResponse("somestuff"));
        }

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

Ответы [ 2 ]

0 голосов
/ 06 ноября 2019

Я наконец-то нашел ответ, а именно:

Необходимо реализовать и переопределить интерфейс IHttpControllerActivator на уровне GlobalConfiguration.Configuration.Services (это важно, поскольку config.Services работает только с уже созданными экземплярами). контроллеры).

Вот некоторые фрагменты:

Startup.cs

    // the following will make sure that any errors that happen within the constructor
    // of any controller due to dependency injection error will also get logged
    GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator),
              new ExceptionHandlingControllerActivator(                        
                 GlobalConfiguration.Configuration.Services.GetHttpControllerActivator())
                    );


ExceptionHandlingControllerActivator.cs

    /// <summary>
    /// This class handles instantiation of every api controller. It handles and logs 
    /// any exception that occurs during instatiation of each controller, e.g. errors
    /// that can happen due to dependency injection.
    /// </summary>
    public class ExceptionHandlingControllerActivator : IHttpControllerActivator
    {
        private IHttpControllerActivator _concreteActivator;
        private static readonly ILog _logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public ExceptionHandlingControllerActivator(IHttpControllerActivator concreteActivator)
        {
            _concreteActivator = concreteActivator;
        }

        public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
        {
            try
            {
                return _concreteActivator.Create(request, controllerDescriptor, controllerType);
            }
            catch (Exception ex)
            {
                _logger.Error("Internal server error occured while creating API controller " + controllerDescriptor.ControllerName, ex);

                throw new HttpResponseException(request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Unexpected error while creating controller " + controllerDescriptor.ControllerName));
            }
        }
    }
0 голосов
/ 05 ноября 2019

Это очень хорошо описано в этом блоге . Выдержка для ответа на вопрос ниже:

Создайте класс:

public class GlobalExceptionHandler : ExceptionHandler
{
    public async override Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
    {
        // Access Exception
        // var exception = context.Exception;

        const string genericErrorMessage = &quot;An unexpected error occured&quot;;
        var response = context.Request.CreateResponse(HttpStatusCode.InternalServerError, 
            new
            { 
                Message = genericErrorMessage
            });

        response.Headers.Add(&quot;X-Error&quot;, genericErrorMessage);
        context.Result = new ResponseMessageResult(response);
    }
}

Затем зарегистрируйте свой обработчик исключений, как показано ниже, при запуске приложения или настройке owin, как показано ниже:

public static class SetupFiltersExtensions
{
    public static IAppBuilder SetupFilters(this IAppBuilder builder, HttpConfiguration config)
    {
        config.Services.Replace(typeof (IExceptionHandler), new GlobalExceptionHandler());

        return builder;
    }
}

Как указано в его сообщении, он не входит в вышеуказанный метод, но предпочитает делать это через GlobalErrorLogger как таковой:

public class GlobalErrorLogger : ExceptionLogger
{
    public override void Log(ExceptionLoggerContext context)
    {
        var exception = context.Exception;
        // Write your custom logging code here
    }
}

Зарегистрирован как таковой:

public static class SetupFiltersExtensions
{
    public static IAppBuilder SetupFilters(this IAppBuilder builder, HttpConfiguration config)
    {
        config.Services.Replace(typeof (IExceptionHandler), new GlobalExceptionHandler());
        config.Services.Add(typeof(IExceptionLogger), new GlobalErrorLogger());

        return builder;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...