Can I get WebApi to work with IoC Aspects/Interceptor - c#

I'm from a WCF background where I successfully used IoC with Aspects/Interceptors to abstract functions such as Authentication and Logging. I would simply just add the required interfaces to the aspects constructor the same way as you would with any typical IoC setup.
I'm now trying to apply the same sort of process to webapi, but as the controllers inherit from a ApiController and do not implement a interface. I'm assuming there is a different way of applying aspects maybe?
public class MyController: ApiController
{
private readonly IUnitOfWork _unitOfWork;
private readonly ILoginService _loginService;
private readonly ILog _log;
public LoginController(ILoginService loginService, IUnitOfWork unitOfWork, ILog log)
{
this._loginService = loginService;
this._unitOfWork = unitOfWork;
this._log = log;
}
// I WANT TO INTERCEPT THIS METHOD USING UserTokenAuthenticationInterceptor
public HttpResponseMessage Get(Guid id)
{
_log.Log(log something);
// some code thats gets some data using this._loginService
_log.Log(log the save);
_unitOfWork.Save();
}
}
The Aspect
public class UserTokenAuthenticationInterceptor : IInterceptionBehavior
{
private readonly ILoginService _loginService;
private readonly ILog _log;
public UserTokenAuthenticationInterceptor(ILog log, ILoginService loginService)
{
this._log = log;
this._loginService = loginService;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
_log.Log(log entering authentication aspect);
// do some authentication here using this._loginService
_log.Log(log exiting authentication aspect);
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public bool WillExecute { get { return true; }}
}
Container registration:
container.RegisterType<IUnitOfWork, UnitOfWork.UnitOfWork>(new HierarchicalLifetimeManager());
container.RegisterType<ILoginService , LoginService>();
container.RegisterType<ILog, LogService>();
I'm using unity in this example.
Can anyone point me in the right direction?

Thanks for the help everyone, I eventually figured it out.
I got most of my answer from this article https://unity.codeplex.com/discussions/446780
I used the the following nuget packages.
Unity (I added this 1 first)
Unity.WebApi (has unity version problem if unity isnt added first)
First I needed a new IFilterProvider implementation.
Its job it to register all actionfilters with the container.
public class UnityActionFilterProvider : ActionDescriptorFilterProvider, IFilterProvider
{
private readonly IUnityContainer container;
public UnityActionFilterProvider(IUnityContainer container)
{
this.container = container;
}
public new IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
{
var filters = base.GetFilters(configuration, actionDescriptor);
foreach (var filter in filters)
{
container.BuildUp(filter.Instance.GetType(), filter.Instance);
}
return filters;
}
}
Then a registration method was required to register the new actionfilterprovider and remove the original webapi implementation.
This needs to be executed in the RegisterComponents() method which is in the UnityConfig.cs file the Unity.WebApi nuget package creates.
public static void RegisterFilterProviders(IUnityContainer container)
{
var providers = GlobalConfiguration.Configuration.Services.GetFilterProviders().ToList();
GlobalConfiguration.Configuration.Services.Add(typeof(System.Web.Http.Filters.IFilterProvider),
new UnityActionFilterProvider(container));
var defaultprovider = providers.First(p => p is ActionDescriptorFilterProvider);
GlobalConfiguration.Configuration.Services.Remove(typeof(System.Web.Http.Filters.IFilterProvider), defaultprovider);
}
In the same RegisterComponents() method I registered my Types
container.RegisterType<IUnitOfWork, UnitOfWork.UnitOfWork>(new HierarchicalLifetimeManager());
container.RegisterType<ILoginService , LoginService>();
container.RegisterType<ILog, LogService>();
Next, I needed to create a class based on AuthorizeAttribute.
public class UserTokenAuthenticationAttribute : AuthorizeAttribute
{
private ILoginService _loginService;
// This is the magic part - Unity reads this attribute and sets injects the related property. This means no parameters are required in the constructor.
[Microsoft.Practices.Unity.Dependency]
public ILoginService LoginService
{
get
{
return this._loginService;
}
set
{
this._loginService = value;
}
}
protected override bool IsAuthorized(HttpActionContext actionContext)
{
// Authorise code goes here using injected this._loginService
}
}
A log action filter is also required ActionFilterAttribute
public sealed class LogAttribute : ActionFilterAttribute
{
private ILog _log;
// This is the magic part - Unity reads this attribute and sets injects the related property. This means no parameters are required in the constructor.
[Microsoft.Practices.Unity.Dependency]
public ILog Log
{
get
{
return this._log;
}
set
{
this._log = value;
}
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
this._log.Info("Exited " + actionContext.Request.Method);
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
this._log.Info("Entering" + actionContext.Request.Method);
}
}
Now lets configure the webapi controller. We need to decorate the class with our new attributes
[UserTokenAuthentication] // magic attribute in use
[Log] // magic attribute in use
public class MyController: ApiController
{
private readonly IUnitOfWork _unitOfWork;
private readonly ILoginService _loginService;
private readonly ILog _log;
public MyController(ILoginService loginService, IUnitOfWork unitOfWork, ILog log)
{
this._loginService = loginService;
this._unitOfWork = unitOfWork;
this._log = log;
}
[System.Web.Http.AllowAnonymous] // doesnt require authentication as were not logged in yet
public HttpResponseMessage Get(Guid id)
{
_log.Log(log something);
// some code thats gets some data using this._loginService
_log.Log(log the save);
_unitOfWork.Save();
}
public HttpResponseMessage GetMyDetails(Guid id)
{
_log.Log(log something);
// some code thats gets some data using this._loginService
_log.Log(log the save);
_unitOfWork.Save();
}
}

I'm an Autofac guy myself, but according to this blog post the same thing can be done in Unity: You hand over controller instantiation to your IoC container and then you can use dependency injection in the controllers.
This being said, I've never worked with interceptors so I'm not sure how these can be registered to work properly. And it seems that the IInterceptionBehavior is obsolete in Unity and no longer maintained.

In WebApi, you can create an ActionFilter which can be called before and after a controller action is invoked:
public sealed class UserTokenAuthenticationAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
...
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
...
}
}
There are different types of filter available depending on what you need do do for example AuthorizationFilterAttribute and ExceptionFilterAttribute.
You can register a single instance of this in GlobalConfiguration.Configuration.Filters.Add(new UserTokenAuthenticationAttribute ()) if you want it to apply for all controller actions, or you can apply it to an individual controller or action if you need more flexibility about when that action filter is used.
By default, action filters are not resolved from an IOC container, they are essentially created by Activator.CreateInstance.
I'm not sure if it is possible in Unity as I've never used it but Autofac can resolve action filters if configured to do so using the RegisterWebApiFilterProvider method in the Autofac WebApi extension.

