webhooks

Oct 18, 2011 at 12:16 PM

Hi, 

As Chargify doco now states that Webhooks are a prefered method over postbacks could you provide us with a small example of their usage and support in Chargify.NET?

Regards Ismar

Oct 19, 2011 at 2:15 PM

Hi Again, 

I can see that there is a IHttpHandler class  - Webhookhandler.cs that can be used to handle webhook requests.

It parses the headers and passes the content to the application via override of OnChargifyUpdate method.

Since the content of Chargify data POST is of type "application/x-www-form-urlencoded"  I'm thinking that , in the ProcessRequest method of the handler, it might be better to pass in the  the request.Forms (NamevalueCollection)  to the OnChargifyUpdate rather then just oassing the row string with form values encoded in it? These would be easier to parse and get event types and payloads from the content ?

Ismar

Oct 25, 2011 at 4:55 PM

I created .NET web application that will capture Chargify postback data and save it into a local SQL database.

It writes the data into 3 relational tables, customers, orders and payments.   It parses the data, saves it in an object and writes it to the database based on the event.  It has a debug location for capturing the chargify data, and web page to resend the data for testing.

I am willing to donate my work if others are interested, please let me know if anyone is intereted.

Oct 26, 2011 at 7:05 AM

That sounds great , not just because I'm in the process of doing a similar thing :-).

Maybe you can add the code to the source as a separate project. 

Also, for webhook handlers one needs a public-facing url, so here is some code that would "redirect" the requests to your local development server for easy debugging of incoming events (change the url in the WebRequest.Create method to point to your handler).

if (Request.HttpMethod == "POST")
        {
            //
            // Get the post stream and put it to the buffer from chargify
            var buffer = new byte[Request.InputStream.Length];
            Request.InputStream.Read(buffer, 0, buffer.Length);

            //
            // Create a new request with the address you want to redirect
            var request = (HttpWebRequest)WebRequest.Create("http://csdevl068:77/Compusight.esign365/ChargifyWebbhook.axd");
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = buffer.Length;
            //request.UseDefaultCredentials = true;

            foreach (string name in Request.Headers.AllKeys)
            {
                if ((string.Compare(name, ChargifyWebHookSignatureHeader) == 0) ||
                    (string.Compare(name, ChargifyWebHookIdHeader) == 0))
                {
                    request.Headers.Add(name, Request.Headers[name]);
                }
            }

            // Write it to the request stream and make the call
            var stream = request.GetRequestStream();
            stream.Write(buffer, 0, buffer.Length);
            stream.Close();

            var result = request.GetResponse();

            Response.Write("OK");
        }

Note that I have tried doing just a simple Redirect but the Chargify detects this as an invalid operation (maybe because of security?) and will not accept it (after support call to Chargify).
You may also need something like Rinetd utility to map requests to your IIS onto your development server.
Regards and looking forward to seeing your code.

 

Oct 26, 2011 at 4:53 PM

I am not much of a programmer any more, tried to read your example but did not follow it much.  I just grab the data in the form load event of the web page, and parse the data into an object.  Then I save to the data base based on the object type. 

I had trouble getting the data to my development workstation, so I just ended up debugging with text files right on the IIS server.  It was lots of tedious work setting up the parsing object and the database structure.  I created a DB that contains most of the fields Chargify sends, garbage in garbage out approach, never know when data might be important.  In the Database save I everything for new sign up events, and only need to update a few fields for other events. 

Here is the my code where I grab the chargify data:



        protected void Page_Load(object sender, EventArgs e)
        {
            //we recieved Chargify post data.  We parse the data and transfer to
            //Chargify data object.  We then save data as needed to database.

            StringBuilder sb = new StringBuilder();
            ChargifyPostData buyrecord = new ChargifyPostData();
            try
            {
                StreamReader reader = new StreamReader(Page.Request.InputStream);
                String data = reader.ReadToEnd();
                sb.AppendLine(data);


                //here we save the postback data to debug location
                System.IO.File.WriteAllText(Server.MapPath(".") + @"\debug\" + Guid.NewGuid() + ".txt", sb.ToString());


                buyrecord.debug = "Post data parsed, below are unmached items will listed";


                string[] split1  = data.Split(new char[] { '&' });
                //System.Console.WriteLine("{0} words in text:", words.Length);

                foreach (string entry in split1)
                {
                    string[] split2 = entry.Split(new char[] { '=' });
                    if (split2.Length == 2)
                    {

                        //payload[subscription][customer][reference]
                        string name = split2[0];
                       
                        string value = split2[1];

                        buyrecord.addproperty(split2[0], split2[1]);
                       

                    }
         
                }


                buyrecord.SavetoDatabase();

Oct 27, 2011 at 8:49 AM
Thanks,
I think it would be much simpler to get payloads as a collection of namevalue pairs (this is how Chargify sends them as they use "application/x-www-form-urlencoded" type for data).
This would require changes to the OnChargifyUpdate abstract class to say replace last parameter of rowdata (string) with HttpContext.Request of the Chargify context. In this way one could get both row data (needed for verification) and NameValueCollection of data for parsing of different payloads.
Your approach will work OK for your purposes though, but should one need to get hold of individual payload items then my approach would be better.
Regards


From: [email removed]
To: [email removed]
Date: Wed, 26 Oct 2011 09:53:21 -0700
Subject: Re: webhooks [chargify:276278]

From: bcurtin
I am not much of a programmer any more, tried to read your example but did not follow it much. I just grab the data in the form load event of the web page, and parse the data into an object. Then I save to the data base based on the object type.
I had trouble getting the data to my development workstation, so I just ended up debugging with text files right on the IIS server. It was lots of tedious work setting up the parsing object and the database structure. I created a DB that contains most of the fields Chargify sends, garbage in garbage out approach, never know when data might be important. In the Database save I everything for new sign up events, and only need to update a few fields for other events.
Here is the my code where I grab the chargify data:

protected void Page_Load(object sender, EventArgs e)
{
//we recieved Chargify post data. We parse the data and transfer to
//Chargify data object. We then save data as needed to database.
StringBuilder sb = new StringBuilder();
ChargifyPostData buyrecord = new ChargifyPostData();
try
{
StreamReader reader = new StreamReader(Page.Request.InputStream);
String data = reader.ReadToEnd();
sb.AppendLine(data);

//here we save the postback data to debug location
System.IO.File.WriteAllText(Server.MapPath(".") + @"\debug\" + Guid.NewGuid() + ".txt", sb.ToString());

buyrecord.debug = "Post data parsed, below are unmached items will listed";

string[] split1 = data.Split(new char[] { '&' });
//System.Console.WriteLine("{0} words in text:", words.Length);
foreach (string entry in split1)
{
string[] split2 = entry.Split(new char[] { '=' });
if (split2.Length == 2)
{
//payload[subscription][customer][reference]
string name = split2[0];

string value = split2[1];
buyrecord.addproperty(split2[0], split2[1]);

}

}

buyrecord.SavetoDatabase();
Read the full discussion online.
To add a post to this discussion, reply to this email (chargify@discussions.codeplex.com)
To start a new discussion for this project, email chargify@discussions.codeplex.com
You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.
Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com