0

We are wrapping a Viewmodel inside a ApiRequestModel and pass it as a parameter to the DoAuditModel web Api method.DoAuditModel calls the DoAudit generic method. Since there are multiple Viewmodels we had to create a ApiRequestModel for each Viewmodel type. But we don't want to create a Api method/endpoint for each model. We want to create a single Api method that can do this DoAuditModel task.

Below is our simplified model structure for API Method call. It has some common data like Token AppCode and a Model (ViewModel). These models (ModelA,ModelB etc) don't have a base class or implements an interface.

// Api Request Base
public class ApiRequest : IApiRequest
{
    public string Token { get; set; }
    public string AppCode { get; set; }
    ...
}

// Api Request For ModelA 
public class ApiRequestForModelA : ApiRequest
{
    public ModelA MyModel { get; set; }
    ...
}

// Api Request For ModelB
public class ApiRequestForModelB : ApiRequest
{
    public ModelB MyModel { get; set; }
    ...
}

API Controller has multiple methods for each model type that calls a generic method.

public class MyAuditController : ApiController
{
   [HttpPost]
   public Task DoAuditModelA(ApiRequestForModelA modelReq)
   {
      // Generic Method
      DoAudit<ApiRequestForModelA>(modelReq.MyModel);
    
      ...
   }

  [HttpPost]
  public Task DoAuditModelB(ApiRequestForModelB modelReq)
  {
     // Generic Method
     DoAudit<ApiRequestForModelB>(modelReq.MyModel);    
    
     ...
  }
    
}

I want to avoid this web method duplication (DoAuditModelA) and creating ApiRequest models (ApiRequestForModelA) for each model type since all I want is to call that generic DoAudit<T>(T model){...} I want to create a single Api method as AuditModel. So I created a generic Api Request as below.

// Generic API Request
public class ApiRequest<T> : ApiRequest
{
   public ApiRequest(T model)
   {
      this.MyModel = model;
   }

   public T MyModel { get; set; }
   ...

}

Now the problem is that Web Api method doesn't know the model type and how to bind/deserialize data. I ended up using ApiRequest<dynamic>. Below is my new Api Method.

[HttpPost]
public Task DoAuditModel(ApiRequest<dynamic> modelReq)
{       
   var myModelObj = modelReq.GetType().GetProperty("MyModel").GetValue(modelReq);

   // Get model Type
   var typeData = auditReq.ModelAssemblyQualifiedName;     
   Type t = Type.GetType(typeData);
   // how to use this t to create model instance or convert/deserialize data 
   
   var myModel = //myModelObj should cast to the original model type.(I'm stuck here)

   DoAudit(myModel);
   ...
}

// DoAudit Generic method
private void DoAudit<T>(T myModel)
{
   ...
}

So this is my approach to pass these ViewModels to DoAudit generic method in the web api and avoid multiple web api endpoints. I'm also concern about what type of overhead that Api will have to handle is this approach. Generic controller will not work for me here.

Summery

I want to create a single API Endpint for DoAuditModel task which calls DoAudit generic method

MKEF
  • 163
  • 2
  • 12
  • 1
    This can help you https://stackoverflow.com/a/59980395 – Vivek Nuna Feb 13 '21 at 07:25
  • Thanks. It seems using dynamic is my best option mentioned in there. Unfortunately I'm stuck at the same point where trying to figure out how to use this 't' Type and proceed with "object data = create an instance of t base on the model values;" mentioned in the solution – MKEF Feb 13 '21 at 09:38
  • Does `ApiRequestForModelA` have any extra fields? Why not just `ApiModel : ApiRequest { T model ... }`? – Jeremy Lakeman Feb 15 '21 at 04:57
  • Also, in dotnet core you could replace `IApplicationFeatureProvider` https://www.strathweb.com/2018/04/generic-and-dynamically-generated-controllers-in-asp-net-core-mvc/ – Jeremy Lakeman Feb 15 '21 at 05:03
  • Actually there are more fields in ApiRequestForModelA. public class ApiRequestForModelA : ApiRequest { public ModelA MyNewModel { get; set; } public ModelA MyPreviousModel { get; set; } } Solution is on .NET 4.5 not .NET Core – MKEF Feb 15 '21 at 05:11

0 Answers0