2

クライアントアプリケーションによって消費される余分なデータが必要なのでIHttpActionResultをラップしたいと思います。ラッピングIHttpActionResult - 汎用ソリューション

私の最初のアプローチが成功した場合、結果オブジェクトをラップする、シンプルなDTOを作成して返すようにした。

レスポンスDTO:

public class Response<T> 
{ 
    public string ErrorMessage { get; set; } 
    public bool Success { get; set; } 
    public string CodeStatus { get; set; } 
    public T Result { get; set; } 

    public Response(bool isSuccess, [Optional] T result, [Optional] string codeStatus, [Optional] string errorMessage) 
    { 
     Success = isSuccess; 
     Result = result; 
     CodeStatus = codeStatus; 
     ErrorMessage = errorMessage; 
    } 
} 

コントローラー:

public IHttpActionResult Get(int id) 
    { 
     return BadRequest(new Response<MyObjectClass>(false, null,"Invalid Id",400)); 
     ... 
     return Ok(new Response<MyObjectClass>(true, result); 

    } 

、私は非常にそれを見つけましたラッピングに対処するには効果的ではありません。私はそれを非常にエレガントな方法で見つけることはできません。

例コントローラのアクション::これはまだレスポンスDTOを返す

public IHttpActionResult GetById(int id) 
    { 
     var result = _someService.Get(id); 

     if (result == null) 
      return NotFound().WithError("Invalid Id"); 

     return Ok().WithSuccess(result); 
    } 

いくつかの一般的な解決策を考え出したし、次になってしまったと私が試してみました。

私はレスポンスDTOの作成に対処するためIHttpActionResultを包みました:

public class HttpActionResult : IHttpActionResult 
{ 
    private readonly string _errorMessage; 
    private readonly IHttpActionResult _innerResult; 
    private readonly object _result; 
    private readonly bool _isSuccess; 

    public HttpActionResult(IHttpActionResult inner, bool isSuccess, object result,string errorMessage) 
    { 
     _errorMessage = errorMessage; 
     _innerResult = inner; 
     _result = result; 
     _isSuccess = isSuccess;    
    } 


    public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) 
    { 
     HttpResponseMessage response = await _innerResult.ExecuteAsync(cancellationToken); 
     response.Content = new ObjectContent(typeof(Response), new Response(_isSuccess, _result, ((int)response.StatusCode).ToString(), _errorMessage), new JsonMediaTypeFormatter()); 
     return response; 
    } 
} 

は最後に、私は、コントローラで簡単に使用することにIHttpActionResultに拡張メソッドを追加しました:

public static class IHttpActionResultExtensions 
    { 
     public static IHttpActionResult WithSuccess(this IHttpActionResult inner, object result = null, string message = null) 
     { 
      return new HttpActionResult(inner, true, result, message); 
     } 

     public static IHttpActionResult WithError(this IHttpActionResult inner, string message = null) 
     { 
      return new HttpActionResult(inner, false,null, message); 
     } 
    } 

はに代わる何ですかAPIコントローラーでhttpメッセージをラッピングすることに対処しますか? 私の弱点は何ですか?

答えて

1

はところで、私はあなたのアプローチにいくつかの弱点を参照してください。

  1. WebAPIのは、RESTfulなWebサービスを作成するために使用されることを意味しています。なぜあなたはステータスや他の詳細の別の層を提供しようとしていますか? HTTPは、これらの要件を満たすために十分に豊富です。たとえば、次のように標準ステータスコードとサブコードを使用できます。500.1500.2

  2. 成功または失敗は、HTTPステータスコードで簡単に表現できます。成功した操作の範囲は2XXで、成功しない操作の範囲はたとえば400(不正リクエスト)です。不正アクセスのための401 ...サーバーの障害のため500 ...

  3. WebAPIのは、すでにフレームワークが応答オブジェクトを作成してみましょうするModelStateを提供します。それを使用して、ホイールを再発明しないでください。

  4. また、単純にしてください。レスポンス・エンティティはレスポンス・ボディに入ります。成功または失敗はステータスコードで表されます。不正なリクエストに関する詳細は、ModelState辞書に追加されています。応答のReasonPhraseにエラーメッセージを設定する必要があります。

IHttpActionResult実装は、ドメイン結果をHTTP応答に変換するためのものです。つまり、応答オブジェクトを返信しようとするときを除いて、あなたは正しい軌道に入っています。です。IHttpActionResultを使用して、独自の応答オブジェクトのすべての詳細を標準のHTTPセマンティクスに設定し、うまく機能しているModelStateのエラーを通知する必要があります。

+0

Ad.1-2。新しいステータスコードの作成は私の意図ではありませんでした。私はちょうどこれを応答の本体に含めることを望んでいました。私はそれが応答の本文ですべてを持つことは非常に一般的なパターンであり、実際の結果はこれらの余分な情報で包まれていることを見てきました。 – laszczm

+0

広告。 3-4。私は 'ModelState'を詳述しますが、私はこのシナリオでは考慮しませんでした。私はそれを検証の目的でのみ使っています。 – laszczm

+0

@laszczm誰もが宣伝しているほどRESTfulではありません:D 3-4については、モデル検証では 'ModelState'が使用されますが、エラーの伝達だけでなく、 –

1

IHttpActionResultを避けて、結果タイプとしてHttpResponseExceptionをビジネスエンティティに使用してください。ソリューションの場合と同様に、静的に型指定されたテストケースを記述することはできません。例えば

protected void ThrowHttpError(HttpStatusCode statusCode, string message) 
{ 
    throw new HttpResponseException(
     new HttpResponseMessage(statusCode) { 
      ReasonPhrase = message, 
      // HTTP 2.0 ignores ReasonPhrase 
      // so we send ReasonPhrase again in the Content 
      Content = new StringContent(message) 
    }); 
} 


// some generic option... 
protected void ThrowHttpError<T>(HttpStatusCode statusCode, T content) 
    where T:class 
{ 
    throw new HttpResponseException(
     new HttpResponseMessage(statusCode) { 
      ReasonPhrase = "Error", 
      Content = JsonConvert.Serialize(content) 
    }); 
} 

あなたの方法、さらに詳しくは

public async Task<Product> Get(long id){ 

    var product = await context.Products 
     .FirstOrDefaultAsync(x=> x.ProductID == id); 

    if(product==null){ 
     ThrowHttpError(HttpStatusCode.NotFound, 
      $"Product not found for {id}"); 
    } 

    if(product.RequiresValidation){ 

     // generic version.... 

     ThrowHttpError(HttpStatusCode.Conflict, 
      new Product{ 
       ProductID = product.ProductID, 
       ValidationRequestCode = product.ValidationRequestCode 
     }); 
    } 

    return product; 
} 

、あなたのニーズに合った方法をThrowHttpErrorをカスタマイズすることができます。最も重要な部分は、まだテスト可能です。

関連する問題