WCF通过使用Entity Framework Complex来返回JSON

时间:2010-12-01 04:11:03

标签: json entity-framework serialization wcf-rest

最近我用EF4设置了WCF restful服务。 返回XML格式响应时,一切都很顺利。但是当谈到JSON时,我得到了504错误。 unable to return json data, WCF Resful Service .NET 4.0

通过使用服务跟踪查看器深入挖掘: 我发现了这个错误:

  

'类型'xxx.DataEntity.AppView'   无法序列化为JSON,因为   其IsReference设置为“True”。该   JSON格式不支持   引用,因为没有   表示的标准化格式   引用。要启用序列化,   禁用上的IsReference设置   类型或适当的父类   类型。'

“AppView”是一个复杂的对象类,由EF4从商店程序生成。 我花了相当多的时间谷歌如何禁用IsReference,到目前为止很少有结果。

人?有什么解决方案吗?

提前致谢

代码:

[OperationContract]
        [WebInvoke(Method = "GET",
            BodyStyle = WebMessageBodyStyle.Wrapped,
            UriTemplate = "App/{id}/{format}")]
        AppView FuncDetail(string id, string format);



public AppView FuncDetail(string id, string format)
        {
            SetResponseFormat(format);
            return AppSvcs.GetById(id);
        }


private void SetResponseFormat(string format)
            {
                if (format.ToLower() == "json")
                {
                    ResponseContext.Format = WebMessageFormat.Json;
                }
                else
                {
                    ResponseContext.Format = WebMessageFormat.Xml;
                }
            }

4 个答案:

答案 0 :(得分:1)

我遇到了同样的问题,因为使用了自动生成的ADO实体模型。我没有找到针对此问题的直接修复,但作为一种解决方法,我将响应序列化为json。

所以在你的例子中,AppView FuncDetail看起来像这样:

public object FuncDetail(string id, string format)
    {
        SetResponseFormat(format);

        // where AppSvc is the object type and the enumerable list of this type is returned by the GetById method, cast it to a json string
        return JSONSerializer.ToJson<AppSvc>(AppSvcs.GetById(id));
    }

以下是我正在使用的序列化程序:

public static class GenericSerializer 
{
public static DataTable ToDataTable<T>(IEnumerable<T> varlist)
{
    DataTable dtReturn = new DataTable();

    // column names 
    PropertyInfo[] oProps = null;

    if (varlist == null) return dtReturn;

    foreach (T rec in varlist)
    {
        // Use reflection to get property names, to create table, Only first time, others will follow 
        if (oProps == null)
        {
            oProps = ((Type)rec.GetType()).GetProperties();
            foreach (PropertyInfo pi in oProps)
            {
                Type colType = pi.PropertyType;

                if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition()
                == typeof(Nullable<>)))
                {
                    colType = colType.GetGenericArguments()[0];
                }

                dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
            }
        }

        DataRow dr = dtReturn.NewRow();

        foreach (PropertyInfo pi in oProps)
        {
            dr[pi.Name] = pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue
            (rec, null);
        }

        dtReturn.Rows.Add(dr);
    }
    return dtReturn;
}

}

public static class JSONSerializer 
{
public static string ToJson<T>(IEnumerable<T> varlist)
{
    DataTable dtReturn = GenericSerializer.ToDataTable(varlist);
    return GetJSONString(dtReturn);
}

    static object RowsToDictionary(this DataTable table)
{

    var columns = table.Columns.Cast<DataColumn>().ToArray();

    return table.Rows.Cast<DataRow>().Select(r => columns.ToDictionary(c => c.ColumnName, c => r[c]));

}

static Dictionary<string, object> ToDictionary(this DataTable table)
{

    return new Dictionary<string, object>
    {
        { table.TableName, table.RowsToDictionary() }
    };

}

static Dictionary<string, object> ToDictionary(this DataSet data)
{

    return data.Tables.Cast<DataTable>().ToDictionary(t => "Table", t => t.RowsToDictionary());

}

public static string GetJSONString(DataTable table)
{

    JavaScriptSerializer serializer = new JavaScriptSerializer();

    return serializer.Serialize(table.ToDictionary());

}

public static string GetJSONString(DataSet data)
{

    JavaScriptSerializer serializer = new JavaScriptSerializer();

    return serializer.Serialize(data.ToDictionary());

}}

答案 1 :(得分:1)

使用实体元数据而不是反射更清晰。 元数据非常广泛。

答案 2 :(得分:1)

我遇到了完全相同的问题。它只发生在我试图返回JSON序列化实体对象的一个​​服务方法上。对于我所有的其他方法,我返回的是JSON序列化数据传输对象(DTO),它们是独立的,没有连接到Entity框架。我正在使用DTO将数据发布到方法中。通常,您发送的数据不需要存储在模型或数据库中的所有数据,例如ID值,更新日期等。映射在模型类中完成,如下所示:

public partial class Location
{

    public static LocationDto CreateLocationDto(Location location)
    {
        LocationDto dto = new LocationDto
        {
            Accuracy = location.Accuracy,
            Altitude = location.Altitude,
            Bearing = location.Bearing                
        };
        return dto;
    }

它可能看起来有点笨重,但它可以工作,它确保您只发送您想要发回的数据字段。它适用于我,因为我只有5或6个实体,但我可以看到,如果你有很多课程,它会有点乏味。

答案 3 :(得分:0)

另一种方法是使用LINQ创建一个匿名类型,其中包含您需要从实体获得的字段子集,然后使用JSON.NET来序列化您在LINQ语句中创建的非类型集合。然后通过序列化将该集合作为字符串保留。