2013-02-22 3 views
2

У меня возникли проблемы с Swagger plugin to ServiceStack. Я настроил описания маршрутов для моего сервиса, но полученный POST не содержит тело.Swagger for ServiceStack POST пустой корпус

My Service выглядит следующим образом:

/// <summary> 
/// Define your ServiceStack web service request (i.e. Request DTO). 
/// </summary> 
/// <remarks>The route is defined here rather than in the AppHost.</remarks> 
[Api("GET or DELETE a single movie by Id. Use POST to create a new Movie and PUT to update it")] 
[Route("/movie", "POST", Summary = @"POST a new movie", Notes = "Send a movie here")] 
[Route("/movie/{Id}", "GET,PUT,DELETE", Summary = @"GET, PUT, or DELETE a movie", Notes = "GET a specific movie by Id, or PUT a thing, or delete a movie")] 
public class Movie 
{ 
    /// <summary> 
    /// Initializes a new instance of the movie. 
    /// </summary> 
    public Movie() 
    { 
     this.Genres = new List<string>(); 
    } 

    /// <summary> 
    /// Gets or sets the id of the movie. The id will be automatically incremented when added. 
    /// </summary> 
    //[AutoIncrement] 
    [ApiMember(Name = "Id", Description = "The Id of this movie", ParameterType = "body", DataType = "string", IsRequired = false)] 
    public string Id { get; set; } 

    [ApiMember(Name = "ImdbId", Description = "The ImdbId of this movie", ParameterType = "body", DataType = "string", IsRequired = false)] 
    public string ImdbId { get; set; } 

    [ApiMember(Name = "Title", Description = "The Title of this movie", ParameterType = "body", DataType = "string", IsRequired = false)] 
    public string Title { get; set; } 

    [ApiMember(Name = "Rating", Description = "The Rating of this movie", ParameterType = "body", DataType = "decimal", IsRequired = false)] 
    public decimal Rating { get; set; } 

    [ApiMember(Name = "Director", Description = "The Director of this movie", ParameterType = "string", DataType = "string", IsRequired = false)] 
    public string Director { get; set; } 

    [ApiMember(Name = "ReleaseDate", Description = "The ReleaseDate of this movie", ParameterType = "string", DataType = "Date", IsRequired = false)] 
    public DateTime ReleaseDate { get; set; } 

    [ApiMember(Name = "TagLine", Description = "The TagLine of this movie", ParameterType = "string", DataType = "string", IsRequired = false)] 
    public string TagLine { get; set; } 

    [ApiMember(Name = "Genres", Description = "The Genres of this movie", ParameterType = "string", DataType = "string", IsRequired = false)] 
    public List<string> Genres { get; set; } 
} 

/// <summary> 
/// Define your ServiceStack web service response (i.e. Response DTO). 
/// </summary> 
public class MovieResponse 
{ 
    /// <summary> 
    /// Gets or sets the movie. 
    /// </summary> 
    public Movie Movie { get; set; } 
} 

/// <summary> 
/// Create your ServiceStack restful web service implementation. 
/// </summary> 
public class MovieService : Service 
{ 
    public IMovieRepository MovieRepository { get; set; } 

    /// <summary> 
    /// GET /movies/{Id} 
    /// </summary> 
    public MovieResponse Get(Movie movie) 
    { 
     var item = MovieRepository.FindOne(new ObjectId(movie.Id)); 

     return new MovieResponse 
     { 
      Movie = item, 
     }; 
    } 

    /// <summary> 
    /// POST /movies 
    /// 
    /// returns HTTP Response => 
    ///  201 Created 
    ///  Location: http://localhost/ServiceStack.MovieRest/movies/{newMovieId} 
    ///  
    ///  {newMovie DTO in [xml|json|jsv|etc]} 
    /// 
    /// </summary> 
    public object Post(Movie movie) 
    { 
     MovieRepository.Save(movie); 
     var newMovieId = movie.Id; 

     var newMovie = new MovieResponse 
     { 
      Movie = MovieRepository.FindOne(new ObjectId(movie.Id)) 
     }; 

     return new HttpResult(newMovie) 
     { 
      StatusCode = HttpStatusCode.Created, 
      Headers = { 
       { HttpHeaders.Location, base.Request.AbsoluteUri.CombineWith(newMovieId) } 
      } 
     }; 
    } 

    /// <summary> 
    /// PUT /movies/{id} 
    /// </summary> 
    public object Put(Movie movie) 
    { 
     MovieRepository.Save(movie); 

     return new HttpResult 
     { 
      StatusCode = HttpStatusCode.NoContent, 
      Headers = { 
       { HttpHeaders.Location, this.RequestContext.AbsoluteUri.CombineWith(movie.Id) } 
      } 
     }; 
    } 

