AutoFac MVC Web API - dependency-injection

I have a simple AutoFac example working but now want to apply this to my web api project AND have the correct separation between the layers.
The issue I am seeing is the standard controller x "does not have a default constructor" but i am stumped so asking for advice..
I am calling RegisterApiControllers as well as RegisterControllers..
this is what I have in my DependencyInjectionContainer
public static class DependencyInjectionContainer
{
public static ContainerBuilder Builder;
public static IContainer Container;
public static void Init(Assembly mainAssembly)
{
Builder = new ContainerBuilder();
var config = GlobalConfiguration.Configuration;
RegisterTypes(mainAssembly);
Container = Builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(Container);
DependencyResolver.SetResolver(new AutofacDependencyResolver(Container));
}
private static void RegisterTypes(Assembly mainAssembly)
{
var roomBookingConnectionString = ConfigurationManager.ConnectionStrings["RoomBooking"].ConnectionString;
Builder.RegisterControllers(mainAssembly);
Builder.RegisterType<RoomRepository>().As<IRoomRepository>().WithParameter(new TypedParameter(typeof(string), roomBookingConnectionString));
Builder.RegisterType<RoomService>().As<IRoomService>();
Builder.RegisterApiControllers(mainAssembly);
Builder.RegisterFilterProvider();
}
}
I am calling this in my Global.asax.cs
DependencyInjectionContainer.Init(typeof(MvcApplication).Assembly);
One big assumption here is that this is correct...
Builder.RegisterApiControllers(mainAssembly);
edit---------------------------------------------------------------------
I have just tried moving all of the DI registrations etc in the 2 methods above back to the global.asax.cs and it works!?!?
I think its something to do with the 'RegisterApiControllers'. I am passing the calling assembly into the above init method using 'typeof(MvcApplication).Assembly'. Is there something wrong with this?
Thanks.

The RegisterApiControllers method is used by Autofac to locate the controllers.
When you do Builder.RegisterApiControllers(mainAssembly); are you sure the mainAssembly parameter is the assembly containing the controllers?
Anyway, if you have this kind of problems, you can do something like this (guessing you have a controller called RoomBookingController) :
builder.RegisterApiControllers(typeof(RoomBookingController).Assembly);
This way Autofac will locate the assembly containing your controller, no matter where it is.

Related

Instantiate class using dependency injection

