Detect whether I am running from an HttpContext of a ThreadContext - c#

With StructureMap, I am registering an interface as follow:
public class PersistenceRegistry : Registry
{
public PersistenceRegistry()
{
For<IClearableSessionProvider>().HybridHttpOrThreadLocalScoped().Use<FirebirdSessionProvider>();
}
}
I would like to know if it is possible to detect by any ways if the resolved instance is resolved from an HttpContext or a "ThreadContext". I don't even need to have access to the context. I just want to know whether I am in the context of an HttpRequest or from a background thread.
I tried several things consisting of injecting the HttpContext if it exists, but whatever I tried, I always get a null reference.
I tried to register an IHttpContextProvider:
public interface IHttpProvider
{
HttpContext GetHttpContext();
}
public class HttpProvider
{
HttpContext GetHttpContext()
{
return HttpContext.Current;
}
}
But HttpContext.Current is always null (even once I get into the controller call).
I tried to register an HttpContextWrapper but also always null:
For<HttpContextBase>().Use(() => new HttpContextWrapper(HttpContext.Current))
I am using StructureMap-2.6.3.0. I am not sure how to formulate correctly but the app is built upon OWIN (which explains why my attempts always return null if I understand correctly what I have been reading before coming here).

Related

HttpContext.Current is null inside Identity Framework's methods

I am using ASP.NET MVC 5 and Identity Framework. When I call UserManager.UpdateAsync(...) my eventhandlers on ApplicationDbContext() SaveChanges will run. Here I am using HttpContext.Current for different purposes (logging and auditing) so I must get say current user. However the whole method runs in a worker thread, and here HttpContext.Current is null.
The biggest problem that the UserManager's "sync" methods are only wrappers around the async version, so the calls are serialized, but the methods (and eventhandlers) still run in a different worker thread.
Please note this issue has nothing to do with the async/await context. In the controller after the await (or calling the 'sync' version) I have back the correct HttpContext, even the controller's method is continuing in an other thread. That's fine.
So the problem is inside the async worker which will run in both the "sync" and async versions. I think I am understanding the phenomena (but I am not happy with the fake 'sync' method versions, real sync methods would not exhibit this issue.) I just does not know how to deal/workaround it.
[btw: Would not it be more natural to implement UserManager's operarations as simple pure sync versions, then wrap them by async multithreaded wrappers?. IF we continue this async fashion without thinking we will soon invent the async assignment operator. It costs me dozens of hours (just this issue), and costs worldwide zillion dollars, I am sure in many cases less return than its price.]
Bonus: We are talking about UserManager which's impact pretty marginal, but the same principles and issues can apply any out of the box library (black box for you) which authors do not implement sync versions and or do not care about the controller thread's context. What about EF, it is not so marginal... and what about DI containers instantiation infrastructure like "request scope" or "session scope". Surely they misbehave if resolving occurs in a thread with no HttpContext.Current. Recently I refreshed SendGrid NuGet, and (as a breaking change) Deliver() method gone, and now only DeliverAsync() is existing...
I would like to have a safe reliable way, how can I access the HttpContext inside this worker for logging and audit purposes.
Sample code, the controller 'sync' version:
[AcceptVerbs(HttpVerbs.Post)]
public virtual ActionResult Edit(ApplicationUser user)
{
// validation etc
// Update() seems to be only a poor wrapper around the async version, still uses a worker thread.
var result = UserManager.Update(user);
// Note: HttpContext is correct here so it is not an async/await problem
// error handling, creating ActionResult etc.
}
Sample code, the controller async version:
[AcceptVerbs(HttpVerbs.Post)]
public virtual async Task<ActionResult> Edit(ApplicationUser user)
{
// validation etc
var result = await UserManager.UpdateAsync(user);
// Note: HttpContext is correct here so it is not an async/await problem
// error handling, creating ActionResult etc.
}
and the event handler where HttpContext is null:
public ApplicationDbContext() : base("DefaultConnection", false)
{
InitializeAudit();
}
private void InitializeAudit()
{
var octx = ((IObjectContextAdapter) this).ObjectContext;
octx.SavingChanges +=
(sender, args) =>
{
// HttpContext.Current is null here
};
}
Any ideas?
As you said, this occurs because of threading. The delegate runs in a different thread, making the HttpContext inaccessible.
You can move the variable outside of the delegate, making it a closure.
private void InitializeAudit()
{
var octx = ((IObjectContextAdapter) this).ObjectContext;
HttpContext context = HttpContext.Current;
octx.SavingChanges +=
(sender, args) =>
{
// context is not null
};
}
You are using asp.net identity through owin,
so one instance of the dbcontext is created per request,
and you can get this reference from anywhere in the request pipeline.
nb. this is handy but i think the dbcontext shouldn't be accessed outside the manager.
In asp.net identity design, only the manager should be aware of the store.
I believe the dbcontext is exposed because several asp.net identity middleware have a dependance on it.
But, it could help resolve you problem:
Allow your custom dbcontext handler to be set outside the class:
public EventHandler SavingChangesEventHandler
{
set
{
(((System.Data.Entity.Infrastructure.IObjectContextAdapter)this).ObjectContext).SavingChanges += value;
}
}
Declare a custom ActionFilter class and register it, then override OnActionExecuting:
Filtering in ASP.NET MVC
https://msdn.microsoft.com/en-us/library/gg416513(VS.98).aspx
public class CustomizeAppDbcontextFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var dbcontext = HttpContext.GetOwinContext().Get<ApplicationDbContext>();
var currentuser = HttpContext.Current.User;
dbcontext.SavingChangesEventHandler = (sender, args) =>
{
// use currentuser
};
}
}
you may need these using statements to be able to call the identity.owin extension methods:
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
You should be in the controller thread because OnActionExecuting is wrapping the controller action.
I did not test it, so it may need some polishing but the concept should work.

