Question

I won't go into all the things I've tried...

This is approximately what I'm trying to accomplish.

public interface IClientDTO {
    string FirstName { get; }
    string LastName { get; }
}

public class DTO : IClientDTO {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string SSN { get; set; }
}

class Program {
    static void Main(string[] args) {
        DTO dto = new DTO() { FirstName = "John", LastName = "Doe", SSN = "111001111" };
        IClientDTO clientDTO = dto;
        string sDTO = JsonConvert.SerializeObject(dto);
        string sClientDTO = JsonConvert.SerializeObject(clientDTO);

        Debug.WriteLine(sDTO);
        Debug.WriteLine(sClientDTO);
    }
}

I would like my output to look like this...

{"SSN":"111001111","FirstName":"John","LastName":"Doe"}

{"FirstName":"John","LastName":"Doe"}

I didn't think it would be that difficult, but since the Serializer always determines the type as DTO I always get the SSN value even on the occasions I don't want to.

This is of course just a little test. Lets say that I have a WebAPI application mocked up something like this.

public class AdminController : ApiController {
    public DTO Get() { return new Model().DTO); }
}

public class ClientController : ApiController {
    public IClientDTO Get() { return new Model().DTO); }
}

I'd like the Serializer to serialize only those items defined in the return type.

Was it helpful?

Solution

You can use the JsonIgnoreAttribute to always not include SSN.

public class DTO : IClientDTO {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    [JsonIgnore]
    public string SSN { get; set; }
}

If you want to programatically determine weather or not to include it, you could create two classes - a base ClientDTO with FirstName, LastName, etc. Then a ClientWithSSN type, that inherits from ClientDTO and contains just SSN. Then, when chosing to return SSN or not, cast to the base type with no ssn or return the actual ClientWithSSN type.

OTHER TIPS

I like controlling object access through returned interfaces. Its nice that the compiler controls access and visibility.

However when it comes to serialization the compiler isn't there to referee. So I think my question is a moot one. As soon as the Json.net serializer issues...

return base.Serializer._contractResolver.ResolveContract(value.GetType());

It's pretty much a done deal. Sure, you can jack with things and poke things, but if you can't do it globally based on type I don't really see the point. So I'm going with something like this based on Cam's suggestion.

public interface IClientDTO {
    string FirstName { get; }
    string LastName { get; }
}

public interface IAdminDTO {
    string FirstName { get; }
    string LastName { get; }
    string SSN { get; }
}

class ClientDTO : IClientDTO {
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

class AdminDTO : IAdminDTO {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string SSN { get; set; }
}

class Model {
    class DTO {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string SSN { get; set; }
    }
    private DTO dto = new DTO() { FirstName = "John", LastName = "Doe", SSN = "111001111" };
    public IClientDTO ClientDTO { get { return new ClientDTO() { FirstName = dto.FirstName, LastName = dto.LastName }; } }
    public IAdminDTO AdminDTO { get { return new AdminDTO() { SSN = dto.SSN, FirstName = dto.FirstName, LastName = dto.LastName }; } }
}

class Program {

    static void Main(string[] args) {

        Model model = new Model();
        string sClientDTO = JsonConvert.SerializeObject(model.ClientDTO);
        string sAdminDTO = JsonConvert.SerializeObject(model.AdminDTO);

        Debug.WriteLine(sClientDTO);
        Debug.WriteLine(sAdminDTO);

    }
}

Sure it's a little clunky and repetitive, but it still allows me to maintain access through the interfaces and I can let the serializer do its thing unhindered, and I suspect it will be easier to maintain in the long run.

You can use a ContractResolver to handle this:

private class IgnoreSSNResolver : DefaultContractResolver
{

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        Debug.Write(type.Name);
        var properties = base.CreateProperties(type, memberSerialization);

        var props = properties.Where((x) => x.PropertyName != "SSN");


        return props.ToList();
    }
}

Then when you serialize, you just do this:

JsonSerializerSettings sets = new JsonSerializerSettings();
sets.ContractResolver = new IgnoreSSNResolver();

string sClientDTO = JsonConvert.SerializeObject (clientDTO,sets);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top