Castle windsor 3.0 and ASP.NET MVC Controllers - c#

I am using Castle Windsor 3.0 and it worked perfectly for me until I tried to register controllers (I used WCF facility and IoC for repository/service layer). Here is my controllers installer class:
public class ControllersInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
RegisterAllBasedOnWithCustomComponentRegistration(container, typeof(IController),
typeof(HomeController).Assembly,
cr => cr.LifeStyle.Transient);
}
private void RegisterAllBasedOnWithCustomComponentRegistration(IWindsorContainer container, Type baseType,
Assembly assemblyWithImplementations, Func<ComponentRegistration, ComponentRegistration<object>> customComponentRegistrationCb)
{
container.Register(
AllTypes.FromAssembly(assemblyWithImplementations)
.BasedOn(baseType)
.If(t => t.Name.EndsWith("Controller"))
.Configure(c => customComponentRegistrationCb(c)));
}
}
And here is my controller factory:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
public override void ReleaseController(IController controller)
{
_kernel.ReleaseComponent(controller);
}
public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
var controllerComponentName = controllerName + "Controller";
return _kernel.Resolve<IController>(controllerComponentName);
}
}
From my global.asax I call the next method:
InversionOfControl.InstallControllers(FromAssembly.This());
which lies in an another project. And in there I do call the installation code:
public static void InstallControllers(IWindsorInstaller install)
{
_container.Install(install);
}
it seems like I am doing something wrong and I hope I am because it could be a "never use awny beta again" moment for me.
I get the next exception : No component for supporting the service System.Web.Mvc.IController was found altough I can see the controller in the debug mode being registered in the container

In your ControllerFactory, you don't shouldn't Resolve IController but rather the concrete controller type. Here's a typical Windsor-base ControllerFactory I always use:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IWindsorContainer _container;
public WindsorControllerFactory(IWindsorContainer container)
{
_container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return (IController)_container.Resolve(controllerType);
}
public override void ReleaseController(IController controller)
{
_container.Release(controller);
}
}

In this case add .WithServices(typeof(IController)) and name all components.
cr => cr.LifeStyle.Transient.Named(cr.Implementation.Name)
and your registration should look like:
.Register(
AllTypes.FromAssembly(assemblyWithImplementations)
.BasedOn(baseType)
.WithServices(typeof(IController))
.If(t => t.Name.EndsWith("Controller"))...)

Related

Unity IOC, can't fix the parameterless constructor issue

