-
Notifications
You must be signed in to change notification settings - Fork 28
Description
Describe the Bug
In a .NET Framework 4.7.2 MVC/Web API OWIN application using Autofac 6.5.0 and Autofac.WebApi2 6.1.0, HttpContext.Current is null inside the controller action when an async Web API action filter (IAutofacActionFilter) uses await in OnActionExecutingAsync.
- If the filter’s OnActionExecutingAsync contains no awaits (i.e., purely sync), HttpContext.Current is available.
- If I downgrade to Autofac.WebApi2 6.0.1, HttpContext.Current remains available even when the filter is async.
This looks like a regression/change in behavior between 6.0.1 → 6.1.0.
Steps to Reproduce
Reproduction Steps
-
Create a .NET Framework 4.7.2 “ASP.NET Web Application (.NET Framework)” with MVC + Web API.
-
Install NuGet packages:
- Autofac 6.5.0 - Autofac.WebApi2 6.1.0 - Autofac.WebApi2.Owin 6.0.0 - Autofac.Owin 6.0.1 - Microsoft.Owin 4.2.3 - Microsoft.Owin.Host.SystemWeb 4.2.3 - Owin 1.0 -
Register Autofac and the Web API filter in OWIN Startup.
-
Add a Web API controller ValuesController and apply the Autofac Web API filter to it (controller or action level).
-
In the filter’s OnActionExecutingAsync, include at least one await (e.g., await Task.Yield() or any real async call).
-
Inside the controller action, read HttpContext.Current (or anything that uses it).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Reflection;
using System.Threading;
using System.Web.Http;
using System.Web.Http.ExceptionHandling;
using Autofac;
using Autofac.Integration.WebApi;
using Microsoft.Owin;
using Microsoft.Owin.Logging;
using Newtonsoft.Json.Serialization;
using Owin;
using TestReproApp.Controllers;
[assembly: OwinStartup(typeof(TestReproApp.Startup))]
namespace TestReproApp
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
// Get your HttpConfiguration.
var config = new HttpConfiguration();
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
config.MapHttpAttributeRoutes();
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().FirstOrDefault();
if (jsonFormatter != null)
{
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// Register the Autofac filter provider.
builder.RegisterWebApiFilterProvider(config);
builder.RegisterType<ActionFilter>()
.WithParameter(new NamedParameter("name", "initial"))
.AsWebApiActionFilterFor<ValuesController>()
.InstancePerRequest();
var container = builder.Build();
var dependencyResolver = new AutofacWebApiDependencyResolver(container);
config.DependencyResolver = dependencyResolver;
// Register the Autofac middleware FIRST, then the Autofac Web API middleware,
// and finally the standard Web API middleware.
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
// By default the IncludeErrorDetail policy is only for Local. Overriding the value to get the details always.
// ref: https://blogs.msdn.microsoft.com/youssefm/2012/06/28/error-handling-in-asp-net-webapi/
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
config.EnsureInitialized();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using Autofac.Integration.WebApi;
namespace TestReproApp.Controllers
{
public class ActionFilter : IAutofacActionFilter
{
public ActionFilter(string name)
{
}
public async Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
{
try
{
var x = new HttpContextWrapper(System.Web.HttpContext.Current).CurrentHandler;
Console.WriteLine("Action executed.");
//throw new NotImplementedException();
await Task.Delay(3000).ConfigureAwait(false);
return;
}
catch (Exception ex) { }
}
public async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
try
{
var x = new HttpContextWrapper(System.Web.HttpContext.Current).CurrentHandler;
Console.WriteLine("Action executing.");
await Task.Delay(3000).ConfigureAwait(false);
return;
}
catch(Exception ex) { }
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Web;
using System.Web.Http;
namespace TestReproApp.Controllers
{
[RoutePrefix("Help/Api")]
public class ValuesController : ApiController
{
// GET api/values
[Route("GET-api-Values")]
public IEnumerable<string> Get()
{
using (var cancellationTokenSource = new System.Threading.CancellationTokenSource(3000))
{
// Null HttpContext.Current
var x = new HttpContextWrapper(System.Web.HttpContext.Current).CurrentHandler;
Thread.Sleep(4000); // Simulate some work
return new string[] { "value1", "value2" };
}
}
// GET api/values/5
public string Get(int id)
{
return "value";
}
// POST api/values
public void Post([FromBody] string value)
{
}
// PUT api/values/5
public void Put(int id, [FromBody] string value)
{
}
// DELETE api/values/5
public void Delete(int id)
{
}
}
}Expected Behavior
HttpContext.Current is non-null in the controller action.
Exception with Stack Trace
Put the exception with stack trace here.
Dependency Versions
- Autofac 6.5.0
- Autofac.WebApi2 6.1.0
- Autofac.WebApi2.Owin 6.0.0
- Autofac.Owin 6.0.1