MVC5 Ninject binding and HttpContext

I am trying to set up a new project and I've added a new class MembershipService that requires the HttpContext to be passed in it's constructor.
In a previous project I used the code
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IMembershipService>()
.To<MembershipService>()
.InRequestScope()
.WithConstructorArgument("context", HttpContext.Current);
....
}
However in the new project I'm using Ninject Modules, and after some searching on StackOverflow and Google, I've come up with the code below:
public class ServiceHandlerModule : NinjectModule
{
public override void Load()
{
Bind<IMembershipService>()
.To<MembershipService>()
.WithConstructorArgument("context", ninjectContext=> HttpContext.Current);
this.Kernel.Bind(x =>
{
x.FromAssemblyContaining(typeof(NinjectWebCommon))
.SelectAllClasses()
.Where(t => t != typeof(MembershipService))
.BindDefaultInterface();
});
this.Kernel.Bind(x =>
{
x.FromAssemblyContaining<BrandServiceHandler>()
.SelectAllClasses()
.Where(t => t != typeof(MembershipService))
.BindDefaultInterface();
});
}
}
However, I get the error below:
Description: An unhandled exception occurred during the execution of
the current web request. Please review the stack trace for more
information about the error and where it originated in the code.
Exception Details: Ninject.ActivationException: Error activating
string No matching bindings are available, and the type is not
self-bindable. Activation path:
5) Injection of dependency string into parameter filename of
constructor of type HttpRequest
4) Injection of dependency HttpRequest into parameter request of
constructor of type HttpContext
3) Injection of dependency HttpContext into parameter httpContext of
constructor of type MembershipService
2) Injection of dependency IMembershipService into parameter
membershipService of constructor of type HomeController
1) Request for HomeController
Can someone point out where I'm going wrong?
Thanks,
John
Steven was right about the HttpContext being a runtime value. Its values are not even populated at the time the application is composed.
This makes sense if you think about it because the application should be initialized outside of any individual user context.
However, Steven's solution only moved the problem to a different service. After all, the class that implements IUserContext will still need to take HttpContext as a dependency.
The solution is to use an Abstract Factory to allow the HttpContext instance to be accessed at runtime instead of when the factory is wired up.
Important: HttpContext is not an abstraction, so it cannot be swapped or mocked. To ensure we are dealing with an abstraction, Microsoft has provided the HttpContextBase abstract class and the default concrete type HttpContextWrapper. HttpContextBase has exactly the same interface as HttpContext. You should always use HttpContextBase as the abstract reference type within your services, not HttpContext.
With those 2 things in mind, you can create a factory for your HttpContext, as follows:
public interface IHttpContextFactory
{
HttpContextBase Create();
}
public class HttpContextFactory
: IHttpContextFactory
{
public HttpContextBase Create()
{
return new HttpContextWrapper(HttpContext.Current);
}
}
Your MembershipService can then be modified to accept an IHttpContextFactory in its constructor:
public class MembershipService : IMembershipService
{
private readonly IHttpContextFactory httpContextFactory;
// This is called at application startup, but note that it
// does nothing except get our service(s) ready for runtime.
// It does not actually use the service.
public MembershipService(IHttpContextFactory httpContextFactory)
{
if (httpContextFactory == null)
throw new ArgumentNullException("httpContextFactory");
this.httpContextFactory = httpContextFactory;
}
// Make sure this is not called from any service constructor
// that is called at application startup.
public void DoSomething()
{
HttpContextBase httpContext = this.httpContextFactory.Create();
// Do something with HttpContext (at runtime)
}
}
And you need only inject the HttpContextFactory at composition time.
kernel.Bind<IHttpContextFactory>()
.To<HttpContextFactory>();
kernel.Bind<IMembershipService>()
.To<MembershipService>();
This alone might not solve the entire issue, though. You need to ensure that the rest of your application does not try to use HttpContext before it is ready. In terms of DI, it means you can't use HttpContext in any constructor of types that are composed in application start or any service members that one of those constructors calls. To solve that, you may need to create additional abstract factories to ensure those services don't call members of IMembershipService until HttpContext is ready.
See this answer for more information about how to accomplish that.
Steven's solution also entailed creating a Facade around HttpContext. While this does not really help solve the problem at hand, I agree that this might be a good idea if your MembershipService (and perhaps other services) only uses a small number of members of HttpContext. Generally, this pattern is to make a complex object simpler to work with (such as flattening it down to a few members that may be nested deep within its hierarchy). But you really need to weigh the extra maintenance of adding another type against the complexity of using HttpContext within your application (or the value of swapping out a section of it) to make that decision.
I've added a new class MembershipService that requires the HttpContext
to be passed in it's constructor.
This is where you're going wrong. The HttpContext is a runtime value, but your object graph should only consist of compile-time or configuration-time dependencies. Anything else, the runtime values, should either be passed through method calls, or should be exposed as properties from the services that are injected.
Not following this guideline, will make it much harder to compose and test your object graphs. Testing your composition root is a good example, since HttpContext.Current is not available when run inside a testing framework.
So prevent this MembershipService from taking a constructor dependency on HttpContext. Instead, inject a service that exposes the HttpContext as a property, because this allows you to request this context after the object graph is constructor.
But perhaps even better is to hide the HttpContext behind an abstraction that is application specific. HttpContext is not an abstraction; it is a big and ugly API that makes your code much harder to test and much harder to comprehend. Instead, create very narrow/focused interfaces, for instance an interface like this:
public interface IUserContext
{
User CurrentUser { get; }
}
Now your MembershipService can depend on a IUserContext that exposes a User object through a property. Now you can create an AspNetUserContext implementation that uses the HttpContext.Current internally, when the CurrentUser property is called. This results in much cleaner, more maintainable code.
Here's a possible implementation:
public class AspNetUserContext : IUserContext
{
public User CurrentUser
{
// Do not inject HttpContext in the ctor, but use it
// here in this property
get { return new User(HttpContext.Current.User); }
}
}
I agree with Steven, however, you could also:
kernel.Bind<HttpContext>().ToMethod(c => HttpContext.Current);