Im trying to use a HTML view to string rendering class i found online. Its called PDFRender atm cause this is what it will be used for. Ive been told that its set up using Dependency Injection and that it should work out of the box.
Im not sure how to instantiate it though. Since the dependencies are supposed to be injected through the constructor.
My class constructor look like this
public PdfRender(IRazorViewEngine viewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider)
{
_viewEngine = viewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
And i set it up in the Startup classes ConfigureMetod() like this
// Set up Report PDF html renderer
services.AddScoped<PdfRender, PdfRender>();
Now m trying this in my code (after looking at the links example)
PdfRender pdfRender;
string iWantToBetml = pdfRender.ModelToHTML(inspection);
But i get an error (ofcourse) saying that i cant use an unassigned variable. I guess i dont understand how the DI is supposed to be used. Im assuming the idea is to give the default viewEngine, dataProvider and serviceProviders.
You just need to add a PdfRender parameter to the constructor of your controller:
public PdfRender(PdfRender pdfRender, IRazorViewEngine viewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider)
{
_pdfRender = pdfRender;
_viewEngine = viewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
Then you can use in in an instance method on that controller
public SomeMethod(){
string iWantToBetml = _pdfRender.ModelToHTML(inspection);
}
Note that in your controller constructor you don't necessarily need to specify all these parameters, just specify the ones that the class needs and then those will be injected in from the DI container provided their types have been registered with the DI container at startup.

Simple Injector MVC5 property injection on ActionFilterAttribute not working [duplicate]

The action filter I want to inject into starts like this
public class UserAuthorisation : AuthorizeAttribute
{
public IWcfClientProxy<IAppFrameworkServiceChannel>
FrameworkServiceProxy { get; set; }
I have setup my container like this:
container.Register<IWcfClientProxy<IAppFrameworkServiceChannel>>(
()=> new WcfClientProxy<IAppFrameworkServiceChannel>());
container.RegisterInitializer<UserAuthorisation>(handler =>
{
handler.FrameworkServiceProxy = container
.GetInstance<IWcfClientProxy<IAppFrameworkServiceChannel>>();
});
When I run this the FrameworkServiceProxy property is null.
I have read this post: Simple Injector: Injecting a property in a base class and followed the answer. I have also read example in this page Simple Injector Documentation.
I am not injecting into a base class and maybe that is the issue?
## UPDATE ##
I am adding more information as I think it should be working from what has been said in Stevens answer.
I am using the NuGet package for MVC 3. This adds the following to the application:
public static class SimpleInjectorInitializer
{
/// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
public static void Initialize()
{
var container = new Container();
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.RegisterMvcAttributeFilterProvider();
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
private static void InitializeContainer(Container container)
{
container.Register<IWcfClientProxy<IAppFrameworkServiceChannel>>(() => new WcfClientProxy<IAppFrameworkServiceChannel>());
container.RegisterInitializer<UserAuthorisation>(handler =>
{
handler.FrameworkServiceProxy = container.GetInstance<IWcfClientProxy<IAppFrameworkServiceChannel>>();
});
}
This includes the container.RegisterMvcAttributeFilterProvider(); that as I now understand it should register a filter provider and should mean that filters are created through the container (this understanding might be wrong) and then properties are automatically wired-up.
My filter is registered in the Global.asax.cs like so:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new UserAuthorisation());
}
It seems to me that the filter is not being created by the container so I think I need to do something else to get that to happen ?
I have selected Stevens answer as the answer as it got me to a solution and I am now using the command handler that he mentioned in the comments.
I have put a simple work around in to get my global filters injected.
In the App_Start\SimpleInjectorInitializer.cs I have added RegisterGlobalFilters like this:
public static void RegisterGlobalFilters(GlobalFilterCollection filters, Container container)
{
//Add simple injector resolved types.
filters.Add(container.GetInstance<UserAuthorisation>());
}
And in the Initialize method I have added this RegisterGlobalFilters(GlobalFilters.Filters, container);
The complete method looks like this:
/// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
public static void Initialize()
{
var container = new Container();
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.RegisterMvcAttributeFilterProvider();
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
RegisterGlobalFilters(GlobalFilters.Filters, container);
}
As I said very simple. Just get my instances from simple injector and then add them to the global list, I am sure there are better ways to do this.
This way does mean you do not need to change the global.asax.cs which is possibly a good thing.
You are registering an initializer on your UserAuthorisation attribute. Initializers however, are only used by the container when a type is created by the container itself. Since attributes are created by the CLR, the initializer won't go off.
The SimpleInjector.Integration.Web.Mvc.dll (this NuGet package) contains a RegisterMvcAttributeFilterProvider extension method. This will register an AttributeFilterProvider that will do implicit property injection (and call into the container.InjectProperties method). After calling container.RegisterMvcAttributeFilterProvider(), you will see that this property is injected automatically.

Manual resolve Unity dependency

Is possible make a Resolve<> inside a method instead inject the dependency in the constructor or in a property of the class?
public void Foo()
{
if (...)
var context = Unity.Resolve<Context>();
}
The idea is a conditional dependency resolve that uses the Unity to manage the lifetime of the object created as in the usual DI usage. The DI is set in a Web Api project so the MVC DependencyResolver.Current will not work.
While this is considered a bad pattern by some, you can implement a form of simple static Service Locator pattern like this:
public static class Unity
{
private static IUnityContainer _container;
public static void SetAppContainer(IUnityContainer container)
{
_container = container;
}
public static T Resolve<T>()
{
return _container.Resolve<T>();
}
}
That's not a good idea. The only part of your application that should have knowledge of your container is the composition root. This is an example of a service locator which is an anti-pattern, because dependencies aren't explicitly declared.
It sounds like you want to introduce a factory type that can be injected via constructor injection.

How to share the same instance in ASP.NET MVC 5 with Ninject?

I am trying to use Ninject for IoC with ASP.NET MVC 5.
My controller has a constructor like this:
private readonly IUnitOfWork _unit;
private readonly IContactService contactService;
public ContactsController(IUnitOfWork unit, IContactService contactService)
{
this._unit = unit;
this._contactService = contactService;
}
So the ContactService has a constructor (IUnitOfWork unit) and should share the same instance of the IUnitOfWork, but Ninject is giving a new different instance. My ContactService derives of a class with this constructor:
public ServiceBase(IUnitOfWork unit)
{
_unit = unit;
_repository = _unit.GetRepository<TEntity>();
}
My ninject config bindings:
public static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
kernel.Bind<IContactService>().To<ContactService>().InRequestScope();;
}
I hope that InRequestScope() give the same instance per request, but that is not happening.
I had exactly the same problem now. I had Ninject and Ninject.Web.Common packages installed and I was injecting dependencies using my custom NinjectControllerFactory. Using Erik's response linked by BatteryBackupUnit's in comments, I have decided to uninstall my Ninject packages and I have installed Ninject.MVC5 package.
The package generated a NinjectWebCommon.cs Ninject confgiuration file in the App_Start folder. The only thing you need to do is to copy your bindings to RegisterServices method in NinjectWebCommon.cs file and stop using your custom NinjectControllerFactory (if you have one).
It solved my problem, hope it solves your problem as well.

asp.net mvc test project cannot find windsor file

Hi there Im using windsor as a DI container,
my code is below
public static class ContainerBuilder
{
public static IWindsorContainer Build()
{
var container = new WindsorContainer("Configuration\\Windsor.config");
// automatically register controllers
container.Register(AllTypes
.Of<Controller>()
.FromAssembly(Assembly.GetExecutingAssembly())
.Configure(c => c.LifeStyle.Transient.Named(c.Implementation.Name.ToLower())));
container.Register(
Component.For<IServiceLocator>().Instance(new WindsorServiceLocator(container)),
Component.For(typeof(IRepository<>)).ImplementedBy(typeof(NHibernateRepository<>)).LifeStyle.Transient
);
return container;
}
}
I need to call this from a test project , the problem is that when I do this the windsor.config is never found and the test seems to always fail, where is the best way to place this config file or is there a better approach to doing this?
Thanks
Just make the config path configurable, e.g.
public static IWindsorContainer Build(string configPath) {
var container = new WindsorContainer(configPath);
...
}
In your app the configPath is "Configuration\Windsor.config" while in your tests you'll have a path like "....\Configuration\Windsor.config".
Note that you shouldn't generally depend on the container in your tests, unless you're running some integration tests.
Also a static container builder doesn't seem like a good idea, take a look at Windsor Installers to register your components in a modular way.

Resources