2

ServiceStack への Swagger プラグインに問題があります。サービスのルート記述を構成しましたが、結果の POST に本文が含まれていません。

私のサービスは次のようになります。

/// <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()
        };
    }
}

Swagger インターフェイスは要素を正しく取得しているようです。

ここに画像の説明を入力

結果は 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 が発生します。

私が間違っていることを誰かが見ることができますか?

4

2 に答える 2

4

私が見るいくつかの問題...

  • Swagger-UIを使用してフォームの投稿を模倣しようとしていると思います。この機能は先月中にswagger ( https://github.com/wordnik/swagger-core/issues/69 )に追加されたばかりなので、Nugetのダウンロードでは利用できないと思います。

  • DTOの各プロパティのParameterTypeが「body」であるため、空の本文が表示されています。Swaggerは、リクエストの本文の内容全体を含む単一の「body」値を必要としています。ボディコンテンツを構成するために、各「ボディ」プロパティをループすることはありません。[評価]テキストボックスに入力すると、リクエストにその値が表示されます(評価は「body」ParameterTypeを持つ最後のプロパティです)。

ここの例を参照してくださいhttp://petstore.swagger.wordnik.com/#!/pet/addPet_post_1

ChromeまたはFirebugを使用すると、swagger-ui.jsの行#1182の周りにブレークポイントを設定して、リクエストの本文の内容(bodyParam変数)がどのように構築されているかを確認できます。

于 2013-02-23T04:38:55.517 に答える
3

ServiceStack.Api.Swagger の最新バージョンでは、Swagger での要求本文ドキュメントのサポートが大幅に改善されていることに注意してください。現在のベスト プラクティスに従うには、必ず NuGet から ServiceStack.Api.Swagger (および他のすべての ServiceStack パッケージ) を更新してください。Api.Swagger 更新で HTML/JS/CSS ファイルを必ずマージしてください。ApiMemberすべての属性を単純なDescription属性 (System.ComponentModel.DescriptionAttribute)に置き換えます。ApiMember 属性の Name または DataType プロパティはもう必要ありません。これは、Swagger コードがリクエスト DTO でリフレクションを実行することによってこれを自動検出するためです。

ApiMember最新のコードでは、属性をまったく持つ必要がないことに注意してくださいParameterType = "body"。そのような属性がない場合は、正しいデータ型とドキュメントを含む Swagger リクエスト本文テキストエリアが自動的に生成されます。

PUT リクエストを適切に文書化するために、プロパティに1 つのApiMember属性を追加し直す必要がある場合があります。IdParameterType = "path"Verb = "PUT"

于 2013-07-26T12:42:45.113 に答える