JsonProperty WebApi请求和响应模型

时间:2015-12-18 19:28:00

标签: json asp.net-web-api json.net

我有一个与另一个API对话的API。 响应模型如下所示:

public class AddressResponseModel
{
    public string Id { get; set; }
    public string SaveAs { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Phone { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string County { get; set; }
    public string Country { get; set; }
    public string PostCode { get; set; }
}

所以,我需要将它发送到另一个API。我真的不想在JavaScript中使用响应,我只想将它发送到我的端点并让服务器处理它的分解。 所以,我试着这样做:

public class AddressBindingModel
{
    [Required]
    [JsonProperty("address_1")]
    public string Address1 { get; set; }

    [JsonProperty("address_2")]
    public string Address2 { get; set; }

    [Required]
    [JsonProperty("city")]
    public string City { get; set; }

    [Required]
    [JsonProperty("county")]
    public string County { get; set; }

    [Required]
    [JsonProperty("postcode")]
    public string PostCode { get; set; }

    [Required]
    [JsonProperty("country")]
    public string Country { get; set; }

    [JsonProperty("save_as")]
    public string SaveAs { get; set; }
}

但问题是它希望json遵循相同的属性格式。 如何让它期望我的未修改的响应模型,但输出带有下划线的JSON?

为了澄清,我将发布我的模型:

{
    address1: '123',
    address2: 'Some street',
    city: 'London',
    county: 'London',
    country: 'GB',
    saveAs: 'Home'
}

然后我的API会将此信息发送到另一个API:

{
    address_1: '123',
    address_2: 'Some street',
    city: 'London',
    county: 'London',
    country: 'GB',
    save_as: 'Home'
}

1 个答案:

答案 0 :(得分:0)

如果您想使用相同的类自动生成具有不同属性名称的JSON,而不必为每个属性名称编写自定义JsonConverter,那么您将需要创建自己的{{3例如:

如果您有一种确定的方法将所有.Net属性名称映射到给定使用上下文(post或get-from-api)的相应属性名称,您可以创建一个像上面的一个合同解析器。

但是,如果没有为JSON属性名映射.Net属性名称的一般规则,并且每个上下文可能需要一些每个属性的自定义,您可以创建自己的ContractResolver适用于特定的命名上下文,以及您自己的System.Attribute,它提供在此上下文中使用的JSON上下文名称和属性名称。即:

[System.AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true, Inherited = true)]
public class JsonConditionalNameAttribute : System.Attribute
{
    readonly string contextName;
    readonly string propertyName;

    public string ContextName { get { return contextName; } }
    public string PropertyName { get { return propertyName; } }

    public JsonConditionalNameAttribute(string contextName, string propertyName)
    {
        this.contextName = contextName;
        this.propertyName = propertyName;
    }
}

public class ConditionalNameContractResolver : DefaultContractResolver
{
    readonly string contextName;
    public string ContextName { get { return contextName; } }

    public ConditionalNameContractResolver(string contextName)
        : base()
    {
        if (string.IsNullOrEmpty(contextName))
            throw new ArgumentNullException();
        if (string.IsNullOrEmpty(contextName))
            throw new ArgumentException();
        this.contextName = contextName;
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var jProperty = base.CreateProperty(member, memberSerialization);
        var attrs = jProperty.AttributeProvider.GetAttributes(typeof(JsonConditionalNameAttribute), true)
            .Cast<JsonConditionalNameAttribute>()
            .Where(a => a.ContextName == ContextName)
            .Select(a => a.PropertyName)
            .Distinct()
            .ToList();
        if (attrs.Count == 1)
        {
            jProperty.PropertyName = attrs[0];
        }
        else if (attrs.Count > 1)
        {
            throw new JsonSerializationException(string.Format("Multiple conditional property attributes found for \"{0}\" in in context \"{1}\": \"{2}\"", jProperty, contextName, String.Join(",", attrs)));
        }
        return jProperty;
    }
}

然后你的绑定模型看起来像:

public static class AddressBindingModelContexts
{
    public const string Post = "post";
    public const string GetFromApi = "getFromApi";
}

public class AddressBindingModel
{
    [JsonConditionalName(AddressBindingModelContexts.GetFromApi, "address_1")]
    [JsonConditionalName(AddressBindingModelContexts.Post, "address1")]
    public string Address1 { get; set; }

    [JsonConditionalName(AddressBindingModelContexts.GetFromApi, "address_2")]
    [JsonConditionalName(AddressBindingModelContexts.Post, "address2")]
    public string Address2 { get; set; }

    [JsonProperty("city")]
    public string City { get; set; }

    [JsonProperty("county")]
    public string County { get; set; }

    [JsonProperty("postcode")]
    public string PostCode { get; set; }

    [JsonProperty("country")]
    public string Country { get; set; }

    [JsonConditionalName(AddressBindingModelContexts.GetFromApi, "save_as")]
    [JsonConditionalName(AddressBindingModelContexts.Post, "saveAs")]
    public string SaveAs { get; set; }
}

测试:

        var jsonFromApi = GetJsonFromApi();

        var postContract = new ConditionalNameContractResolver(AddressBindingModelContexts.Post);
        var getFromApiContract = new ConditionalNameContractResolver(AddressBindingModelContexts.GetFromApi);

        var model = JsonConvert.DeserializeObject<AddressBindingModel>(jsonFromApi, new JsonSerializerSettings { ContractResolver = getFromApiContract });

        var postJson = JsonConvert.SerializeObject(model, Formatting.Indented, new JsonSerializerSettings { ContractResolver = postContract });

        Debug.WriteLine(postJson); // Verify the postJson has the necessary properties and data.

要更改从Web API返回的所有结果的合约解析程序,请参阅This Answer。要在返回特定Web Api调用的结果时使用自定义合约解析程序,请参阅JSON and XML Serialization in ASP.NET Web API: Camel Casing