【问题标题】:Dynamically return fields from a web method从 Web 方法动态返回字段
【发布时间】:2018-07-19 02:18:30
【问题描述】:

我有一个 WebAPI 服务,我希望允许用户指定他们希望返回的字段。例如,假设我有以下Person 类:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
}

调用/api/people/ 会为所有人返回所有三个字段。如何处理像/api/people?fields=FirstName,Email 这样的请求,只为所有人返回这两个字段?如果我可以将first_name 之类的内容映射到FirstName,则可以加分,但这不是必需的。

【问题讨论】:

  • 相信你在找OData
  • @CamiloTerevinto 纠正我如果我错了,但我认为 OData 处于 alpha 阶段对吗?
  • @EdwardChopuryan 可能是,还没有真正将它用于 ASP.NET Core
  • 看起来 OData 具有通过 $select 属性提供的功能,但核心支持充其量是参差不齐。
  • @PhillipCopley 是的,它处于 alpha 阶段。如果它困扰你,你必须编写自己的控制器。应该没那么难。

标签: c# json asp.net-core .net-core


【解决方案1】:

这是Dynamic Language Runtime 尤其是ExpandoObject 的工作,据此您只返回在运行时确定的所需属性

public dynamic GetPerson()
{
    bool firstNameRequired = true; // TODO: Parse querystring
    bool lastNameRequired = false; // TODO: Parse querystring

    dynamic rtn = new ExpandoObject();

    if (firstNameRequired)
        rtn.first_name = "Steve";

    if (lastNameRequired)
        rtn.last_name = "Jobs";

    // ... and so on

    return rtn;
}

void Main()
{
    // Using the serializer of your choice:
    Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(GetPerson()));
}

输出:

{"first_name":"史蒂夫"}

我现在没有办法对其进行测试 [我在 vanilla Web API 上的生产中有类似的东西,具有大量可选字段],但是通过 .NET Core 文档,Web 方法看起来会有所不同像这样,尽管没有硬编码值!:

[HttpGet()]
public IActionResult Get([FromQuery(Name = "fields")] string fields)
{
    var fieldsOptions = fields.Split(',');

    dynamic rtn = new ExpandoObject();

    if (fieldsOptions.Contains("FirstName"))
        rtn.first_name = "Steve";

    if (fieldsOptions.Contains("LastName"))
        rtn.last_name = "Jobs";

    if (fieldsOptions.Contains("Email"))
        rtn.email = "steve@apple.com";

    return new ObjectResult(rtn);
}

您需要引用System.Dynamic.Runtime 包。

【讨论】:

    【解决方案2】:

    您可以使用conditional serialization。您将只根据 fields 参数是否包含标识该字段的字符串来确定您的 ShouldSerialize 返回值。这适用于您想与该字段关联的任何字符串。如果您愿意,您甚至可以为每个字段接受多个字符串。

    要将 fieldList 放入您想要序列化的对象(Person)中,您可以将它或包含它的东西(HttpRequest.Query 或一些自定义选项类)传递给构造函数。

    public bool ShouldSerializeFirstName(){  
        return fieldList.Contains("FirstName");            
    }
    

    【讨论】:

    • 这不是将您与 NewtonSoft 的 json 序列化程序紧密结合吗?您将如何从查询字符串中注入字段列表?
    • 但是,如果您希望它与自定义序列化程序一起使用,它必须支持与 Json.NET 一致的条件序列化。
    • 这是一个简洁的概念,我将鼠标悬停在 +1 按钮上,但您似乎没有回答 @Mardoxx 的问题“您将如何从请求参数?”。看起来ShouldSerializeFirstName 需要在Person 类中定义,因此您必须使用静态HttpContext.Current 属性才能获取请求详细信息。我不确定我是否喜欢在我的域对象中拥有这种依赖关系,除非它们严格只面向 Web。至少,如果我的评估是正确的,如果 HttpContext.Current 为 null,您应该返回 true
    • 我在任何地方都没有看到他说 Person 是域对象。而且我认为如何将 WebApi DTO 与域对象分离超出了这个问题的范围。如果他确实有这种需求,那么在应用层 PersonDTO 中创建一个带有序列化成员的包装器将是一个简单的解决方案。包装器可以只传递来自 Person 对象 get{return base.FirstName;} 等的公共数据
    • @StephenKennedy 我已经在编辑中解决了您的一些问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多