In normal ASP.MVC projects we configure the dependency resolver with Unity and the Unity.Mvc3 package from http://unitymvc3.codeplex.com/
We have this test service registered with a HierarchicalLifetimeManager
container.RegisterType<ITestService, TestService>(new HierarchicalLifetimeManager());
And we hook up the container with Mvc in Global.asax.cs:
System.Web.Mvc.DependencyResolver.SetResolver(new Unity.Mvc3.UnityDependencyResolver(container));
And we run this test controller:
public class TestController : Controller
{
private readonly ITestService _service;
public TestController(ITestService service)
{
this._service = service;
}
public ActionResult Test()
{
var locatedService = System.Web.Mvc.DependencyResolver.Current.GetService<ITestService>();
if (_service == locatedService)
return View("Success - Same Service");//This is always the result in an MVC controller
else
throw new Exception("Failure - Different Service Located");//This is never the result in an MVC controller
}
}
However, on this project we are adding a number of WebAPI controllers.
We have this configuration in global.asax.cs (using http://unitywebapi.codeplex.com/ for now. But I am open to suggestions):
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
We have created an ApiTestController similar to TestController inheriting from ApiController rather than from Controller.
However, the ApiTestController fails its test. I understand that the System.Web.Mvc.DependencyResolver class and the System.Web.Mvc.DependencyResolver.Current property are specific to Mvc. But does WebAPI have an equivalent?
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver.GetService does not work because the System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver instance is the parent container that I configured. It is not the child controller that was used to inject the ITestService into the constructor.
This user seems to have a similar problem: http://unitywebapi.codeplex.com/discussions/359413
But I feel that this probably has more to do with ASP.NET's WebAPI than it has to do with Unity.
Thanks
After looking over the source of http://unitymvc3.codeplex.com/ and http://unitywebapi.codeplex.com/ I created this class:
public class MyUnityDependencyResolver : Unity.Mvc3.UnityDependencyResolver, System.Web.Http.Dependencies.IDependencyResolver
{
public MyUnityDependencyResolver(IUnityContainer container)
: base(container)
{
}
public System.Web.Http.Dependencies.IDependencyScope BeginScope()
{
return this;
}
public void Dispose()
{
Unity.Mvc3.UnityDependencyResolver.DisposeOfChildContainer();
}
}
Configuration in gobal.asax.cs:
var myResolver = new MyUnityDependencyResolver(container);
System.Web.Mvc.DependencyResolver.SetResolver(myResolver);
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = myResolver;
Unity.Mvc3.UnityDependencyResolver uses HttpContext.Current.Items to manage child containers. MyUnityDependencyResolver may not be the most "correct" implementation of System.Web.Http.Dependencies.IDependencyResolver, but it seems to work so far.
I will mark this as the answer in a couple days if no one else has any better answers.
Unfortunately, when you call the GlobalConfiguration.Configuration.DependencyResolver.GetService, it completely ignores any scope and resolves using the outer non-child container which is around for the lifetime of the application. This is an issue with Web Api and makes it impossible to use constructor injection for per-request dependencies outside of controllers. Confusingly this is completely different behaviour from MVC as you say.
What you can do is use the GetDependencyScope() extension method off HttpRequestMessage. Anything you resolve using this will be in per request scope when using HierarchicalLifetimeManager in conjunction with Unity.WebApi. The request is available from action filters and handlers so may be a viable workaround.
Obviously this is pure service location rather than dependency injection which is far from ideal but I have not found another way to access per-request dependencies outside of controllers.
See this post for more info.
The DependencyResolver is not the right seam for dependency injection in ASP.NET WebAPI.
Mark Seemann has two really good posts on DI with WebAPI.
Dependency Injection and Lifetime Management with ASP.NET Web API
Dependency Injection in ASP.NET Web API with Castle Windsor
If you want to do it right you should have a look at them.
Related
I am hosting WebApi controller inside a stateless service with one instance. The service instance (I mean the instance of the WebApiService class created by the SF runtime) maintains some transient state as member fields, exposing the state through internal (thread-safe) methods. The WebApi controller needs to call the methods to access that state.
WebApiService.cs:
-----------------
internal sealed class WebApiService : StatelessService
{
private int _state;
internal int GetState() { return this._state; }
ServiceController.cs:
---------------------
public class ServiceController : ApiController
{
public async Task<IHttpActionResult> GetStateAsync()
{
// Here I'd like to grab somehow the WebApiService instance
// and call its GetState internal method.
My questions are:
How can the controller get a reference to the WebApiService instance?
Is it safe to store the WebApiService instance in a static field (perhaps set in the WebAspiService constructor)?
Inject the service instance as a dependency to your controllers through a DI container.
Here's an example with Web API hosted on Katana using Unity. It's a stateful service but it works exactly the same way for a stateless service: https://github.com/Azure-Samples/service-fabric-dotnet-getting-started/tree/master/Services/WordCount/WordCount.Service
Here's an example using Asp.Net Core and its built-in dependency injection container (also stateful, but same thing applies): https://github.com/vturecek/service-fabric-xray/tree/master/src/xray.Data
I think you could use a DI container for that. I can recommend simpleinjector (but there are many that can do the same), simpleinjector has got object lifetime management also per request and a web api package. You could put your state instance in a container as a singleton and inject it in your controllers, that would be a thread safe way, better stay away from static fields in a multithreaded web environment.
You have to resolve the stateless service in your controller before you can call the methods of the stateless service:
public async Task<IHttpActionResult> GetStateAsync()
{
var proxyLocation = new ServiceUriBuilder("WebApiService");
var svc = ServiceProxy.Create<IWebApiService>(proxyLocation.ToUri());
return svc.GetState();
}
You need to create an interface IWebApiService that contains the GetState method. WebApiService needs to implement it. Basically you need to abstract WebApiService with the IWebApiService interface.
this question Ninject Dependency Injection in MVC3 - Outside of a Controller is close to what I'm experiencing, but not quite.
I have an ASP.NET MVC3 site using Ninject 3 and it works wonderfully with constructor injection. All my dependencies are resolved, including those that pass in HttpContext.Current.
My issue is that in global.asax, I kick off a TaskManager class that periodically performs some tasks on a timer. Inside the TaskManager class, I don't have controllers, so if I need access to one of my dependencies (like my error logging service), I use a static wrapper class that has access to the kernel object:
var logger = MyContainer.Get<ILoggingService>();
logger.Error("error doing something...", ex);
The .Get method simply performs a kernel.Get call resolve my dependency. Works great every time I use this method on my other dependencies. However, ILoggingService has a dependency called MyWebHelper that is injected via it's constructor and includes HttpContext in it's constructor.
public class DefaultLogger : ILoggingService
{
public DefaultLogger(IRepository<Log> logRepository, IWebHelper webHelper)
{
_logRepository = logRepository;
_webHelper = webHelper;
}
}
public class MyWebHelper : IWebHelper
{
public MyWebHelper(HttpContext httpContext)
{
_httpContext = httpContext;
}
}
In the rest of my web site, this all works just fine because all the dependencies are injected into my MVC controllers. But what doesn't work is if I manually call my static wrapper class to get my dependencies that way. I get the error:
Error activating HttpContext using binding from HttpContext to method
Provider returned null.
So, it's not giving me an HttpContext like it does throughout the rest of my MVC application. I hope this makes sense, I'm not a ninject expert yet, but I'm trying...
My issue is that in global.asax, I kick off a TaskManager class that
periodically performs some tasks on a timer.
That's a bad idea as Phil Haack explains in details. Don't do this in your web application. Those recurring tasks should be done in a separate application (Windows Service or some console application which is scheduled to run at regular intervals).
Now the thing is that you are running background threads. Those background threads run outside of any user HTTP request and as a consequence HttpContext.Current is obviously null inside them. So even if you don't follow Phil Haack's advice and continue running background tasks in your ASP.NET application you will have to rearchitecture your method so that it no longer depends on any HttpContext because there's no such thing in those background threads.
I'm using StructureMap for IoC and it works fine for regular controllers but I can't make it work with Areas. I have the following AccountController in Administration Area:
public class AccountController : Controller
{
private readonly IFormsAuthenticationService formsService;
private readonly IMembershipService membershipService;
public AccountController(IFormsAuthenticationService formsService, IMembershipService membershipService)
{
this.formsService = formsService;
this.membershipService = membershipService;
}
...
}
And here's the error:
System.InvalidOperationException: An error occurred when trying to create a controller of type 'Foo.Areas.Administration.Controllers.AccountController'. Make sure that the controller has a parameterless public constructor. ---> System.MissingMethodException: No parameterless constructor defined for this object.
Any help would be greatly appreciated!
EDIT
StructureMap couldn't resolve MembershipProvider.
Here's the solution:
For<MembershipProvider>().Use(Membership.Providers["AspNetSqlMembershipProvider"]);
I doubt that this is a problem with areas because I am using them happily. It is more likely a pure IOC issue. You get this error when one of the injected services cannot be resolved by your container, which has the consequence that the container cannot match a signature for the constructor and tries to fall back to the empty constructor, which doesn't exist, rightly.
So, my first instinct would be to make sure that the two injected services are available. It is possible that one of them did not get created properly; a common cause is that the Membership provider cannot connect to its database, or similar.
For diagnosing, in your global.asax, after the container has been created, see if you can manually resolve those two services. I don't know SM, but something like:
var s = container.Resolve<IMembershipService>();
Satisfy yourself that both those services can be resolved.
I am creating a MVC3 website that will expose a REST API using WCF Web API.
To register routes to the REST API I add code to the Global.asax similar to the code below.
routes.MapServiceRoute<RelationsService>("relations");
This works well enough but i need to use a DI approach to inject the dependencies that the Service depends on.
As you can see in the code above the MVC framework is creating the instance of the RelationsService but this should be done by the DI container.
Does anyone know how to configure MVC3 so that my own DI container is used for creating the instances of the Services?
You have to extend your current service registration call with an IHttpHostConfigurationBuilder that has been created with an IResourceFactory.
var configurationBuilder = HttpHostConfiguration.Create()
.SetResourceFactory(new ResourceFactory());
routes.MapServiceRoute<RelationsService>("relations", configurationBuilder);
Then if you for instance use StructureMap as preferred IoC/DI tool you can just ask for the service in the GetInstance method.
public class ResourceFactory : IResourceFactory
{
public object GetInstance(Type serviceType, InstanceContext instanceContext, HttpRequestMessage request)
{
return ObjectFactory.GetInstance(serviceType);
}
}
It seems like at least 90+% of the Controller Actions I am writing will need to access the database. To me it seems like a logical step to have the database context automatically injected.
I have never used dependency injection before so I want to confirm this is something that is a pattern. If it is, how should I go about doing this? I know ASP.NET MVC 3 has "improved dependency injection" support, but do I still need an external framework? If so what is the default and how do I configure it to create a new database context per http request?
ASP.NET MVC 3 doesn't have improved DI support - it has improved support for the Service Locator anti-pattern (go figure). Fortunately it has had support for DI since MVC 1 through the IControllerFactory interface.
To answer the question, however, yes, it sounds like a perfectly normal thing to inject a Repository into a Controller (although normally we would slide a Domain Model in between the two).
This is best done with Constructor Injection like this:
public class MyController
{
private readonly IMyRepository repository;
public MyController(IMyRepository repository)
{
if (repository == null)
{
throw new ArgumentNullException("repository");
}
this.repository = repository;
}
public ViewResult MyAction(int barId)
{
var bar = this.repository.SelectBar(barId);
return this.View(bar);
}
}
You'll need to provide a custom IControllerFactory to enable Constructor Injection with the MVC framework - the easiest thing is to derive from DefaultControllerFactory.
Once you have a custom IControllerFactory, you can register it in Global.asax like this:
ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());