I have the following constructor (only one for the controller):
[Authorize]
public class AccountController : Controller
{
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager,
IAccountService accountSrv)
{
UserManager = userManager;
SignInManager = signInManager;
AccountService = accountSrv;
}
private IAccountService AccountService { get; }
private ApplicationSignInManager SignInManager { get; }
private ApplicationUserManager UserManager { get; }
And I'd like MVC to call it with proper parameters, so I tried this:
Global.asax.cs
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
DALMapper.Mapping();
LabMapper.Mapping();
var container = new UnityContainer();
container
.RegisterType<IDALContext, DALContext>()
.RegisterType<IConsultantService, ConsultantService>()
.RegisterType<IProjectService, ProjectService>()
.RegisterType<IAccountService, AccountService>()
.RegisterType<AccountController, AccountController>()
.RegisterType<ApplicationUserManager, ApplicationUserManager>()
.RegisterType<ApplicationSignInManager, ApplicationSignInManager>()
.RegisterInstance<IAccountService>(new AccountService(new DALContext()), new ContainerControlledLifetimeManager())
;
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
(UnityDependencyResolver being:)
public class UnityDependencyResolver : IDependencyResolver
{
private readonly IUnityContainer _container;
public UnityDependencyResolver(IUnityContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
try
{
return _container.Resolve(serviceType);
}
catch
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _container.ResolveAll(serviceType);
}
catch
{
return new List<object>();
}
}
}
Where I register every types needed (the result feel weird though when in/from types are the same (I'm that new to Unity)).
But it doesn't work. (As far as I know, since MV3, the default controller factory will use the service locator, so one doesn't need to implement it's own factory).
What's wrong?
Current result:
Server Error in '/' Application.
No parameterless constructor defined for this object.
If I understand your problem correctly, there's a problem resolving the dependencies for ApplicationUserManager and ApplicationSignInManager.
This is the code that solved the problem for me:
//for accountcontroller
container.RegisterType<DbContext, ApplicationDBContext>(new HierarchicalLifetimeManager());
container.RegisterType<UserManager<ApplicationUser>>(new HierarchicalLifetimeManager());
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new HierarchicalLifetimeManager());
container.RegisterType<IAuthenticationManager>(new InjectionFactory(o => HttpContext.Current.GetOwinContext().Authentication));
After digging it up more (downloaded the Unity source code, built it, added a reference to the dll, added the pdb to the symbols locations (debug))*, I could see the error was coming from another constructor which requirs parameters.
public class ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
: base(store)
{
}
(I've yet to solve this, but that should be easy).
*is there an easier way to step into a third party library's code? Let me know in the comment.

Autofac module registration in ASP.NET WebAPI

Until now I have done type registration inside a class within my MVC project but I am now trying to do it with Modules. My project is structured as follows
Project.Data: contains my entityframework classes and DataContext. I have refactored my datacontect to implement an interface (IDbContext) which I register via an autofac module
Project.Business: contains business logic classes into which and IDbContext instance is injected. Classes implement corresponding interfaces which are also registered via an autofac module
Project.Web: asp.net project which uses assembly scanning to register all autofac modules
Sample Code
Project.Data
//IDbContext
public interface IDbContext
{
IDbSet<MyData> MyDatas { get; set; }
....
}
//DataContext
public class DataContext : DbContext, IDbContext
{
public IDbSet<MyData> MyDatas { get; set; }
}
//Module
public class DataInjectionModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<DataContext>().As<IDbContext>();
}
}
Project.Business
public interface IServeDataService
{
IEnumerable<object> GetData();
}
public class ServeDataService : IServeDataService
{
private IDbContext context;
public ServeDataService()
{
this.context = context;
}
public IEnumerable<object> GetData()
{
}
}
public class BusinessInjectionModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<ServeDataService>().As<IServeDataService>();
}
}
Project.Web
public partial class Startup
{
public void RegisterContainer()
{
var builder = new ContainerBuilder();
var assemblies = BuildManager.GetReferencedAssemblies().Cast<Assembly>();
builder.RegisterAssemblyModules(assemblies.ToArray());
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
}
}
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
RegisterContainer();
}
}
//controller
public class DataController : ApiController
{
private IServeDataService dataService;
public DataController(IServeDataService dataService)
{
this.dataService = dataService;
}
public async Task<IHttpActionResult> Get()
{
var data = dataService.GetData();
return Ok(data);
}
}
however when I try to call the api service, I get the following error
An error occurred when trying to create a controller of type 'DataController'. Make sure that the controller has a parameterless public constructor.
I have debugged and set break points in the RegisterContainer methid and that gets called, I have also looked at the assemblies listed and my Business and Data assemblies are listed, but my module registrations are never run. What am I doing wrong?
It seems that you didn't configure Web API to use your Autofac container.
To get Autofac integrated with Web API you need to reference the Web API integration NuGet package, register your controllers, and set the dependency resolver. You can optionally enable other features as well.
> Autofac - Web API documentation.
In order to make it work you have to add a reference on the Autofac ASP.NET Web API Integration nuget package and add the following line in your RegisterContainer method :
// Set the dependency resolver to be Autofac.
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

How do I use Castle Windsor a different assembly from mvc web application?

