Failing to resolve dependencies with Unity and WebAPI - c#

I'm receiving this odd error when trying to run my controller action in WebAPI:
An error occurred when trying to create a controller of type 'PostController'. Make sure that the controller has a parameterless public constructor.
Resolution of the dependency failed, type = "Example.Controllers.PostController", name = "(none)".
Exception occurred while: Calling constructor Example.Models.PostRepository().
Exception is: NullReferenceException - Object reference not set to an instance of an object.
Here's the problematic code:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
container.RegisterType<IPostRepository, PostRepository>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "ExampleApi",
routeTemplate: "api/{controller}"
);
}
}
public class PostController : ApiController
{
IPostRepository _repository;
public PostController(IPostRepository repository)
{
_repository = repository;
}
public IEnumerable<Post> GetAllProducts()
{
return _repository.GetAll();
}
}
public class PostRepository : IPostRepository
{
private IDbConnection _connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
public IEnumerable<Post> GetAll()
{
return _connection.Query<Post>("SELECT * FROM Posts").ToList();
}
}
public class UnityResolver : IDependencyResolver
{
protected IUnityContainer Container;
public UnityResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.Container = container;
}
public object GetService(Type serviceType)
{
if (!Container.IsRegistered(serviceType))
{
if (serviceType.IsAbstract || serviceType.IsInterface)
{
return null;
}
}
return Container.Resolve(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return Container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = Container.CreateChildContainer();
return new UnityResolver(child);
}
public void Dispose()
{
Container.Dispose();
}
}
Does anyone have any idea of what might be the cause? I followed this tutorial: http://www.asp.net/web-api/overview/advanced/dependency-injection

In my experience when I see this message its normally some dependency is not able to be constructed or is missing a dependency. You have IPostRepository registered to PostRepository so that looks good. What about the SqlConnection created in PostRepository? Could you run some test code against just the repository to see if it constructs OK on its own?
Also just in browsing through your code is the check for interfaces blocking your resolution of the IPostRepository in the UnityResolver class?
if (serviceType.IsAbstract || serviceType.IsInterface)
{
return null;
}

The following link has a working project which is based on the same tutorial that you mentioned.
Not much difference to your code except the database will be targeting localdb, and on the UnityResolver there is no checks for Abstract class, which doesn't make any difference I think.
Now, you can use the project as a startup point to add your logic, and know exactly when it fails and why.
hope this helps.

Related

An error occurred when trying to create a controller of type 'SaleController'. Make sure that the controller has a parameterless public constructor

I have been following this article:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/dependency-injection#dependency-scope-and-controller-lifetime
The error I get is in the title:
Make sure that the controller has a parameterless public constructor.
Basically the Unity code is the same as in the project from microsoft.
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var container = new UnityContainer();
container.RegisterType<ITrace, Trace>(new HierarchicalLifetimeManager());
container.RegisterType<IUtility, Utility>(new HierarchicalLifetimeManager());
container.RegisterType<IValidator, Validator>(new HierarchicalLifetimeManager());
container.RegisterType<IDeliveryService, DeliveryService>(new HierarchicalLifetimeManager());
container.RegisterType<ISaleService, SaleService>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
I have UnityResolver:
public class UnityResolver : IDependencyResolver
{
protected IUnityContainer container;
public UnityResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = container.CreateChildContainer();
return new UnityResolver(child);
}
public void Dispose()
{
container.Dispose();
}
Unity should instantiate the controllers using this. My only concern is the db context. I tried searching for ways to register but I got nothing.
As asked here is my dbcontext:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false)
{
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
Configuration.ValidateOnSaveEnabled = false;
}
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
I am using Unity for the first time.
In Unity sometimes custom classes that have a specific constructor also require an additional parameter-less constructor (It may be doing nothing but has to exist) like
public UnityResolver(){ }
Afaik this is mostly related to (de)serialization. Not sure why it is required in our specific case .. but that is what the error tries to tell you ;)

DbContext is Disposed When Using Unity Dependency Injection on WebApi project

