Как реализовать Удалить вызов службы с помощью 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"?

  1. Можно ли определить маршрут с помощью глагола "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.