Sunday 24 July 2016

Complete Facebook bot messenger implementation & Integration in C#

Most of the messenger platforms already welcomed "BOTS" to their platforms. Facebook is one of them. With a whooping 1 billion active monthly users, it is a great platform for developers & businesses to develop "Bot" for FB messenger.

In this article I'm not going to discuss about what are bots and why do we need to implement.

This article will give you the idea on how to implement basic Bot in C#.

Setup C# project:

1) Create am empty WebApi project.




2) Prefer host it in cloud. (All microsoft developers get $25 free credit in Azure. Utilize it and create a free web app). Facebook needs a secure public URL for integration.

3) Once the project is created, create an empty webapi controller and give a proper name to it. This is a very important step. This controller is the only gateway to facebook. We need to configure this in FB webhooks as part of integration(That will come later).

4) We need to create two methods in the controller. One is "Get" and another is "Post". 
  • "Get" method will be called for the first time when we integrate webhook with the FB app. This will check that our secret key is matching the configured key. If matched FB app initiates the connection and sends all the messages to "Post" method of the WebApi controller.
public async Task<HttpResponseMessage> Get()  
     {  
       var verify_token = "Your_Verification_Token";  
       var hub_verify_token = string.Empty;  
       var challenge = string.Empty;  
       if (!string.IsNullOrEmpty(HttpContext.Current.Request.QueryString["hub.challenge"]))  
       {  
         challenge = HttpContext.Current.Request.QueryString["hub.challenge"];  
         hub_verify_token = HttpContext.Current.Request.QueryString["hub.verify_token"];  
       }  
       if (verify_token == hub_verify_token)  
       {  
         return new HttpResponseMessage()  
         {  
           Content = new StringContent(  
             challenge,  
             Encoding.UTF8,  
             "text/html"  
           )  
         };  
       }  
       return new HttpResponseMessage()  
       {  
         Content = new StringContent(  
             challenge,  
             Encoding.UTF8,  
             "text/html"  
           )  
       };  
     }  
  • "Post" method is the operation part. Each message from facebook will have "sender", "recipient" and "message" nodes. In the "Post" method we have to catch all the messages and send the appropriate message back to the sender. Sample Json message from FB is like below.



Setup Facebook app:

1) Create a Facebook App and Page

Create a new Facebook App and Page or use existing ones. Go to the App Dashboard and under Product Settings click "Add Product" and select "Messenger."




2) Setup Webhook

In the Webhooks section, click "Setup Webhooks."



Enter a URL for a webhook(This is the URL for the project we hosted in the cloud. Eg: "https://mydemo.azurewebsites.net/api/webhook"), enter a Verify Token (We need to use the same token what we have used in the project WebApi "Get" method.) and select message_deliveries, messages, messaging_optins, and messaging_postbacks under Subscription Fields.



3) Get a Page Access Token

In the Token Generation section, select your Page. A Page Access Token will be generated for you. Copy this Page Access Token. Note: The generated token will NOT be saved in this UI. Each time you select that Page a new token will be generated. However, any previous tokens created will continue to function.

This token will be used in code to send back messages to FB app.


4) Subscribe the App to the Page

 In the Webhooks section, you can subscribe the webhook for a specific page.



Send & Receive messages:

Now the project is setup and  Facebook app & page are also setup. Now the main implementation of the app. When some one sends a message to the page, the message will be delivered to "Post" method in the WebApi.

We need to create two model classes for request and response.

FbRequest class:

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Web;  
 namespace FbBot.Models  
 {  
   public class FbRequest  
   {  
     public IEnumerable<Entry> entry { get; set; }  
   }  
   public class Entry  
   {  
     public long id { get; set; }  
     public long time { get; set; }  
     public IEnumerable<Messaging> messaging { get; set; }  
   }  
   public class Messaging  
   {  
     public Person sender { get; set; }  
     public Person recipient { get; set; }  
     public long timestamp { get; set; }  
     public Message message { get; set; }  
     public postback postback { get; set; }  
   }  
   public class Person  
   {  
     public string id { get; set; }  
   }  
   public class Message  
   {  
     public string mid { get; set; }  
     public string seq { get; set; }  
     public string text { get; set; }  
   }  
   public class postback  
   {  
     public string payload { get; set; }  
   }  
 }  


