Web API Generic Action

Controller having a generic action method

With default implementations of the framework, No, you cannot have such action:

public IHttpActionResult InsertData([FromBody] T model)

This is the exception which you receive:

Cannot call action method 'XXXX' on controller 'XXXX' because the action method is a generic method.

But the framework is very extensible and if you get a very good understanding of Routing and Action Selection in ASP.NET Web API and learn how routing, controller selection, action selection, parameter binding and action invocation work, then you can implement some customization for the framework to support generic action method selection and invocation.

In your custom logic, to be able to execute the action in run-time, you need to resolve T at run-time. To do so, you can rely on attributes to limit it to some known types or you can rely on some context information like route data, header values, some special values like $type in body an so on.

Providing a custom implementation to handle generic action method is too broad for this post. That said, let me share other solutions.

Derive from a generic base controller

You can have a base generic controller then having two non-generic controllers derived from the base controller and handle the request by a single method which is implemented in the base controller. I assume you have seen this post which has already suggested the same solution:

public class MyBaseController<T> : ApiController
{
    public IHttpActionResult InsertData([FromBody] T model)
    {
        //Write the generic code here, for example:
        dbContext.Set<T>().Add(model);
        dbContext.SaveChanges();
        return some value;            
    }
}

Then:

public class ProductController : MyBaseController<Product> { }
public class CustomerController : MyBaseController<Customer> { }

Rely on dynamic and resolve the type later based on context information

Another option is having the following action method:

public IHttpActionResult InsertData([FromBody] dynamic model)

Then based on some context information like route values, header values, some special values like $type in body an so on, you can resolve model type and call your private generic method:

public IHttpActionResult InsertData([FromBody] dynamic model)
{
    Type t = resolve type base on context information
    object data = create an instance of t base on the model values;

    var method = this.GetType().GetMethod(nameof(InsertDataPrivate),
        BindingFlags.NonPublic | BindingFlags.Instance);
    var result = (int)method.MakeGenericMethod(t)
       .Invoke(this, new object[] { data });

    return Ok(result);
}
private int InsertDataPrivate<T>(T model) where T
{
    //Write the generic code here, for example:
    dbContext.Set<T>().Add(model);
    dbContext.SaveChanges();
    return some value;
}