    /// <summary> 
    /// DELETE /movies/{Id} 
    /// </summary> 
    public object Delete(Movie request) 
    { 
     MovieRepository.Remove(new ObjectId(request.Id)); 

     return new HttpResult 
     { 
      StatusCode = HttpStatusCode.NoContent, 
      Headers = { 
       { HttpHeaders.Location, this.RequestContext.AbsoluteUri.CombineWith(request.Id) } 
      } 
     }; 
    } 
} 

/// <summary> 
/// Define your ServiceStack web service request (i.e. Request DTO). 
/// </summary> 
/// <remarks>The route is defined here rather than in the AppHost.</remarks> 
[Api("Find movies by genre, or all movies if no genre is provided")] 
[Route("/movies", "GET, OPTIONS")] 
[Route("/movies/genres/{Genre}")] 
public class Movies 
{ 
    public string Genre { get; set; } 
} 

/// <summary> 
/// Define your ServiceStack web service response (i.e. Response DTO). 
/// </summary>  
public class MoviesResponse 
{ 
    /// <summary> 
    /// Gets or sets the list of movies. 
    /// </summary> 

    public List<Movie> Movies { get; set; } 
} 

/// <summary> 
/// Create your ServiceStack RESTful web service implementation. 
/// </summary> 
public class MoviesService : Service 
{ 
    public IMovieRepository MovieRepository { get; set; } 

    /// <summary> 
    /// GET /movies 
    /// GET /movies/genres/{Genre} 
    /// </summary> 
    public object Get(Movies request) 
    { 
     return new MoviesResponse 
     { 
      Movies = MovieRepository.FindAll().ToList() 
     }; 
    } 
} 

чванство интерфейс, кажется, подобрали элементы правильно:

enter image description here

Результаты является 500 ошибка:

POST http://localhost:57853/movie HTTP/1.1 
Host: localhost:57853 
Connection: keep-alive 
Content-Length: 0 
Accept: application/json, text/javascript, */*; q=0.01 
Origin: http://localhost:57853 
X-Requested-With: XMLHttpRequest 
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17 
Content-Type: application/json 
Referer: http://localhost:57853/swagger-ui/index.html 
Accept-Encoding: gzip,deflate,sdch 
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6 
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 

POST корпус не прилагается Swagger. Content-Length: 0. Результатом является пустой объект запроса, что приводит к исключению NullReferenceException.

Может ли кто-нибудь увидеть что-нибудь, что я делаю неправильно?

+0

Хорошо, я вижу, что это неправильный тип здесь. Если я верну их к примитивным типам, до сих пор не буду радоваться. – Junto

ответ

4

Пара вопросов, я вижу ...

  • Я думаю, что вы пытаетесь имитировать форму пост, используя Swagger-интерфейс. Эта функция была добавлена ​​в swagger (https://github.com/wordnik/swagger-core/issues/69) в течение последнего месяца, поэтому я не думаю, что она доступна в загрузке Nuget.

  • Вы видите пустое тело, потому что ваш ParameterType является «телом» для каждого свойства вашего DTO. Swagger хочет получить одно «тело», которое должно содержать содержимое всего тела запроса. Это не зацикливание каждого из ваших свойств тела, чтобы составить содержимое тела. Если вы заполняете текстовое поле «Рейтинг», вы должны увидеть его значение в запросе («Рейтинг» - это ваше последнее свойство с «body» ParameterType).

см пример здесь http://petstore.swagger.wordnik.com/#!/pet/addPet_post_1

Использование Chrome или Firebug вы можете установить контрольную точку вокруг линии # 1182 в чванство-ui.js, чтобы посмотреть, как это наращивая содержимое тела запроса (переменная bodyParam)

3

Обратите внимание, что в последней версии ServiceStack.Api.Swagger значительно улучшена поддержка документации тела запроса в Swagger. Чтобы следовать текущей лучшей практике, убедитесь, что вы обновили ServiceStack.Api.Swagger (и все остальные пакеты ServiceStack) от NuGet. Убедитесь, что вы объединились в файлы HTML/JS/CSS в обновлении Api.Swagger. Замените все свои атрибуты ApiMember на простые атрибуты Description (System.ComponentModel.DescriptionAttribute). Вам больше не нужны свойства Name или DataType из атрибутов ApiMember, потому что код Swagger автоматически обнаружит это, отразив ваш запрос DTO.

Обратите внимание, что с последним кодом вам не нужно иметь никаких атрибутов ApiMember с ParameterType = "body". Если у вас нет таких атрибутов, он автоматически генерирует текстовое поле запроса запроса Swagger с правильным типом данных и документацией.

Вы можете добавить один ApiMember атрибут обратно для Id собственности, с ParameterType = "path" и Verb = "PUT" правильно документировать запрос PUT.