I'm fairly new at using dependency injection and I think I must be overlooking something really simple.
I have a Web API project where I'm registering generic repositories. The repositories take a dbContext as a parameter in their constructor.
The behavior I find strange is that I can make one successfull call to the service but any subsequent calls tell me that the dbcontext has been disposed. I do have a using statement in there but that shouldn't be a problem since DI is supposed to be creating new instances of my dependencies for each web request(although I could be wrong).
Here is my generic repository:
public class GenericRepository<T> : IGenericRepository<T> where T : class
{
internal DbContext _context;
internal DbSet<T> _dbSet;
private bool disposed;
public GenericRepository(DbContext context)
{
_context = context;
_dbSet = _context.Set<T>();
}
/// <summary>
/// This constructor will set the database of the repository
/// to the one indicated by the "database" parameter
/// </summary>
/// <param name="context"></param>
/// <param name="database"></param>
public GenericRepository(string database = null)
{
SetDatabase(database);
}
public void SetDatabase(string database)
{
var dbConnection = _context.Database.Connection;
if (string.IsNullOrEmpty(database) || dbConnection.Database == database)
return;
if (dbConnection.State == ConnectionState.Closed)
dbConnection.Open();
_context.Database.Connection.ChangeDatabase(database);
}
public virtual IQueryable<T> Get()
{
return _dbSet;
}
public virtual T GetById(object id)
{
return _dbSet.Find(id);
}
public virtual void Insert(T entity)
{
_dbSet.Add(entity);
}
public virtual void Delete(object id)
{
T entityToDelete = _dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Delete(T entityToDelete)
{
if (_context.Entry(entityToDelete).State == EntityState.Detached)
{
_dbSet.Attach(entityToDelete);
}
_dbSet.Remove(entityToDelete);
}
public virtual void Update(T entityToUpdate)
{
_dbSet.Attach(entityToUpdate);
_context.Entry(entityToUpdate).State = EntityState.Modified;
}
public virtual void Save()
{
_context.SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
//free managed objects here
_context.Dispose();
}
//free any unmanaged objects here
disposed = true;
}
~GenericRepository()
{
Dispose(false);
}
}
Here is my generic repository interface:
public interface IGenericRepository<T> : IDisposable where T : class
{
void SetDatabase(string database);
IQueryable<T> Get();
T GetById(object id);
void Insert(T entity);
void Delete(object id);
void Delete(T entityToDelete);
void Update(T entityToUpdate);
void Save();
}
This is my WebApiConfig:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var container = new UnityContainer();
container.RegisterType<IGenericRepository<Cat>, GenericRepository<Cat>>(new HierarchicalLifetimeManager(), new InjectionConstructor(new AnimalEntities()));
container.RegisterType<IGenericRepository<Dog>, GenericRepository<Dog>>(new HierarchicalLifetimeManager(), new InjectionConstructor(new AnimalEntities()));
config.DependencyResolver = new UnityResolver(container);
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
This is my DependencyResolver(which is pretty standard):
public class UnityResolver : IDependencyResolver
{
protected IUnityContainer container;
public UnityResolver(IUnityContainer container)
{
this.container = container ?? throw new ArgumentNullException(nameof(container));
}
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = container.CreateChildContainer();
return new UnityResolver(child);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
container.Dispose();
}
}
And finally this is part of the controller that's giving me trouble:
public class AnimalController : ApiController
{
private readonly IGenericRepository<Cat> _catRepo;
private readonly IGenericRepository<Dog> _dogPackRepo;
public AnimalController(IGenericRepository<Cat> catRepository,
IGenericRepository<Dog> dogRepository)
{
_catRepo = catRepository;
_dogRepo = dogRepository;
}
[HttpGet]
public AnimalDetails GetAnimalDetails(int tagId)
{
var animalDetails = new animalDetails();
try
{
var dbName = getAnimalName(tagId);
if (dbName == null)
{
animalDetails.ErrorMessage = $"Could not find animal name for tag Id {tagId}";
return animalDetails;
}
}
catch (Exception ex)
{
//todo: add logging
Console.WriteLine(ex.Message);
animalDetails.ErrorMessage = ex.Message;
return animalDetails;
}
return animalDetails;
}
private string getAnimalName(int tagId)
{
try
{
//todo: fix DI so dbcontext is created on each call to the controller
using (_catRepo)
{
return _catRepo.Get().Where(s => s.TagId == tagId.ToString()).SingleOrDefault();
}
}
catch (Exception e)
{
//todo: add logging
Console.WriteLine(e);
throw;
}
}
}
The using statement around the _catRepo object is not behaving as expected. After I make the first service call the _catRepo is disposed of. On a subsequent call I'm expecting to have a new _catRepo instantiated. However, this is not the case since the error I'm getting talks about the dbcontext being disposed.
I've tried changing the LifeTimeManager to some of the other ones available but that didn't help.
I also started going down a different route where the generic repository would take a second generic class and instantiate its own dbcontext from it. However, when I did that Unity couldn't find my controller's single-parameter constructor.
I guess what I really need, per the comments below, is a way to instantiate the DbContext on a per-request basis. I don't know how to go about doing that though.
Any hints would be greatly appreciated.
Let's take a look at your registration:
container.RegisterType<IGenericRepository<Cat>, GenericRepository<Cat>>(
new HierarchicalLifetimeManager(),
new InjectionConstructor(new AnimalEntities()));
container.RegisterType<IGenericRepository<Dog>, GenericRepository<Dog>>(
new HierarchicalLifetimeManager(),
new InjectionConstructor(new AnimalEntities()));
You are creating two instances of AnimalEntities at startup, but those instances are reused for the duration of the whole application. This is a terrible idea. You probably intend to have one DbContext per request, but the instance wrapped by the InjectionConstructor is a constant.
You should change your configuration to the following:
container.RegisterType<IGenericRepository<Cat>, GenericRepository<Cat>>(
new HierarchicalLifetimeManager());
container.RegisterType<IGenericRepository<Dog>, GenericRepository<Dog>>(
new HierarchicalLifetimeManager());
// Separate 'scoped' registration for AnimalEntities.
container.Register<AnimalEntities>(
new HierarchicalLifetimeManager()
new InjectionFactory(c => new AnimalEntities()));
This is much simpler and now the AnimalEntities is registered as 'scoped' as well.
What's nice about this is that Unity will now dispose your AnimalEntities once the scope (the web request) ends. This prevents you from having to implement IDisposable on consumers of AnimalEntities, as explained here and here.
I figured out what was going on. As several people have indicated, my repository doesn't need to inherit from IDisposable since the Unity container will dispose of these repositories when the time is right. However, that wasn't the root of my problems.
The main challenge to overcome was getting one dbContext per request. My IGenericRepository interface has stayed the same but my GenericRepository implemenation now looks like this:
public class GenericRepository<TDbSet, TDbContext> :
IGenericRepository<TDbSet> where TDbSet : class
where TDbContext : DbContext, new()
{
internal DbContext _context;
internal DbSet<TDbSet> _dbSet;
public GenericRepository(DbContext context)
{
_context = context;
_dbSet = _context.Set<TDbSet>();
}
public GenericRepository() : this(new TDbContext())
{
}
/// <summary>
/// This constructor will set the database of the repository
/// to the one indicated by the "database" parameter
/// </summary>
/// <param name="context"></param>
/// <param name="database"></param>
public GenericRepository(string database = null)
{
SetDatabase(database);
}
public void SetDatabase(string database)
{
var dbConnection = _context.Database.Connection;
if (string.IsNullOrEmpty(database) || dbConnection.Database == database)
return;
if (dbConnection.State == ConnectionState.Closed)
dbConnection.Open();
_context.Database.Connection.ChangeDatabase(database);
}
public virtual IQueryable<TDbSet> Get()
{
return _dbSet;
}
public virtual TDbSet GetById(object id)
{
return _dbSet.Find(id);
}
public virtual void Insert(TDbSet entity)
{
_dbSet.Add(entity);
}
public virtual void Delete(object id)
{
TDbSet entityToDelete = _dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Delete(TDbSet entityToDelete)
{
if (_context.Entry(entityToDelete).State == EntityState.Detached)
{
_dbSet.Attach(entityToDelete);
}
_dbSet.Remove(entityToDelete);
}
public virtual void Update(TDbSet entityToUpdate)
{
_dbSet.Attach(entityToUpdate);
_context.Entry(entityToUpdate).State = EntityState.Modified;
}
public virtual void Save()
{
_context.SaveChanges();
}
}
The default constructor is now responsible for creating a new DbContext of the type specified when the class is instantiated(I actually have more than one type of DbContext in my application). This allows for a new DbContext to be created for every web request. I tested this by using the using statement in my original repository implementation. I was able to verify that I no longer get the exception about the DbContext being disposed on subsequent requests.
My WebApiConfig now looks like this:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var container = new UnityContainer();
container.RegisterType<IGenericRepository<Cat>, GenericRepository<Cat, AnimalEntities>>(new HierarchicalLifetimeManager(), new InjectionConstructor());
container.RegisterType<IGenericRepository<Dog>, GenericRepository<Dog, AnimalEntities>>(new HierarchicalLifetimeManager(), new InjectionConstructor());
config.DependencyResolver = new UnityResolver(container);
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
One thing that was causing me a lot of pain here is that I didn't realize I still had to call the InjectionConstructor in order to use the parameterless constructor of the repository class. Not including the InjectionConstructor was causing me to get the error about my controller's constructor not being found.
Once I got over that hurdle I was able to change my controller what I have below. The main difference here is that I'm no longer using using statments:
public class IntegrationController : ApiController
{
private readonly IGenericRepository<Cat> _catRepo;
private readonly IGenericRepository<Dog> _dogPackRepo;
public IntegrationController(IGenericRepository<Cat> catRepository,
IGenericRepository<Dog> dogRepository)
{
_catRepo = catRepository;
_dogRepo = dogRepository;
}
[HttpGet]
public AnimalDetails GetAnimalDetails(int tagId)
{
var animalDetails = new animalDetails();
try
{
var dbName = getAnimalName(tagId);
if (dbName == null)
{
animalDetails.ErrorMessage = $"Could not find animal name for tag Id {tagId}";
return animalDetails;
}
}
catch (Exception ex)
{
//todo: add logging
Console.WriteLine(ex.Message);
animalDetails.ErrorMessage = ex.Message;
return animalDetails;
}
return animalDetails;
}
private string getAnimalName(int tagId)
{
try
{
return _catRepo.Get().Where(s => s.TagId ==
tagId.ToString()).SingleOrDefault();
}
catch (Exception e)
{
//todo: add logging
Console.WriteLine(e);
throw;
}
}
}
The way I solved my problem is a little different than what these answers suggest.
I'm in an MVC app but the logic should be similar for this.
As others have stated, creating an instance of an object inside and InjectionContructor essentially creates a static copy of that instance that is used for all future instances of the resolving type. To fix this, I simply register the context as a type and then let Unity resolve the context when it resolves the service. By default, it creates a new instance each time:
UnityConfig:
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<PrimaryContext>(new InjectionConstructor());
container.RegisterType<LocationService>();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
PrimaryContext:
//Allows for a default value if none is passed
public PrimaryContext() : base(Settings.Default.db) { }
public PrimaryContext(string connection) : base(connection)
{
}
LocationService:
PrimaryContext _context;
public LocationService(PrimaryContext context)
{
_context = context;
}
I can't give a ton of specifics about exactly how it works, but this appears to have fixed the problem I was having (I was getting the same error message) and it's super simple.

OWIN and Global.asax.cs file

I use in my project Owin and Katana for OAuth authorization. And all work good but in global.asax.cs file I have some code for IOC container:
Bootstrapper.IncludingOnly.Assembly(Assembly.Load("Dashboard.Rest")).With.SimpleInjector().With.ServiceLocator().Start();
Container container = Bootstrapper.Container as Container;
GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
I added this code in Startup.cs file but after it I catch next exception:
An exception of type
'Bootstrap.Extensions.Containers.NoContainerException' occurred in
Bootstrapper.dll but was not handled in user code
Additional information: Unable to continue. The container has not been
initialized.
and if I call someone api methods I catch next exception:
Unable to continue. The container has not been initialized.
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:
Bootstrap.Extensions.Containers.NoContainerException: Unable to
continue. The container has not been initialized.
Source Error:
Line 21: public Startup() Line 22: { Line 23:
Bootstrapper.IncludingOnly.Assembly(Assembly.Load("Dashboard.Rest")).With.SimpleInjector().With.ServiceLocator().Start();
Line 24: Container container = Bootstrapper.Container as
Container; Line 25:
GlobalConfiguration.Configuration.DependencyResolver = new
SimpleInjectorWebApiDependencyResolver(container);
I don't know how to fix it. Help me please. Thanks.
UPDATE
I have some SimpleInjectorRegisterTypes class for connect my interfaces and services:
public class SimpleInjectorRegisterTypes : ISimpleInjectorRegistration
{
public void Register(Container container)
container.RegisterSingle<IApplication, ApplicationService>();
}
}
And I have service where I write logic for API.
And in my controllers I create constructor for call my method with help interfaces:
public class ApplicationController : ApiController
{
private readonly IApplication _application;
public ApplicationController(IApplication application)
{
_application = application;
}
[HttpGet]
public IHttpActionResult GetAllApps()
{
var apps = _application.GetAllApps();
return apps == null ? (IHttpActionResult)Ok(new Application()) : Ok(apps);
}
....
I fix this problems. I just use other IOC container Unity
Here is an implementation of IDependencyResolver that wraps a Unity container.
public class UnityResolver : IDependencyResolver
{
protected IUnityContainer container;
public UnityResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = container.CreateChildContainer();
return new UnityResolver(child);
}
public void Dispose()
{
container.Dispose();
}
}
WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
container.RegisterType<IProductRepository, ProductRepository>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);
// Other Web API configuration not shown.
}
Some controllers with use IoC containers:
public class ProductsController : ApiController
{
private IProductRepository _repository;
public ProductsController(IProductRepository repository)
{
_repository = repository;
}
// Other controller methods not shown.
}
Dependency Injection in ASP.NET Web API 2

