4
votes

I have a POCO class, which inherits from a few classes to give it INotifyPropertyChanged and DataAnnotations support. When WebApi returns an instance of Court, the JSON.NET serializer chokes on the anonymous method delegate in ModelPropertyAnnotationsValidation with an exception (showing the RAW response from Fiddler):

{"Message":"An error has occurred.","ExceptionMessage":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.","ExceptionType":"System.InvalidOperationException","StackTrace":null,"InnerException":{"Message":"An error has occurred.","ExceptionMessage":"Error getting value from 'CS$<>9_CachedAnonymousMethodDelegate5' on 'Sample.Data.Models.Court'.","ExceptionType":"Newtonsoft.Json.JsonSerializationException","StackTrace":" at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)\r\n at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value)\r\n at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value)\r\n at System.Net.Http.Formatting.JsonMediaTypeFormatter.<>c_DisplayClassd.b_c()\r\n at System.Threading.Tasks.TaskHelpers.RunSynchronously(Action action, CancellationToken token)","InnerException":{"Message":"An error has occurred.","ExceptionMessage":"Common Language Runtime detected an invalid program.","ExceptionType":"System.InvalidProgramException","StackTrace":" at GetCS$<>9_CachedAnonymousMethodDelegate5(Object )\r\n at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)"}}}

Court class (redacted for brevity):

using System;
using System.Collections.Generic;
using Sample.Data.Models.Infrastructure;

namespace Sample.Data.Models
{
    [Serializable]
    public partial class Court : ModelPropertyAnnotationsValidation
    {
        public Court()
        {
        }

        private int _courtID;
        public int CourtID
        {
            get { return _courtID; }
            set 
            { 
                _courtID = value; 
                OnPropertyChanged(() => CourtID);
            }
        }
    }
}

Here is the inherited abstract class where the issue resides (if I change the getter on public string this[string columnName] to return an empty string, it works:

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;

namespace Sample.Data.Models.Infrastructure
{
    public abstract class ModelPropertyAnnotationsValidation : ModelBase
    {
        public string this[string columnName]
        {
            get
            {
                var type = GetType();
                var modelProperties = TypeDescriptor.GetProperties(type).Cast<PropertyDescriptor>();

                var enumerable = from modelProperty in modelProperties.Where(modelProp => modelProp.Name == columnName)
                                 from attribute in modelProperty.Attributes.OfType<ValidationAttribute>().Where(attribute => !attribute.IsValid(modelProperty.GetValue(this)))
                                 select attribute.ErrorMessage;
                return enumerable.FirstOrDefault();
            }
            private set { ; } //http://developerstreasure.blogspot.com/2010/05/systemruntimeserializationinvaliddataco.html
        }

        public string Error
        {
            get { return null; }
            private set { ; } //http://developerstreasure.blogspot.com/2010/05/systemruntimeserializationinvaliddataco.html
        }


        public virtual bool IsValid
        {
            get
            {
                var validationContext = new ValidationContext(this, null, null);
                var valid = Validator.TryValidateObject(this, validationContext, null, validateAllProperties: true);
                return valid;
            }
            private set { ; } //http://developerstreasure.blogspot.com/2010/05/systemruntimeserializationinvaliddataco.html
        }
    }
}

And for completeness, here is ModelBase:

using System;
using System.ComponentModel;
using System.Linq.Expressions;

namespace Sample.Data.Models.Infrastructure
{
    public abstract class ModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(Expression<Func<object>> property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(BindingHelper.Name(property)));
            }
        }
    }
}

And the WebApi controller (which is super simple for this purpose):

using System.Web.Http;
using Sample.Data.Models;

namespace Sample.Services.Api.Controllers
{
    public class CourtsController : ApiController
    {
        // GET api/values
        public Court Get()
        {
            return new Court {Abbreviation = "TEST", FullName = "Test Court", Active = true};
        }

    }
}

How can I get what is I suppose an anonymous delegate to pass through the serialization... ignored or otherwise?

1

1 Answers

4
votes

What version of Json.NET are you using? If you aren't using the latest (5.0.8) then upgrade to it and run your application again.