Error Handling in Asp .Net Web API and the System.Net.Http dll conflict

Tags: Asp .Net, Web Api

Catching Global Errors

In Asp .Net we can capture global errors by overriding the method Application_Error in the global.asax file.

public class WebApiApplication : System.Web.HttpApplication
	{
        private static Logger _logger = LogManager.GetCurrentClassLogger();

        protected void Application_Start()
		{
            _logger.Info("Application_Start_BEGIN");

			GlobalConfiguration.Configure(WebApiConfig.Register);
			FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
			RouteConfig.RegisterRoutes(RouteTable.Routes);
			DependencyInjectionConfig.Register(GlobalConfiguration.Configuration);

            _logger.Info("Application_Start_END");
        }

        protected void Application_Error(object sender, EventArgs e)
        {
            Exception exception = Server.GetLastError();
            if (exception != null)
            {
                _logger.Error(exception, "Application_Error: " + Request);

            }
        }
    }

Some Web API errors will not be caught including the following:

System.MissingMethodException: Method not found: 'System.Net.Http.HttpRequestMessage System.Web.Http.ApiController.get_Request()'.
   at TokenApplication.Controllers.TokenController.<Post>d__4.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at TokenApplication.Controllers.TokenController.Post()
   at lambda_method(Closure , Object , Object[] )
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass6_3.<GetExecutor>b__3(Object instance, Object[] methodParameters)
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext() System.MissingMethodException: Method not found: 'System.Net.Http.HttpRequestMessage System.Web.Http.ApiController.get_Request()'.
   at TokenApplication.Controllers.TokenController.<Post>d__4.MoveNext()
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at TokenApplication.Controllers.TokenController.Post()
   at lambda_method(Closure , Object , Object[] )
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass6_3.<GetExecutor>b__3(Object instance, Object[] methodParameters)
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext()

Catching Web Api Errors

To catch Web Api errors we need to register an instance of IExceptionLogger during Web Api configuration:

public static class WebApiConfig
	{
		public static void Register(HttpConfiguration config)
		{
            //Register it here
            config.Services.Replace(typeof(IExceptionLogger), new UnhandledExceptionLogger());

            // Web API configuration and services

		}
	}

    public class UnhandledExceptionLogger : ExceptionLogger
    {
        private static Logger _logger = LogManager.GetCurrentClassLogger();

        public override void Log(ExceptionLoggerContext context)
        {
            _logger.Error(context.Exception, "Application_Error: " + context.Exception);
        }
    }

More about the error message

The error message is an instance of System.Net.Http DLL conflict.

The build outputs the System.Net.Http dll into the bin folder of the Web Api application.
It has a version which conflicts with the .Net Framework version of the DLL.

      <dependentAssembly>
        <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
      </dependentAssembly>

The binding redirect block the application from using this file and fall back to the .net framework one.

image

Sources:

No Comments

Add a Comment