答案 0 :(得分:1)
第一个解决方案适用于网格编辑模式,但是我们对已经包含循环引用的对象行的网格加载存在同样的问题,为了解决这个问题,我们需要创建一个新的IClientSideObjectWriterFactory和一个新的IClientSideObjectWriter。 。 这就是我的工作:
1-创建一个新的IClientSideObjectWriterFactory:
public class JsonClientSideObjectWriterFactory : IClientSideObjectWriterFactory
{
public IClientSideObjectWriter Create(string id, string type, TextWriter textWriter)
{
return new JsonClientSideObjectWriter(id, type, textWriter);
}
}
2-创建一个新的IClientSideObjectWriter,这次我没有实现接口,我继承了ClientSideObjectWriter并重写了AppendObject和AppendCollection方法:
public class JsonClientSideObjectWriter : ClientSideObjectWriter
{
public JsonClientSideObjectWriter(string id, string type, TextWriter textWriter)
: base(id, type, textWriter)
{
}
public override IClientSideObjectWriter AppendObject(string name, object value)
{
Guard.IsNotNullOrEmpty(name, "name");
var data = JsonConvert.SerializeObject(value,
Formatting.None,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new PropertyNameIgnoreContractResolver()
});
return Append("{0}:{1}".FormatWith(name, data));
}
public override IClientSideObjectWriter AppendCollection(string name, System.Collections.IEnumerable value)
{
public override IClientSideObjectWriter AppendCollection(string name, System.Collections.IEnumerable value)
{
Guard.IsNotNullOrEmpty(name, "name");
var data = JsonConvert.SerializeObject(value,
Formatting.Indented,
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new PropertyNameIgnoreContractResolver()
});
data = data.Replace("<", @"\u003c").Replace(">", @"\u003e");
return Append("{0}:{1}".FormatWith((object)name, (object)data));
}
}
注意:替换它,因为网格在编辑模式下为客户端模板呈现html标记,如果我们不编码,则浏览器将呈现标记。如果没有使用替换字符串对象,我还没有找到workarround。
3-在Global.asax.cs上的Application_Start上我注册了我的新工厂:
DI.Current.Register<IClientSideObjectWriterFactory>(() => new JsonClientSideObjectWriterFactory());
它适用于Telerik拥有的所有组件。我唯一没有改变的是PropertyNameIgnoreContractResolver,它与EntityFramework类相同。
答案 1 :(得分:0)
我将新调用放入Application_Start中以实现CustomGridActionResultFactory但是create方法从未调用过...
答案 2 :(得分:0)
我采取了一种稍微不同的方法,我认为这可能更容易实施。
我所做的就是将一个扩展的[Grid]
属性应用于网格json返回方法,而不是普通的[GridAction]
属性
public class GridAttribute : GridActionAttribute, IActionFilter
{
/// <summary>
/// Determines the depth that the serializer will traverse
/// </summary>
public int SerializationDepth { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="GridActionAttribute"/> class.
/// </summary>
public GridAttribute()
: base()
{
ActionParameterName = "command";
SerializationDepth = 1;
}
protected override ActionResult CreateActionResult(object model)
{
return new EFJsonResult
{
Data = model,
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
MaxSerializationDepth = SerializationDepth
};
}
}
和
public class EFJsonResult : JsonResult
{
const string JsonRequest_GetNotAllowed = "This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.";
public EFJsonResult()
{
MaxJsonLength = 1024000000;
RecursionLimit = 10;
MaxSerializationDepth = 1;
}
public int MaxJsonLength { get; set; }
public int RecursionLimit { get; set; }
public int MaxSerializationDepth { get; set; }
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (JsonRequestBehavior == JsonRequestBehavior.DenyGet &&
String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(JsonRequest_GetNotAllowed);
}
var response = context.HttpContext.Response;
if (!String.IsNullOrEmpty(ContentType))
{
response.ContentType = ContentType;
}
else
{
response.ContentType = "application/json";
}
if (ContentEncoding != null)
{
response.ContentEncoding = ContentEncoding;
}
if (Data != null)
{
var serializer = new JavaScriptSerializer
{
MaxJsonLength = MaxJsonLength,
RecursionLimit = RecursionLimit
};
serializer.RegisterConverters(new List<JavaScriptConverter> { new EFJsonConverter(MaxSerializationDepth) });
response.Write(serializer.Serialize(Data));
}
}
将此与我的序列化程序Serializing Entity Framework problems结合使用,您可以采用一种简单的方法来避免循环引用,还可以选择序列化多个级别(我需要)
注意:Telerik最近为我添加了这个虚拟的CreateActionResult,因此您可能需要下载最新版本(不确定,但我认为可能是1.3 +)
答案 3 :(得分:0)
另一个好的模式是不要避免从模型中创建ViewModel
。
包含ViewModel
是一个很好的模式。它使您有机会对模型进行最后一刻的UI相关调整。例如,您可以调整bool以获得关联的字符串Y
或N
,以帮助使UI看起来更好,反之亦然。
有时ViewModel
与模型完全相同,复制属性的代码似乎没有必要,但模式是好的,坚持使用是最好的做法。