Как реализовать Удалить вызов службы с помощью ServiceStack
У меня есть несколько вопросов, связанных с реализацией службы REST с использованием ServiceStack.
-
Для операции GET я определяю свой запрос DTO следующим образом:
[Route("/Customer/{ID}", Verbs = "GET")]
public class GetCustomer : IReturn<GetCustomerResponse>
{
....
....
}
Здесь "GetCustomer" - запрос DTO, а "GetCustomerResponse" - ответ DTO. Но для операции PUT/POST/DELETE мне просто нужно знать, успешно ли операция успешно завершена или нет, и если "нет", то каково исключение. Итак, каково должно быть мое определение запроса для POST/PUT/DELETE? Должен ли он использовать IReturnVoid, как показано ниже?
[Route("/Customer/{ID}", Verbs = "DELETE")]
public class DeleteCustomer : IReturnVoid
{
....
....
}
Если мне нужно использовать IReturnVoid, то как я могу получить любую информацию об исключении, которая может возникнуть при совершении моей операции?
В документе обработки ошибок для стека служб он написан и цитирую ниже
Типы ответов об ошибках
Ответ на ошибку, возвращаемый при исключении Exception зависит от того, является ли условно названный {RequestDto} Response DTO существует или нет.
Если он существует:
Ответ {RequestDto} возвращается независимо от службы тип ответа метода. Если DTO {RequestDto} Response DTO имеет Свойство ResponseStatus, оно заселено иначе ResponseStatus будут возвращены. (Если вы украсили ответ {ResponseDto} класса и свойств с атрибутами [DataContract]/[DataMember], затем ResponseStatus также необходимо украсить, чтобы заполнить).
В противном случае, если это не так:
Общий ответ ErrorResponse возвращается с заполненным ResponseStatus свойство.
Клиенты службы прозрачно обрабатывают различные ответы об ошибках типы, а для безрисковых форматов, таких как JSON/JSV/etc, нет фактических видимая разница между возвратом ResponseStatus в пользовательском или generic ErrorResponse - поскольку оба они выдают один и тот же ответ на провода.
То, что я не получаю сверху, должно быть типом возврата для моего метода Delete в моей реализации сервиса? Как я могу реализовать свой метод удаления без определения ответа DTO удаления, но все же я могу получить информацию об исключении "ErrorResponse"?
- Можно ли определить маршрут с помощью глагола "DELETE"? У меня есть реализация.
Маршрут:
[Route("/DeleteCustomer/{ID}", Verbs = "DELETE")]
public class DeleteCustomer : IReturn<DeleteCustomerResponse>
{
public int ID { get; set; }
}
Реализация метода:
public DeleteContactResponse Delete(DeleteContact request)
{
.....
}
Но всякий раз, когда я вызываю это удаление с помощью моего клиента, я всегда получаю исключение "NotFound". Я пробовал разные клиенты, но со всем получаю ошибку 404.
Одна из ссылок доступных вместе с документом Servicestack, повторно использует глагол "GET" и "DELETE" вместе.
В другой ссылке показано, что не все браузеры поддерживают операцию удаления.
Так интересно, как должна быть реализована операция удаления?
Ответы
Ответ 1
Я получил исправление для своего второго вопроса из следующих двух ссылок:
1. Link1
2. Link2
Я не полностью понимаю это исправление, но выполнение вышеперечисленных изменений сработало для меня, и теперь я могу вызывать функцию Delete от любых клиентов.
Для 1-го вопроса, pls ссылаются на @mythz ответ ниже подробно.
Ответ 2
Подробнее об оформлении REST-ful API с ServiceStack см. в этом более раннем ответе.
CustomerRestExample содержит полный автономный пример службы REST ServiceStack клиента:
Определение обслуживания клиентов
Вот пример пользовательских маршрутов и запроса DTO, к которым может выглядеть типичная служба REST клиента:
[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 мы теперь можем реализовать эту службу REST клиентов, добавив реализацию для каждого запроса DTO - в этом примере, используя 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 Service клиента мы можем повторно использовать запрос DTO с ServiceStack .NET Service Clients, чтобы предоставить конечный результат, для конечного типизированного API без кода-gen, то есть:
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-операции, выполняемые в каждом примере Service Client.