How to handle async calls with Ninject InRequestScope?

We are using Ninject in an ASP.NET Web Api application, and we bind our DbContext with InRequestScope. This works well with most of our requests, because they do all their work synchronously, so the context can be safely disposed after the request is completed.
However, we have on request in which we do an asynchronous web service call, that has a continuation method passed as a callback, and that callback method needs to use the database context. However our request shouldn't wait for the asynchronous service call to finish, but return immediately (this is an explicit requirement).
Here is a simplified example of the situation.
public class MyController : ApiController
{
private readonly MyDbContext dbContext;
private readonly SomeWebService service;
public MyController(MyDbContext dbContext, SomeWebService service)
{
this.dbContext = dbContext;
this.service = service;
}
public IHttpActionResult MyActionWithAsyncCall()
{
// Doing stuff.
// Calling webservice method, passing the Callback as the continuation.
service.MethodWithCallback(param1, param2, this.Callback);
// Returning without waiting for the service call to be completed.
return Ok();
}
private void Callback()
{
// Trying to use the DbContext:
var person = dbContext.People.First();
// The above line sometimes throws exception, because the context has been disposed.
}
}
How should this situation be handled with Ninject? Is there a way to somehow "prolong" the lifetime of a bound DbContext instance explicitly? Or should the Callback method create completely new DbContext? If it should, what scope should it use?
There's is no way to explicitly prolong the lifetime of an object with .InRequestScope() to extend to after the request end.
If there's not a business requirement that the work during the request and # callback must happen in a single transaction i would go for using two DbContext instances. One during the request and one during the callback. Note: As far as i know this also means you can't take an entity from the first context and update/save it in the second context. This means you must only pass identifier (and other data relevant to the operation) from request to callback. The callback has to "create" a new DbContext and retrieve the according entitites from the context.
Conditional Binding Alternative
As an alternative you might declare a special binding for this special case. Ninject supports so called contextual bindings. This means you would have two bindings, the standard binding and a contextual, special case binding:
Bind<DbContext>().ToSelf().InRequestScope();
Bind<DbContext>().ToSelf()
.WhenInjectedInto<SomeController>();
Notice that the second binding does not specify a scope - that means SomeController is responsible to call .Dispose(). In your case that would mean the callback would have to dispose the context. You'd also need to dispose of the context in all errors cases (errors in the callback code, errors occurring before callback is triggered,....).
Also, in reality your application is probably a bite more complex and .WhenInjectedInto<SomeController> is not going to be enough/correct, because you might want to inject the same instance into the controller plus a repository plus a query object.. what not.
That means you will need scoping, but a scope different from .InRequestScope(). You might use .InCallScope() or named scope - both are included in the named scope extension.
Furthermore you would need to adapt the When condition. You could adapt it so to traverse the requests and see if there is FooController anywhere in the request chain. But that's not very performant, instead i would recommend using a ninject IParameter to specify that you want special case treatment. The parameter would be:
public class NonRequestScopedParameter : Ninject.Parameters.IParameter
{
public bool Equals(IParameter other)
{
if (other == null)
{
return false;
}
return other is NonRequestScopedParameter;
}
public object GetValue(IContext context, ITarget target)
{
throw new NotSupportedException("this parameter does not provide a value");
}
public string Name
{
get { return typeof(NonRequestScopedParameter).Name; }
}
// this is very important
public bool ShouldInherit
{
get { return true; }
}
}
which would be applied at the bindings like:
kernel.Bind<SomeController>().ToSelf()
.WithParameter(new NonRequestScopedParameter());
kernel.Bind<DbContext>().ToSelf()
.When(x => x.Parameters.OfType<NonRequestScopedParameter>().Any())
.InCallScope(); // or whatever scope you're using

