I want to know if there is a better to way to handle this.
I've set up Unity for dependency injection for our project. The project itself is an ASP.NET application that uses Web API.
I have the following packages installed.
Unity
Unity.ASPNet.WebAPI
I see no option to close/dispose the DBContext right after fetching the data.
My controller
public class NinjasController : ApiController
{
public Ninja Get(int id)
{
INinjaRepository repository = UnityConfig.Container.Resolve(typeof(INinjaRepository), null) as INinjaRepository;
Ninja ninja = repository.GetNinjaById(id);
repository.CanBeDisposed = true;
repository = null;
UnityConfig.PerRequestLifetimeManager.Dispose();
return ninja;
}
}
UnityConfig
public static class UnityConfig
{
private static Lazy<IUnityContainer> container =
new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
public static IUnityContainer Container => container.Value;
public static PerRequestLifetimeManager PerRequestLifetimeManager;
public static void RegisterTypes(IUnityContainer container)
{
PerRequestLifetimeManager = new PerRequestLifetimeManager();
container.RegisterType<INinjaRepository, NinjaRepository>(PerRequestLifetimeManager);
}
}
Lifetime Manager
public class PerRequestLifetimeManager : TransientLifetimeManager, IDisposable
{
private static List<IBaseRepository> list = new List<IBaseRepository>();
public override void SetValue(object newValue, ILifetimeContainer container = null)
{
base.SetValue(newValue, container);
IBaseRepository disposable = newValue as IBaseRepository;
if (disposable != null)
list.Add(disposable);
}
public void Dispose()
{
foreach (IBaseRepository item in list.FindAll(item => item.CanBeDisposed))
{
if (item != null)
{
try
{
item.Dispose();
}
catch (Exception)
{
// log exception and continue
}
}
}
list.RemoveAll(item => item.CanBeDisposed);
}
}
Repository
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
internal DbContext _context;
internal DbSet<TEntity> _dbSet;
public bool CanBeDisposed { get; set; }
public GenericRepository(DbContext context)
{
_context = context;
_dbSet = context.Set<TEntity>();
}
protected void Dispose(bool disposing)
{
if (disposing)
{
if (_context != null)
{
_context.Dispose();
_context = null;
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
First you might want to add one more Unity bootstrapper to your project Unity.AspNet.Mvc
https://msdn.microsoft.com/en-us/library/dn507440(v=pandp.30).aspx
To use the PerRequestLifetimeManager class in an ASP.NET Web API application, you must also add the the Unity bootstrapper for ASP.NET MVC NuGet package to your project.
Unity.Mvc and Unity.AspNet.WebApi will register your controllers for DI.
UnityConfig.cs
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<INinjaContext, NinjaContext>(new PerRequestLifetimeManager());
container.RegisterType<INinjaRepository, NinjaRepository>(new PerRequestLifetimeManager());
}
UnityWebApiActivator.cs Uncomment the line...
public static void Start()
{
// Use UnityHierarchicalDependencyResolver if you want to use
// a new child container for each IHttpController resolution.
var resolver = new UnityHierarchicalDependencyResolver(UnityConfig.Container);
...
}
UnityMvcActivator.cs Uncomment the line...
public static void Start()
{
...
// TODO: Uncomment if you want to use PerRequestLifetimeManager
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
}
Your controller is simply
public class NinjasController : ApiController
{
private readonly INinjaRepository repository;
public NinjasController(INinjaRepository repository)
{
this.repository = repository;
}
public Ninja Get(int id)
{
var ninja = repository.GetNinjaById(id);
return ninja;
}
}
With PerRequestLifetimeManager Unity will take care of disposal after the request is complete.
I have an example here https://github.com/jasenhk/MovieStar
If you are using OWIN see Unity IoC does not inject dependency into Web API Controller
I understand the concept of how to create generic class in C# quit well but what I'm trying to archive is a little bit different from what I've done before.
I use to create Service Management classes and write and all the methods I'll be needing in the controller layer using dependency Injections but i figured that am doing the same thing over and over for all my entities so I wanted to leverage the concept of Generic class which am already using as my Repository in the service layer as well so I'll cut the pain of rewriting the same thing over and over.
So this is what I've done so far, I went ahead and create the a concrete Generic Class
/// <summary>
/// Base Service Generic Class
/// </summary>
/// <typeparam name="TEntity"> Domain Entity</typeparam>
/// <typeparam name="TDataObject"> Data Object</typeparam>
public class BaseServices<TEntity, TDataObject> where TEntity : class, IDataObject, new()
{
public FMDbContext _context;
public IFactoryInit _factory;
public IUnitOfWork _uow;
public BaseServices(IUnitOfWork uow, IFactoryInit factory)
{
_uow = uow;
_factory = factory;
}
private Repository<TEntity> _repository { get; }
private ServiceFactory _serviceFactory { get; }
public Repository<TEntity> Repository
{
get { return _repository ?? new Repository<TEntity>(_context); }
}
public ServiceFactory SFactory
{
get { return _serviceFactory ?? new ServiceFactory(); }
}
public class ServiceFactory : BaseFactory<TEntity, TDataObject>
{
}
public TDataObject GetSingle(Guid id)
{
try
{
TEntity _entity = Repository.GetById(id);
var _obj = SFactory.SingleMappingEntityToObject(_entity);
return _obj;
}
catch (Exception ex)
{
throw ex;
}
}
public IEnumerable<TDataObject> GetMany()
{
try
{
var entities = Repository.Get(null, null, false);
var _objs = SFactory.ListMappingEntitiesToObjects(entities);
return _objs;
}
catch (Exception ex)
{
throw ex;
}
}
public Task<TDataObject> CreateAsync(TDataObject obj)
{
return Task.Run(() =>
{
try
{
var entity = SFactory.SingleMappingObjectToEntity(obj);
entity.Id = IdentityGenerator.NewSequentialGuid();
Repository.Insert(entity: entity);
_context.SaveChangesAsync();
var _resp = SFactory.SingleMappingEntityToObject(entity);
return _resp;
throw new InvalidOperationException("Internal Server Error!");
}
catch (Exception ex)
{
throw ex;
}
});
}}
As you've seen I brought in my IUnitOfWork where am initialising all my repository inside.
And now this is how am calling it on my service
public class ProductService : BaseServices<Product, ProductObject>
{
public ProductService(IUnitOfWork uow, IFactoryInit factory) : base(uow, factory)
{
}
}
Then I went ahead to bring all the servies in one class so I can use .Net Core Dependency Injection to bind it once
public class ServiceInit : IServiceInit
{
private IFactoryInit _factory;
private IUnitOfWork _uow;
private ProductService _productService;
public ProductService ProductServices
{
get { return _productService ?? new ProductService(_uow, _factory); }
}
}
That's all I've done but I keep getting Null Reference Exception in my UnitOfWork initialisation and I even tried this
public IUnitOfWork UnitOfWork
{
get
{
if (_uow == null)
{
_uow = new UnitOfWork(_context);
}
return _uow;
}
}
Explicitly and am still get null reference
But this pattern is still working perfectly well, which is the pattern of creating services repeatedly for all my entity which am very tired of
{
public class VendorManagementServices : IVendorManagementServices
{
private IFactoryInit _factory;
private IUnitOfWork _uow;
public VendorManagementServices(IUnitOfWork uow, IFactoryInit factory)
{
_uow = uow;
_factory = factory;
}
}
So, I dont know what am missing in my BaseService that keeps throwing
System.NullReferenceException: Object reference not set to an instance of an object.
Any Ideas guys?
I am working on an asp.net mvc web application. now i have created multiple repositories classes, for example i have the following abstract repository classes:-
public interface ISkillRepository : IDisposable
{//code goes here..
&
public interface IStaffRepository : IDisposable
{//code goes here
and the model Repositories:-
public class SkillRepository : ISkillRepository , IDisposable
{
private SkillManagementEntities context = new SkillManagementEntities();
//code goes here
&
public class StaffRepository : IStaffRepository , IDisposable
{
private SkillManagementEntities context = new SkillManagementEntities();
now inside y controller i am intializing and creating the repo as follow:-
public class SkillController : Controller
{
private ISkillRepository skillRepository;
public SkillController() : this(new SkillRepository()) {}
public SkillController(ISkillRepository repository)
{
skillRepository = repository;
}
but currently i got the following error inside my application:
The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.
and the problem is that i need to be passing the same context accross the repos and controllers. so can anyone adivce on this:-
how i can inside one model repo to reference another repo using the same context class. for example inside the Staff repositoryto referecne the skill repository?
how i can inside a controller class to refer multiple repos , but at the same time pass the same context object among them , so if i issue a save() it will wrap all the statements inside one transaction. for example insie my skillController to reference both the skill & staff repos using the same context object ?
Thanks
Edit
I have created the following Unit of work class:-
public class UnitOfWork : IDisposable
{
private SkillManagementEntities context = new SkillManagementEntities();
private SkillRepository skillRepository;
private StaffRepository staffRepository;
private SecurityRoleRepository securityroleRepository;
public SkillRepository SkillRepository
{
get
{
if (this.skillRepository == null)
{
this.skillRepository = new SkillRepository(context);
}
return skillRepository;
}
}
public StaffRepository StaffRepository
{
get
{
if (this.staffRepository == null)
{
this.staffRepository = new StaffRepository(context);
}
return staffRepository;
}
}
public SecurityRoleRepository SecurityRoleRepository
{
get
{
if (this.staffRepository == null)
{
this.staffRepository = new SecurityRoleRepository(context);
}
return securityroleRepository;
}
}
public async Task Save()
{
await context.SaveChangesAsync();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
and then inside my repo i did the following:-
public class SecurityRoleRepository : ISecurityRoleRepository , IDisposable
{
private SkillManagementEntities context;// = new SkillManagementEntities();
public SecurityRoleRepository(SkillManagementEntities context)
{
this.context = context;
and on the controller class i will be referencing the UnitOfWork as follow:-
public class SecurityRoleController : Controller
{
private UnitOfWork unitOfWork = new UnitOfWork();
public async Task<ActionResult> Index(string filter = null, int page = 1, int pageSize = 20, string sort = "Name", string sortdir = "ASC")
{
try
{
var records = new PagedList<SecurityRole>();
ViewBag.filter = filter;
records.Content = await unitOfWork.SecurityRoleRepository.GetSecurityRoleForGrid(filter, page, pageSize, sort, sortdir).ToListAsync();
now i am facing a problem is that how i can referecne a repo from another Repo ? for example how i can reference the Skill repo inside the SecurityRole repo ?
EDIT Final
i did the following steps:-
1. i install
Install-Package Ninject.MVC5
2. then i created the following dependency class:-
public class YourDependencyResolverClass : IDependencyResolver
{
private IKernel kernel;
public YourDependencyResolverClass()
{
kernel = new StandardKernel();
AddBindings();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
private void AddBindings()
{
kernel.Bind<ISkillRepository>().To<SkillRepository>();
kernel.Bind<IStaffRepository>().To<StaffRepository>();
kernel.Bind<ISecurityRoleRepository>().To<SecurityRoleRepository>();
kernel.Bind<ICustomerRepository>().To<CustomerRepository>();
kernel.Bind<ISkillVersionHistoryRepository>().To<SkillVersionHistoryRepository>();
}
}
}
3.now inside my SkillRepository class i will be referencing the StaffRepository as follow:-
public class SkillRepository : ISkillRepository , IDisposable
{
private SkillManagementEntities context ;
private IStaffRepository staffrepo = (IStaffRepository)DependencyResolver.Current.GetService(typeof(IStaffRepository));
public SkillRepository(SkillManagementEntities context)
{
this.context = context;
}
Finally inside my action method i will be calling the Uiteofwork class as follow:-
public class StaffController : Controller
{
//private SkillManagementEntities db = new SkillManagementEntities();
UnitOfWork unitofwork = new UnitOfWork();
public async Task<ActionResult> AutoComplete(string term)
{
var staff = await unitofwork.StaffRepository.GetAllActiveStaff(term).Select(a => new { label = a.SamAccUserName }).ToListAsync();
return Json(staff, JsonRequestBehavior.AllowGet);
and the unite of work class is :-
public class UnitOfWork : IDisposable
{
private SkillManagementEntities context = new SkillManagementEntities();
private SkillRepository skillRepository;
private StaffRepository staffRepository;
private SecurityRoleRepository securityroleRepository;
private CustomerRepository customerRepository;
private SkillVersionHistoryRepository SVH;
public SkillRepository SkillRepository
{
get
{
if (this.skillRepository == null)
{
this.skillRepository = new SkillRepository(context);
}
return skillRepository;
}
}
public StaffRepository StaffRepository
{
get
{
if (this.staffRepository == null)
{
this.staffRepository = new StaffRepository(context);
}
return staffRepository;
}
}
public CustomerRepository CustomerRepository
{
get
{
if (this.customerRepository == null)
{
this.customerRepository = new CustomerRepository(context);
}
return customerRepository;
}
}
public SecurityRoleRepository SecurityRoleRepository
{
get
{
if (this.securityroleRepository == null)
{
this.securityroleRepository = new SecurityRoleRepository(context);
}
return securityroleRepository;
}
}
public SkillVersionHistoryRepository SkillVersionHistoryRepository
{
get
{
if (this.SVH == null)
{
this.SVH = new SkillVersionHistoryRepository(context);
}
return SVH;
}
}
public async Task Save()
{
await context.SaveChangesAsync();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
So can you adivce if my approach of using unitefwork and DI will guarantee that all my statements will be warped inside a single DB transaction ? thnaks?
We handle this by sharing a context using a singleton that is scoped to the request using HttpContext:
public MyContext GetContext()
{
if (System.Web.HttpContext.Current.Items["MyScopedContext"] == null)
{
System.Web.HttpContext.Current.Items["MyScopedContext"] = new MyContext();
}
return (MyContext)System.Web.HttpContext.Current.Items["MyScopedContext"];
}
The context object (repository) itself essentially houses a Unit of Work. The code I added above just gives you a way to share a single repository across all code running within a request. If your repository classes are defined in the scope of a web application, you can just replace your direct instantiation of SkillManagementEntities() with a call to a GetContext() method.
On the other hand if your repositories are defined in a layer shared by heterogeneous applications, you may need to get your context from a factory object that you can inject as needed. Either way, creating a new context object per repository is what's causing your issue.
Not an answer: this "use DI" suggestion answers a bit different question - OP is looking for "unit-of-work" pattern - while basic case (lifetime of unit of work matches lifetime of request/controller) can easily be solved with any DI framework, managing multiple units of work or units of work with longer lifetime is much harder and dedicated "unit of work factory" (sample usage) is likely the solution.
Usually when you go that far with interfaces/repositories and constructor dependency injection you have some Dependency Injection framework. There is a good chance that one you are using already provides "per HTTP request" resolution or allows to easily add one.
I.e. if you using Unity there is PerRequestLifetime lifetime manager that makes all .Resolve calls for the same interface/object to return the same instance for given request. See more info in DI with Unity MSDN article.
Approximate sample:
container.RegisterType<ISkillRepository, SkillRepository>();
container.RegisterType<IOtherRepository, OtherRepository>();
container.RegisterType<TheContext, TheContext>(new PerRequestLifetime());
With such registration and assuming you've configured ASP.Net MVC to use Unity to resolve types when controller is created it will get necessary dependencies (new instances as registered with default lifetime), but both will share the same context (assuming each depends on TheContext class either via constructor or property injection).
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.
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.