FbResponse class:

using Newtonsoft.Json;  
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Web;  
 namespace FbBot.Models  
 {  
   [Serializable]  
   public class FbResponse  
   {  
     public Person recipient { get; set; }  
     public ResponseMessage message { get; set; }  
   }  
   [Serializable]  
   public class ResponseMessage  
   {  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public string text { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public Attachment attachment { get; set; }  
   }  
   public class Attachment  
   {  
     public string type { get; set; }  
     public Payload payload { get; set; }  
   }  
   public class Payload  
   {  
     public string template_type { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public string text { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public IEnumerable<Button> buttons { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public IEnumerable<Element> elements { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public Address address { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public Summary summary { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public IEnumerable<Adjustment> adjustments { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public string recipient_name { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public string order_number { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public string currency { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public string payment_method { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public string order_url { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public string timestamp { get; set; }  
   }  
   public class Button  
   {  
     public string type { get; set; }  
     public string url { get; set; }  
     public string title { get; set; }  
     public string payload { get; set; }  
   }  
   public class Element  
   {  
     public string title { get; set; }  
     public string image_url { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public string item_url { get; set; }  
     public string subtitle { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public IEnumerable<Button> buttons { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public string price { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public string currency { get; set; }  
     [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]  
     public string quantity { get; set; }  
   }  
   public class Address  
   {  
     public string street_1 { get; set; }  
     public string street_2 { get; set; }  
     public string city { get; set; }  
     public string postal_code { get; set; }  
     public string state { get; set; }  
     public string country { get; set; }  
   }  
   public class Summary  
   {  
     public string subtotal { get; set; }  
     public string shipping_cost { get; set; }  
     public string total_tax { get; set; }  
     public string total_cost { get; set; }  
   }  
   public class Adjustment  
   {  
     public string name { get; set; }  
     public string amount { get; set; }  
   }  
 }  


These classes are very handy. These will be useful for strict binding.

Now the "Post" method:

[HttpPost]  
     // POST api/<controller>  
     public async Task<IHttpActionResult> Post([FromBody] FbRequest request)  
     {  
         
       FbResponse fbResponse = null;  
       foreach (var item in request.entry.LastOrDefault().messaging)  
       {  
         var messageEvent = item;  
         var sender = item.sender.id;  
         var messageText = item.message?.text ?? string.Empty;  
         if (!string.IsNullOrEmpty(messageText))  
         {  
           try  
           {  
             fbResponse = new FbResponse() { recipient = new Person { id = sender }, message = new ResponseMessage { text = "You sent " + messageText } };  
             if (fbResponse != null)  
             {  
               PostBackRequest(fbResponse);  
             }  
           }  
           catch (Exception ex)  
           {  
             logger.TrackException(ex);  
           }  
         }  
       }  
       return StatusCode(HttpStatusCode.OK);  
     }  

The above method just sends back the message what user sent. We will get the FbRequest as input to the Post method.

The following method, will send response back to the user.

private HttpStatusCode PostBackRequest(FbResponse fbResponse)  
     {  
       var accessToken = "Page_Access_Token_Generated";  
       var baseAddress = new Uri("https://graph.facebook.com/v2.6/me/messages?access_token=" + accessToken);  
       using (var httpClient = new HttpClient())  
       {  
         var input = JsonConvert.SerializeObject(fbResponse);  
         try  
         {  
           var response = httpClient.PostAsync(baseAddress, new StringContent(input.ToString(), Encoding.UTF8, "application/json"));  
           return response.Result.StatusCode;  
         }  
         catch (WebException e)  
         {  
           var httpResponse = (HttpWebResponse)e.Response;  
           if (httpResponse.StatusCode == HttpStatusCode.BadRequest)  
           {  
             logger.TrackException(e);  
           }  
         }  
       }  
       return HttpStatusCode.OK;  
     }  


The above code is a simple example that echo backs what user sent.

The FbResponse class is capable of sending Text, Image, Button, Generic, File & Receipt attachments.

All you need is create the proper response object as per the facebook reference guidelines.

Reference: https://developers.facebook.com/docs/messenger-platform/send-api-reference

I wish this will be very useful for beginners who would like to step into the bot programming.

Happy coding :)