how do I get access to the object that I'm intercepting?

I'm using Castle Core to create a custom attribute and interceptor to inject security checks into our code using attributes.
e.g. [Security("Role1")]
In the implementation of the interceptor:
public class SecurityInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
object o;
MethodInfo mi = invocation.Method;
SecurityAttribute[] atts = (SecurityAttribute[])mi.GetCustomAttributes(typeof(SecurityAttribute), true);
// if method not marked with Security attribute, then pass on call
if (atts.Length == 0)
{
invocation.Proceed();
}
else
{
//for now assume that there is only one security attribute on the method
//do some security test
{
invocation.Proceed();
}
}
}
In the "do some security test" section above, I need access to the HttpContext.Session object in order to retrieve some saved objects to do the security test.
Assume the method that this attribute is on, is a code-behind asp.net page, i.e an instance of the Page class)
I can't just use this.Context in the attribute like this [Security("Role1", this.Context)]
as attributes don't allow that.
So how do I get access to the httpContext inside the Intercept method?
Or is there a better way of doing this in an aspect-like way?
The InvocationTarget property of the IInvocation instance has the target object. So in your case, if you are certain that the interception happens on a Page object, you should be able to do this:
var page = (Page)invocation.InvocationTarget;
If that is not always the case, you should gain access to the HTTP context in another way.
It's true, as Ben points out, that HttpContext.Current gives you access to the current HttpContext from anywhere, but accessing that static property is just icky. There's a better way, however, and that is by registering a factory method that allows for injection of the session state:
container.Register(
Component.For<ISessionState>()
.UsingFactoryMethod(k => new SessionWrapper(HttpContext.Current.Session)
.Lifestyle.PerWebRequest));
assuming that you have created the ISessionState interface and an appropriate wrapper that has the API you wish to use when interacting with the ASP.NET HttpSessionState object.
Now, since the interceptor is pulled from the container like everything else, it can depend on ISessionState:
public class SecurityInterceptor : IInterceptor
{
public SecurityInterceptor(ISessionState sessionState)
{
//...
}
}
which makes your interceptor nice and testable.
There's probably many other ways to do this, and possible better ways as well. This is just an idea on how you can get on with your project :)
You can use HttpContext.Current.Session from anywhere so long as the code is being called from an ASP.net process.

.NET Remoting and HttpContext.Current