Better write your custom AuthorizeAttribute implementation. Example:
public class ApiAuthorizeAttribute : AuthorizeAttribute{
protected override bool IsAuthorized(HttpActionContext actionContext){
// Make your logic to check is user authorized
}
public override void OnAuthorization(HttpActionContext actionContext){
// Make your authorization logic
}
}
Then use it for all your ApiController's
[ApiAuthorize]
public class MyController: ApiController{
private readonly IUnitOfWork _unitOfWork;
private readonly ILoginService _loginService;
private readonly ILog _log;
// That method don't need authorization
[AllowAnonymous]
public LoginController(ILoginService loginService, IUnitOfWork unitOfWork, ILog log)
{
this._loginService = loginService;
this._unitOfWork = unitOfWork;
this._log = log;
}
// Before calling that method will be called logic from `ApiAuthorizeAttribute`
public HttpResponseMessage Get(Guid id)
{
_log.Log(log something);
// some code thats gets some data using this._loginService
_log.Log(log the save);
_unitOfWork.Save();
}
}
It will work the same as Aspect(actualy it is an Aspect but in ASP.NET MVC way) except that you will work with HttpActionContext(more hight level model, which will help you to achive the same but in the faster way. Also you will able to manipulate with HTTP headers) instead of working with low-level IInvocation.

Related

How can I use dependency injection in asp.net core action filter?