I'm stuck. I want to configure Castle Windsor in a different class library and I configured, build is fine, no error, ok... But I get an exception at run time.
Castle.MicroKernel.ComponentNotFoundException: No component for supporting the service App.Web.UI.Controllers.HomeController was found
When I get the configure file back to the same assembly (App.Web.UI), I don't get any exception at run time, work is fine.
I tried many ways, but I could not. Is there another bind method except FromThisAssembly? Or Solution?
Castle Windsor configuration is here:
namespace App.Infrastructure.Configurations
{
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
public override void ReleaseController(IController controller)
{
_kernel.ReleaseComponent(controller);
}
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 class ControllersInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<IController>().Unless(x => x.Name == "BaseController").LifestyleTransient());
}
}
public class ServiceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For(typeof (IRepository<>)).ImplementedBy(typeof (Repository<>)).LifestyleTransient(),
Component.For<IUserService>().ImplementedBy<UserService>().LifestylePerWebRequest(),
Component.For<IFormsAuthenticationService>().ImplementedBy<FormsAuthenticationService>().LifestylePerWebRequest(),
Component.For<ILoggingService>().ImplementedBy<LoggingService>().LifestyleTransient(),
Component.For<IFeedbackService>().ImplementedBy<FeedbackService>().LifestylePerWebRequest()
);
}
}
}
In your code, the Classes.FromThisAssembly() references the assembly containing your Windsor stuff -- not your web application. Try telling Windsor to register components from a specific assembly. This should work:
Classes.FromAssembly(Assembly.GetEntryAssembly())
The entry assembly should be the AppDomain running your MVC code.

Resolving from Castle Windsor container in an API controller