Resolving dbcontext per request with Unity in WebApi

I am struggling to make this work. I've got Unity and Unity.AspNet.WebApi packages (v 3.5.1404) installed and below activation code which came with the packages
public static class UnityWebApiActivator
{
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start()
{
var container = UnityConfig.GetConfiguredContainer();
var resolver = new UnityHierarchicalDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
// DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
}
/// <summary>Disposes the Unity container when the application is shut down.</summary>
public static void Shutdown()
{
var container = UnityConfig.GetConfiguredContainer();
container.Dispose();
}
}
and my type registration looks like this:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IAuditService, AuditService>(
new PerThreadLifetimeManager(),
new InjectionConstructor(new SecurityDbContext()));
}
So far I've tried PerThreadLifetimeManager and TransientLifetimeManager with no success. I've also got the Unity.Mvc package and tried using the PerRequestLifetimeManager as suggested by msdn but no luck. It always gives me the same instance of dbcontex.
I rather do not include any MVC dependency as this is purely WebApi but when I try to use Unity.Mvc, I ended up some http runtime errors too.
Anyone has a good suggestion/example to resolve dbcontext per request with Unity in WebApi, preferably without any mvc dependency?
The way I was injecting db context was the problem here. Unity remembers the instance created and injects the same instance for all new AuditService instance created. I simply needed to resolve the db context as below.
container.RegisterType<DbContext, SecurityDbContext>(new PerThreadLifetimeManager());
PerThreadLifetimeManager did the work and it should be fine considering each web requests will be served by a different thread.
I managed to resolve per request by declaring my custom UnityResolver's class within the WebApiConfig class. The UnityResolver class uses the HttpConfiguration class assuming you're using an OWIN context.
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var _container = new UnityContainer();
DependencyConfiguration.ConfigureContainer(_container);
config.DependencyResolver = new UnityResolver(_container);
}
The ConfigureContainer class is simply a class where I declare my IOC dependencies as shown below:
private static void RegisterReleaseEnv(IUnityContainer container)
{
//Repository Registration
container
.RegisterType(typeof(IRepository<>), typeof(GenericRepository<>), new HierarchicalLifetimeManager());
}
It is very important that you use the HierarchicalLifetimeManager lifetime manager so that you get a new instance per request.
The UnityResolver class then looks like this:
public class UnityResolver : IDependencyResolver
{
protected IUnityContainer container;
public UnityResolver(IUnityContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
this.container = container;
}
public object GetService(Type serviceType)
{
try
{
return container.Resolve(serviceType);
}
catch (ResolutionFailedException)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = container.CreateChildContainer();
return new UnityResolver(child);
}
public void Dispose()
{
container.Dispose();
}
}
I then get a new DB Context using a Generic Repistory as shown below:
public class GenericRepository<TEntity> : IRepository<TEntity>, IDisposable where TEntity : class
{
internal BackendContainer context;
internal DbSet<TEntity> dbSet;
public GenericRepository(BackendContainer context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public GenericRepository()
: this(new BackendContainer())
{
}
public virtual IQueryable<TEntity> All()
{
return dbSet.AsQueryable();
}
}
Because of the Unity Resolver, the Generic Repository is instantiated per request and so is the DbContext (BackendContainer).
I hope this helps.
For more information: http://www.asp.net/web-api/overview/advanced/dependency-injection

How do I connect the various pieces of my Web API Castle Windsor DI code?

How do I connect the various pieces of my Web API Castle Windsor DI code so that the Controller's routing selects the correct interface implementation?
Note: After several false starts/dead ends and partial victories (here and here and here), I am going to bountify this ASAP for the maximum 500 points. But I'm only going to award a really good answer - IOW, one that is clear enough that I can understand it and "plug it in" to my project so that I can hook a given concrete class to a particular Controller.
Here goes nothing: I have a Web API ("MVC") project. Really, though, this server project has no "V" (View), so maybe a better acronym would be MRC (Model/Repository/Controller).
At any rate, I'm trying to add DI to it using Castle Windsor.
I grok, and dig, the concept of swapping out concrete classes via constructor interface args. Just how to implement this functionality, though,
has been a beast I've been wrestling with, and I'm quite bruised and bloody at present, with mussed-up hair and mud-encrusted nostrils to boot.
I have, I think, most of the code I need - to start with, anyway. With DI in mind, I've now got a "DIPlumbing" folder, and a "DIInstallers" folder.
The "DIPlumbing" folder contains two classes: WindsorCompositionRoot.cs, and WindsorControllerFactory.cs.
The "DIInstallers" folder has, for now, three files, namely ISomethingProvider.cs, SomethingProvider.cs, and SomethingProviderInstaller.cs
SomethingProviderInstaller seems to be key in connecting the interfaces/classes in DIInstallers to the stuff in the DIPlumbing folder.
(I have also modified Global.asax.cs to replace the default controller routing business with the Castle Windsor replacement).
But I'm confused as to what classes I should be placing in the DIInstallers folder. Are these supposed to take the place of my Repositories (which likewise have an interface and a concrete class that implements that interface for each model)? IOW, should I basically move my Repository code into the DIInstallers folder - and then get rid of the IRepository and Repository units?
This, of course, would cause necessary changes to be made in the Controller classes, which as of now reference Repository classes.
Or do the Repositories and DIInstallers classes coexist? If so, what is the connection/affiliation between the Controllers, Installers, and Repositories?
It seems the more I read up on DI and Castle Windsor, the more confused I get. I don't know if I'm too dense for it, or if I'm trying to make it harder than it is, or if conflicting styles of using/presenting it are the problem. The bottom line is: I'm stuck in quicksand and need Johnny Quest to extend a sturdy bamboo rod.
The best answer of all, perhaps, and probably too much to ask for, would be a visual representation of how all these components - Controllers, Models, Repositories, Installers, Global.asax.cs, composition roots, factories, providers, etc., relate to each other.
For purposes of "full disclosure," I will add what I hope are the key elements of my code below to show what I've got and how it (hopefully) connects to each other.
Composition Root:
public class WindsorCompositionRoot : IHttpControllerActivator
{
private readonly IWindsorContainer container;
public WindsorCompositionRoot(IWindsorContainer container)
{
this.container = container;
}
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
var controller =
(IHttpController)this.container.Resolve(controllerType);
request.RegisterForDispose(
new Release(
() => this.container.Release(controller)));
return controller;
}
private class Release : IDisposable
{
private readonly Action release;
public Release(Action release)
{
this.release = release;
}
public void Dispose()
{
this.release();
}
}
}
Controller Factory:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel kernel;
public WindsorControllerFactory(IKernel kernel)
{
this.kernel = kernel;
//According to my understanding of http://docs.castleproject.org/Windsor.Typed-Factory-Facility.ashx, I might need this:
kernel.AddFacility<TypedFactoryFacility>();
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
}
return (IController)kernel.Resolve(controllerType);
}
public override void ReleaseController(IController controller)
{
kernel.ReleaseComponent(controller);
}
// Note: The "Something" below will hopefully eventually be "Departments" and then other classes now represented in Models and their corresponding Repositories and Controllers
ISomethingProvider:
public interface ISomethingProvider
{
// These are placeholder methods; I don't know which I will need yet...
//bool Authenticate(string username, string password, bool createPersistentCookie);
//void SignOut();
}
SomethingProvider:
public class SomethingProvider : ISomethingProvider
{
// TODO: Implement methods in ISomethingProvider, once they have been added
}
SomethingProviderInstaller:
public class SomethingProviderInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.BasedOn(typeof(ISomethingProvider))
.WithServiceAllInterfaces());
// From http://app-code.net/wordpress/?p=676; see also http://devlicio.us/blogs/krzysztof_kozmic/archive/2009/12/24/castle-typed-factory-facility-reborn.aspx
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IMyFirstFactory>().AsFactory());
}
}
Controller:
public class DepartmentsController : ApiController
{
private readonly IDepartmentRepository _deptsRepository;
public DepartmentsController(IDepartmentRepository deptsRepository)
{
if (deptsRepository == null)
{
throw new ArgumentNullException("deptsRepository is null");
}
_deptsRepository = deptsRepository;
}
public int GetCountOfDepartmentRecords()
{
return _deptsRepository.Get();
}
public IEnumerable<Department> GetBatchOfDepartmentsByStartingID(int ID, int CountToFetch)
{
return _deptsRepository.Get(ID, CountToFetch);
}
. . .
}
IRepository:
public interface IDepartmentRepository
{
int Get();
IEnumerable<Department> Get(int ID, int CountToFetch);
}
Repository:
public class DepartmentRepository : IDepartmentRepository
{
private readonly List<Department> departments = new List<Department>();
public DepartmentRepository()
{
using (var conn = new OleDbConnection(
#"Provider=Microsoft.ACE.OLEDB.12.0;[bla]"))
{
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = "SELECT td_department_accounts.dept_no, IIF(ISNULL(t_accounts.name),'No Name provided',t_accounts.name) AS name FROM t_accounts INNER JOIN td_department_accounts ON t_accounts.account_no = td_department_accounts.account_no ORDER BY td_department_accounts.dept_no";
cmd.CommandType = CommandType.Text;
conn.Open();
int i = 1;
using (OleDbDataReader oleDbD8aReader = cmd.ExecuteReader())
{
while (oleDbD8aReader != null && oleDbD8aReader.Read())
{
int deptNum = oleDbD8aReader.GetInt16(0);
string deptName = oleDbD8aReader.GetString(1);
Add(new Department { Id = i, AccountId = deptNum, Name = deptName });
i++;
}
}
}
}
}
public int Get()
{
return departments.Count;
}
private Department Get(int ID) // called by Delete()
{
return departments.First(d => d.Id == ID);
}
public IEnumerable<Department> Get(int ID, int CountToFetch)
{
return departments.Where(i => i.Id > ID).Take(CountToFetch);
}
. . .
}
Global.asax.cs:
public class WebApiApplication : System.Web.HttpApplication
{
private static IWindsorContainer container;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
BootstrapContainer();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
private static void BootstrapContainer()
{
container = new WindsorContainer().Install(FromAssembly.This());
var controllerFactory = new WindsorControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator), new WindsorCompositionRoot(container));
}
protected void Application_End()
{
container.Dispose();
}
UPDATE
In trying to run the server, so that it could test it with Fiddler2 to see just what is being passed around, it failed on this line in WindsorControllerFactory:
public WindsorControllerFactory(IKernel kernel)
{
this.kernel = kernel;
kernel.AddFacility<TypedFactoryFacility>(); <-- throws exception here
}
...with "System.ArgumentException was unhandled by user code
HResult=-2147024809
Message=Facility of type 'Castle.Facilities.TypedFactory.TypedFactoryFacility' has already been registered with the container. Only one facility of a given type can exist in the container.
Source=Castle.Windsor
StackTrace:
at Castle.MicroKernel.DefaultKernel.AddFacility(String key, IFacility facility)
at Castle.MicroKernel.DefaultKernel.AddFacility(IFacility facility)
at Castle.MicroKernel.DefaultKernel.AddFacilityT
at HandheldServer.DIPlumbing.WindsorControllerFactory..ctor(IKernel kernel) in c:\HandheldServer\HandheldServer\DIPlumbing\WindsorControllerFactory.cs:line 28
at HandheldServer.WebApiApplication.BootstrapContainer() in c:\HandheldServer\HandheldServer\Global.asax.cs:line 69
at HandheldServer.WebApiApplication.Application_Start() in c:\HandheldServer\HandheldServer\Global.asax.cs:line 39"
UPDATE 2
In response to Cristiano's answer:
So are you saying I should add the following two files to my Installers folder (I do have a DIInstallers folder already)
PlatypusInstallerFactory.cs:
public class PlatypusInstallerFactory : InstallerFactory
{
public override IEnumerable<Type> Select(IEnumerable<Type> installerTypes)
{
var windsorInfrastructureInstaller = installerTypes.FirstOrDefault(it => it == typeof(WindsorInfrastructureInstaller));
var retVal = new List<Type>();
retVal.Add(windsorInfrastructureInstaller);
retVal.AddRange(installerTypes
.Where(it =>
typeof(IWindsorInstaller).IsAssignableFrom(it) &&
!retVal.Contains(it)
));
return retVal;
}
}
WindsorInfrastructureInstaller.cs:
public class WindsorInfrastructureInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<TypedFactoryFacility>();
}
}
In your global.asax you'll create&use you installer factory as following
var installerFactory = new PlatypusInstallerFactory();
container.Install(FromAssembly.This(installerFactory));
If yes, what will that do for me? Does the above automagically register my Controller and/or Repository classes?
UPDATE 3
I am now using a lot of code from [http://blog.kerbyyoung.com/2013/01/setting-up-castle-windsor-for-aspnet.html#comment-form]
The key parts are, I think:
global.asax.cs:
private static IWindsorContainer _container;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ConfigureWindsor(GlobalConfiguration.Configuration);
}
public static void ConfigureWindsor(HttpConfiguration configuration)
{
_container = new WindsorContainer();
_container.Install(FromAssembly.This());
_container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
var dependencyResolver = new WindsorDependencyResolver(_container);
configuration.DependencyResolver = dependencyResolver;
}
WindsorDependencyResolver.cs:
namespace HandheldServer
{
public class WindsorDependencyResolver : System.Web.Http.Dependencies.IDependencyResolver
{
private readonly IWindsorContainer _container;
public WindsorDependencyResolver(IWindsorContainer container)
{
_container = container;
}
public IDependencyScope BeginScope()
{
return new WindsorDependencyScope(_container);
}
public object GetService(Type serviceType)
{
if (!_container.Kernel.HasComponent(serviceType))
{
return null;
}
return this._container.Resolve(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
if (!_container.Kernel.HasComponent(serviceType))
{
return new object[0];
}
return _container.ResolveAll(serviceType).Cast<object>();
}
public void Dispose()
{
_container.Dispose();
}
}
public class WindsorDependencyScope : IDependencyScope
{
private readonly IWindsorContainer _container;
private readonly IDisposable _scope;
public WindsorDependencyScope(IWindsorContainer container)
{
this._container = container;
this._scope = container.BeginScope();
}
public object GetService(Type serviceType)
{
if (_container.Kernel.HasComponent(serviceType))
{
return _container.Resolve(serviceType);
}
else
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this._container.ResolveAll(serviceType).Cast<object>();
}
public void Dispose()
{
this._scope.Dispose();
}
}
public class ApiControllersInstaller : IWindsorInstaller
{
public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly() // should it be Types instead of Classes?
.BasedOn<ApiController>()
.LifestylePerWebRequest());
}
}
// This idea from https://github.com/argeset/set-locale/blob/master/src/client/SetLocale.Client.Web/Configurations/IocConfig.cs
public class ServiceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IDeliveryItemRepository>().ImplementedBy<DeliveryItemRepository>().LifestylePerWebRequest(),
Component.For<IDeliveryRepository>().ImplementedBy<DeliveryRepository>().LifestylePerWebRequest(),
Component.For<IDepartmentRepository>().ImplementedBy<DepartmentRepository>().LifestylePerWebRequest(),
Component.For<IExpenseRepository>().ImplementedBy<ExpenseRepository>().LifestylePerWebRequest(),
Component.For<IInventoryItemRepository>().ImplementedBy<InventoryItemRepository>().LifestylePerWebRequest(),
Component.For<IInventoryRepository>().ImplementedBy<InventoryRepository>().LifestylePerWebRequest(),
Component.For<IItemGroupRepository>().ImplementedBy<ItemGroupRepository>().LifestylePerWebRequest());
}
}
}
UPDATE 4
This question is probably too general for SO, so I posted it on "Programmers"
UPDATE 5
Note: According to "The DI Whisperer" (Mark Seemann), IDependencyResolver should not be used, because it lacks a Release method (p. 207 of his book)
You should not mix installation vs resolving.
IOW your should not have
kernel.AddFacility<TypedFactoryFacility>();
in the WindsorControllerFactory
But the generic container configuration such registering TypedFactoryFacility should be executed in an installer called as earlier as possible.
In order to drive installer execution, you should use an Installer factory
public class YourInstallerFactory : InstallerFactory
{
public override IEnumerable<Type> Select(IEnumerable<Type> installerTypes)
{
var windsorInfrastructureInstaller = installerTypes.FirstOrDefault(it => it == typeof(WindsorInfrastructureInstaller));
var retVal = new List<Type>();
retVal.Add(windsorInfrastructureInstaller);
retVal.AddRange(installerTypes
.Where(it =>
typeof(IWindsorInstaller).IsAssignableFrom(it) &&
!retVal.Contains(it)
));
return retVal;
}
}
Where windsorInfrastructureInstaller will be somenthing like this
public class WindsorInfrastructureInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
// Resolvers
//container.Kernel.Resolver.AddSubResolver(new ArrayResolver(container.Kernel));
// TypedFactoryFacility
container.AddFacility<TypedFactoryFacility>();
}
}
In your global.asax you'll create&use you installer factory as following
var installerFactory = new YourInstallerFactory();
container.Install(FromAssembly.This(installerFactory));
Your "FrontEnd"(for example the mvc/webapi) project has a folder containing all installers(WindsorInfrastructureInstaller will be one of those) and the installer factory as well or at least that's the way I'm use to organize my solution.
In answer to my own question, I would simply say: There are no shortcakes! Without stopping go or further ado, go here and get this book. Resign yourself to take the time necessary to read it carefully.
So I'm not the only one; here's a quote from Jeff Beck, who wrote that book's foreword: "Often those who start using DI quickly find themselves lost in a sea of confusion."
Don't want to repeat everything again, so just check out my answer on How do I get Web API / Castle Windsor to recognize a Controller?.
As another note - I would advise against doing anything in your repository constructors if you can help it. The reason I say this is that the constructors get called as Windsor is trying to instantiate the correct instance of your repository. What this means is that if any kind of error occurs, it happens as WebApi is trying to create the controller. This can make it a bit tricky to track down the problem sometimes, and also ends up hiding the real issues under tons of layers of exceptions.

Categories

Resources