5

试图利用System.Web.Http.OData.Delta在 ASP.NET Web API 服务中实现PATCH方法,但似乎无法将更改应用于 type 的属性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 方法通过以下方式实现对 Person 的修补Delta<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]}

问题的关键在于如何Friends用这些数据让 Delta 更新。另请参阅CodePlex 上的讨论

4

3 回答 3

3

问题可能是 Deta 会尝试将 JSON 分配JArray给您的Hashset<int>

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

在里面, bool TrySetPropertyValue(string name, object value)of Delta<T>,它返回 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; }
    }

您将能够成功更新它们。

于 2013-01-12T17:42:55.290 回答
1

您可以覆盖DeltaTrySetPropertyValue类的方法并使用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);
    }
}
于 2017-03-24T10:45:50.247 回答
0

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

此外,还有一个问题跟踪项目 1 - '670 - Delta 应该支持不可设置的集合。

于 2013-01-12T18:14:48.823 回答