user1647160
user1647160

Reputation: 531

using generics with web api controllers

I have a controller that has 3 methods with the same method body. The only difference is the method type. I have a generic type interface that I'm injecting into the controller. I'm injecting the interface because I'm using an IoC (StructureMap).

The problem is that the return type of the controller methods doesn't match the generic type of the method in my interface. (GetStatistics1 and GetStatistics2)

For demonstration purposes, I changed the 3rd method (GetStatistics3). I have casted the return type from IEnumerable<T> to IEnumerable<Type3>. The code compiles, but I'm not sure if that is the most efficient or eloquent solution.

The code is below:

Interface:

public interface IStatistics<T>
{
    IEnumerable<T> ExecStatistics_SP(DateTime ? date,
    int ? xd, string iap, int? statisticsType );
}

Controller:

public class StatisticsController : ApiController
{
    private readonly IStatistics<T> _repo;

    public StatisticsController(IStatistics<T> repo)
    {
        _repo = repo;
    }

    public IEnumerable<Type1> GetStatistics1(string iap, DateTime date, int? statisticsType, int xd)
    {
        return _repo.ExecStatistics_SP(date,xd,iap,statisticsType).AsEnumerable();
    }

    public IEnumerable<Type2> GetStatistics2(string aip, DateTime date, int? statisticsType, int xd)
    {
       return = _repo.ExecStatistics_SP(date, xd, iap, statisticsType).AsEnumerable();
    }

    public IEnumerable<Type3> GetStatistics3(string iap, DateTime date, int? statisticsType, int xd)
    {
        returnValue = _repo.ExecStatistics_SP(date,xd,iap,statisticsType).AsEnumerable();
        return (IEnumerable<Type3>) returnValue;
    }
}

Upvotes: 1

Views: 1637

Answers (1)

Scott
Scott

Reputation: 5369

TL;DR I doubt this is possible in Web API; you're probably best off creating separate controllers for different classes.

The problem with the code itself lies in the class definition. StatisticsController doesn't know what T is, meaning the compiler cannot check that ExecStatistics_SP returns a compatible type.

Furthermore, since IStatistics<T> is injected into the class, there is no way to differentiate between what T is within each method unless you reflect over T each call.

Another way to approach this is to let the language handle everything and simplify your class in the process. With this solution, the caller of StatisticsController knows what T is, in your example it is either Type1, Type2, or Type3. In reality, T can be any class implementing IStatistics<T>.

public class StatisticsController<T>
{
    private readonly IStatistics<T> _repo;

    public StatisticsController(IStatistics<T> repo)
    {
        _repo = repo;
    }

    public IEnumerable<T> GetStatistics(string iap, DateTime date, int? statisticsType, int xd)
    {
        return _repo.ExecStatistics_SP(date, xd, iap, statisticsType);
    }
}

I'm not sure how your DI framework handles this in the context of Web API, but whoever calls GetStatistics must have already instantiated StatisticsController with a type implementing IStatistics<T>. Usage in your own code would look like the following:

var repo = new StatisticsRepo<Type1>();  // Made-up repo class
var controller = new StatisticsController<Type1>(repo);
IEnumerable<Type1> values = controller.GetStatistics(...);
// etc

Upvotes: 1

Related Questions