I have a FilterAttribute that has two parameters, one defined in dependency injection and one defined on method of controller as as string
public controller : ControllerBase
{
[MyFilter("Parameter1", FromDependency)]
public ActionResult MyMethod()
{
....
}
}
and the filter
public MyFilter : Attribute
{
MyFilter(string parameter1, context fromDependency)
{
}
}
How can I inject the parameter from dependency injection?
You can implement an IFilterFactory for this purpose. The runtime checks for this interface when creating filters and calls the CreateInstance method that gets an IServiceProvider as a parameter. You can use this provider to create services and inject them into the filter.
The following sample is taken from the docs:
public class ResponseHeaderFilterFactory : Attribute, IFilterFactory
{
public bool IsReusable => false;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider) =>
new InternalResponseHeaderFilter();
private class InternalResponseHeaderFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context) =>
context.HttpContext.Response.Headers.Add(
nameof(OnActionExecuting), nameof(InternalResponseHeaderFilter));
public void OnActionExecuted(ActionExecutedContext context) { }
}
}
If you need to both use services from DI and values defined on the attribute, you can use the following approach:
public class ResponseHeaderFilterFactory : Attribute, IFilterFactory
{
private readonly string _attrParam;
public ResponseHeaderFilterFactory(string attrParam)
{
_attrParam = attrParam;
}
public bool IsReusable => false;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
var svc = serviceProvider.GetRequiredService<IMyService>();
return new InternalResponseHeaderFilter(_attrParam, svc);
}
private class InternalResponseHeaderFilter : IActionFilter
{
private readonly string _attrParam;
private readonly IMyService _service;
public InternalResponseHeaderFilter(string attrParam, IMyService service)
{
_attrParam = attrParam;
_service = service;
}
public void OnActionExecuting(ActionExecutingContext context) =>
context.HttpContext.Response.Headers.Add(
nameof(OnActionExecuting), nameof(InternalResponseHeaderFilter));
public void OnActionExecuted(ActionExecutedContext context) { }
}
}
You can then apply the filter like this:
public controller : ControllerBase
{
[ResponseHeaderFilterFactory("Parameter1")]
public ActionResult MyMethod()
{
....
}
}
You can implement ActionFilterAttribute to get DI dependencies from HttpContext.RequestServices:
public sealed class MyAttr : ActionFilterAttribute
{
MyAttr(string parameter1)
{
}
public override void OnActionExecuting(ActionExecutingContext context)
{
//Get dependency from HttpContext services
var myDependency = context.HttpContext.RequestServices.GetService<MyDependency>();
//Use it
myDependency.DoSomething();
//....
}
}
Injecting components into action filter attributes directly is not possible but there are various workarounds to allow us to effectively accomplish the same thing. Using ServiceFilter is a relatively clean way to allow dependency injection into individual action filters.
The ServiceFilter attribute can be used at the action or controller level. Usage is very straightforward:
[ServiceFilter(typeof(MyFilter))]
And our filter:
public class MyFilter: IActionFilter
{
MyFilter(string parameter1, context fromDependency)
{
}
}
Obviously, as we are resolving our filter from the IoC container, we need to register it:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<MyFilter>(x =>
new Service(x.GetRequiredService<IOtherService>(),
"parameter1"));
...
}
more details in Paul Hiles article: here

Asp.net core DI with context

I'm trying implement a simple dependency (in ASP.NET Core) as this:
public partial class BaseController : Controller
{
public new ITempDataDictionary TempData { get; private set; }
public override void OnActionExecuting(ActionExecutingContext context)
{
base.OnActionExecuting(context);
//preparação da tempdata
this.TempData = new TempDataDictionary(HttpContext); //todo: DI?
this.TempData.Load();
}
}
}
The problem is the fact TempDataDictionary depends of HttpContext present in this controller.
How to implement that scenario in DI, since the ServiceLocator has no knowledge of HttpContext at Startup?
As this?
services.AddScoped(); //??????
But where i fill the constructor parameter HttpContext if this present just in controller?
You should create a service to handle your state data and add it as scoped.
public class AppStateService
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ITempDataProvider _tempDataProvider;
private IDictionary<string, object> _data;
public AppStateService(IHttpContextAccessor httpContextAccessor, ITempDataProvider tempDataProvider, UserManager<EntsogUser> userManager, CompanyRepository companyRepository)
{
_httpContextAccessor = httpContextAccessor;
_tempDataProvider = tempDataProvider;
_data = _tempDataProvider.LoadTempData(_httpContextAccessor.HttpContext);
}
private void SetValue(string name, object value)
{
_data[name] = value;
_tempDataProvider.SaveTempData(_httpContextAccessor.HttpContext,_data);
}
private object GetValue(string name)
{
if (!_data.ContainsKey(name))
return null;
return _data[name];
}
}
In Startup.cs (ConfigureServices)
services.AddScoped<AppStateService>();
In your controller
public class TestController : Controller
{
protected readonly CompanyRepository _companyRepository;
public TariffsController(AppStateService appStateService)
{
_appStateService = appStateService;
}
}
you can take a dependency on IHttpContextAccessor and register it with DI
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
then use it to get the HttpContext
However in a controller you have direct access to HttpContext so it isn't clear to me why you would want to inject it there

