ASP.NET MVC with WEB.API and Castle Windsor container - c#

I have ASP.NET MVC application with integrated Castle Windsor container. When I added ApiController, and tried to do POST, I got an error message: "Make Sure That the controller has a parameterless public constructor." Thanks for any advice.
Castle Windsor integration:
public class CastleControllerFactory : DefaultControllerFactory
{
public IWindsorContainer Container { get; protected set; }
public CastleControllerFactory(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentException("container");
}
this.Container = container;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return null;
}
return Container.Resolve(controllerType) as IController;
}
public override void ReleaseController(IController controller)
{
var disposableController = controller as IDisposable;
if (disposableController != null)
{
disposableController.Dispose();
}
Container.Release(controller);
}
}
public class DefaultCastleInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<TypedFactoryFacility>();
//Functions
//container.Register(Component.For<IGetIPAddressesFromRange>().ImplementedBy<GetIPAddressesFromRange>().LifestylePerWebRequest());
container.Register(Component.For<IUnitOfWork>().ImplementedBy<UnitOfWork>().LifestylePerWebRequest());
var contollers = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.BaseType == typeof(Controller)).ToList();
foreach (var controller in contollers)
{
container.Register(Component.For(controller).LifestyleTransient());
}
var apiContollers = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.BaseType == typeof(ApiController)).ToList();
foreach (var apiController in apiContollers)
{
container.Register(Component.For(apiController).LifestyleTransient());
}
}
}
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
//Integrace CastleWindsor
var container = new WindsorContainer();
container.Install(new DefaultCastleInstaller());
var castleControllerFactory = new CastleControllerFactory(container);
ControllerBuilder.Current.SetControllerFactory(castleControllerFactory);
}
}
ApiController:
public class UserVerificationController : ApiController
{
private readonly IUnitOfWork _unitOfWork;
/// <summary>
/// Konstruktor
/// </summary>
/// <param name="unitOfWork"></param>
public UserVerificationController(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
// GET api/<controller>
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}

The problem is that because MVC and Web API controllers are separate entities, you need Windsor configuration for both. You've got Windsor configured to create your MVC controllers. You just need the same for your Web API controllers.
Here's a Web API controller activator, mostly lifted from this blog post.
public class WindsorWebApiControllerActivator : IHttpControllerActivator
{
private readonly IWindsorContainer _container;
public WindsorWebApiControllerActivator(IWindsorContainer container)
{
_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)
{
_release = release;
}
public void Dispose()
{
_release();
}
}
}
And you need to register all of the controller types with the container. Here's an IWindsorInstaller that registers all MVC and Web API controllers:
public class ControllersInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Classes.
FromThisAssembly().
BasedOn<IController>(). //MVC
If(c => c.Name.EndsWith("Controller")).
LifestyleTransient());
container.Register(
Classes.
FromThisAssembly().
BasedOn<IHttpController>(). //Web API
If(c => c.Name.EndsWith("Controller")).
LifestyleTransient());
}
}
Then at startup replace the default Web API controller activator with yours:
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator),
new WindsorWebApiControllerActivator(container));
and be sure to call the installer:
container.Install(new ControllersInstaller());

Related

How to dispose the object created by Unity DI right after the completing the request?

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

Autofac: Type 'MyController' does not have a default constructor