I have an API controller that fires a service that uses constructor dependency injection. I would like to use the Windsor container to inject those dependencies, but I'm not sure the best practice.
Here's part of the API controller factory:
private readonly IWindsorContainer _container;
private readonly ServiceFactory _serviceFactory;
...
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
Arguments args = new Arguments(new { serviceFactory = _serviceFactory });
IHttpController controller = (IHttpController)_container.Resolve(controllerType, args);
request.RegisterForDispose(new Release(() => _container.Release(controller)));
return controller;
}
...
Here's part of the Service Factory:
private readonly IWindsorContainer _container;
...
public IService Create(Type serviceType, ApiRequestModel apiRequest)
{
Arguments args = new Arguments(new { request = apiRequest });
return (IService)_container.Resolve(serviceType, args);
}
...
Here's part of the API controller:
private ServiceFactory _serviceFactory { get; set; }
...
public object Post([FromBody]ApiRequestModel request)
{
...
Type serviceType = Assembly.Load("TestProject").GetType("TestClass");
IService instance = _serviceFactory.Create(serviceType, request);
...
_serviceFactory.Release(instance);
}
...
The Service Factory contains an instance of the Windsor container, so is it a bad idea to expose it to the API controller? If so, what is the best alternative? Thanks.
My solution was to use a generic typed factory facility (e.g. http://thesenilecoder.blogspot.com/2012/04/ioc-windsor-typedfactoryfacility-and.html)
The factory only consists of the following interface:
public interface IServiceFactory
{
T Create<T>(ApiRequestModel request) where T : IService;
void Release(IService service);
}
And here's how it gets installed to the container:
container.AddFacility<TypedFactoryFacility>();
container.Register(
Component.For<IServiceFactory>().AsFactory(),
Classes.FromThisAssembly().BasedOn<IService>().LifestylePerWebRequest());
That gets injected into the API controller and allows me to create generic types. I used reflection to resolve the generic type before I went to the factory.
Type serviceType = Assembly.Load("TestProject").GetType("TestClass");
MethodInfo factoryMethod = _serviceFactory.GetType().GetMethod("Create").MakeGenericMethod(serviceType);
IService instance = (IService)factoryMethod.Invoke(_serviceFactory, new object[] { request });

Using Unit of Work with Windsor Castle inside SignalR Hub

I'm working in an ASPNET MVC 4 project using SignalR and Windsor Castle.
I've mvc controller and WebApi controllers working and instantiating ok with Castle, but my Unit of Work class is not instantiated when it is used inside the Hub of SignalR.
Is there something I'm missing?
This is my code:
IocConfig class
public static class IocConfig
{
public static IWindsorContainer Container { get; private set; }
public static void RegisterIoc(HttpConfiguration config)
{
// Set the dependency resolver for Web API.
var webApicontainer = new WindsorContainer().Install(new WebWindsorInstaller());
GlobalConfiguration.Configuration.DependencyResolver = new WebApiWindsorDependencyResolver(webApicontainer);
// Set the dependency resolver for Mvc Controllers
Container = new WindsorContainer().Install(new ControllersInstaller());
DependencyResolver.SetResolver(new MvcWindsorDependencyResolver(Container));
ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(Container));
var controllerFactory = new WindsorControllerFactory(Container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}
}
}
WebWindsorInstaller class
internal class WebWindsorInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component
.For<RepositoryFactories>()
.ImplementedBy<RepositoryFactories>()
.LifestyleSingleton());
container.Register(Component
.For<IRepositoryProvider>()
.ImplementedBy<RepositoryProvider>()
.LifestylePerWebRequest());
container.Register(Component
.For<IGdpUow>()
.ImplementedBy<GdpUow>()
.LifestylePerWebRequest());
container.Register(Classes
.FromAssemblyContaining<Api.MessagesController>()
.BasedOn<IHttpController>()
.If(t => t.Name.EndsWith("Controller"))
.LifestylePerWebRequest());
}
ControllerInstaller class
public class ControllersInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(FindControllers().Configure(c => c.LifestyleTransient()));
container.Register(Component
.For<RepositoryFactories>()
.ImplementedBy<RepositoryFactories>()
.LifestyleSingleton());
container.Register(Component
.For<IRepositoryProvider>()
.ImplementedBy<RepositoryProvider>()
.LifestylePerWebRequest());
container.Register(Component
.For<IGdpUow>()
.ImplementedBy<GdpUow>()
.LifestylePerWebRequest());
}
private static BasedOnDescriptor FindControllers()
{
return AllTypes.FromThisAssembly()
.BasedOn<IController>()
.If(t => t.Name.EndsWith("Controller"));
}
Hub
using Microsoft.AspNet.SignalR.Hubs;
[HubName("iServerHub")]
public class IServerHub : Hub
{
protected IGdpUow Uow;
public void Send(string name, string message)
{
var messagesList = Uow.UdsMessages.GetAll();
Clients.All.broadcastMessage(messagesList);
}
}
In the Send method Uow is null.
Controllers are inherited from this base class
public abstract class CustomControllerBase : Controller
{
protected IGdpUow Uow { get; set; }
}
And when I use Uow in the controller it is instantiated. I don't understand the difference with using it inside the hub.
NOTE
I'm following the instruction found here on how to set up Windsor Castle to make it work with SignalR, but I can't test it since I'm getting the following error (seems that the proxy cannot be created):
Cannot read property client of undefined
meaning that the proxy to the hub was not created
This is how I have it in the server
public class IServerHub : Hub
and like this in the client
var clientServerHub = $.connection.iServerHub;
I can see the dynamically created file here:
/GdpSoftware.Server.Web/signalr/hubs
So, Why the proxy is not created?
This is my installer file
public class HubsInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component
.For<RepositoryFactories>()
.ImplementedBy<RepositoryFactories>()
.LifestyleSingleton());
container.Register(Component
.For<IRepositoryProvider>()
.ImplementedBy<RepositoryProvider>()
.LifestylePerWebRequest());
container.Register(Component
.For<IGdpUow>()
.ImplementedBy<GdpUow>()
.LifestylePerWebRequest());
container.Register(Classes.FromThisAssembly()
.BasedOn<Hub>()
.LifestyleTransient());
}
}
Thanks in advance! Guillermo.
Where do you expect it to be resolved? I don't see that code.
I don't know ASP.NET MVC very good but last time I used it controllers were receiving dependencies through constructor. How your controllers' ctors look? Do they take IGdpUow as parameter? If not how it is injected? I think Windsor can only inject when you have public setter for property - Castle Windsor property injection.
So I guess your controllers have ctors and your IServerHub doesn't (BTW in .NET this name is a bit misleading for a class)

Categories