We have a plugin system where the plugin code runs on a separate AppDomain from the main process, using .NET remoting for the objects to communicate.
One class is similar to HttpContext.Current (which also suffers from the problem) (edit, the actual implementation):
public class MyClass
{
public static MyClass Instance
{
get
{
if(HttpContext.Current != null)
return HttpContext.Current.Items["MyClassInstance"];
}
set
{
if(HttpContext.Current != null)
HttpContext.Current.Items["MyClassInstance"] = value;
}
}
}
Then, we have a communicating object which inherits from MarshalByRefObject:
public class CommunicatingClass : MarshalByRefObject, ICommunicatingClass
{
public void DoSomething()
{
MyClass.Instance.DoSomething();
}
}
The CommunicatingClass is created on the main AppDomain, and works fine. Then, there's the plugin class, which is created on its AppDomain, and given an instance of the CommunicatingClass:
public class PluginClass
{
public void DoSomething(ICommunicatingClass communicatingClass)
{
communicatingClass.DoSomething();
}
}
The problem is, that even though CommunicatingClass resides on the main appdomain (verified with the Immediate Window), all of the static data such as MyClass.Instance and HttpContext.Current have disappeared and are null. I have a feeling that MyClass.Instance is somehow being retrieved from the plugin AppDomain, but am unsure how to resolve this.
I saw another question that suggested RemotingServices.Marshal, but that did not seem to help, or I used it incorrectly. Is there a way that the CommunicatingClass can access all static methods and properties like any other class in the main AppDomain?
Edit:
The PluginClass is given an instance like this:
public static PluginClass Create()
{
var appDomain = GetNewAppDomain();
var instance = (PluginClass)appDomain.CreateInstanceAndUnwrap(assembly, type);
instance.Communicator = new CommunicatingClass();
return instance;
}
Edit 2:
Might have found the source of the problem. MyClass.Instance is stored in HttpContext.Current.Items (see above edit).
Is there any way at all that HttpContext.Current can access the correct HttpContext? I'm still wondering why, even though it is being run in HttpContext.Current's AppDomain, CommunicatingClass.DoSomething, when calling MyClass.Instance, retrieves stuff from PluginClass' AppDomain (if that makes any sense).
So my co-worker and I worked this out, finally, with a bunch of help from Reflector.
The main problem is that HttpContext.Current is null when accessed via a remoting call.
The HttpContext.Current property is stored in an interesting manor. A few nested setters down, you reach CallContext.HostContext. This is a static object property on a CallContext.
When the CallContext is set, it first checks if the value is an ILogicalThreadAffinitive.
If it is, it stores the value in the current thread's LogicalCallContext.
If it's not, it stores the value in the current thread's IllogicalCallContext.
HttpContext is not an ILogicalThreadAffinitive, so it is stored in the IllogicalCallContext.
Then, there's remoting.
We didn't dig too far in to its source, but what it does was inferred from some other functions.
When a call is made to a remote object from a different AppDomain, the call is not directly proxied to the original thread, running in the exact same execution context.
First, the ExecutionContext of the original thread (the one containing HttpContext.Current) is captured, via ExecutionContext.Capture (more in this in a bit).
Then, the ExecutionContext returned from Capture is passed as the first argument to ExecutionContext.Run, esentially forming the code:
Delegate myRemoteCall; //Assigned somewhere else in remoting
ExecutionContext.Run(ExecutionContext.Capture(), x => { myRemoteCall() }, null);
Then, completely transparently, your code in the remote object is accessed.
Unfortunately, HttpContext.Current is not captured in ExecutionContext.Capture().
Here lies the essential difference between an IllogicalCallContext and a LogicalCallContext.
Capture creates a brand-new ExecutionContext, essentially copying all of the members (such as the LogicalCallContext) in to the new object. But, it does not copy the IllogicalCallContext.
So, since HttpContext is not an ILogicalThreadAffinative, it cannot be captured by ExecutionContext.Capture.
The solution?
HttpContext is not a MarshalByRefObject or [Serializable] (probably for good reason), so it cannot be passed in to the new AppDomain.
But, it can cross ExecutionContexts without problem.
So, in the main AppDomain's MarshalByRefObject which is given as a proxy to the other AppDomain, in the constructor give it the instance of HttpContext.Current.
Then, in each method call of the new object (unfortunately), run:
private HttpContext _context;
private void SyncContext()
{
if(HttpContext.Current == null)
HttpContext.Current = _context;
}
And it will be set without problem. Since HttpContext.Current is tied to the IllogicalCallContext of the ExecutionContext, it will not bleed in to any other threads that ASP.NET might create, and will be cleaned up when the copy ExecutionContext is disposed.
(I could be wrong about much of this, though. It's all speculation and reflection)
I believe you'll need to derive MyClass from MarshalByRefObject as well.

Categories

Resources