Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

checkout_beta.session_succeeded is throwing a null pointer when parsed with EventUtility.ConstructEvent #1452

Closed
da1rren opened this issue Jan 3, 2019 · 8 comments

Comments

@da1rren
Copy link

da1rren commented Jan 3, 2019

Example code:

    [AllowAnonymous]
    [Route("api/[controller]/[action]")]
    public class StripeController : Controller
    {
        private readonly string SigningSecret;
        private readonly IMediator _mediator;

        public StripeController(IMediator mediator, ApplicationConfiguration configuration)
        {
            SigningSecret = configuration.STRIPE_SIGNING_SECRET;
            _mediator = mediator;
        }

        public async Task<IActionResult> Webhook()
        {
            var @event = await GetEventAsync();
            INotification notification = null;

            switch (@event.Type)
            {
                case "invoice.payment_succeeded":
                    notification = new PaymentSuccessfulNotification(@event);
                    break;
                case "invoice.payment_failed":
                    notification = new PaymentFailedNotification(@event);
                    break;
            }

            if(notification != null)
            {
                await _mediator.Publish(notification);
            }

            return Ok();
        }

        // Consider creating a custom model binder instead.
        private async Task<Event> GetEventAsync()
        {
            using (var reader = new StreamReader(Request.Body, Encoding.UTF8))
            {
                var json = await reader.ReadToEndAsync();
                return EventUtility.ConstructEvent(json, Request.Headers["Stripe-Signature"], SigningSecret);
            }
        }
    }
@ob-stripe
Copy link
Contributor

Hi @da1rren. Can you share the stacktrace?

@ob-stripe
Copy link
Contributor

Ah wait, I misunderstood. I thought ConstructEvent was raising a NullReferenceException, but what you're saying is that @event.Data.Object is null, correct? If so, that's expected as the current version of Stripe.net doesn't support checkout_beta.session_succeeded events yet.

@da1rren
Copy link
Author

da1rren commented Jan 3, 2019

@ob-stripe So the expected behaviour of attempting to process a checkout_beta.session_succeeded is an exception?

System.ArgumentNullException
  HResult=0x80004003
  Message=Value cannot be null.
  Source=System.Private.CoreLib
  StackTrace:
   at System.ThrowHelper.ThrowArgumentNullException(ExceptionArgument argument)
   at System.Collections.Generic.Dictionary`2.FindEntry(TKey key)
   at Stripe.Infrastructure.AbstractStripeObjectConverter`1.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonConverter[] converters)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonConverter[] converters)
   at Stripe.Mapper`1.MapFromJson(String json, String parentToken, StripeResponse stripeResponse)
   at Stripe.EventUtility.ConstructEvent(String json, String stripeSignatureHeader, String secret, Int64 tolerance, Int64 utcNow)
   at Stripe.EventUtility.ConstructEvent(String json, String stripeSignatureHeader, String secret, Int64 tolerance)
   at Core.LRS.Portal.Features.Stripe.StripeController.<GetEventAsync>d__4.MoveNext() in C:\Projects\Repositories\CoreLRS\src\Core.LRS.Portal\Features\Stripe\StripeController.cs:line 55

@ob-stripe
Copy link
Contributor

No, that's unexpected. Thanks for the clarification.

So this seems to a combination of two issues:

  • a server-side issue where the object key is missing in the JSON for the nested object
  • a Stripe.net issue where the case where object is missing is not handled

I'll push a fix for Stripe.net in a few minutes, and I've reported the server-side issue internally. Once the server-side issue is fixed, you'll be able to use the branch in #1440 if you want to actually handle checkout_session objects in your webhook handler.

@ob-stripe
Copy link
Contributor

Alright, this should be fixed in 21.8.1 which will be available in NuGet in a few minutes. Feel free to reply if you're still having issues after upgrading.

@da1rren
Copy link
Author

da1rren commented Jan 3, 2019

Thanks @ob-stripe, that seems to have fixed the exception. But do you have any idea when the fix server side will be deployed? As until then I'm going to have to rig it so I can still access the clientReferenceId on the object returned from the server.

@ob-stripe
Copy link
Contributor

Can't make any promises, but hopefully later today!

@remi-stripe
Copy link
Contributor

So we're going to fix object to be checkout_beta server-side. This will still not be deserialized by the library though since it's a beta resource and you'll need to parse the JSON on your end!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants