65.9K
CodeProject 正在变化。 阅读更多。
Home

Entity Framework 的自定义 JSON 序列化器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (12投票s)

2009 年 4 月 29 日

CPOL

1分钟阅读

viewsIcon

54922

downloadIcon

695

Entity Framework 的自定义 JSON 序列化器

引言

实体框架中的实体(与其他实体存在关系)无法使用 .NET Framework 现有的对象(如 JavascriptSerializer DataContract JSON 序列化器或 JsonResult)进行序列化。因此,我需要自己解决这个问题。

背景

在一个项目中,我们使用 ASP.NET MVC 作为表示/业务逻辑层,并使用实体框架作为数据访问层。当时我遇到了这个问题。我需要通过 XMLHttp 请求从客户端 JavaScript 调用服务器端方法。在客户端,我们使用了 JQuery(JavaScript 库)。服务器端方法需要以 Jason 格式返回数据。最初,我尝试使用 JsonResult(MVC 框架)将数据转换为 JSON 格式,但出现了一个错误消息。错误消息是“循环引用错误”。然后我使用了 JavascriptSerializer 类。但同样的事情发生了。然后我尝试了 DataContract JSON 序列化器。我再次得到了相同的错误。

我不知道该怎么办。我首先开始在 Google 上搜索以解决我的问题。在那里我发现实体框架的实体序列化在使用 .NET Framework 提供的现有 JSON 序列化器时存在一些问题。因此,我开始考虑编写自己的小型序列化器来解决并将实体框架与 JSON 一起使用。

解决方案

public class CustomJSonSerializer
{

public static string JsonSerialize<T>(T obj) where T : class
{
    var sb = new StringBuilder("{");

    var parentType = obj.GetType(); // I get type from given object 

    // use reflection to retrieve all properties of that type
    var ms = parentType.GetMembers().Where(v => v.MemberType 
        == MemberTypes.Property).ToList<MemberInfo>();

    const string doubleQuote = "\"";
    var counter = 0;
    var stringTypes = new List<String> { "String", "Guid", 
        "Boolean" };

    //Following Types are used by Entity Framework. So no need to 
    //serialize those types.
    var ignoreEntityTypes = new List<String> { "EntityReference`1", 
        "EntityCollection`1", "EntityState", 
        "EntityKey", "EntitySetName" };

    //Start iteration to navigate each property
    foreach (PropertyInfo p in ms)
    {
        counter++;
        var propertyName = p.Name;
        var propertyType = p.PropertyType;
        var propertyValue = p.GetValue(obj, null);

        //If property type is matched with ignoreTypes then
        //goto next loop
        if (ignoreEntityTypes.Contains(propertyType.Name))
        {
            continue;
        }

        if (stringTypes.Contains(propertyType.Name))
        {
            if (propertyValue == null)
            {
                sb.Append(doubleQuote + propertyName + doubleQuote + 
                          ":" + "null");
            }

            else
            {
                sb.Append(doubleQuote + propertyName + doubleQuote + 
                    ":" + doubleQuote + propertyValue.ToString() + doubleQuote);
            }
        }

        else if (propertyType != null && propertyType.IsPrimitive)
        {
            sb.Append(doubleQuote + propertyName + doubleQuote 
                + ":" + propertyValue.ToString());
        }

        //Still I have doubt how Date Time will be handled.
        else if (propertyType.Name == "DateTime")
        {
            var dt = (DateTime)propertyValue;
            sb.Append(doubleQuote + propertyName 
                + doubleQuote + ":" 
                + "new Date(" + dt.Ticks.ToString() + ")");
        }
        else
        {
            if (propertyValue != null)
            {
                sb.Append(doubleQuote + propertyType.Name + doubleQuote + ":");
                //If property value is another entity, then
                //call the method recursively.
                sb.Append(JsonSerialize(propertyValue));
            }
            else
            {
                continue;
            }
        }
        //If it is not the last property, then add comma
        if (counter < ms.Count)
        {
            sb.Append(",");
        }
    }
    sb.Append("}");
    var result = sb.ToString().Replace(",}", "}");
    return result;
}

局限性

我没有在非常复杂的场景下进行测试。因此可能会出现问题。此外,我还不清楚 JSON 序列化器如何处理日期时间。我使用了 DateTime 方法的 Tick 属性。这可能是不正确的。

结论

我以这种方式解决了我的问题。我希望如果您需要使用实体框架和 JSON 格式,它对您有所帮助。

历史

  • 2009 年 4 月 29 日:初始发布
© . All rights reserved.