I'm currently injecting dependencies into controllers using a IoC container (Castle). This is possible because you need to create a custom controller factory which enables the dependency injection.
What are other examples of dependency injection? At which point in an MVC application would you use it, and where does a 'factory' come into play?
I am using Ninject. At my project:
Service layer objects are injected into controllers (using constructor).
Repositories are injected into service layer objects (using constructor).
ObjectContext is injected into repositories (using constructor).
web.config setting are encapsulated into a class, which implements IAppSettings interface, which is then injected into service layer.
NinjectActionInvoker is injected as IActionInvoker. It takes care of injecting services into ActionFilters.
I have my own implementation of IPrincipal interface, which is injected into service layer, instead of referring to HttpContext.Current.User.
Example using Ninject:
public class UserService : GenericService<User>, IUserService
{
public ISettingService SettingService { get; set; }
public ICTEmailSender CTEmailSender { get; set; }
public ICTSettings CTSettings { get; set; }
public ICTPrincipal User { get; set; }
}
Ninject rules:
Bind<ICTPrincipal>().ToMethod(c => (ICTPrincipal)HttpContext.Current.User).OnlyIf(a => HttpContext.Current.User is ICTPrincipal);
Bind<ICTEmailSender>().To<CTEmailSender>();
Bind<ICTSettings>().To<CTSettings>();
Not only service is injected into controller, but parts of service are injected into it. It makes service more testable. I am sure it can be easily ported into Castle.
Related
In an ASP.NET MVC application, I'm calling "Services" methods from my controllers.
Usually, a controller named ReportingController calls methods from ReportingServices. The service classes are being instantiated with Autofac with the Mvc.Integration.
builder.RegisterControllers(Assembly.GetExecutingAssembly());
The service is then injected into the controller constructor.
public ReportingController(ReportingServices service)
So far so good.
But occasionally, a controller needs to call methods from other services. I changed the autofac configuration:
builder.RegisterControllers(Assembly.GetExecutingAssembly())
.PropertiesAutowired(PropertyWiringOptions.PreserveSetValues);
And added properties to the controllers:
public CommonServices CommonService { get; set; } // new properties
public ReportingController(ReportingServices service) {} // existing ctor
What happens now however is that when the controller is instantiated, all properties are also being set, even if they are never used by a particular ActionMethod.
How can I tell Autofac to delay instantiation of the properties until required or perhaps I should simply not care about this unnecessary initialization?
Autofac supports Lazy<T> out of the box.
So you just need to declare your property as:
public Lazy<CommonServices> CommonService { get; set; }
And Autofac won't instantiate your CommonServices until you don't access your Lazy's value with CommonService.Value.
In my project I had a controller dependency on IRepositoryProvider among others.
public class HomeController : BaseController
{
public HomeController(ISessionWrapper sessionWrapper,
IRepositoryProvider repositoryProvider,
IApplicationConfiguration applicationConfiguration)
: base(sessionWrapper, repositoryProvider, applicationConfiguration)
{}
...
}
IRepositoryProvider and its implementation live in a BLL layer. Another thing to note is that IRepositoryProvider has some parameters also. These are used to determine which connection strings to use (Environment*5 possible connections).
public RepositoryProvider(string environment, IApplicationConfiguration applicationConfiguration)
{
_applicationConfiguration = applicationConfiguration;
_environment = environment;
}
This all works fine with two layers and this Ninject config.
kernel.Bind<IRepositoryProvider>()
.To<RepositoryProvider>()
.InRequestScope()
.WithConstructorArgument("environment",
context => context.Kernel.Get<ISessionWrapper>().CurrentEnvironment)
.WithConstructorArgument("applicationConfiguration",
context => context.Kernel.Get<IApplicationConfiguration>());
My issue develops when I introduced a service layer. Instead of relying on IRepositoryProvider in my controllers for data access, I want to use the service layer. Ideally then I don't want to reference the BLL layer, and only the Service layer.
public class HomeService : IHomeService
{
public IRepositoryProvider RepositoryProvider { get; private set; }
public HomeService(IRepositoryProvider repositoryProvider)
{
RepositoryProvider = repositoryProvider;
}
...
}
So my question is this: Is it possible for me to not reference both the Service and BLL layers from the MVC project? Or is this whole setup a massive code smell?
Thanks.
UPDATE: I suppose I should have said my ideal references. Web -> Service -> BLL. At the moment Web references both Service and BLL in order for Ninject to resolve everything.
UPDATE 2: Does this seem like a possible solution? How to tell Ninject to bind to an implementation it doesn't have a reference to
This is how I usually architect my MVC projects depending on requirements.
Presentation Layer > Service Layer > Business Layer > Data Access Layer.
Presentation Layer contains : ViewModels, Views, Controllers. (References the Service Layer, Ninject ddl)
Service Layer : WCF. (References the BAL, etc)
Business Layer : Contains what I call Orchestrators and their interfaces (References DAL, Domain)
Data Access Layer: Contains the Repositories and their Interfaces (References Domain)
Domain: Contains the POCO objects
Core : Where I actually install and configure Ninject (References the BAL, DAL, etc)
To Add Ninject to a another Project other than the Presentation Layer:
Add the following to Global.Asasx.cs:
DependencyResolver.SetResolver(new NinjectDependencyResolver());
Then create a new project sucche as core. Install Ninject there and add the following class:
You will need to reference the Ninject dll from the Presentation Layer
public class NinjectDependencyResolver : IDependencyResolver {
private IKernel kernel;
public NinjectDependencyResolver()
{
kernel = new StandardKernel();
AddBindings();
}
public object GetService(Type serviceType)
{
return kernel.TryGet(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return kernel.GetAll(serviceType);
}
public IBindingToSyntax<T> Bind<T>()
{
return kernel.Bind<T>();
}
public IKernel Kernel
{
get { return kernel; }
}
private void AddBindings()
{
//Add your Bindings here
}
}
IRepositoryProvider and its implementation live in a BLL layer...
Is it possible for me to not reference both the Service and BLL layers
from the MVC project
With those two statement of yours the answer is NO, it is not possible for you "not" to reference those layers. The best approach of minimizing references is to separate your interfaces from the implementations. You can have for example the following:
The Domain Layer, contains your POCO and interface
Product (a sample class)
IRepository (an interface)
The Service Layer, contains the implementaion of your interfaces
Have a reference to the Domain layer
Implements IRepository (e.g. ProductRepository : IRepository)
Dependency Injection Layer
Is aware of both the Domain and Service layers
The MVC Project
Have a reference to the Domain layer to know about the POCOs and repository signatures
Have a reference to the DI layer but doesn't know how it exactly
works. So you can swap out DI framework later and everything will still work.
You can expand that layer as you see fit. You can insert the BLL layer in between the Domain and Service layer and you don't need reference it anywhere.
I have a very layered MVC3 application (seperate projects for the domain, services, web, infrastructure, etc.)
I understand the concept of controller constructor injection, which MVC3 and Ninject work so kindly together. But what about injection for layers separate from the web layer?
For example, I have a service that relies on a Repository interface. The service is called from the controller, and the service itself will be injected properly by the constructor injection, but what about the repository? How do I inject that?
public class MyService
{
protected virtual IPersonRepository PersonRepository {get; set;}
public virtual void UseRepository()
{
PersonRepository.FindEveryoneInTheWorldButDontReturnThem();
}
}
Where/how do I [n]inject the repository in the above example?
Ninject 3.0
Ninject.Web.MVC 3.0
Inject the repository via constructor injection, and your IoC container (Ninject) will take care of dependency chains (i.e. when you inject MyService as a dependency, any of its dependencies will also be resolved by the container, and their dependencies and so on)
public MyService(IPersonRepository personRepository)
{
this.PersonRepository = personRepository;
}
Recently I moved to MVC 3 and Ninject 2. In most of the code, I use constructor injection, but there are some places, where I had to use Inject attribute. Ninject 2 registers its own IDepencyResolver interface. I don't like DependencyResolver class being part of System.Web.Mvc namespace, because its function is not really strictly related to MVC, but now, when it is there, I can do
public SomeClass
{
public IUserService UserService { get; set; }
public SomeClass()
{
UserService = DependencyResolver.Current.GetService<IUserService>();
instead of
public SomeClass
{
[Inject]
public IUserService UserService { get; set; }
so I don't have to reference Ninject namespace in my classes. Should DependencyResolver be used like that?
I use property injection only for dependencies that are not required for the proper working of the class but could add some functionality if the user sets them. Example of such functionality is logging. So you could have a property which represents a logger where the user can supply his own implementation and if he doesn't the class continues to work normally but it simply doesn't log.
For everything else I use constructor injection. This way you indicate to the consumer that this class has a required dependency on some other service.
So to answer your question about the property injection I would simply have:
public SomeClass
{
public IUserService UserService { get; set; }
public void SomeMethodWhichDoesntEnforceUserService()
{
if (UserService != null)
{
// Provide some additional functionality
}
}
}
and if your class cannot function properly without the user service:
public SomeClass
{
private readonly IUserService _userService;
public SomeClass(IUserService userService)
{
_userService = userService;
}
public void SomeMethodWhichRequiresTheService()
{
_userService.DoSomething();
}
}
So in both cases no reference to any DI specifics. That's what Inversion of Control is all about.
First question I would ask is why you can not perform constructor injection of the IUserService into SomeClass? It may indicate an issue with the design.
To avoid direct reference to the DependencyResolver you could implement some form of abstraction of a Service Locator over the DI framework, e.g. CommonServiceLocator, but as the answer to this question indicates, such abstractions shouldn't be necessary when doing DI correctly. Instead you should adjust the design of the application.
I believe the ninject.web.mvc version for mvc3 now supports constructor injection on filter attributes. Have you tried it?
How to do Dependency Injection on Property of a class Using Structure Map
public class ContactController : Controller
{
public IContactService Service { get; set; }
public ContactController()
: this(null,null)
{
}
[SetterProperty]
public MembershipProvider Provider { get; private set; }
}
Here when i Create instance of ContactController i want provider to be set to Mock<MembershipProvider> please help me how to go about doing this? Mock is Moq Framework class
If you are using a Mock, you are most likely writing test code. If thats the case, you likely don't need a dependency injection tool like StructureMap involved. Just set the Provider property manually to your MembershpProvider in your test setup code.
controller.Provider = Mock<MembershipProvider>
If you really want to configure setter injection using StructureMap, see this answer:
Property Injection into an Action Filter