如何使用ServiceStack实现删除服务调用
How to implement Delete service call using ServiceStack
我有几个关于使用 ServiceStack 实现 REST 服务的问题。
对于 GET 操作,我定义我的请求 DTO 如下:
[Route("/Customer/{ID}", Verbs = "GET")]
public class GetCustomer : IReturn<GetCustomerResponse>
{
....
....
}
这里"GetCustomer"是请求DTO,"GetCustomerResponse"是响应DTO。但是对于 PUT/POST/DELETE 操作,我只需要知道操作是否成功提交,如果 'not' 那么异常是什么。那么我对 POST/PUT/DELETE 的请求 dto 定义应该是什么?它应该使用如下所示的 IReturnVoid 吗?
[Route("/Customer/{ID}", Verbs = "DELETE")]
public class DeleteCustomer : IReturnVoid
{
....
....
}
如果我必须使用 IReturnVoid,那么我如何检索在提交我的操作时可能发生的任何异常信息?
在服务栈的错误处理文档中有写,我在下面引用
Error Response Types
The Error Response that gets returned when an Exception is thrown
varies on whether a conventionally-named {RequestDto}Response DTO
exists or not.
If it exists:
The {RequestDto}Response is returned, regardless of the service
method's response type. If the {RequestDto}Response DTO has a
ResponseStatus property, it is populated otherwise no ResponseStatus
will be returned. (If you have decorated the {ResponseDto}Response
class and properties with [DataContract]/[DataMember] attributes, then
ResponseStatus also needs to be decorated, to get populated).
Otherwise, if it doesn't:
A generic ErrorResponse gets returned with a populated ResponseStatus
property.
The Service Clients transparently handles the different Error Response
types, and for schema-less formats like JSON/JSV/etc there's no actual
visible difference between returning a ResponseStatus in a custom or
generic ErrorResponse - as they both output the same response on the
wire.
我没有从上面得到的是我的服务实现中 Delete 方法的 return 类型应该是什么?我如何在不定义删除响应 DTO 的情况下实现我的删除方法,但我仍然能够检索 'ErrorResponse' n 异常信息?
- 是否可以用"DELETE"动词定义路由?我有以下实施。
路线:
[Route("/DeleteCustomer/{ID}", Verbs = "DELETE")]
public class DeleteCustomer : IReturn<DeleteCustomerResponse>
{
public int ID { get; set; }
}
方法实现:
public DeleteContactResponse Delete(DeleteContact request)
{
.....
}
但是每当我使用我的客户端调用这个删除时,我总是得到 "NotFound" 异常。我尝试了不同的客户端,但都出现了 404 错误。
与 Servicestack 文档一起可用的 reference link 之一一起重用了 "GET" 和 "DELETE" 动词。
另一个 link 表明并非所有浏览器都支持删除操作。
所以我想知道删除操作应该如何实现?
有关如何设计 REST-ful API with ServiceStack 的详细信息,请参阅之前的回答。
CustomerRestExample 包含客户 REST ServiceStack 服务的完整独立示例:
客户服务定义
这是典型客户 REST 服务的自定义路由和请求 DTO 示例:
[Route("/customers", "GET")]
public class GetCustomers : IReturn<GetCustomersResponse> {}
public class GetCustomersResponse
{
public List<Customer> Results { get; set; }
}
[Route("/customers/{Id}", "GET")]
public class GetCustomer : IReturn<Customer>
{
public int Id { get; set; }
}
[Route("/customers", "POST")]
public class CreateCustomer : IReturn<Customer>
{
public string Name { get; set; }
}
[Route("/customers/{Id}", "PUT")]
public class UpdateCustomer : IReturn<Customer>
{
public int Id { get; set; }
public string Name { get; set; }
}
[Route("/customers/{Id}", "DELETE")]
public class DeleteCustomer : IReturnVoid
{
public int Id { get; set; }
}
OrmLite POCO 型号:
public class Customer
{
[AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
}
本质上,自定义路由标识资源,而 HTTP VERB 指示对该资源的操作。查看 HTTP 请求可以更清楚地了解这一点:
GET /customers -> return all Customers
POST /customers -> Create a new Customer
GET /customers/1 -> return Customer 1
PUT /customers/1 -> Update Customer 1
DELETE /customers/1 -> Delete Customer 1
客户服务实施
有了上面的 DTO 定义,我们现在可以通过为每个请求 DTO 添加一个实现来实现这个客户 REST 服务 - 在这个例子中使用 OrmLite:
public class CustomerService : Service
{
public object Get(GetCustomers request)
{
return new GetCustomersResponse { Results = Db.Select<Customer>() };
}
public object Get(GetCustomer request)
{
return Db.SingleById<Customer>(request.Id);
}
public object Post(CreateCustomer request)
{
var customer = new Customer { Name = request.Name };
Db.Save(customer);
return customer;
}
public object Put(UpdateCustomer request)
{
var customer = Db.SingleById<Customer>(request.Id);
if (customer == null)
throw HttpError.NotFound("Customer '{0}' does not exist".Fmt(request.Id));
customer.Name = request.Name;
Db.Update(customer);
return customer;
}
public void Delete(DeleteCustomer request)
{
Db.DeleteById<Customer>(request.Id);
}
}
客户使用示例
通过上述客户 REST 服务实现,我们可以将 Request DTO 与 ServiceStack 的 .NET Service Clients 重用,以提供端到端类型化 API,无需代码生成,即:
var client = new JsonServiceClient(BaseUri);
//GET /customers
var all = client.Get(new GetCustomers()); // Count = 0
//POST /customers
var customer = client.Post(new CreateCustomer { Name = "Foo" });
//GET /customer/1
customer = client.Get(new GetCustomer { Id = customer.Id }); // Name = Foo
//GET /customers
all = client.Get(new GetCustomers()); // Count = 1
//PUT /customers/1
customer = client.Put(
new UpdateCustomer { Id = customer.Id, Name = "Bar" }); // Name = Bar
//DELETE /customers/1
client.Delete(new DeleteCustomer { Id = customer.Id });
//GET /customers
all = client.Get(new GetCustomers()); // Count = 0
以上评论包括在每个服务客户端示例中执行的 HTTP 操作。
我通过以下两个链接找到了第二个问题的解决方案:
1. Link1
2. Link2
我不完全理解此修复,但进行上述更改对我有用,现在我可以从任何客户端调用 Delete 函数。
第一个问题,详细请参考下方@mythz的回复
我有几个关于使用 ServiceStack 实现 REST 服务的问题。
对于 GET 操作,我定义我的请求 DTO 如下:
[Route("/Customer/{ID}", Verbs = "GET")] public class GetCustomer : IReturn<GetCustomerResponse> { .... .... }
这里"GetCustomer"是请求DTO,"GetCustomerResponse"是响应DTO。但是对于 PUT/POST/DELETE 操作,我只需要知道操作是否成功提交,如果 'not' 那么异常是什么。那么我对 POST/PUT/DELETE 的请求 dto 定义应该是什么?它应该使用如下所示的 IReturnVoid 吗?
[Route("/Customer/{ID}", Verbs = "DELETE")]
public class DeleteCustomer : IReturnVoid
{
....
....
}
如果我必须使用 IReturnVoid,那么我如何检索在提交我的操作时可能发生的任何异常信息?
在服务栈的错误处理文档中有写,我在下面引用
Error Response Types
The Error Response that gets returned when an Exception is thrown varies on whether a conventionally-named {RequestDto}Response DTO exists or not.
If it exists:
The {RequestDto}Response is returned, regardless of the service method's response type. If the {RequestDto}Response DTO has a ResponseStatus property, it is populated otherwise no ResponseStatus will be returned. (If you have decorated the {ResponseDto}Response class and properties with [DataContract]/[DataMember] attributes, then ResponseStatus also needs to be decorated, to get populated).
Otherwise, if it doesn't:
A generic ErrorResponse gets returned with a populated ResponseStatus property.
The Service Clients transparently handles the different Error Response types, and for schema-less formats like JSON/JSV/etc there's no actual visible difference between returning a ResponseStatus in a custom or generic ErrorResponse - as they both output the same response on the wire.
我没有从上面得到的是我的服务实现中 Delete 方法的 return 类型应该是什么?我如何在不定义删除响应 DTO 的情况下实现我的删除方法,但我仍然能够检索 'ErrorResponse' n 异常信息?
- 是否可以用"DELETE"动词定义路由?我有以下实施。
路线:
[Route("/DeleteCustomer/{ID}", Verbs = "DELETE")]
public class DeleteCustomer : IReturn<DeleteCustomerResponse>
{
public int ID { get; set; }
}
方法实现:
public DeleteContactResponse Delete(DeleteContact request)
{
.....
}
但是每当我使用我的客户端调用这个删除时,我总是得到 "NotFound" 异常。我尝试了不同的客户端,但都出现了 404 错误。
与 Servicestack 文档一起可用的 reference link 之一一起重用了 "GET" 和 "DELETE" 动词。
另一个 link 表明并非所有浏览器都支持删除操作。
所以我想知道删除操作应该如何实现?
有关如何设计 REST-ful API with ServiceStack 的详细信息,请参阅之前的回答。
CustomerRestExample 包含客户 REST ServiceStack 服务的完整独立示例:
客户服务定义
这是典型客户 REST 服务的自定义路由和请求 DTO 示例:
[Route("/customers", "GET")]
public class GetCustomers : IReturn<GetCustomersResponse> {}
public class GetCustomersResponse
{
public List<Customer> Results { get; set; }
}
[Route("/customers/{Id}", "GET")]
public class GetCustomer : IReturn<Customer>
{
public int Id { get; set; }
}
[Route("/customers", "POST")]
public class CreateCustomer : IReturn<Customer>
{
public string Name { get; set; }
}
[Route("/customers/{Id}", "PUT")]
public class UpdateCustomer : IReturn<Customer>
{
public int Id { get; set; }
public string Name { get; set; }
}
[Route("/customers/{Id}", "DELETE")]
public class DeleteCustomer : IReturnVoid
{
public int Id { get; set; }
}
OrmLite POCO 型号:
public class Customer
{
[AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
}
本质上,自定义路由标识资源,而 HTTP VERB 指示对该资源的操作。查看 HTTP 请求可以更清楚地了解这一点:
GET /customers -> return all Customers
POST /customers -> Create a new Customer
GET /customers/1 -> return Customer 1
PUT /customers/1 -> Update Customer 1
DELETE /customers/1 -> Delete Customer 1
客户服务实施
有了上面的 DTO 定义,我们现在可以通过为每个请求 DTO 添加一个实现来实现这个客户 REST 服务 - 在这个例子中使用 OrmLite:
public class CustomerService : Service
{
public object Get(GetCustomers request)
{
return new GetCustomersResponse { Results = Db.Select<Customer>() };
}
public object Get(GetCustomer request)
{
return Db.SingleById<Customer>(request.Id);
}
public object Post(CreateCustomer request)
{
var customer = new Customer { Name = request.Name };
Db.Save(customer);
return customer;
}
public object Put(UpdateCustomer request)
{
var customer = Db.SingleById<Customer>(request.Id);
if (customer == null)
throw HttpError.NotFound("Customer '{0}' does not exist".Fmt(request.Id));
customer.Name = request.Name;
Db.Update(customer);
return customer;
}
public void Delete(DeleteCustomer request)
{
Db.DeleteById<Customer>(request.Id);
}
}
客户使用示例
通过上述客户 REST 服务实现,我们可以将 Request DTO 与 ServiceStack 的 .NET Service Clients 重用,以提供端到端类型化 API,无需代码生成,即:
var client = new JsonServiceClient(BaseUri);
//GET /customers
var all = client.Get(new GetCustomers()); // Count = 0
//POST /customers
var customer = client.Post(new CreateCustomer { Name = "Foo" });
//GET /customer/1
customer = client.Get(new GetCustomer { Id = customer.Id }); // Name = Foo
//GET /customers
all = client.Get(new GetCustomers()); // Count = 1
//PUT /customers/1
customer = client.Put(
new UpdateCustomer { Id = customer.Id, Name = "Bar" }); // Name = Bar
//DELETE /customers/1
client.Delete(new DeleteCustomer { Id = customer.Id });
//GET /customers
all = client.Get(new GetCustomers()); // Count = 0
以上评论包括在每个服务客户端示例中执行的 HTTP 操作。
我通过以下两个链接找到了第二个问题的解决方案: 1. Link1 2. Link2
我不完全理解此修复,但进行上述更改对我有用,现在我可以从任何客户端调用 Delete 函数。
第一个问题,详细请参考下方@mythz的回复