How to reuse an InstancePerRequest instance create in composition root using Autofac

I have an Asp.NET MVC5 application in which I registre my types using Autofac in Startup class in this way:
public class Startup
{
public void Configuration(IAppBuilder app)
{
IContainer container = null;
var builder = new ContainerBuilder();
// Register Services
builder.RegisterType<SalesRepository>().As<ISalesRepository>().InstancePerRequest();
builder.RegisterType<SalesService>().As<ISalesService>().InstancePerRequest();
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.AsClosedTypesOf(typeof(IHandle<>))
.AsImplementedInterfaces()
.InstancePerRequest();
builder.Register<IAppEvents>(_ => new AppEvents(container)).InstancePerRequest();
// Register MVC Controllers
builder.RegisterControllers(Assembly.GetExecutingAssembly());
container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
}
}
These are my services (this is a simplified scenario, only for demonstration).
The SalesService class receives a ISalesRepository interface as dependency . In addition I have an AppEvents class where I want to resolve IHandle types:
public interface ISalesRepository { }
public class SalesRepository : ISalesRepository
{
public SalesRepository() { }
}
public interface ISalesService { }
public class SalesService : ISalesService
{
ISalesRepository _repo;
public SalesService(ISalesRepository repo)
{
_repo = repo;
}
}
public interface IHandle<T>
{
void Handle();
}
public class SalesActionHandle : IHandle<string>
{
ISalesRepository _repo;
public SalesActionHandle(ISalesRepository repo)
{
_repo = repo;
}
public void Handle() { }
}
public interface IAppEvents
{
void Raise<T>();
}
public class AppEvents : IAppEvents
{
private readonly IContainer _container;
public AppEvents(IContainer container)
{
if (container == null)
throw new ArgumentNullException("container");
_container = container;
}
public void Raise<T>()
{
var handlers = _container.Resolve<IEnumerable<IHandle<T>>>(); // Runtime error here
foreach (var handler in handlers)
handler.Handle();
}
}
And this is my only (simplified) controller:
public class HomeController : Controller
{
ISalesService _service;
IAppEvents _events;
public HomeController(ISalesService service, IAppEvents events)
{
_service = service;
_events= events;
}
public ActionResult Index()
{
_events.Raise<string>();
return View();
}
}
The problem I have is that I get an error at this line when it is executed:
var handlers = _container.Resolve<IEnumerable<IHandle<T>>>();
No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
I resolve it by doing this:
public void Raise<T>()
{
using (var scope = _container.BeginLifetimeScope("AutofacWebRequest"))
{
var handlers = scope.Resolve<IEnumerable<IHandle<T>>>();
foreach (var handler in handlers)
handler.Handle();
}
}
But in this case, when IHandle is resolved (with SalesActionHandle instance), a new instance of SalesRepository is passed as parameter in SalesActionHandle constructor. What I want is to "reuse" the same instance that SalesService is using (it was created when ISalesService was resolved. I want the same SalesRepository instance for the request)
Is there any way to achieve this behaviour?
The sample code is avaible in Github: https://github.com/josmonver/AutofacTest
You may want to use
AutofacDependencyResolver.Current.RequestLifetimeScope
to match your current request scope, but not to create a new request scope.

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