В ядре asp.net я хотел бы настроить свой контроллер API, чтобы сделать следующее:
по умолчанию return View(model);
/api/id.json return model;
как json
/api/id.xml return model;
как xml
Второе два может быть достигнуто с помощью [FormatFilter]
см. Здесь
[FormatFilter]
public class ProductsController
{
[Route("[controller]/[action]/{id}.{format?}")]
public Product GetById(int id)
Однако для этого требуется, чтобы метод возвращал объект, а не объект View (объект). Есть ли все-таки, чтобы чисто поддерживать и возвращать Views?
Если вы собираетесь использовать этот шаблон много, чтобы ваши контроллеры были максимально чистыми, вы могли бы создать базовый класс, который раскрыл бы метод "FormatOrView":
[FormatFilter]
public abstract class FormatController : Controller
{
protected ActionResult FormatOrView(object model)
{
var filter = HttpContext.RequestServices.GetRequiredService<FormatFilter>();
if (filter.GetFormat(ControllerContext) == null)
{
return View(model);
}
else
{
return new ObjectResult(model);
}
}
}
И тогда ваш контроллер может наследовать от этого и использовать метод FormatOrView
public class ProductsController : FormatController
{
[Route("[controller]/[action]/{id}.{format?}")]
public ActionResult GetById(int id)
{
var product = new { Id = id };
return FormatOrView(product);
}
}
Отредактируйте список окончательного принятого ответа GreyCloud: Вот общий упрощенный метод, который вы можете поместить в контроллер (или сделать метод расширения или поместить в абстрактный базовый класс, как указано выше). Обратите внимание?. в случае, если услуга по какой-либо причине не определена.
private ActionResult<T> FormatOrView<T>(T model) {
return HttpContext.RequestServices.GetRequiredService<FormatFilter>()?.GetFormat(ControllerContext) == null
? View(model)
: new ActionResult<T>(model);
}
Вы не можете выполнять оба действия в одном и том же действии. Однако вы можете разделить общую функциональность на частный метод, а затем реализовать два действия с минимальным дублированием кода:
[Route("[controller]")]
[FormatFilter]
public class ProductsController : Controller
{
private Product GetByIdCore(int id)
{
// common code here, return product
}
[HttpGet("[action]/{id}")]
[ActionName("GetById")]
public IActionResult GetByIdView(int id) => View(GetByIdCore(id));
[HttpGet("[action]/{id}.{format}")]
public Product GetById(int id) => GetByIdCore(id);
}
Здесь необходимо использовать разные имена действий, потому что подписи метода не могут отличаться только от типа возврата. Тем не менее, [ActionName]
может использоваться как указано выше, чтобы заставить их отображаться одинаковое имя для целей генерации URL и т.д.
Вы можете добиться этого только одним действием. Вот пример того, как я получил его для работы:
[FormatFilter]
public class ProductsController : Controller
{
[Route("[controller]/[action]/{id}.{format?}")]
public IActionResult GetById(int id, string format)
{
var yourModel = ...;
if (string.IsNullOrWhiteSpace(format))
return View(yourModel);
return Ok(yourModel);
}
Используя IActionResult
в качестве возвращаемого типа, вы можете вернуть либо ViewResult
либо OkObjectResult
. Вы можете получить доступ к значению format
, взяв его в качестве параметра в своем действии, проверить, пуст ли он, а затем реагировать соответствующим образом.
Я также добавил Controller
в качестве базового класса, чтобы получить доступ к методам удобства для создания соответствующих результатов (View(...)
и Ok(...)
).
FormatFilter является частью согласования содержимого вашего приложения, в AspNetCore у вас есть элемент управления для обработки ваших входных или выходных форматов также в ConfigureServices, где у вас больше контроля, даже если вы можете добавить больше типов медиа там
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options .OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
options .InputFormatters.Add(new XmlDataContractSerializerInputFormatter(options ));
//more output formatters
var jsonOutputFormatter = options.OutputFormatters.OfType<JsonOutputFormatter>().FirstOrDefault();
if (jsonOutputFormatter != null)
{
jsonOutputFormatter.SupportedMediaTypes.Add("application/vnd.myvendormediatype");
}
}
}
Но вернувшись к обсуждению контента в контроллерах, вы можете сохранить только один. Единственное, что вам нужно знать mediaType, чтобы вернуть ваш View или ваш json-контент. Только обязательно передайте заголовок accept с типом контента, который вы хотите. С типом контента, который вы определяете для api или для приложения mvc, которое представляет собой содержимое/формат, который должен ожидать клиент
[HttpGet("[action]/{id}")]
public IActionResult public Product GetById(int id, [FromHeader(Name = "Accept")] string mediaType)
{
if (mediaType == "application/vnd.myvendormediatype")
{
var data = GetYourData(...)
return Json(data);
}
else return View("YourDefaultView");
}