dotnet核心web API JSON响应包含不必要的元素

i7uaboj4  于 2023-06-25  发布在  其他
关注(0)|答案(4)|浏览(96)

我很懒地将我的表数据加载到JSON结果中,然后将它们发送到前端应用程序。但是当我得到这些数据时,我注意到有不必要的元素,在响应中存在空元素。正因为如此,我的PUT或update操作不适用于这些内部JSON属性。

{
           "image":null,
           "paragraph":null,
           "question":{
              "grid":null,
              "elements":[

              ],
              "offeredAnswers":[

              ],
              "lazyLoader":{

              },
              "id":"1",
              "text":"How can we serve you better?",
              "type":"textarea",
              "questionRequired":false,
              "pageFlowModifier":false,
              "gridId":null,
              "min":null,
              "max":null
           },
           "lazyLoader":{

           }
   }

如果我改变text的值,它不会得到更新,但如果我改变paragraph,那么它将在数据库中被改变。
这里有一个新的属性lazyLoader,我也需要去掉它。和elementsofferedAnswers实际上不需要,因为它们是空的。我通过在引用的类中添加virtual关键字来实现延迟加载。

public partial class Questions
{
    public Questions()
    {
        Elements = new HashSet<Elements>();
        OfferedAnswers = new HashSet<OfferedAnswers>();
    }

    public string Id { get; set; }
    public string Text { get; set; }
    public string Type { get; set; }
    public bool QuestionRequired { get; set; }
    public bool PageFlowModifier { get; set; }
    public int? GridId { get; set; }
    public long? Min { get; set; }
    public long? Max { get; set; }

    public virtual Grids Grid { get; set; }
    public virtual ICollection<Elements> Elements { get; set; }
    public virtual ICollection<OfferedAnswers> OfferedAnswers { get; set; }
}

我在Startup.cs文件中有这一行来停止引用循环处理,因为没有这一行,POST操作就不起作用,因为我发布的JSON对象非常复杂,里面有引用循环。

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
                .AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

我已经启用了延迟加载代理。

services.AddDbContext<RDS_Context>
            (options => options.UseLazyLoadingProxies().UseSqlServer(connection));
utugiqy6

utugiqy61#

您可以将数据库实体模型与希望在前端显示的模型分开。将需要并希望包含到新前端模型中的实体模型的特性Map。
不实现新模型的更快方法是使用匿名对象,如:

myDbContext.MyObjects.Select(x => new { Prop1 = x.Property1, Prop2 = x.Property2 });

如果你的实体类中真的有LazyLoader属性(例如注入ILazyLoader,如本文所述),您可以改为使用JsonIgnore attribtue来装饰它。

aydmsdu9

aydmsdu92#

您可以通过迭代JObjectJProperty来从json中删除空的ObjectArray,如下所示

class Program
{
    static void Main(string[] args)
    {
        string json = File.ReadAllText(@"C:\Users\xxx\source\repos\ConsoleApp4\ConsoleApp4\Files\json6.json");

        JObject data = JObject.Parse(json);

        //Getting all those children that have value are empty from outer json
        var result1 = data.Children<JProperty>()
             .Where(x => (x.Value.Type == JTokenType.Object) && !x.Value.HasValues)
            .ToList();

        //Getting all those children that have value are empty from "question" object
        var result2 = data["question"].Children<JProperty>()
            .Where(x => (x.Value.Type == JTokenType.Object && !x.Value.HasValues) || (x.Value.Type == JTokenType.Array && !x.Value.HasValues))
            .ToList();

        //Remove all above empty object or arrays
        result1.ForEach(x => x.Remove());
        result2.ForEach(x => x.Remove());

        var obj = data.ToObject<JObject>();

        Console.WriteLine(obj);

        Console.ReadLine();
    }
}
    • 输出:**

    • 注意:**如果你想在整个json中只删除空的lazyLoader对象,那么在上面的代码中使用下面的行。
//Getting "lazyLoader" children that have value are empty from outer json
var result1 = data.Children<JProperty>()
     .Where(x => x.Value.Type == JTokenType.Object && !x.Value.HasValues && x.Name == "lazyLoader")
     .ToList();

//Getting "lazyLoader" children that have value are empty from "question" object
var result2 = data["question"].Children<JProperty>()
     .Where(x => (x.Value.Type == JTokenType.Object && !x.Value.HasValues && x.Name == "lazyLoader"))
     .ToList();
    • 输出:**

amrnrhlw

amrnrhlw3#

在Entity Framework中,如果有一个对象的一个或多个属性使用延迟加载,请使用GetType(). Name检查其运行时类型名称。例如,对于Car类的对象,您会注意到运行时类型实际上是名为CarProxy的东西,它是Entity Framework使用反射创建的临时内存类型。这个“假”代理类的基类是Car,并且具有所有原始的Car属性,但包括一个额外的名为 LazyLoader 的属性,用于可能需要它的属性。
如果你进一步检查这个“fake”CarProxy类型,你还会看到Assembly.IsDynamic = true,这表明这个类是用反射动态创建的(参见documentation):

var TheCar = DBContext.Cars.Find(1);
Console.WriteLine(TheCar.GetType().Assembly.IsDynamic.ToString()); //will echo "true"

幸运的是,Newtonsoft.json在**JsonConvert.SerializeObject()**方法上有一个覆盖,它允许我们提供一个基类型,这样得到的JSON就不会包含该类型中不存在的属性。因此,要消除 LazyLoader 属性,只需提供对象的BaseType作为类型参数:

var TheCar = DBContext.Cars.Find(1);
var TheJSON = Newtonsoft.Json.JsonConvert.SerializeObject(TheCar, TheCar.GetType().BaseType);

为了确保序列化时不会得到任何循环引用循环(使用延迟加载时可能性很高),请使用以下设置调用序列化器:

var TheCar = DBContext.Cars.Find(1);
var Settings = new Newtonsoft.Json.JsonSerializerSettings
{
    ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};
var TheJSON = Newtonsoft.Json.JsonConvert.SerializeObject(TheCar, TheCar.GetType().BaseType, Settings);

**注意:当序列化器遍历对象时,这可能只在第一层深度上工作。如果您提供给序列化程序的对象还有更多的延迟加载子属性,则可能会再次出现“LazyLoader”属性。我还没有测试过,所以我不能确定。

ql3eal8s

ql3eal8s4#

基于a suggestion at EFCore reposanother SO answer it referenced,我将把这种替代方法留给那些只想摆脱lazyLoader属性的人
创建CustomContractResolver.cs

public class CustomContractResolver : DefaultContractResolver
{
    public static CustomContractResolver Instance { get; } = new CustomContractResolver();

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        if (member.Name == "LazyLoader")
        {
            property.Ignored = true;
        }
        return property;
    }

}

并修改Startup.csConfigureServices方法以使用ContractResolver

services
    .AddMvc(...)
    .AddJsonOptions(options => {
        options.SerializerSettings.ContractResolver = CustomContractResolver.Instance;
    });

相关问题