I have a Web Api app that consumes another REST Api client. I wrapped the REST API client into a service.
myproj/services/PostDataService.cs
public interface IPostDataService
{
Task<IList<Post>> GetAllPosts();
}
public class PostDataService : IPostDataService
{
private static IDataAPI NewDataAPIClient()
{
var client = new DataAPI(new Uri(ConfigurationManager.AppSettings["dataapi.url"]));
return client;
}
public async Task<IList<Post>> GetAllPosts()
{
using (var client = NewDataAPIClient())
{
var result = await client.Post.GetAllWithOperationResponseAsync();
return (IList<Post>) result.Response.Content;
}
}
}
....
I am using AutoFac and injecting the service in the controller
myproj/controllers/PostController.cs
public class PostController : ApiController
{
private readonly IPostDataService _postDataService;
public PostController(IPostDataService postDataService)
{
_postDataService = postDataService;
}
public async Task<IEnumerable<Post>> Get()
{
return await _postDataService.GetAllPosts();
}
}
But I am getting this error.
An error occurred when trying to create a controller of type
'PostController'. Make sure that the controller has a parameterless
public constructor.
Here is my Global.asax.cs
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
ContainerConfig.Configure();
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
public static class ContainerConfig
{
private static IContainer _container;
public static IContainer GetContainer()
{
if (_container != null)
return _container;
var builder = new ContainerBuilder();
builder.RegisterType<PostDataService>()
.AsSelf()
.InstancePerLifetimeScope()
.AsImplementedInterfaces();
_container = builder.Build();
return _container;
}
public static IContainer Configure()
{
var container = GetContainer();
var webApiResolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = webApiResolver;
return container;
}
Can someone spot what I am missing here?
Thanks
I'm missing
builder.RegisterApiControllers(typeof(PostController).Assembly).
Apparently, the controller also needs to be registered.

Dynamic register controller in C# Web Api

tl;dr: I'm creating Type (by reflection) that is extending ApiController. How can I dynamically register it (it can be registered at startup; no need to do this at runtime).
Long story:
So in my application I have multiple interfaces, i.e.:
interface IMyInterface
{
MyResponse Hello(MyRequest request);
}
The thing that I want to achive is for each interface create controller that should look like this:
public class IMyInterfaceController : ApiController
{
public IMyInterface MyInterface { get; set; }
public MyResponse Hello([FromBody] MyRequest request)
{
return MyInterface.Hello(request);
}
}
Generating this controller is already done using heavy C# reflection. The thing is that I want to do right now is to register this controller under /api/{controller}/{action}.
In Global.asax right now I got this:
public class MvcApplication : System.Web.HttpApplication
{
private readonly InterfaceReader _reader = new InterfaceReader(); // this class is doing all staff with reflection to create controller class
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
var controller = _reader.CreateController(new MyImplementation()); // MuImplementation implements IMyInterface
}
}
Solution with IHttpControllerFactory
I guess that what you need is a controller factory:
public class MyHttpControllerFactory : IHttpControllerFactory
{
private readonly InterfaceReader _reader;
private readonly HttpConfiguration _configuration;
public MyHttpControllerFactory(InterfaceReader reader, HttpConfiguration configuration)
{
_reader = reader;
_configuration = configuration;
}
public IHttpController CreateController(HttpControllerContext controllerContext, string controllerName)
{
if (controllerName == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", controllerContext.Request.RequestUri.AbsolutePath));
}
// Change the line below to whatever suits your needs.
var controller = _reader.CreateController(new MyImplementation());
controllerContext.Controller = controller;
controllerContext.ControllerDescriptor = new HttpControllerDescriptor(configuration, controllerName, controller.GetType());
return controllerContext.Controller;
}
public void ReleaseController(IHttpController controller)
{
// You may want to be able to release the controller as well.
}
}
Then in the Global.asax you need to register the custom controller factory:
public class MvcApplication : System.Web.HttpApplication
{
private readonly InterfaceReader _reader = new InterfaceReader(); // this class is doing all staff with reflection to create controller class
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configuration.ServiceResolver.SetService(typeof(IHttpControllerFactory), new MyHttpControllerFactory(_reader, GlobalConfiguration.Configuration));
}
}
Solution with IHttpControllerActivator
If you use Web Api 2 then the solution is to use either IDependencyResolver or IHttpControllerActivator instead of the factory. I guess that the IHttpControllerActivator is better option in your case.
public class MyServiceActivator : IHttpControllerActivator
{
private readonly InterfaceReader _reader;
private readonly HttpConfiguration _configuration;
public MyServiceActivator(InterfaceReader reader, HttpConfiguration configuration)
{
_reader = reader;
_configuration = configuration;
}
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
// Change the line below to whatever suits your needs.
var controller = _reader.CreateController(new MyImplementation());
return controller;
}
}
Then in the Global.asax you need to register the custom activator:
public class MvcApplication : System.Web.HttpApplication
{
// this class is doing all staff with reflection to create controller class
private readonly InterfaceReader _reader = new InterfaceReader();
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
HttpConfiguration config = GlobalConfiguration.Configuration;
config.Services.Replace(typeof(IHttpControllerActivator), new MyServiceActivator(_reader, config));
}
}
I hope this helps.
You need to create your own class that implements IHttpControllerActivator
Here's an example that I use for DI with Windsor
public class WindsorCompositionRoot : IHttpControllerActivator
{
private readonly IWindsorContainer _container;
public WindsorCompositionRoot(IWindsorContainer container)
{
_container = container;
}
public IHttpController Create(
HttpRequestMessage request,
HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
var controller =
(IHttpController) _container.Resolve(controllerType);
request.RegisterForDispose(
new Release(
() => _container.Release(controller)));
return controller;
}
private class Release : IDisposable
{
private readonly Action _release;
public Release(Action release)
{
_release = release;
}
public void Dispose()
{
_release();
}
}
}
Then you need to wire it up in the Global.asax in Application_Start()
Container = new WindsorContainer().Install(FromAssembly.This());
GlobalConfiguration.Configuration.Services.Replace(
typeof (IHttpControllerActivator),
new WindsorCompositionRoot(Container));
Installing the controllers is done in a Windsor Installer class
public class ControllersInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.BasedOn<IHttpController>()
.LifestyleTransient());
}
}

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.

How to wire up a controller's dependancy

So I went through the asp.net mvc tutorial for castle windsor, and my registrations look like:
private static IWindsorContainer _container = new WindsorContainer();
private static void BootstrapContainer()
{
_container = new WindsorContainer()
.Install(FromAssembly.This());
var controllerFactory = new WindsorControllerFactory(_container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}
protected void Application_End()
{
_container.Dispose();
}
So in my HomeController I have this:
public class HomeController : Controller
{
private IUserService _userService;
public HomeController(IUserService userService)
{
this._userService = userService;
}
}
How would I go about wiring this controller up to setup the IUserService?
Update
In case in matters how I need to wire things up, my vs.net projects are:
web, interfaces, entities, data (nhibernate), services
The implementation of WindsorControllerFactory should look like this from the doco http://docs.castleproject.org/Windsor.Windsor-tutorial-part-two-plugging-Windsor-in.ashx?HL=ikernel.
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel kernel;
public WindsorControllerFactory(IKernel kernel)
{
this.kernel = kernel;
}
public override void ReleaseController(IController controller)
{
kernel.ReleaseComponent(controller);
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
// Throw exception. Can't resolve null type.
}
return (IController)kernel.Resolve(controllerType);
}
}
UPDATED
Each interface that needs to be resolved by dependancy injection need to be registered.
This can be done by calling the .Register method on the container.
container.Register(Component.For<IUserService>().ImplementedBy<UserService>().LifeStyle.Transient);
More info here: http://docs.castleproject.org/Windsor.Registering-components-one-by-one.ashx

Categories

Resources