Reputation: 81
Context
I am trying wireup Audit.Net in an MVC5 app with .Net Framework 4.8.
Dataprovider: EntityFramework
Output: Cosmos
DI Provider: Autofac
The Problem
I have tried the following call backs to try and write the username to the AuditEvent.
Configuration.AddOnCreatedAction(scope =>
{
var username = HttpContext.Current.User.Identity.GetUserId();
scope.SetCustomField("User2", username);
});
Configuration.AddOnSavingAction(scope =>
{
var username = HttpContext.Current.User.Identity.GetUserId();
scope.SetCustomField("User2", username);
});
Configuration.AddOnSavingAction(scope =>
{
var user = AutofacDependencyResolver.Current.Resolve<IPrincipal>();
scope.SetCustomField("User2", user.Identity.GetUserId());
});
These for work for synchronous calls to dbContext.SaveChanges(), when SaveChangesAsync() is called then I cannot access the current HttpContext as it is always null.
Any suggestions?
Upvotes: 2
Views: 1152
Reputation: 891
You may capture the HttpContext earlier in the Asp .Net pipeline:
public interface IHttpContextContainer
{
HttpContextBase HttpContextBase { get; set; }
}
In your controller or service you may attach the lifetime scope to your custom Audit event:
public abstract class MyAuditEvent : AuditEvent
{
[JsonIgnore]
public ILifetimeScope LifetimeScope { get; set; }
}
Add JsonIgnoreAttribute to prevent serializing the LifetimeScope.
In the global event handler you may now access the custom audit event:
Configuration
.AddCustomAction(
ActionType.OnScopeCreated,
auditScope =>
{
if (auditScope.Event is MyAuditEvent auditEvent)
{
var scope = auditEvent.LifetimeScope;
var httpContextContainer = scope.Resolve<IHttpContextContainer>();
// ...
// access HttpContextBase from httpContextContainer
}
});
Upvotes: 0
Reputation: 23924
The key (which might help in search terms) is async
. A quick search for async httpcontext mvc
gets us to this existing question with a lot of information about async
/await
and HttpContext
usage.
The super short version: in MVC, the HttpContext
gets carried around in the thread synchronization context (which is also where, say, the culture and other thread settings are carried around) but it's expensive to cart that context from thread to thread so the default is to not do that. You need to enable it explicitly to work.
Here's a blog article explaining the various knobs you can turn in web.config to get it to work but the net result is, basically, to make sure <httpRuntime targetFramework="4.5" />
is set (well, set that value to 4.5 or higher).
If that's already set, then... maybe there's something else at play, like a call has the ConfigureAwait(false)
set on it so it's not returning to a thread context that has the HttpContext
. But, more than likely, that httpRuntime
flag should fix it.
Upvotes: 1