bchavez / Coinbase.Commerce

:moneybag: A .NET/C# implementation of the Coinbase Commerce API.
https://commerce.coinbase.com/docs/
Other
48 stars 9 forks source link

The application completed without reading the entire request body. #7

Closed chuksgpfr closed 5 years ago

chuksgpfr commented 5 years ago

Request.Body.Seek(0, SeekOrigin.Begin); using (var reader = new StreamReader(Request.Body)) { var json =await reader.ReadToEndAsync(); }

when testing my webhook, it throws 500 internal server error. and then in my server i see this error "The application completed without reading the entire request body."

bchavez commented 5 years ago

Hi @chuksgpfr ,

You'll have to provide more information:

chuksgpfr commented 5 years ago
  1. I can't get stack trace now..
  2. The complete controller handling the webhook is...
        [HttpPost]
        [AllowAnonymous]
        public async Task<ActionResult> BalanceAccount()
        {
            string sharedSecret = "ff9a9b56-4b94-ffac-9c9f-97f9937d2d6c";
            var requestSignature = Request.Headers[HeaderNames.WebhookSignature];
            Request.Body.Seek(0, SeekOrigin.Begin);
            using (var reader = new StreamReader(Request.Body))
            {
                var json =await reader.ReadToEndAsync();

                if (WebhookHelper.IsValid(sharedSecret, requestSignature, json))
                {
                    var webhook = JsonConvert.DeserializeObject<Webhook>(json);
                    var chargeInfo = webhook.Event.DataAs<Charge>();
                    //the customer id created in the charge controller
                    var customerId = chargeInfo.Metadata["customerId"].ToObject<string>();

                    if (webhook.Event.IsChargeConfirmed)
                    {
                        var user = await _userRepo.FindById(customerId);
                        //if (user != null)
                        //{
                        var bal = _contextRepo.FindBalanceByUserId(customerId);
                        FundAccount newFund = new FundAccount()
                        {
                            User = user,
                            Amount = chargeInfo.Pricing["Amount"].Amount,
                            PaymentMethod = "BITCOIN",
                            AccountDetails = chargeInfo.Addresses["bitcoin"],
                            TransactionId = Guid.NewGuid().ToString(),
                            Status = "PAID",
                            Date = chargeInfo.ConfirmedAt
                        };
                        if (bal == null)
                        {
                            Balance newBalance = new Balance()
                            {
                                User = user,
                                Amount = chargeInfo.Pricing["Amount"].Amount,
                                DateUpdated = DateTime.UtcNow
                            };
                            _contextRepo.CreateBalance(newBalance);
                        }
                        else
                        {
                            bal.Amount += chargeInfo.Pricing["Amount"].Amount;
                            bal.DateUpdated = DateTime.UtcNow;
                            _contextRepo.UpdateBalance(bal);
                        }

                        _contextRepo.FundAccount(newFund);
                        // return RedirectToAction("fundlist", "dashboard");
                        //}

                        return Ok(new { userId = "Yes" });
                    }
                }
            }
            //var json = await new StreamReader(Request.Body).ReadToEndAsync();

            // StreamReader SourceReader = System.IO.File.OpenText()

            //Create a successful payment page
            return Ok(new { userId = "customerId"});
        }
  1. ASP.NET core version 2.1 .NET core 2.2 OS is windows 10. Hosting environment is IISExpress
bchavez commented 5 years ago

@chuksgpfr , you might want to call this.Request.EnableRewind() so you can rewind the request stream. For performance reasons, the request stream can only be read forward once. So, you'll need to tell ASPNET you want to rewind the stream. Here's a working example of how to read from the request body stream.

using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.Mvc;

namespace FooBar.Controllers
{
   [Route("api/[controller]")]
   [ApiController]
   public class ValuesController : ControllerBase
   {
      // POST api/values
      [HttpPost]
      public async Task<ActionResult> Post()
      {
         this.Request.EnableRewind(); // <-- This is very important

         var body = this.Request.Body;
         body.Seek(0, SeekOrigin.Begin);

         using (var reader = new StreamReader(body))
         {
            var payload = await reader.ReadToEndAsync();

            return Ok(payload);
         }
      }
   }
}

Reference: #1

bchavez commented 5 years ago

Hi @chuksgpfr , I hope my last post help you solve your issue. If you have any other questions, feel free to continue posting here. For now, I'm going to close the issue. Thanks again for asking your question.

-Brian

chuksgpfr commented 5 years ago

Hi @bchavez I'm sorry for the late reply, SCHOOL ISSUES...

While sending a test webhook from coinbase, i'm still getting 500 internal server error...

Please can u create an actual project and try. This will be very helpful to me.

Thanks..

PS: I'm testing locally using ngrok. Thanks. Coinbase Shows "Remote server at 6f7d068b.ngrok.io returned an HTTP 502" while ngrok shows no error using https

chuksgpfr commented 5 years ago

Thanks man.....

Just fixed it.

chuksgpfr commented 5 years ago

Quick question... When sending a test from coinbase, does it carry any information on the body and is the test different from the actual webhook. Because this lines of code refuse to run.

AccountDetails = chargeInfo.Addresses["bitcoin"] Amount = chargeInfo.Pricing["Amount"].Amount

bchavez commented 5 years ago

Hi @chuksgpfr ,

The HTTP body of the webhook should contain something. You'll need to read the body into the webhook object model to get more details about what that object is. The line below illustrates how to read the body into a Webhook object:

var webhook = JsonConvert.DeserializeObject<Webhook>(Request.Body.Json);

Again, don't forget to EnableRewind() to read the body. Set a breakpoint on the line above to debug.

Also, you'll have to examine the ngrok Web Interface to look at more details of the webhook payload that is hitting your endpoint for the exact HTTP payload details of what was sent to you.

cmd_3324

From these, it should be clear after examining the breakpoint on the webhook object and by examining the ngrok web interface what is being delivered to your endpoint; and ultimately, what you have access to.

Additionally, chargeInfo.Pricing["Amount"].Amount seems redundant. It should be something more simple like chargeInfo.Pricing.Amount.


Lastly, I want to help with friendly advice: please remember, anytime you have an issue with code and you have to report an issue to a person who is not next to you (like over the Internet), please always remember that the other person doesn't have access to your computer and it is very hard for the other person to get an idea of what your problem is without being next to you to help you.

It's very difficult for everyone to provide help over the Internet just by writing text. :cry: So, here are some helpful tips to make the process more successful for everyone:

When reporting an issue to someone --

The more things you can provide about the problem, the more successful we will all be in helping you resolve those issues.