最近我用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;
}
}
答案 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语句中创建的非类型集合。然后通过序列化将该集合作为字符串保留。