代码之家  ›  专栏  ›  技术社区  ›  GreyCloud

Asp.net核心最干净的返回视图或Json/XML的方法

  •  2
  • GreyCloud  · 技术社区  · 8 年前

    默认情况下 return View(model);

    /api/id.json到 return model; 作为json

    /api/id.xml到 回报模型; 作为xml

    通过使用 [FormatFilter] see here

    [FormatFilter]
    public class ProductsController
    {
        [Route("[controller]/[action]/{id}.{format?}")]
        public Product GetById(int id)
    

    4 回复  |  直到 8 年前
        1
  •  2
  •   GreyCloud    8 年前

    如果要经常使用此模式,为了尽可能保持控制器干净,可以创建一个公开“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);
    

    }

        2
  •  4
  •   Chris Pratt    8 年前

    [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等。

        3
  •  2
  •   Kirk Larkin    8 年前

    你可以通过一个动作来实现这一点。下面是我如何让它工作的一个例子:

    [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(...) ).

        4
  •  0
  •   Zinov    8 年前

    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才能返回视图或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");
            }