【问题标题】:How do I patch enumerables with System.Web.Http.OData.Delta?如何使用 System.Web.Http.OData.Delta 修补可枚举?
【发布时间】:2013-01-12 14:13:54
【问题描述】:

试图在 ASP.NET Web API 服务中使用System.Web.Http.OData.Delta 实现PATCH 方法,但似乎无法将更改应用于IEnumerable<T> 类型的属性。我正在使用 Delta 的最新 Git 版本(2012.2-rc-76-g8a73abe)。有没有人能够完成这项工作?

考虑这种数据类型,它应该可以在对 Web API 服务的 PATCH 请求中更新:

public class Person
{
    HashSet<int> _friends = new HashSet<int>();

    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public IEnumerable<int> Friends
    {
        get { return _friends; }
        set
        {
            _friends = value != null ? new HashSet<int>(value) : new HashSet<int>();
        }
    }

    public Person(int id, string firstName, string lastName)
    {
        Id = id;
        FirstName = firstName;
        LastName = lastName;
    }

    public Person()
    {
    }
}

此 Web API 方法通过Delta&lt;Person&gt; 实现对 Person 的修补:

public void Patch(int id, Delta<Person> delta)
{
    var person = _persons.Single(p => p.Id == id);
    delta.Patch(person);
}

如果我向服务发送带有以下 JSON 的 PATCH 请求,则应更新此人的 Friends 属性,但可惜不会发生:

{"Friends": [1]}

问题的关键在于如何让Delta更新Friends这个数据。另请参阅discussion at CodePlex

【问题讨论】:

    标签: rest asp.net-web-api odata


    【解决方案1】:

    问题可能是 Deta 会尝试将 JSON 的 JArray 分配给您的 Hashset&lt;int&gt;

    如果你对 JsonMEdiaTypeFormatter 使用它并且你内化了 Delta 代码(这意味着你可以修改它),你必须做这样的事情(这很粗糙,但有效):

    在内部,Delta&lt;T&gt;bool TrySetPropertyValue(string name, object value),它返回 false:

            if (value != null && !cacheHit.Property.PropertyType.IsPrimitive && !isGuid && !cacheHit.Property.PropertyType.IsAssignableFrom(value.GetType()))
            {
               return false;
            }
    

    改为:

    var valueType = value.GetType();
    var propertyType = cacheHit.Property.PropertyType;
    if (value != null && !propertyType.IsPrimitive && !propertyType.IsAssignableFrom(valueType))
    {
        var array = value as JArray;
        if (array == null)
            return false;
    
        var underlyingType = propertyType.GetGenericArguments().FirstOrDefault() ??
            propertyType.GetElementType();
        if (underlyingType == typeof(string))
        {
            var a = array.ToObject<IEnumerable<string>>();
            value = Activator.CreateInstance(propertyType, a);
        }
        else if (underlyingType == typeof(int))
        {
            var a = array.ToObject<IEnumerable<int>>();
            value = Activator.CreateInstance(propertyType, a);
        }
        else
            return false;
    }
    

    这仅适用于 intstring 的集合,但希望能将您推向一个好的方向。

    例如,现在你的模型可以有:

    public class Team {
            public HashSet<string> PlayerIds { get; set; }
            public List<int> CoachIds { get; set; }
        }
    

    您将能够成功更新它们。

    【讨论】:

    • 谢谢,你让我开心(又一次)!我不得不对您的代码进行重大更改才能使其正常工作。
    • 谢谢,好吧,我没有直接在这里测试就输入了这个:)
    【解决方案2】:

    您可以覆盖Delta 类的TrySetPropertyValue 方法并使用JArray 类:

    public sealed class DeltaWithCollectionsSupport<T> : Delta<T> where T : class
    {
        public override bool TrySetPropertyValue(string name, object value)
        {
            var propertyInfo = typeof(T).GetProperty(name);
    
            return propertyInfo != null && value is JArray array
                ? base.TrySetPropertyValue(name, array.ToObject(propertyInfo.PropertyType))
                : base.TrySetPropertyValue(name, value);
        }
    }
    

    【讨论】:

      【解决方案3】:

      如果您使用的是 ODataMediaTypeFormatter,这应该可以正常工作。不过,有几点需要注意。 1)您的收藏品必须是可设置的。 2)整个集合被替换。您不能删除/添加单个元素。

      另外,还有一个问题跟踪项 1 - '670 -Delta should support non-settable collections.'

      【讨论】:

      • 不,我猜我正在使用 JsonMediaTypeFormatter,无论 Web API 中的默认值是什么,因为我只是直接插入了 Delta,而没有进行任何其他更改。使用 ODataMediaTypeFormatter 有什么特别的注意事项吗?它是否会以任何特定方式更改我的 API?
      • 在哪里可以找到有关使用 ODataMediaTypeFormatter 而不是 JsonMediaTypeFormatter 的信息?
      • Alex James blog 提供了非常好的关于将 odata 与 webapi 结合使用的信息。
      • 我已经阅读了那篇博文,它并没有真正启发我只实现部分更新 (PATCH) 而不是完整的 OData。
      猜你喜欢
      • 1970-01-01
      • 2020-07-07
      • 1970-01-01
      • 2010-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多