question on IoC
I've been relying on IoC pattern for 1 year now using structuremap & asp.net mvc. IoC is really neat especially if you have a lot of dependencies in your class, just inject dependency in your constructor and your done, the IoC will auto-inject it for you.
My question is that im using asp.net mvc with a controller class which have IServices dependencies.
I need the dependency services only for a certain controller action let say "/customer/add" but i don't need those dependency on other action let say "/Customer/Index". However, since i'm using a DI (Dependency injection) in constructor, the dependency are always instantiated even if i don't need them. Is that any good? object creation is expensive and consume memory footprint.
Of course, i can do container.GetInstance inside an action, but it is not a good practice since you will heavily be dependent on IoC in your code and unit testing.
Any suggestion? correc开发者_StackOverflowt me if im wrong with something.
Updated in response to jgauffins comment
I see two straightforward ways to solve your issue:
Inject a service factory to your constructor and create the service on demand.
interface IFooService
{
void Bar();
}
interface IFooServiceFactory
{
IFooService CreateFooService();
}
class YourController
{
public YourController(IFooServiceFactory fooServiceFactory)
{
this.fooServiceFactory = fooServiceFactory;
}
public void YourAction()
{
IFooService fooService = this.fooServiceFactory.CreateFooService();
fooService.Bar();
}
}
Inject a service proxy to your constructor and let the proxy create the real service on demand.
interface IFooService
{
void Bar();
}
class FooServiceProxy : IFooService
{
private IFooService realFooService;
void IFooService.Bar()
{
IFooService realFooService = GetRealFooService();
realFooService.Bar();
}
private IFooService GetRealFooService()
{
if(this.realFooService == null)
{
this.realFooService = CreateRealFooService();
}
return this.realFooService;
}
private IFooService CreateRealFooService()
{
// You could inject the service factory in the constructor of the proxy and use it here to create the real service.
}
}
class YourController
{
Inject FooServiceProxy here
v
v
public YourController(IFooService fooService)
{
this.fooService = fooService;
}
public void YourAction()
{
this.fooService.Bar();
}
}
I always use constructors. imho properties should only be used to solve circular dependencies.
The reason is that the intent is not clear when using properties. Nothing in your code says that MyController.DoThat
wont work if the property MyController.MyProperty
is not set.
If a method needs a specific service, then the service is required for your whole class. Else you'll break the contract that your class exposes.
the dependency are always instantiated even if i don't need them. Is that any good?
Although not every part of the class requires the dependency, the class itself needs that dependency and it is therefore not an optional dependency. Typically when you see that some dependencies are used in one part of the class and other dependency in another part, your class might be violating the SRP; it might be doing more than one thing. Splitting them up however, would probably not help you since MVC Controller
classes are more focused around interfaces, so I would just leave it as it is.
object creation is expensive and consume memory footprint.
Reference types always have a 8 bytes overhead (on the 32 bits platform), so that's not much. The service object you would normally inject do contain very little state, often just some configuration values and references to their dependencies. From a memory perspective, it is nothing compared to the data that flows through you application (such as data from the database or the strings that get generated by MVC to build the HTML). It does depend on the DI framework you use, but typically even a relatively big dependency graph will get generated in a split second. And even when graph construction takes too much time, there are other ways to optimize performance. Consider defining some services with a singleton lifestyle for instance. When this is not enough, you might want to consider switching to a faster DI framework. StructureMap however, is one of the faster DI containers in the field (of the more commonly known ones), so for normal application development, this shouldn't be a problem.
The way I've always done it was that for injected dependencies that are optional (such as in the scenario you just described where only certain methods requires the dependency), set them up as properties. For required dependencies, use constructor injection.
StructureMap supports delayed instantiation - no need to craft your own service factory/proxy solution. If you only want IService
instantiated when in the actions it is used, inject a Func<IService>
into your constructor instead. Then, in your action that needs it, invoke the Func to return the instance.
class CustomerController {
Func<IService> _service;
public CustomerController(Func<IService> service){
_service = service;
}
public ActionResult Index(){
_service().CallMethodOnService();
}
}
However, I would first make sure that instantiating the service really is a performance problem before going to this extra effort.
精彩评论