【问题标题】:Dynamically select attributes to serialize in JSON response in asp.net core在 asp.net 核心中动态选择要在 JSON 响应中序列化的属性
【发布时间】:2018-11-13 21:47:43
【问题描述】:

我有一个这样的控制器:

using Microsoft.AspNetCore.Mvc;

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

[Route("api/[controller]")]
public class ValuesController : Controller {
    [HttpGet]
    public IActionResult Get() {
        return new OkObjectResult(new[] {
            new Person { FirstName = "John", LastName = "Doe" }
        });
    }
}

我希望能够从 asp.net 核心 REST API 的响应中指定我想要的属性。
例如,GETapi/values 应该返回一个包含所有属性的对象:

{
  "FirstName":"John",
  "LastName":"Doe"
}

虽然,GETapi/values?fields=FirstName 应该只返回 FirstName 属性:

{
  "FirstName":"John"
}

我尝试在我的 Startup 类中指定一个 ContractResolver,如下所示:

class QueryStringResolver : DefaultContractResolver {
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) {
        HttpContextAccessor httpContextAccessor = new HttpContextAccessor();
        string fieldsQuery = httpContextAccessor.HttpContext.Request.Query["fields"];
        if (!string.IsNullOrEmpty(fieldsQuery)) {
            var fields = from f in fieldsQuery.Split(",", StringSplitOptions.RemoveEmptyEntries) select f.Trim().ToLowerInvariant();
            return base.CreateProperties(type, memberSerialization).Where(p => fields.Contains(p.PropertyName.ToLowerInvariant())).ToList();
        } else {
            return base.CreateProperties(type, memberSerialization);
        }
    }
}

public class Startup {
    public void ConfigureServices(IServiceCollection services) {
        services
            .AddMvc()
            .AddJsonOptions(options => {
                options.SerializerSettings.ContractResolver = new QueryStringResolver();
            });
    }
    // rest of Startup class omitted...
}

问题在于CreateProperties 方法仅在第一个请求时调用,而不是针对每个请求。

有没有办法指定在每个请求中应该序列化哪些属性?

请注意,我不想更改 Get 方法的实现或返回的类定义,我只想对序列化进行操作,以便可以重复使用相同的查询几种方法中的字符串参数。

【问题讨论】:

  • 条件属性序列化意味着为我的每个对象的每个属性添加一个 ShouldSerializeXXX 方法。
  • 在这个例子中很好,但我宁愿在真正的 API 中避免这种情况。
  • @PaoloTedesco 你的问题是你在哪里实例化了QueryStringResolver。你在StartUp 上做了它,当你需要它时,根据你想要的结果启动它。你把它放在哪里是有道理的,但你解释的行为表明你利用资源太远了。尝试先在 APIController 上使用QueryStringResolver ,然后一次将其提升一级。

标签: c# asp.net-core


【解决方案1】:

使用您想要的值创建一个通用对象。

var obj = new {
  FirstName = "John"
  , LastName = "Doe"
};

var json = JsonConvert.SerializeObject(obj);

【讨论】:

  • 我真的更喜欢对序列化采取行动。此外,我想指定请求中的字段,并且每个请求的字段可能不同。这是一个编译时解决方案...
  • 然后在你的代码中处理泛型的构造。您知道您的条件情况,您应该在控制器的主体中处理它并根据需要进行抽象。
  • @GoldBIshop,泛型对象仍然不是这里的解决方案,因为我们的类可能有很多字段,并且客户可以指定他想要包含的字段的任何组合,我们可能不得不最终制作多达数千种排列!
  • @SDP190 通用对象仍然是序列化为 JSON 的最灵活的类型。如果您希望拥有更多的具体类型,那么至少使用通用对象对结构进行建模,然后实现具体类型。更重要的是发送者和接收者了解正在传输的信息而不是方法。
  • @GoldBishop - 我想你不理解我。当我创建 REST Api 时,我如何知道客户可能有兴趣获得哪些字段组合(假设它是一个公共 api)?所以我不能为泛型创建所有类型。
猜你喜欢
  • 2017-11-04
  • 2022-11-25
  • 2019-05-12
  • 1970-01-01
  • 1970-01-01
  • 2017-01-30
  • 1970-01-01
  • 2018-09-12
  • 2019-02-21
相关资源
最近更新 更多