web-dev-qa-db-ja.com

ApiControllerで生のPOSTリクエストを取得する

Paypalの即時支払い通知(IPN)を実装しようとしています

プロトコル

  1. Paypal HTTPは、イベントを通知するIPNメッセージをリスナーにPOSTします。
  2. リスナーはPaypalに空のHTTP200応答を返します。
  3. リスナーは、変更されていない完全なメッセージをPaypalにHTTPPOSTします。メッセージには、元のメッセージと同じフィールド(同じ順序)が含まれ、元のメッセージと同じ方法でエンコードされている必要があります。
  4. Paypalは、VERIFIED(メッセージが元のメッセージと一致する場合)またはINVALID(メッセージが元のメッセージと一致しない場合)のいずれかの単一の単語を送り返します。

これまでのところ私は持っています

        [Route("IPN")]
        [HttpPost]
        public void IPN(PaypalIPNBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                // if you want to use the Paypal sandbox change this from false to true
                string response = GetPayPalResponse(model, true);

                if (response == "VERIFIED")
                {

                }
            }
        }

        string GetPayPalResponse(PaypalIPNBindingModel model, bool useSandbox)
        {
            string responseState = "INVALID";
            // Parse the variables
            // Choose whether to use sandbox or live environment
            string paypalUrl = useSandbox ? "https://www.sandbox.Paypal.com/"
            : "https://www.Paypal.com/cgi-bin/webscr";

            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(paypalUrl);
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));

                //STEP 2 in the Paypal protocol
                //Send HTTP CODE 200
                HttpResponseMessage response = client.PostAsync("cgi-bin/webscr", "").Result;

                if (response.IsSuccessStatusCode)
                {
                    //STEP 3
                    //Send the Paypal request back with _notify-validate
                    model.cmd = "_notify-validate";
                    response = client.PostAsync("cgi-bin/webscr", THE RAW Paypal REQUEST in THE SAME ORDER ).Result;

                    if(response.IsSuccessStatusCode)
                    {
                        responseState = response.Content.ReadAsStringAsync().Result;
                    }
                }
            }

            return responseState;
        }

私の問題は、同じ順序でパラメーターを使用して元のリクエストをPaypalに送信する方法がわからないことです。 HttpContentを使用してPaypalIPNBindingModelを作成することはできますが、順序を保証することはできません。

これを達成する方法はありますか?

ありがとうございました

11
Marc

パラメータバインディングを使用するのではなく、生のリクエストを自分で読むだけでよいと思います。その後、自分でモデルに逆シリアル化できます。または、Web APIのモデルバインディングを活用すると同時に、生のリクエスト本文にアクセスする場合は、次の方法が考えられます。

Web APIがリクエスト本文をパラメータにバインドすると、リクエスト本文ストリームは空になります。その後、再度読むことはできません。

[HttpPost]
public async Task IPN(PaypalIPNBindingModel model)
{
    var body = await Request.Content.ReadAsStringAsync(); // body will be "".
}

したがって、WebAPIパイプラインでモデルバインディングを実行する前に本文を読み取る必要があります。メッセージハンドラを作成すると、そこに本文を準備して、リクエストオブジェクトのプロパティディクショナリに保存できます。

public class MyHandler : DelegatingHandler
{
    protected async override Task<HttpResponseMessage> SendAsync(
                                           HttpRequestMessage request, 
                                             CancellationToken cancellationToken)
    {
        if (request.Content != null)
        {
            string body = await request.Content.ReadAsStringAsync();
            request.Properties["body"] = body;
        }

        return await base.SendAsync(request, cancellationToken);
    }
}

次に、コントローラーから、次のように本文の文字列を取得できます。この時点で、生のリクエスト本文とパラメータバインドモデルがあります。

[HttpPost]
public void IPN(PaypalIPNBindingModel model)
{
    var body = (string)(Request.Properties["body"]);
}
14
Badri