I have a http Action that will needs to take in two different object model. The Implementation looks at the two model object and know what to do at that point. Can I use a generic object?
[HttpPost]
public IHttpActionResult InsertData(string accessKey, [FromBody] T content)
{
try
{
MobileAppService ms = new MobileAppService();
ResultStatus resultStatus = ms.ProcessAppLogging(t);
return Ok(resultStatus.ResultCode);
}
catch (Exception e)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(e);
}
}
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With