序列化类的子集

时间:2014-04-23 00:05:15

标签: c# json rest json.net

我不会涉及我尝试过的所有事情......

这正是我想要完成的事情。

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);
    }
}

我希望我的输出看起来像这样......

  

{ “SSN”: “111001111”, “姓”: “约翰”, “名字”: “Doe的”}

     

{ “姓”: “约翰”, “名字”: “Doe的”}

我认为这不会那么困难,但由于Serializer总是将类型确定为DTO,因此即使在我不想要的情况下也总是得到SSN值。

这当然只是一个小小的考验。假设我有一个WebAPI应用程序模拟了这样的东西。

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

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

我希望Serializer只序列化返回类型中定义的那些项目。

3 个答案:

答案 0 :(得分:1)

您可以使用JsonIgnoreAttribute 始终不包含SSN。

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

如果您想以编程方式确定天气是否包含它,您可以创建两个类 - 具有FirstName,LastName等的基础ClientDTO。然后是ClientWithSSN类型,继承自{{ 1}}并且只包含SSN。然后,当选择是否返回SSN时,转换为没有ssn的基本类型或返回实际的ClientDTO类型。

答案 1 :(得分:1)

我喜欢通过返回的接口控制对象访问。很好,编译器控制访问和可见性。

然而,当涉及到序列化时,编译器不在那里进行裁判。所以我认为我的问题没有实际意义。一旦Json.net序列化器发出......

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

这几乎是一个完成的交易。 当然,你可以用东西来捅东西,但是如果你不能在全球范围内根据类型做到这一点,我就不会明白这一点。所以我会根据Cam的建议来做这样的事情。

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);

    }
}

当然它有点笨重和重复,但它仍然允许我通过接口维护访问,我可以让序列化器不受阻碍地做它的事情,我怀疑从长远来看它将更容易维护。

答案 2 :(得分:0)

您可以使用ContractResolver来处理此问题:

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();
    }
}

然后当你序列化时,你就这样做了:

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

string sClientDTO = JsonConvert.SerializeObject (clientDTO,sets);