1

我正在使用 ServiceStack 框架构建一个 RESTful API。我需要更新的很多资源都很大,每个类最多有 40 个属性,所以我想做部分更新而不是替换整个资源。通常客户端只需要更新 40 个属性中的一两个属性,所以我想只发送一个由少数属性组成的 JSON 正文。

由于所有属性组合都是可能的,因此按照此处的建议为每个类创建一个“更新”类是不可行的:https ://github.com/ServiceStack/ServiceStack/wiki/New-Api#patch-request-example

在 Microsoft ASP.NET WebAPI OData 包中有一个 Delta 类,它采用类的子集并根据该子集更新资源 ( http://www.strathweb.com/2013/01/easy-asp-net- web-api-resource-updates-with-delta/)。这是我想要的功能,因为我将有很多类,所以通用方法是最好的。

基本上,如果我有课

public class MyClass {
   public int a { get; set; }
   public int b { get; set; }
   ...
   public int z { get; set; }
}

我想用带有正文的 PATCH 请求更新 MyClass 的资源

{"a":42,"c":42}

使用 ServiceStack 是否有标准或推荐的方法来完成此任务?

4

2 回答 2

4

将 DTO 中的任何标量值声明为可为空。这将允许您确定请求中实际发送了哪些字段:

public class MyClass {
    public int? a { get; set; }
    public int? b { get; set; }
    public int? c { get; set; }
    // etc.
    // object-type properties are already nullable of course
    public string MyString { get; set; }
}

现在,如果客户端发送部分请求,如下所示:

{ "a": 1, "b": 0 }

在检查 DTO 时,您将能够确定实际发送了哪些属性:

myClass.a == 1
myClass.b == 0
myClass.c == null
myClass.MyString == null
etc.

PATCH为你的 DTO设置一个路由并Patch在你的服务中实现一个方法:

public object Patch(MyClass request)
{
    var existing = GetMyClassObjectFromDatabase();
    existing.PopulateWithNonDefaultValues(request);
    SaveToDatabase(existing);
    ...
}

PopulateWithNonDefaultValues是这里的关键。它会将值从您的请求对象复制到数据库实体,但只会复制不是默认值的属性。因此,如果一个值为空,它不会复制它,因为客户端没有为它发送一个值。请注意,它会复制一个零整数值,因为我们将其设为可为空的 int,并且此方法认为可为空的 int 的默认值为 null,而不是零。将您的 DTO 属性声明为可为空的不应在您的其余代码中造成太多麻烦。

请注意,这种方法很容易与 JSON 一起使用。如果您需要支持 XML 请求/响应,您可能需要对DataContract/DataMember属性进行一些额外的工作,以确保正确处理空值。

于 2013-08-21T13:22:55.773 回答
2

虽然 esker 的响应很好,但我想补充一点,对于可为空的字段可能还不够——因为您不知道反序列化程序或用户是否创建了该空字段。

一种方法是查看原始请求。

另一种方法是要求用户提供额外的请求(查询字符串)参数以明确指定要修补的字段。类似于:patch_fields=name,description,field3 这种方法的好处是最终用户可以更好地控制补丁并且不会错误地覆盖值(因为他使用了原始实体并忘记清除某些字段)

于 2014-09-26T00:39:33.767 回答