Web API Generi c Действие - PullRequest
       6

Web API Generi c Действие

5 голосов
/ 24 января 2020

У меня есть http-действие, которое необходимо выполнить в двух разных объектных моделях. Реализация смотрит на два объекта модели и знает, что делать в этот момент. Могу ли я использовать универсальный c объект?

[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);
    }
}

Ответы [ 2 ]

9 голосов
/ 30 января 2020

Контроллер, имеющий общий c метод действия

При реализации по умолчанию платформы, Нет, вы не можете иметь такое действие:

public IHttpActionResult InsertData([FromBody] T model)

Это полученное исключение:

Невозможно вызвать метод действия 'XXXX' на контроллере 'XXXX', поскольку метод действия является обобщенным c методом.

Но Фреймворк очень расширяемый, и если вы получите очень хорошее представление о Выбор маршрутизации и действий в ASP. NET Веб-API и узнаете, как работают маршрутизация, выбор контроллера, выбор действий, привязка параметров и вызов действий затем вы можете реализовать некоторую настройку для платформы для поддержки общего выбора и вызова метода действия c.

В вашем пользовательском логе c, чтобы иметь возможность выполнять действие во время выполнения, вам нужно разрешить T во время выполнения. Для этого вы можете положиться на атрибуты, чтобы ограничить его некоторыми известными типами, или вы можете полагаться на некоторую контекстную информацию, такую ​​как данные маршрута, значения заголовка, некоторые специальные значения, такие как $type в теле и так далее.

Предоставление пользовательской реализации для обработки обобщенного c метода действия слишком широко для этого поста. Тем не менее, позвольте мне поделиться другими решениями.

Извлечь из базового * generic c контроллера

Вы можете иметь базовый контроллер generi c с двумя -generi c контроллеры, полученные из базового контроллера и обрабатывающие запрос одним способом, который реализован в базовом контроллере. Я предполагаю, что вы видели этот пост , который уже предложил то же решение:

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;            
    }
}

Тогда:

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

Положитесь на dynamic и разрешить тип позже на основе контекстной информации

Другой вариант заключается в следующем методе действия:

public IHttpActionResult InsertData([FromBody] dynamic model)

Затем на основе некоторой контекстной информации, такой как значения маршрута, значения заголовка, некоторые специальные значения, такие как $type в теле и т. д., вы можете определить тип модели и вызвать свой собственный метод generi c:

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;
}
0 голосов
/ 30 января 2020

Не связывайтесь со всеми объектами, просто выполните приведение.

Тип контента: приложение / json

[ApiController]
public class AdWordsController : ControllerBase
{
    [HttpPost("/Metrics/")]
    [EnableCors("CorsPolicy")]
    public IActionResult GetMetrics(dynamic data)
    {
        return new JsonResult(Metrics((String)data.customerId, (String)data.from, (String)data.to));
    }
...