开发者

How to ignore properties when serializing to json that does not involve attributes

I am using Entity Framework to generate my models. I want to communicate some of these models via JSON. The problem is that I do not want the stuff that EF tacks onto the model to be serialized (EntityKey, EntityState, and all the EntityCollection<> properties)

Since EF generates these models, decorating the properties with ScriptIgnore or something similar is not really feasible.

Is there a way with any json serializer to serialize an object and have it ignore fields that does not require me to change the source开发者_开发百科 for my models? (I can add on to the models, though, if it helps since they are declared as partial classes)


I've just been coming up against a similar problem, in this case it's a custom object property on a Linq to SQL model that I'd much rather just serialise in and out of a database rather than set up lots of extra fields and extra constructors. I'm not sure how closely this matches to your situation but it should be adaptable.

Most solutions I've seen have wanted either attributes to be included (not possible due to auto code generation) or rolling custom converters (overkill, especially if you want to capture nested objects etc).

My thinking is that all the properties I don't want are already given attributes due to LinqToSql, so rather than manually getting the properties I do want then trying to serialize them, Serialize first then DeSerialize. This gives you your object graph which is much easier to work with and all your nesting has been done for you.

Next get the member names we don't want. How you get these is up to you, it might even be a case of giving it the names manually in the same way you'd exclude from model binding in MVC. In my case a bit of Linq and a bit of reflection gets us the names of all properties that Linq to SQL generates.

As our object is a simple Dictonary we iterate over our unwanted members and remove them from the dictionary.

Finally Serialise your dictionary again.

public string JsonMinusProperties(object toSerialize)
    {
        //Replace this with your preferred way of getting your unwanted properties
        var LinqMemberNames = toSerialize.GetType().GetProperties().Where(y=>
            y.GetCustomAttributes(true).Any(x =>
                x.GetType().Namespace == "System.Data.Linq.Mapping"
            )
        ).Select(x=>x.Name);

        JavaScriptSerializer js = new JavaScriptSerializer();
        string json = js.Serialize(toSerialize);
        var tempobj = js.DeserializeObject(json) as Dictionary<string, object>;
        foreach (string linqMember in LinqMemberNames)
        {
            tempobj.Remove(linqMember);
        }
        return js.Serialize(tempobj);
    }

This will only remove from the first level, though in principal should be easy to walk the dictionary if required to remove deeper properties.


If you are using DataContractJsonSerializer to serialize to JSON then it will only serialize properties which have a [DataMember] attribute.

Another option to consider is to have a separate DTO object for the data that you want to expose in JSON. That object would be constructed from your entity models. The benefits of this approach are that you have an explicit class, the DTO, which defines the data contract and it is decoupled from the underlying entity model.


In JayRock, you can create your own IExporter. The basic form could look like this:

class FooExporter : IExporter
{
    public void Export(ExportContext context, object value, JsonWriter writer)
    {
        var properties = value.GetType().GetProperties();

        writer.WriteStartObject();

        foreach (var property in properties)
        {
            var propertyValue = property.GetValue(value, null);
            if (!JsonNull.LogicallyEquals(propertyValue))
            {
                writer.WriteMember(property.Name);
                context.Export(propertyValue, writer);
            }
        }

        writer.WriteEndObject();
    }

    public Type InputType
    {
        get { return typeof(Foo); }
    }
}

You can modify this any way you want (e.g. ignore all properties having a specific name; take the concrete type in constructor). You can then use it like this:

var context = JsonConvert.CurrentExportContextFactory();
context.Register(new FooExporter());
// always use this context
JsonConvert.CurrentExportContextFactory = () => context;
string json = JsonConvert.ExportToString(new Foo { … });

Another option is to implement IJsonExportable in your entities. It has a Export() method, very similar to the one above.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