Search code examples
c#asp.net-web-apidependency-injectioninversion-of-controlautofac

Child interface of generic interface IoC bindnig in c#


I have base generic interface

public interface ICRUDStore<Model> where Model : class
{
    Task<IEnumerable<Model>> FindAsync();
    Task<Model> FindAsync(int id);
    Task UpdateAsync(int id, Model updatedRecord);
    Task DeleteAsync(int id);
    Task CreateAsync(Model record);
}

and it's child interface

public interface ICourseStore : ICRUDStore<Course>
{
    Task<IEnumerable<Course>> FindByMenuIdAsync(int menuId);
}

where Course is basic model class. I'm implementig this repository with PgCourseStore : PgStore<Course>, ICourseStore where PgStore<Course> is a base class for working with Postgres.

I have abstract base controller class

 public abstract class BaseController<Model, Store> : ApiController
                                        where Model : class
                                        where Store : ICRUDStore<Model>
 protected readonly Store store;

with basic CRUD methods and its child controller with special queries CoursesController : BaseController<Course, ICourseStore> where I need store variable to be ICourseStore to call special queries.

So when i'm trying to bind PgCourseStore with ICourseStore with different IoC containers (like DryIOC, Autofac) everything works fine when FindAsync methods are called from my base controller. But when i'm trying to call Update, Delete or Create methods i'm getting Microsoft.CSharp.RuntimeBinder.RuntimeBinderException whith message that ICourseStore doesn't have definition for CreateAsync method. Yes, I can store store like ICRUDStore type and casting it when I need, but may be there is more beautiful solution?

UPD: BaseController looks like

public abstract class BaseController<Model, Store> : ApiController
      where Model : class
      where Store : ICRUDStore<Model>
{
    protected abstract Model Parse(dynamic model);

    protected readonly Store store;

    public BaseController(ICRUDStore<Model> store)
    {
        this.store = store;
    }

    public virtual async Task<HttpResponseMessage> Get()
    {
        var records = await store.FindAsync();
        return Request.CreateResponse(HttpStatusCode.OK, records);
    }

    public virtual async Task<HttpResponseMessage> Post(dynamic value)
    {
        var model = Parse(value);
        await store.CreateAsync(model);
        return Request.CreateResponse(HttpStatusCode.Created);
    }
}

And CourseController

public class CoursesController : BaseController<Course, ICourseStore>
{
    public CoursesController(ICourseStore store) : base(store) { }
}

So I don't see any meaningfull difference between using of Create* and Find* methods. Both of these methods are defined in my base PgStore<Model> class (not in PgCourseStore) while I'm binding just ICourseStore and PgCourseStore.


Solution

  • It was the dynamic type that caused runtime binding error. Changing to object could help you:

        public virtual async Task<HttpResponseMessage> Post(object value)
        {
            var model = Parse(value);
            await store.CreateAsync(model);
            return Request.CreateResponse(HttpStatusCode.Created);
        }