Shane van Wyk
Shane van Wyk

Reputation: 1900

Simple Injector Property Injection

How do you perform property injection with Simple Injector.

The with Ninject you do is as per bellow:

[Inject]
public IUnitOfWork UnitOfWork { get; set; }

How can I do the equivalent to this with Simple Injector. I tried finding a solution online but had no luck.

Why do I want to use Property Injection?

I want to use property injection to set up unit of work in my base controller so that it will create a new unit of work OnActionExecuting and commit the changes OnResultExecuted. It also means I don't have to pass in the UoW with each new controller I create through the constructor.

Upvotes: 1

Views: 583

Answers (2)

Ric .Net
Ric .Net

Reputation: 5540

Another option is to use the RegisterInitializer method:

container.RegisterInitializer<BaseControllerType>(controller =>
{
   controller.UnitOfWork = container.GetInstance<IUnitOfWork>();
}

It keeps all configuration in your composition root and does not pollute your code base with all kinds of attributes.

Update: (as promised)

While this is a direct answer to your question I have to provide you with a better option, because the usage of a base class for this is a IMO not the correct design, for multiple reasons.

  1. Abstract classes can become real PITA classes as they tend to grow towards a god class which has all kinds of cross cutting concerns
  2. An abstract class, especially when used with property injection, hides the needed dependencies.

With focus on point 2. When you want to unit test a controller which inherits from the base controller, you have no way of knowing that this controller is dependent on IUnitOfWork. This you could solve by using constructor injection instead of property injection:

protected abstract class BaseController : Controller
{
    protected readonly IUnitOfWork uoW;
    protected BaseController (IUnitOfWork uoW)
    {
        this.uoW = uoW;
    }

}
public class SomeController : BaseController
{
    public SomeController(IUnitOfWork uoW) : base(uoW) { }
}

While this solves point 2, point 1 is still lurking. The main reason you're wanting this, as you say, is because you do not want to commit your changes in every Action method. Changes must just be saved by the context when the request is done. And thinking about design in this way is a good thing, because Saving changes is, or can be seen as a cross cutting concern and the way you're implementing this is more or less known as AOP.

If it's comes to AOP, especially if you're working with atomic actions in the action methods of your controllers, there is a far better, more SOLID and more flexible design possible which deals with this very nicely.

I'm referring to the Command/Handler pattern which is described in great detail here (also read this for the query part of your application).

With this patterns you don't inject a generic IUnitOfWork abstraction, but inject the specific needed ICommandHandler<TCommand> abstractions.

The action methods would fire the responsible commandhandler for this specific action. All commandhandlers can simple be decorated by a single open-generic SaveChangesCommandHandlerDecorator, 'ValidationDecorator', 'CheckPermissionsDecorator', etc...

A quick example:

public class MoveCustomerCommand
{
    public int CustomerId;
    public Address NewAddress;
}

public class MoveCustomerCommandHandler : ICommandHandler<MoveCustomerCommand>
{
    public void Handle(MoveCustomerCommand command)
    {
        // retrieve customer from database
        // change address
    }
}

public class SaveChangesCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand>
{
    private readonly ICommandHandler<TCommand> decoratee;
    private readonly DbContext db;

    public SaveChangesCommandHandlerDecorator(
           ICommandHandler<TCommand> decoratee, DbContext db)
    {
        this.decoratee = decoratee;
        this.db = db;
    }

    public void Handle(TCommand command)
    {
        this.decoratee.Handle(command);
        this.db.SaveChanges();
    }
}

// Register as 
container.Register(typeof(ICommandHandler<>), new []{Assembly.GetExecutingAssembly() });
container.RegisterDecorator(typeof(ICommandHandler<>), 
                       typeof(SaveChangesCommandHandlerDecorator<>));

// And use in controller as
public ActionResult MoveCustomer(int customerId, Address address)
{
     var command = new MoveCustomerCommand 
                   { CustomerId = customerId, Address = address };
     this.commandHandler.Handle(command);

     return View(new ResultModel());
}

This keeps your controllers clean and let it do what it must do, namely be the layer between the business logic (the commandhandler implementation in this case) and the view.

Upvotes: 3

Shane van Wyk
Shane van Wyk

Reputation: 1900

Need to create the following:

First create the attribute class

[System.AttributeUsage(System.AttributeTargets.Property]
public class Inject : Attribute
{
}

Then create a custom property behavior

class PropertySelectionBehavior<TAttribute> : IPropertySelectionBehavior
where TAttribute : Attribute
{
    public bool SelectProperty(Type type, PropertyInfo prop)
    {
        return prop.GetCustomAttributes(typeof(TAttribute)).Any();
    }
}

Finally tell the container to use custom behavior

container.Options.PropertySelectionBehavior = new PropertySelectionBehavior<Inject>();

All that is left to do is decorate the property with the attribute

[Inject]
public IUnitOfWork UnitOfWork { get; set; }

Upvotes: 2

Related Questions