In a controller action I'm running
public ActionResult MyAction()
{
Task.Factory.StartNew( () =>
{
myService.ExecuteMethod( someArgs );
} );
}
The service will call other class methods that call others, and somewhere down the line, an IPrincipal is injected into the constructor of a class.
The IPrincipal is created by doing HttpContext.Current.User.
Since the code is in a Task, it runs on a different thread, and the action has returned so HttpContext.Current is null.
If I try doing Thread.CurrentPrincipal, it exists, but is set to something other than what the HttpContext.Current.User was. Also, if I try accessing Thread.CurrentPrincipal.Identity.Name, I get an ObjectDisposedException thrown.
I'm using Ninject for my IoC container. The IPrincipal binding looks like this
Bind<IPrincipal>().ToMethod( x => HttpContext.Current.User );
Is there a way to get the correct or even a usable IPrincipal in the code ran from a Task in a controller action?
the HttpContext.Current.User is basically something like a temporary ThreadLocal. As such, you'll need to retrieve it's value before starting a task which is run in a different thread. There's no way to find out which thread has executed Task.Factory.StartNew and retrieve it's ThreadLocal values.
Consider, that once you do Task.Factory.StartNew the webrequest may end even before the task has actually started.
So what you need to do is something along the lines of:
IPrincipal principal = HttpContext.Current.User;
Task.Factory.StartNew( () =>
{
myService.ExecuteMethod(principal);
} );
Now however if IPrincipal is (ctor-)injected into myService and myService is instantiated per request (.InTransientScope(), .InRequestScope()) your current binding would work, since the controller is instanciated for each request (also see lifecycle of an asp.net mvc5 application).
The problem would only arise when injecting Lazy<IPrincipal> or when doing IResolutionRoot.Get<IPrincipal> (this includes usage of ninject.extensions.factory, like Func<IPrincipal>!), because at that point HttpContext.Current.User may not be valid any more.
I suggest that if you want an answer more precise and more to the point, you need to post a Minimal, Complete, and Verifiable example
Related
In my Startup.cs file, I have set up a data context to participate in DI.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyDbContext>(options =>
{
options.UseSqlServer("Connection String");
});
}
According to Dependency Injection Doc, the above code automatically puts the data context as Scoped in the IoC container. I am under the impression that an instance of MyDbContext is created for every request. A subsequent request would then have a new MyDbContext instance throughout its lifetime.
I have a controller set up and I'm passing MyDbContext via constructor DI. I make a simple GET request, and I get the data I want. I make a change to that very entity in SQL Management Studio, like change the value of one property/column. I make that same GET request. I don't get the new value that I set in SQL Management Studio.
This makes me think that ASP.net Core holds on to the same instance of MyDbContext across the lifetime of my application. If I stopped and restarted the application, that GET request will return the value I expected.
How do I refresh this data context for each request if I set it up with DI?
Am I missing something? I might post more code if needed.
I am new to ServiceStack, so this is probably a noob question:
I am working on an ASP.NET MVC4 application that uses ServiceStack and am trying to figure out how I could get a hold of the current IAuthSession from within a class (either a EF context or a PetaPoco Database) used by my MVC4 controllers derived from ServiceStackController.
The class in question is registered with Funq with the ReuseScope.Request scope (i.e. on the per-HTTP request basis), and ideally I'd like every instance of it to be autowired with the current IAuthSession using either a constructor parameter or a public property.
How do I do that?
UPDATE
After some digging I came up with what I think might work.
In my AppHost.Configure I register a lambda that returns a session from the current request:
container.Register<IAuthSession>(c =>
HttpContext.Current.Request.ToRequest().GetSession());
Also:
container.RegisterAutoWired<EFCatalogDb>();
where EFCatalogDb is my EF context that takes IAuthSession as a constructor argument:
public class EFCatalogDb : DbContext
{
public EFCatalogDb(IAuthSession session) : base()
{ }
// ...etc....
}
Unfortunately I am not at the point in my development when I can test this workaround, so have to ask others if it makes sense at all.
My first suggestion would be to try to keep IAuthSession out of your database classes since that creates a dependency on ServiceStack that seems unnecessary.
That being said, I think you could go the route of registering IAuthSession and having the container automatically inject IAuthSession. A better way might be creating your own 'wrapper class' around IAuthSession and injecting that into your database classes. That would then break the dependency on ServiceStack.
If you have no issue keeping a dependency on ServiceStack another possibility would be using the SessionFeature class and doing something like
var key = SessionFeature.GetSessionKey();
authSession = AppHost.Resolve<ICacheClient>().Get<IAuthSession>(key);
I'm wondering if this is possible. I have a typical MVC action method with a signature that looks like this:
public ActionResult View(MyModel model)
{
IAnObject myObject = new AnObject();
//several lines of code follow.....
return View(model);
}
I'd like to get rid of that new keyword and inject an instance of IAnObject into the action method. But I'm not sure if MVC allows for this, injecting a class along side a model in an action method? Has anyone run across this, and are there ways of tackling it? (Our IoC container is Windsor, in case that makes a difference.)
If you are expecting to inject this reference into the action method as a parameter, you can look to the ControllerActionInvoker, which has an InvokeActionMethod method, which I believe is called from InvokeAction. This method has a list of parameters passed into it, and a description of the action (ActionDescriptor class). This action descriptor has a GetParameters method that will give you more detailed information about the parameter, such as type information that you would need for the dependency injector. I've not done this, so I don't know quite how it works out, but it seems possible.
I also don't know how that might affect how MVC selects an action method to post to, so factor that in.
You may want to do your injection in OnActionExecuting which is called before any action on the controller is executed. This will give you context such as the Request but will allow you to set member variables - thus 'simulating' constructor injection. And of course you only have to do it once for the whole controller.
[NonAction]
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
_myService = .........; // get from IoC container
base.OnActionExecuting(filterContext);
}
Well, I agree with the guys on the comments, but if you want to take an instance in the method scope, try to get it from your container of IoC, something like this:
public ActionResult View(MyModel model)
{
// take from the container of IoC
IAnObject myObject = _continerIoC.Resolve<IAnObject >();
//several lines of code follow.....
return View(model);
}
Avoid using the new to create your instance and your concrete type in the container and decouple your controller from dependecies/references.
I really consider using constructor/property Injection. There is a method injection too.
var mockedService = new Mock<IService>();
mockedService.Setup(x => x.InterfaceMethod(args)).Returns(value);
_Service = mockedService.Object;
MyController controller =new MyController(_Service);
var result = (ViewResult)controller.Foo();
Now this Foo() Method contains the Following API Call
HttpContext.GetGlobalResourceObject(...,..);
But the HTTPContext is null, as i'm just unit testing , i have not Authenticated. and hence not populated the HTTPContext Object.
I cant set expectations on this class because the HTTPContext is sealed.
I've been searching in the net , but there were only samples to fake the HTTPContextBase
Now how do i get my Unit Test to Pass. Any Suggestions.?
thanks ,
vijay
The problem is you are not setting up an expectation for the "Centres" method. When you mock an object all implementations are replaced with a Noop until you specify otherwise using an Expectation.
I'm guessing you mocked GetValueFromResource rather than Centres because Centres calls GetValueFromResource. If this is the case, mocking GetValueFromResource is likely a superfluous fake and you don't need it.
Also, as has been pointed out on several other Moq posts, you'll need to make sure that you are not mocking what you are testing. If you are actually trying to test MyController, you'd want to mock any dependencies it has, but not MyController itself. This will cause you no end of confusion.
Edit
Based on this feedback it seems you have learned that your true problem is that you need to mock HTTPContext. Mocking HTTPContext is nontrivial. There are a few tools that can do it natively, like Type Mock, but the problem is that ambient context is not testable.
What you should be doing is requesting dependencies that give you the information you need while abstracting away their implementation. For example, in your case it seems like you are using HTTPContext to access resources. If you need something like this a good interface you could use would be:
public interface IResourceStore
{
object GetGlobalResource(string classKey, string resourceKey);
}
Your default implementation would use HTTPContext, but now you have an interface you can mock and have your MyController class use, rather than HTTPContext directly.
Mock<IResourceStore> resourceStore = new Mock<IResourceStore>();
//setup resourceStore expectations here
MyController testingTarget = new MyController(_Service, resourceStore.Object);
//target assertions here
Hope this helps.
Currently I have an ActionFilter that gets the current users name from HttpContext and passes it into the action which uses it on a service method. eg:
Service.DoSomething(userName);
I now have a reason to do this not at the action level but the controller constructor level. Currently I'm using structure map to create controllers and inject the service. I'm looking at something like:
public interface IUserProvider
{
string UserName { get; }
}
public class HttpContextUserProvider : IUserProvider
{
private HttpContext context;
public HttpContextUserProvider(HttpContext context)
{
this.context = context;
}
public string UserName
{
get
{
return context.User.Identity.Name;
}
}
}
That said, my IoC foo is really weak as this is the first project I've used it on.
So my question is... how can I tell structure map to pass in HttpContext in the constructor for HttpContextUserProvider? This just seems weird... I'm not sure how to think of HttpContext.
It sounds like you should be using HttpContextBase instead of HttpContextUserProvider. This is a out-of-box abstraction of HttpContext and allows you to create a mock, write UnitTests and inject your dependencies.
public class SomethingWithDependenciesOnContext
{
public SomethingWithDependenciesOnContext(HttpContextBase context) {
...
}
public string UserName
{
get {return context.User.Identity.Name;}
}
}
ObjectFactory.Initialize(x =>
x.For<HttpContextBase>()
.HybridHttpOrThreadLocalScoped()
.Use(() => new HttpContextWrapper(HttpContext.Current));
Have an interface abstract HttpContext.Current. Expose only the methods you need. GetUserName() would call HttpContext.Current.User.Identity.Name in the implementation, for example. Make that as thin as possible.
Take that abstraction and inject it into your other provider class. This will allow you to test the provider by mocking the http context abstraction. As a side benefit, you can do other nifty things with that HttpContext abstraction besides mock it. Reuse it, for one thing. Add generic type params to bags, etc.
I'm not sure why you're bothering. It seems like just using HttpContext.Current directly in HttpContextUserProvider is the right thing to do. You're never going to be substituting in a different HttpContext...
Maybe I left something out, but the above answer doesn't work for me (has since been deleted -- it was still a useful answer though -- it showed how to tell SM to pass constructor arguments). Instead if I do:
ObjectFactory.Initialize(x =>
{
x.BuildInstancesOf<HttpContext>()
.TheDefault.Is.ConstructedBy(() => HttpContext.Current);
x.ForRequestedType<IUserProvider>()
.TheDefault.Is.OfConcreteType<HttpContextUserProvider>();
});
I get it to work. I did this after finding: If you need something in StructureMap, but you can’t build it with new()…
Edit:
Thanks to Brad's answer I think I have a better handle on HttpContext. His answer definitely works, I just am not sure I like having the call to HttpContext.Current inside a class (it seems like it hides the dependency, but I'm far from an expert on this stuff).
The above code should work for injecting HttpContext as far as I can tell. Matt Hinze brings up the added that point that if all I need from HttpContext is the User.Identity.Name, my design should be explicit about that (having an Interface around HttpContext only exposing what I need). I think this is a good idea.
The thing is over lunch I kinda realized my service really only needs to depend on a string: userName. Having it depend on IUserProvider might not have much added value. So I know I don't want it to depend on HttpContext, and I do know all I need is a string (userName) -- I need to see if I can learn enough StructureMap foo to have make this connection for me. (sirrocoo's answer gives a hint on where to start but he deleted it :*( ).