Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I solved these issues with the following classes:</p> <pre><code>public class EFJavaScriptSerializer : JavaScriptSerializer { public EFJavaScriptSerializer() { RegisterConverters(new List&lt;JavaScriptConverter&gt;{new EFJavaScriptConverter()}); } } </code></pre> <p>and</p> <pre><code>public class EFJavaScriptConverter : JavaScriptConverter { private int _currentDepth = 1; private readonly int _maxDepth = 1; private readonly List&lt;object&gt; _processedObjects = new List&lt;object&gt;(); private readonly Type[] _builtInTypes = new[] { typeof(int?), typeof(double?), typeof(bool?), typeof(bool), typeof(byte), typeof(sbyte), typeof(char), typeof(decimal), typeof(double), typeof(float), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(short), typeof(ushort), typeof(string), typeof(DateTime), typeof(DateTime?), typeof(Guid) }; public EFJavaScriptConverter() : this(1, null) { } public EFJavaScriptConverter(int maxDepth = 1, EFJavaScriptConverter parent = null) { _maxDepth = maxDepth; if (parent != null) { _currentDepth += parent._currentDepth; } } public override object Deserialize(IDictionary&lt;string, object&gt; dictionary, Type type, JavaScriptSerializer serializer) { return null; } public override IDictionary&lt;string, object&gt; Serialize(object obj, JavaScriptSerializer serializer) { _processedObjects.Add(obj.GetHashCode()); var type = obj.GetType(); var properties = from p in type.GetProperties() where p.CanRead &amp;&amp; p.GetIndexParameters().Count() == 0 &amp;&amp; _builtInTypes.Contains(p.PropertyType) select p; var result = properties.ToDictionary( p =&gt; p.Name, p =&gt; (Object)TryGetStringValue(p, obj)); if (_maxDepth &gt;= _currentDepth) { var complexProperties = from p in type.GetProperties() where p.CanRead &amp;&amp; p.GetIndexParameters().Count() == 0 &amp;&amp; !_builtInTypes.Contains(p.PropertyType) &amp;&amp; p.Name != "RelationshipManager" &amp;&amp; !AllreadyAdded(p, obj) select p; foreach (var property in complexProperties) { var complexValue = TryGetValue(property, obj); if(complexValue != null) { var js = new EFJavaScriptConverter(_maxDepth - _currentDepth, this); result.Add(property.Name, js.Serialize(complexValue, new EFJavaScriptSerializer())); } } } return result; } private bool AllreadyAdded(PropertyInfo p, object obj) { var val = TryGetValue(p, obj); return _processedObjects.Contains(val == null ? 0 : val.GetHashCode()); } private static object TryGetValue(PropertyInfo p, object obj) { var parameters = p.GetIndexParameters(); if (parameters.Length == 0) { return p.GetValue(obj, null); } else { //cant serialize these return null; } } private static object TryGetStringValue(PropertyInfo p, object obj) { if (p.GetIndexParameters().Length == 0) { var val = p.GetValue(obj, null); return val; } else { return string.Empty; } } public override IEnumerable&lt;Type&gt; SupportedTypes { get { var types = new List&lt;Type&gt;(); //ef types types.AddRange(Assembly.GetAssembly(typeof(DbContext)).GetTypes()); //model types types.AddRange(Assembly.GetAssembly(typeof(BaseViewModel)).GetTypes()); return types; } } } </code></pre> <p>You can now safely make a call like <code>new EFJavaScriptSerializer().Serialize(obj)</code></p> <p><strong>Update</strong> : since version Telerik v1.3+ you can now override the GridActionAttribute.CreateActionResult method and hence you can easily integrate this Serializer into specific controller methods by applying your custom <code>[GridAction]</code> attribute:</p> <pre><code>[Grid] public ActionResult _GetOrders(int id) { return new GridModel(Service.GetOrders(id)); } </code></pre> <p>and</p> <pre><code>public class GridAttribute : GridActionAttribute, IActionFilter { /// &lt;summary&gt; /// Determines the depth that the serializer will traverse /// &lt;/summary&gt; public int SerializationDepth { get; set; } /// &lt;summary&gt; /// Initializes a new instance of the &lt;see cref="GridActionAttribute"/&gt; class. /// &lt;/summary&gt; public GridAttribute() : base() { ActionParameterName = "command"; SerializationDepth = 1; } protected override ActionResult CreateActionResult(object model) { return new EFJsonResult { Data = model, JsonRequestBehavior = JsonRequestBehavior.AllowGet, MaxSerializationDepth = SerializationDepth }; } } </code></pre> <p>and finally..</p> <pre><code>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 &amp;&amp; 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&lt;JavaScriptConverter&gt; { new EFJsonConverter(MaxSerializationDepth) }); response.Write(serializer.Serialize(Data)); } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. COLooks good :) I'll take a closer look at the code soon. I think there are some performance/logical improvements to be made (from having written similar code before I went for my alternative approach). If you'd like, I can give you some feedback later, or edit the code and let you decide if you want to roll it back. Also, what is `RelationshipManager`? Should that be removed?
      singulars
    2. COYes, please do provide performance feedback/suggestions. In my case its part of one off/small scale object serialization so perf is not critical. 'RelationshipManager' I believe is a property that gets added to the EF4 DynamicProxies (maybe only in POCO mode), if you remove that line it will end up serializing that property into your JSON which you probably do not want.
      singulars
    3. COI was thinking that you should be able to pass in the supported types, and also be able to pass in a list of deliberately ignored types (types it "handles", then ignores). The list of supported types could be generated by a T4 template if you're generating your types off the model, or is somewhat easy to create manually. Also, getting the hash code alone isn't enough to establish uniqueness. You have to check `Equals` too. I suggest using `HashSet<object>` with an `IEqualityComparer<object>` that returns the normal hash code, and checks *reference* equality rather than calling `Equals`.
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload