【问题标题】:Web API 2 Patch using OData - how to best handle case sensitivity?使用 OData 的 Web API 2 补丁 - 如何最好地处理区分大小写?
【发布时间】:2014-06-17 02:15:14
【问题描述】:

我正在将 JSON 从客户端修补到我的 Web API 2 控制器。

请求看起来像:

Request URL: http://localhost:28029/PlaylistItem/5df2b99f-e021-4c81-8ff5-a34c013470aa
Request Payload: { sequence: 5000 }

我的控制器的方法如下:

[Route("{id:guid}")]
[HttpPatch]
public void Patch(Guid id, Delta<PlaylistItemDto> playlistItemDto)
{
}

PlaylistItemDto 的样子:

public class PlaylistItemDto
{
    public Guid PlaylistId { get; set; }
    public Guid Id { get; set; }
    public int Sequence { get; set; }
    ...
}

这成功向控制器发送请求,但由于区分大小写而无法正常工作。 OData 库未将序列正确转换为序列。

我找到了一个关于该问题的线程asp.net mvc web api partial update with OData Patch,但我发现解决方案乏善可陈。这个问题目前没有可行的解决方案吗?区分大小写似乎是 PATCHing JSON 数据从客户端到服务器的一个非常常见的用例。

【问题讨论】:

  • 你最后是怎么解决的?下面的答案似乎集中在 JSON.net 序列化程序上,Odata 使用完全不同的序列化程序。我现在有同样的问题。我最终修复了有效负载,因为 Odata 是一个标准,并且不想真正改变任何不是真正预期的东西。

标签: json asp.net-web-api2


【解决方案1】:

使用继承 CamelCasePropertyNamesContractResolver 并实现 CreateContract 方法的自定义合同解析器可以很容易地完成,该方法查看 delta 的具体类型并获取实际属性名称,而不是使用来自 json 的名称。摘要如下:

public class DeltaContractResolver : CamelCasePropertyNamesContractResolver
{
        protected override JsonContract CreateContract(Type objectType)
        {
            // This class special cases the JsonContract for just the Delta<T> class. All other types should function
            // as usual.
            if (objectType.IsGenericType &&
                objectType.GetGenericTypeDefinition() == typeof(Delta<>) &&
                objectType.GetGenericArguments().Length == 1)
            {
                var contract = CreateDynamicContract(objectType);
                contract.Properties.Clear();

                var underlyingContract = CreateObjectContract(objectType.GetGenericArguments()[0]);
                var underlyingProperties =
                    underlyingContract.CreatedType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                foreach (var property in underlyingContract.Properties)
                {
                    property.DeclaringType = objectType;
                    property.ValueProvider = new DynamicObjectValueProvider()
                    {
                        PropertyName = this.ResolveName(underlyingProperties, property.PropertyName),
                    };

                    contract.Properties.Add(property);
                }

                return contract;
            }

            return base.CreateContract(objectType);
        }

        private string ResolveName(PropertyInfo[] properties, string propertyName)
        {

            var prop = properties.SingleOrDefault(p => p.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase));

            if (prop != null)
            {
                return prop.Name;
            }

            return propertyName;
        }
}

【讨论】:

  • 正如another answer 的评论中所述,DynamicObjectValueProvider 可以在 here 中找到,并且在 WebApiConfig 中设置为这样 config.Formatters.JsonFormatter.SerializerSettings.ContractR‌​esolver = new DeltaContractResolver();
猜你喜欢
  • 2018-06-29
  • 2014-10-25
  • 1970-01-01
  • 1970-01-01
  • 2014-06-11
  • 1970-01-01
  • 1970-01-01
  • 2014-07-24
  • 1970-01-01
相关资源
最近更新 更多