First of all, this is not exactly a duplication of the dozens of other posts and I have tried all of them and none of them work.
I have a model that contains many more values than my web api consumers need.
public class Publication
{
[Key]
public int PublicationID { get; set; }
public string PublicationTitle { get; set; }
public string Frequency { get; set; }
public DateTime NextIssueDate { get; set; }
public DateTime SpaceDeadline { get; set; }
public DateTime MaterialsDeadline { get; set; }
public DateTime CreatedDt { get; set; }
public string CreatedBy { get; set; }
public DateTime UpdatedDt { get; set; }
public string UpdatedBy { get; set; }
}
I only want say a few of the fields to be passed in the API. I've tried this code but instead of leaving out say UpdateBy in the Json result, it returns it with a null value. How do I get rid of that? I've tried several dozen variations but they either fail to compile or fail to return results.
public IQueryable<Publication> GetPublications()
{
return db.Publications
.ToList()
.Select(p => new Publication {
PublicationID = p.PublicationID,
PublicationTitle = p.PublicationTitle,
Frequency = p.Frequency,
NextIssueDate = p.NextIssueDate
})
.AsQueryable();
}
答案 0 :(得分:10)
不要序列化您的DAO。创建一个完整的合同,然后有选择地序列化它。要为不同的案例创建不同的合同,您可以使用Json.Net简化它;你可以创建一个自定义合约解析器,并将其用作SerializeObject()的参数,如此
static void Main(string[] args)
{
var person = new TestContract {FirstName = "John", LastName = "Doe", Age = 36};
var firstNameContract = new SelectiveSerializer("firstname");
var allPropertiesContract = new SelectiveSerializer("firstname, lastname, age");
var allJson = JsonConvert.SerializeObject(
person,
Formatting.Indented,
new JsonSerializerSettings {ContractResolver = allPropertiesContract});
var firstNameJson = JsonConvert.SerializeObject(
person,
Formatting.Indented,
new JsonSerializerSettings {ContractResolver = firstNameContract});
Console.WriteLine(allJson);
// {
// "FirstName": "John",
// "LastName": "Doe",
// "Age": 36
// }
Console.WriteLine(firstNameJson);
// {
// "FirstName": "John",
// }
}
public class SelectiveSerializer : DefaultContractResolver
{
private readonly string[] _fields;
public SelectiveSerializer(string fields)
{
var fieldColl = fields.Split(',');
_fields = fieldColl
.Select(f => f.ToLower().Trim())
.ToArray();
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = o => _fields.Contains(member.Name.ToLower());
return property;
}
}
public class TestContract
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
如果没有太多努力,您可以将其用于默认的mediatype格式化程序(在管道中)以在请求中查找名为“fields”或其他的参数,然后使用自定义合约解析程序(如果存在),然后它将是无缝默认行为,如果指定则限制字段,如果未指定则序列化整个对象。
在学术方面,这是正当理由: 对数据的任何修改都被视为“视图关注点”,这意味着在API中,它应该由查询参数控制并接受标题。在这种情况下,数据的“表示”是application / json,您选择“过滤”返回的字段。所有这些都可以(并且应该是,imo)在序列化期间处理。因此,在这种情况下,您的“模型”将始终是完整模型与模型的某个子集。此示例中的完整模型包含名字,姓氏和年龄。实际上,这可能是数百个属性。如果您希望允许客户端选择完整模型的子集,那么您可以通过选择性序列化来实现这一目标。
您可以在图表api中使用类似的行为。在那里,大型模型的默认设置是,如果您没有指定字段,则会获得一个空对象,迫使客户端对其要求的内容非常具体,这在有效负载大小很重要时很有用(例如移动应用程序)。并且,没有什么能阻止创建像'name'这样的字段预设,这可能意味着'firstname,lastname'或'all'包含所有属性。
我从来不喜欢拥有数百个数据对象,这些数据对象都是为在20个不同的上下文中使用的数据集提供一些临时要求,其中某些情况需要更多数据而其他情况需要更少数据。 IMO如果您必须通过相同的过程来获取数据,无论是否完成,您都不应该浪费时间创建额外的对象来为客户端构建数据框架,这应该可以帮助您实现这一目标。
答案 1 :(得分:7)
这是因为您正在返回Publication
个对象的集合,因此您将获得该类中包含的每个属性,无论您是否填充它。如果要返回属性的子集,则创建一个只包含要返回的属性的类,并在查询中创建该类的实例。
public IQueryable<WhatIReallyWantToReturn> GetPublications()
{
return db.Publications
.ToList()
.Select(p => new WhatIReallyWantToReturn {
PublicationID = p.PublicationID,
PublicationTitle = p.PublicationTitle,
Frequency = p.Frequency,
NextIssueDate = p.NextIssueDate
})
.AsQueryable();
}
private class WhatIReallyWantToReturn
{
public int PublicationID { get; set; }
public string PublicationTitle { get; set; }
public string Frequency { get; set; }
public DateTime NextIssueDate { get; set; }
}
答案 2 :(得分:1)
正如Craig W.所说你可以使用viewmodel,你也可以使用匿名类型 (注意viewmodel是更好的方法,因为你可以使用像automapper这样的实用程序来自动映射你的属性)
答案 3 :(得分:1)
JsonIgnore注释对我有用
[JsonIgnore]
public int Ranking { get; set; }
答案 4 :(得分:0)
import tkinter as tk
from PIL import ImageTk, Image
global counter
counter = 0
def load_next_img(counter):
#global counter
# rest of your code
counter += 1
global tk_image
image_data_base64_encoded_string = df_time_text_frames["Frame_(base_64)"][counter]
image = tk.PhotoImage(image_data_base64_encoded_string)
tk.Label(root, image=im).pack()
counter += 1
root = tk.Tk()
nextbutton = tk.Button(text="next",
command=lambda counter: load_next_image(counter))
nextbutton.pack()
root.mainloop()
答案 5 :(得分:0)
Here是一篇很棒的文章(2019年12月)。它通过使用ExpandoObject和Type Reflection提供了一种数据整形解决方案。然后,客户端所需的属性可以作为查询参数(即用逗号分隔)传递给请求。本文还提供了JSON序列化问题的解决方案。
Startup.cs文件:
services.AddControllers(config =>
{
config.RespectBrowserAcceptHeader = true;
config.ReturnHttpNotAcceptable = true;
})
.AddXmlDataContractSerializerFormatters()
.AddNewtonsoftJson();