在ApiController中获取原始帖子请求

时间:2014-10-30 19:10:39

标签: c# asp.net asp.net-web-api paypal

我正在尝试实施Paypal即时付款通知(IPN)

protocol

  1. PayPal HTTP向您的侦听器发送一条IPN消息,通知您事件。
  2. 您的侦听器向PayPal返回一个空的HTTP 200响应。
  3. 您的侦听器HTTP将完整的,未更改的消息发回 贝宝;消息必须包含相同的字段(以相同的顺序) 作为原始消息并以与之相同的方式进行编码 原始信息。
  4. PayPal发回一个单词 - 验证(如果是消息 匹配原始)或INVALID(如果消息不匹配 原)。
  5. 到目前为止我已经

            [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,但我无法保证订单。

    有什么方法可以实现这个目标吗?

    谢谢

1 个答案:

答案 0 :(得分:13)

我相信你不应该使用参数绑定,只是自己阅读原始请求。随后,您可以自己反序列化到模型中。或者,如果您想利用Web API的模型绑定,同时访问原始请求体,这是我能想到的一种方式。

当Web API将请求主体绑定到参数中时,请求主体流将被清空。随后,你再也看不懂了。

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

因此,您必须在Web API管道中运行模型绑定之前读取正文。如果您创建了一个消息处理程序,则可以在那里准备好主体并将其存储在请求对象的属性字典中。

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"]);
}