skip to Main Content

I have a generic interface IViewModelService.cs

public interface IViewModelService<T> where T : class
{
    public Task<T> Get(); // returns a view model
}

Which is implemented by two different View Model Services that I assume are closed types:

public class HomeViewModelService : IViewModelService<HomeViewModel>
{
    public HomeViewModelService()
    {
        // Dependency injection for Db Context here
    }

    public async Task<HomeViewModel> Get()
    {
        //requires some async _dbContext logic
        return new HomeViewModel(); // for testing purposes
    }
}

and

public class ProfileViewModelService : IViewModelService<ProfileViewModel>
{
    public ProfileViewModelService()
    {
        // Dependency injection for Db Context here
    }

    public async Task<ProfileViewModel> Get()
    {
        //requires some async _dbContext logic
        return new ProfileViewModel(); // for testing purposes
    }
}

Been researching on dependency injection, and I wanted to know how would I be able to implement these services into Startup.cs. I tried these:

services.AddTransient(typeof(IViewModelService<>), typeof(HomeViewModelService)); 

// ERROR: Open generic service type 'IViewModelService`1[T]' requires registering an open generic implementation type. (Parameter 'descriptors')'
services.AddTransient(typeof(IViewModelService<HomeViewModelService>), typeof(HomeViewModelService)); 

// ERROR: Implementation type 'HomeViewModelService' can't be converted to service type 'IViewModelService`1[HomeViewModelService]'

services.AddScoped<IViewModelService<HomeViewModelService>, HomeViewModelService>(); 

// ERROR: This type cannot be used as a type parameter 'TImplementation' in the generic type or method. 
// There is no implicit reference conversion from HomeViewModelService to IViewModelService<HomeViewModelService>

2

Answers


  1. Try

     services.AddScoped<IViewModelService<HomeViewModel>, HomeViewModelService>();
    

    Read this answer to know more

    Login or Signup to reply.
  2. I tried as below to accomplish dependency injection for open type generic interface.if you don’t want to implement the intereface and regist the services too much times ,you could try this

    public class HomeViewModel
        {
            public HomeViewModel()
            {
                id = 1;
                name = "name1";
            }
            public int id { get; set; }
            public string name { get; set; }
        }
        public class AnotherViewModel
        {
            public AnotherViewModel()
            {
                id = 2;
                name = "name2";
            }
            public int id { get; set; }
            public string name { get; set; }
        }
    

    Modified the codes of service class:

    public interface IViewModelService<T> where T : class
        {
            public T Get(); 
        }
        public class ViewModelService<T> : IViewModelService<T> where T : class
        {
            public ViewModelService()
            {
                
            }
    
            public  T Get()
            {
                Type t = typeof(T);
                if(t==typeof(HomeViewModel))
                {
                    HomeViewModel homeviewmodel = new HomeViewModel();
                    return (T)(object)homeviewmodel;
                }
                else if (t == typeof(AnotherViewModel))
                {
                    AnotherViewModel anotherviewmodel = new AnotherViewModel();
                    return (T)(object)anotherviewmodel;
                }           
                return default(T);
                
            }
        }
    

    regist it in startup:

    services.AddTransient(typeof(IViewModelService<>), typeof(ViewModelService<>));
    

    in controller:

    public IActionResult Test1([FromServices] IViewModelService<HomeViewModel> viewModelService)
            {
                var homeviewmodel = viewModelService.Get();
                return Ok();
            }
            public IActionResult Test2([FromServices] IViewModelService<AnotherViewModel> viewModelService)
            {
                var anotherviewmodel = viewModelService.Get();
                return Ok();
            }
    

    Test Result:
    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search