Simple Injector: Different DbContext for selected

2019-05-23 16:41发布

问题:

I am trying to separate reads/writes in my MVC application. I am using Simple Injector as Ioc and I have following structure:

new Service(
  new Repository(
     new UnitOfWork(
        new DbContext())))

So UnitOfWork registered per web request all the rest Transient.

So idea was to create separate read-only controllers and make a registration of DbContext to supply a different connection if controller is read-only. And that could be achievable with improved RegisterWithContext extension BUT it will not work in my case because not all graph nodes are Transient.

Is there any way (more elegant than register each Repository with improved RegisterWithContext extension where need to supply another read-only UnitOfWork and manually resolve all other arguments that passed into Repository) how the described scenario can be achieved?

回答1:

Since the choice is based on the type of controller, you can make the descision in a custom IControllerFactory. For instance:

public class ConnectionSelector {
    public bool AsReadOnly { get; set; }
}

private class ReadOnlySwitchControllerFactory : DefaultControllerFactory {
    private readonly Container container;

    public ReadOnlySwitchControllerFactory(Container container) {
        this.container = container;
    }

    protected override IController GetControllerInstance(RequestContext requestContext, 
        Type controllerType) {
        var selector = this.container.GetInstance<ConnectionSelector>();

        selector.AsReadOnly = 
            typeof(IReadOnlyController).IsAssignableFrom(controllerType);

        return base.GetControllerInstance(requestContext, controllerType);
    }
}

You can register this as follows:

container.RegisterPerWebRequest<ConnectionSelector>();

container.RegisterPerWebRequest<DbContext>(() => new DbContext(
    container.GetInstance<ConnectionSelector>().AsReadOnly 
        ? "ReadOnlyConnection" 
        : "NormalConnection"));

container.RegisterSingle<IControllerFactory>(
    new ReadOnlySwitchControllerFactory(container));