3
votes

I'm having problem in passing parameter dynamically to class constructor using simple injector.

I have following code structure.

Controller example:

public class HomeController : Controller
{
    private readonly ICheckService _checkService;

    public HomeController(ICheckService checkService)
    {
        _checkService= checkService;
    }

    // GET: Home
    public ActionResult Index()
    {
        var list = _checkService.GetAll();
        return View(list);
    }
}

Service layer (in this layer I need to pass the two constructor parameter for CheckRepository<T> which is implementing ICheckRepository<T>. How do I achieve this using simple injector? I tried but not getting solution around. One example in order to achieve would be really grateful)

public interface ICheckService
{
      List<CheckType> GetAll();
}

public class CheckService : ICheckService
{
    private readonly ICheckRepository<CheckType> _checkRepository;

    public CheckService(ICheckRepository<CheckType> checkRepository)
    {
        _checkRepository= checkRepository;
    }

    public List<T> GetAll()
    {
        return _checkRepository.GetAll().ToList();
    }
}

Repository Layer:

public abstract class RepositoryBase<T> where T : class
{
    public string Types { get; set; }
    public string Segment { get; set; }

    public RepositoryBase(string type)
    {
        Types = type;
    }

    public RepositoryBase(string type, string segment)
    {
        Types = type;
        Segment = segment;
    }
}

public interface ICheckRepository<T> where T : class
{
    IEnumerable<T> GetAll();
}

public class CheckRepository<T> : RepositoryBase<T>, ICheckRepository<T> where T : class
{
    public CheckRepository(string types, string segment)
        : base(types, segment)
    {

    }

    public IEnumerable<T> GetAll()
    {
        var list = new List<T>();
        using (DbAccess dbAccess = new DbAccess(ConnectionString, DatabaseType.SqlServer))
        {
            return dbAccess.ExecuteReader<T>(StoredProc, CommandType.StoredProcedure).ToList();
        }
    }
}

My Simple Injector initializer class:

public static void InitializeInjector()
{
    var container = new Container();

    InitializeContainer(container);

    container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
    container.RegisterMvcIntegratedFilterProvider();
    container.Verify();

    DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}

private static void InitializeContainer(Container container)
{
    container.Register(typeof(IFilterRepository<>), typeof(FilterRepository<>));
  //Here is where I am struggling to bind dynamic constructor parameter registering

}

Does anyone have any solution for the above code?

Thanks again.

1
What values do you want to put in those two parameters? Does every repository have its own connectionstring or stored procedure, or are these configuration constants and equal to every repository? Can you update your question with an example of how you would create these repositories without the use of a container? - Steven
Its just a string and it doesn't matter what exactly I put in. but these string parameter may vary with different repository. i didn't get your last question coz thats the answer am looking for. The code above explained to the point where i got stuck. - Joshua I
That's not the answer you are looking for. You are looking for a way to register this with Simple Injector. But for us to help, you will have to show ushow you would have newed those repositories up by hand, if you didn't have Simple Injector. Something like new CheckService(new FilterRepository<CheckType>(whatgoedhere?)). Please show examples of the different repositories that you want to have created. This gives us the knowledge of what you are trying to achieve and it allows us to formulate the correct answer to your question. - Steven
I know what am looking for probably I dont know what you are looking for. I think you are just trying to go in squares.I told you its just a string.I really do not understand what you are looking. You cant expect me to copy paste entire project for you. - Joshua I
The answer of the question is completely dependent on what data you wish to inject. For instance, if the data changes per request, your solution is wrong in the first place, as explained here. If the value changes per closed-type, you will have to register each closed-type individually as you would do with non-generic types. - Steven

1 Answers

4
votes

In case the parameters are fixed to the specific closed-generic types, you should make the registrations as follows:

c.Register<ICheckRepo<Customer>>(() => new CheckRepository<Customer>(constr, "cust_sp"));
c.Register<ICheckRepo<Order>>(() => new CheckRepository<Order>(constr, "order_sp"));
c.Register<ICheckRepo<Product>>(() => new CheckRepository<Product>(constr, "prod_sp"));
// more registrations here

In case your repository mixes dependencies with configuration values, you can also use contextual registration mixed with the registration of the open-generic type:

// Registrations
// One registration for the open generic type
c.Register(typeof(ICheckRepository<>), typeof(CheckRepository<>));

// One registration for the connection string (assuming you only have one)
container.RegisterConditional(typeof(string), CreateStringConstant(constr),
    c => c.Consumer.Target.Name == "connectionString");

// Conditional registrations for each closed ICheckRepository<T>
RegisterStoredProcForCheckRepository<Customer>("cuts_sp");
RegisterStoredProcForCheckRepository<Order>("order_sp");
RegisterStoredProcForCheckRepository<Product>("prod_sp");
// more registrations here

// Helper methods
Registration CreateStringConstant(string value) =>
    Lifestyle.Singleton.CreateRegistration(typeof(string), () => value, container);

void RegisterStoredProcForCheckRepository<TEntity>(string spName) {
    container.RegisterConditional(typeof(string), CreateStringConstant(container, spName),
        c => c.Consumer.Target.Name == "segment"
            && c.Contumer.ImplementationType == typeof(CheckRepository<TEntity>));
}

In case the connection string or stored procedure varies per request, you should change the design, as explained here.