question

wavemaster avatar image
0 Votes"
wavemaster asked wavemaster commented

Webhook Stripe Event handler - calling a PATCH action method from a method in a single Controller (Microsoft?)

I have an existing Stripe integration that I am modernizing to a Web API. Using a Stripe CLI (command line interface) I can trigger a Stripe Event to my local Controller:

         [HttpPost("webhook")]
         public async Task<IActionResult> Webhook()
         {
             var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
             var ignoredEvents = new List<string>() { "payment_method.attached", "payment_intent.created", "payment_intent.succeeded", "customer.source.created", "source.chargeable", "customer.subscription.updated", "customer.updated", "invoiceitem.created", "invoiceitem.updated", "invoice.created", "plan.created", "plan.updated" };
    
             try
             {
                 var stripeEvent = EventUtility.ParseEvent(json);
                 if (!ignoredEvents.Contains(stripeEvent.Type))
                 {
                     if (stripeEvent.Type == Events.InvoiceSent)
                     {
                         var invoiceSent = stripeEvent.Data.Object as Invoice;
                         if (invoiceSent.Status == "open")
                         {
                             if (invoiceSent.SubscriptionId == null)
                             {
                                 //OwnerTxn workflow
                                 updateOwnerTxn(invoiceSent);

invoiceSent is a Stripe Invoice Object that is passed to updateOwnerTxn (a method in the same Controller:

         public void updateOwnerTxn(Invoice invoiceItem)
             {
             JsonPatchDocument<StOwnerTxn> patchDocOwnerTxn = new();
             patchDocOwnerTxn.Replace(ot => ot.InvoiceSent, invoiceItem.StatusTransitions.FinalizedAt);
             patchDocOwnerTxn.Replace(ot => ot.Modified, DateTime.UtcNow);
             var serializedItem = JsonConvert.SerializeObject(patchDocOwnerTxn);
    
             var response = PatchOwnerTxn(Convert.ToInt32(invoiceItem.Id), 
                 new StringContent(serializedItem, System.Text.Encoding.Unicode, "application/json-patch+json"));

The plan is to create the patchDoc in updateOwnerTxn and then call PatchOwnerTxn in the same Controller:

 [Route("UpdateOwnerTxn/{id}")]  
         [HttpPatch]
         public async Task<IActionResult> PatchOwnerTxn(int id, [FromBody] JsonPatchDocument<StOwnerTxn> ownerTxn)
         {
             if (ownerTxn == null) { return BadRequest(); }
    
             var theOwnerTxn = context.StOwnerTxns.FirstOrDefault(ot => ot.Id == id);
    
             if (theOwnerTxn == null) { return NotFound(); }
             ownerTxn.ApplyTo(theOwnerTxn, ModelState);
    
             var isValid = TryValidateModel(theOwnerTxn);
             if (!isValid) { return BadRequest(ModelState); }
    
             await context.SaveChangesAsync();
             return Ok();
         }

There is a squiggle under new StringContent(serializedItem, System.Text.Encoding.Unicode, "application/json-patch+json"));

Argument 2: Cannot convert from System.Net.Http.StringContent to JsonPatchDocument<BtApiEf5.Model.StOwnerTxn>, which is the red peg square hole issue, understood.

This is my pattern I use for when a Patch request is made directly to the action controller i.e. [FromBody]. What is the pattern that I need to follow here?

dotnet-aspnet-core-webapi
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

DuaneArnold-0443 avatar image
0 Votes"
DuaneArnold-0443 answered wavemaster commented

What? You can't manually format an int to a Josonpatch? You can't take an int and format it to json manually? I don't get it.

          **var response = PatchOwnerTxn(Convert.ToInt32(invoiceItem.Id), 
              new StringContent(serializedItem, System.Text.Encoding.Unicode, "application/json-patch+json"));**

https://docs.microsoft.com/en-us/aspnet/core/web-api/jsonpatch?view=aspnetcore-5.0#json-patch

· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I think you are suggesting that I forego the patchDoc and create one myself.

I have one working Patch pattern in this Blazor Server solution. In the Server project I create two patchDocs and call httpClient.PatchAsync twice. Eventually I need this to be a do or die so they both both succeed or both die. Posted this question a while back, still haven't been able to unblock from this.
In that pattern the patchDoc is in the body apparently of the the http request [From Body]

I prefer that I follow the same pattern with a patchDoc, although it may be overkill, this helps me understand the pattern. Doing this myself manually (if that is what you are suggesting?) is a refinement for later when I understand what I have so far.

In this implementation I receive a Stripe Invoice object in this one controller.
From within this same controller I need to call action method HttpPatch.

Do I need a [FromBody] in this case as this is all happening in the same controller?

Still lost basically

0 Votes 0 ·

This patchDoc thing would make sense to me if it was being applied to an entire object that was being Json serialized. But for an single int property in an object, the casting is questionable particular if the cast can't be done based on the code you have presented. Maybe you should just do it manually.

0 Votes 0 ·

I have since asked this question on Gitter aspnetcore/Blazor group.

Someone there suggested I use a service in the Web API to do the business logic and create the patchDoc there, then call HttpPatch.

No further details on how to implement, so I am still googling around to find some sample code.

0 Votes 0 ·