In this post I’ll demonstrate how to create a newsletter subscription control on your Facebook fan page that feeds data into your Microsoft Dynamics CRM.

In MS Dynamics CRM:

The first thing to do is create an attribute to store whether or not a contact wishes to receive the newsletter.

Go to Settings, once there select ‘Customize Entities’. In the list of entities find and select the Contact entity. From the ‘More Actions’ drop down select Edit. On the left side of the window under the heading ‘Details:’ select Attributes. Create a new attribute and give it the display name ’Receive Newsletter’. Name the attribute ‘new_receive_newsletter’ (Note: Dynamics adds the ‘new_’ prefix automatically to all custom attributes, unless you have changed the default settings.) Next, set the Type field to bit and Save the attribute.

In Asp.Net:

In Visual Studio create a new ASP.NET Web Service project. Right click on the new project and select “Add Web Reference…” from the menu. The “Add Web Reference” window will open, from there you need to enter the url to the MS Dynamics CRM web service. (Note: It’s usually something like “http://urlToYourCRM/MSCRMServices/2007/CRMService.asmx”.) Click “Go” and VS will find any services located at the entered url. In the “Web reference name:” text box enter the name of the Namespace for the web service, I’ll be using “CrmSdk” for this example.

Now open view the code for your web service. The first method we are going to add is for convenience:

Listing 1.
    private CrmService GetCrmService()

    {

        CrmService crmService = new CrmService();

        crmService.Url = “http://urlToYourCRM/MSCRMServices/2007/CRMService.asmx”;

        crmService.Credentials = new NetworkCredential(“username”, “password”, “domain”);

       

        crmService.CrmAuthenticationTokenValue = new CrmAuthenticationToken();

        crmService.CrmAuthenticationTokenValue.OrganizationName = “organization name”;

        return crmService;

    }

This method just creates an instance of the CrmService object and populates it with the information it needs to access you CRM. For simplicity in this example, all the values are inline but in your implementation you could store all this information in the web.config.

Listing 2.
    private contact GetContact(string email)

    {

        ColumnSet columns = new ColumnSet();

        columns.Attributes = new string[] {

            “firstname”,

            “lastname”,

            “emailaddress1”,

            “new_receive_newsletter “ 

        };

        ConditionExpression emailCond = new ConditionExpression();

        emailCond.AttributeName = “emailaddress1”;

        emailCond.Operator = ConditionOperator.Equal;

        emailCond.Values = new object[] { email };

        QueryExpression query = new QueryExpression();

        query.ColumnSet = columns;

        query.EntityName = EntityName.contact.ToString();

        query.Criteria = new FilterExpression();

        query.Criteria.FilterOperator = LogicalOperator.And;

        query.Criteria.Conditions = new ConditionExpression[] { emailCond };

        var result = GetCrmService().RetrieveMultiple(query);

        try

        {

            var u = result.BusinessEntities[0];

            return u as contact;

        }

        catch (Exception)

        {

            return null;

        }

    }

In Listing 2, there is another convienence method for retrieving an existing contact from the CRM by their email address. This is used to ensure that we don’t duplicate a contact.

Listing 3.
    [WebMethod]

    public bool SubscribeUser(string firstName, string lastName, string email)

    {

        bool create = false;

        contact c = this.GetContact(email);

        if (c == null)

        {

            create = true;

            c = new contact();

        }

        c.firstname = firstName;

        c.lastname = lastName;

        c.emailaddress1 = email;

        c.new_receive_newsletter = new CrmBoolean() { Value = true };

        if (create)

        {

            GetCrmService().Create(c);

        }

        else

        {

            GetCrmService().Update(c);

        }

        return true;

    }

Listing 3 is the actual web service method Facebook will be calling. It uses the method from Listing 2 to get an existing contact if there is one, then update it with the information provided by Facebook. Depending on if the contact already exists, the contact is passed to either Create or Update accordingly.

Now that the web service is created we can make it work with Facebook. While ASP.NET web services are capable of responding in JSON, they only do so if the incoming request is sent in JSON as well. Facebook will not be sending the request in JSON, it will be sent as a plain HTTP Post. In order to for this to work we have to intercept responses going to Facebook and convert them to JSON. To achieve this we need to create a HttpModule. Start by adding a new class to the project named FacebookCleanserModule. The class needs to implement the interface IHttpModule, so add that and implicitly implement the interface. We need to add the following code in the resulting class:

Listing 4.
    public void Init(HttpApplication context)

    {

      context.BeginRequest += new EventHandler(context_BeginRequest);

context.ReleaseRequestState += new EventHandler(context_ReleaseRequestState);

    }

    void context_ReleaseRequestState(object sender, EventArgs e)

    {

HttpApplication app = (HttpApplication)sender;

HttpResponse res = app.Response;

if (this.isFBAjax)

{

res.ContentType = “application/json; charset=utf-8”;

res.ContentEncoding = Encoding.UTF8;

res.Filter = new XMLtoJSONFilter(res.Filter);

}

    }

    void context_BeginRequest(object sender, EventArgs e)

    {

HttpApplication app = (HttpApplication)sender;

HttpRequest req = app.Context.Request;

string form = new StreamReader(req.InputStream).ReadToEnd();

if (form.ToLower().Contains(“fb_sig_is_ajax”))

{

this.isFBAjax = true;

}

if (req.InputStream.CanSeek)

{

req.InputStream.Position = 0;

}

    }

Next we have to add the class XMLtoJSONFilter to our project. The class should look like this:

Listing 5.
public class XMLtoJSONFilter : Stream

{

    private readonly Stream _stream;

    private long _position;

    public XMLtoJSONFilter(Stream stream)

    {

        this._stream = stream;

    }

    public override bool CanRead

    {

        get { return this._stream.CanRead; }

    }

    public override bool CanSeek

    {

        get { return this._stream.CanSeek; }

    }

    public override bool CanWrite

    {

        get { return this._stream.CanWrite; }

    }

    public override void Flush()

    {

        this._stream.Flush();

    }

    public override long Length

    {

        get { return this._stream.Length; }

    }

    public override long Position

    {

        get

        {

            return this._position;

        }

        set

        {

            this._position = value;

        }

    }

    public override int Read(byte[] buffer, int offset, int count)

    {

        return this._stream.Read(buffer, offset, count);

    }

    public override long Seek(long offset, SeekOrigin origin)

    {

        return this._stream.Seek(offset, origin);

    }

    public override void SetLength(long value)

    {

        this._stream.SetLength(value);

    }

    public override void Write(byte[] buffer, int offset, int count)

    {

        string b = Encoding.UTF8.GetString(buffer, offset, count);

        XmlDocument doc = new XmlDocument();

        doc.LoadXml(b);

        string json = XmlToJSON(doc);

        byte[] data = Encoding.UTF8.GetBytes(json);

        this._stream.Write(data, 0, data.Length);

    }

    private string XmlToJSON(XmlDocument xmlDoc)

    {

        StringBuilder sbJSON = new StringBuilder();

        sbJSON.Append(“{ “);

        XmlToJSONnode(sbJSON, xmlDoc.DocumentElement, true);

        sbJSON.Append(“}”);

        return sbJSON.ToString();

    }

    //  XmlToJSONnode:  Output an XmlElement, possibly as part of a higher array

    private void XmlToJSONnode(StringBuilder sbJSON, XmlElement node, bool showNodeName)

    {

        if (showNodeName)

            sbJSON.Append(“”” + SafeJSON(node.Name) + “”: “);

        sbJSON.Append(“{“);

        // Build a sorted list of key-value pairs

        //  where   key is case-sensitive nodeName

        //          value is an ArrayList of string or XmlElement

        //  so that we know whether the nodeName is an array or not.

        SortedList childNodeNames = new SortedList();

        //  Add in all node attributes

        if (node.Attributes != null)

            foreach (XmlAttribute attr in node.Attributes)

            {

                if (!attr.Name.ToLower().StartsWith(“xmlns”))

                {

                    StoreChildNode(childNodeNames, attr.Name, attr.InnerText);

                }

            }

        //  Add in all nodes

        foreach (XmlNode cnode in node.ChildNodes)

        {

            if (cnode is XmlText)

                StoreChildNode(childNodeNames, “value”, cnode.InnerText);

            else if (cnode is XmlElement)

                StoreChildNode(childNodeNames, cnode.Name, cnode);

        }

        // Now output all stored info

        foreach (string childname in childNodeNames.Keys)

        {

            ArrayList alChild = (ArrayList)childNodeNames[childname];

            if (alChild.Count == 1)

                OutputNode(childname, alChild[0], sbJSON, true);

            else

            {

                sbJSON.Append(” “” + SafeJSON(childname) + “”: [ “);

                foreach (object Child in alChild)

                    OutputNode(childname, Child, sbJSON, false);

                sbJSON.Remove(sbJSON.Length – 2, 2);

                sbJSON.Append(” ], “);

            }

        }

        sbJSON.Remove(sbJSON.Length – 2, 2);

        sbJSON.Append(” }”);

    }

    //  StoreChildNode: Store data associated with each nodeName

    //                  so that we know whether the nodeName is an array or not.

    private void StoreChildNode(SortedList childNodeNames, string nodeName, object nodeValue)

    {

        // Pre-process contraction of XmlElement-s

        if (nodeValue is XmlElement)

        {

            // Convert  <aa></aa> into “aa”:null

            //          <aa>xx</aa> into “aa”:”xx”

            XmlNode cnode = (XmlNode)nodeValue;

            if (cnode.Attributes.Count == 0)

            {

                XmlNodeList children = cnode.ChildNodes;

                if (children.Count == 0)

                    nodeValue = null;

                else if (children.Count == 1 && (children[0] is XmlText))

                    nodeValue = ((XmlText)(children[0])).InnerText;

            }

        }

        // Add nodeValue to ArrayList associated with each nodeName

        // If nodeName doesn’t exist then add it

        object oValuesAL = childNodeNames[nodeName];

        ArrayList ValuesAL;

        if (oValuesAL == null)

        {

            ValuesAL = new ArrayList();

            childNodeNames[nodeName] = ValuesAL;

        }

        else

            ValuesAL = (ArrayList)oValuesAL;

        ValuesAL.Add(nodeValue);

    }

    private void OutputNode(string childname, object alChild, StringBuilder sbJSON, bool showNodeName)

    {

        if (alChild == null)

        {

            if (showNodeName)

                sbJSON.Append(“”” + SafeJSON(childname) + “”: “);

            sbJSON.Append(“null”);

        }

        else if (alChild is string)

        {

            if (showNodeName)

                sbJSON.Append(“”” + SafeJSON(childname) + “”: “);

            string sChild = (string)alChild;

            sChild = sChild.Trim();

            sbJSON.Append(“”” + SafeJSON(sChild) + “””);

        }

        else

            XmlToJSONnode(sbJSON, (XmlElement)alChild, showNodeName);

        sbJSON.Append(“, “);

    }

    // Make a string safe for JSON

    private string SafeJSON(string sIn)

    {

        StringBuilder sbOut = new StringBuilder(sIn.Length);

        foreach (char ch in sIn)

        {

            if (Char.IsControl(ch) || ch == ”’)

            {

                int ich = (int)ch;

                sbOut.Append(@”u” + ich.ToString(“x4”));

                continue;

            }

            else if (ch == ‘”‘ || ch == || ch == ‘/’)

            {

                sbOut.Append();

            }

            sbOut.Append(ch);

        }

        return sbOut.ToString();

    }

}

This class will act like a normal stream, but by setting it up as the response filter (in Listing 4) it will receive the XML from our web service and parse it out into an equivalent JSON object and return that instead. Now we have to register the module in the web.config.

 

Listing 6.
<configuration>

  <system.web>

    <httpModules>

      <add name=FacebookCleanserModuletype=FacebookCleanserModule/>

    </httpModules>

  </system.web>

</configuration>

Listing 7.
<configuration>

  <system.webServer>

    <modules>

      <add name=FacebookCleanserModuletype=FacebookCleanserModule/>

    </modules>

  </system.webServer>

</configuration>

Listing 6 shows how to register the module on IIS 6.0 or IIS 7.0 running in Classic Mode whereas Listing 7 is for IIS 7.0 running in Integrated Mode. There is just one more change we need to make to the web.config:

Listing 8.
<configuration>

  <system.web>

    <webServices>

      <protocols>

        <add name=HttpPost/>

      </protocols>

    </webServices>

  </system.web>

</configuration>

By adding the HttpPost protocols to webServices we allow Post requests to our web service. Now all of this needs to uploaded to a web accessible host, since Facebook uses a proxy on their local server for AJAX requests, this can’t be hosted on your local machine.

In Facebook:

If you don’t already have a Facebook Fan Page, you need to create one, at the time of this writing it can be done at http://www.facebook.com/pages/create.php. Once you have a Fan Page add the Static FBML application to it. Edit your fan page and under the list of Applications you should see an entry from FBML, click edit on that entry. Start by entering the structural elements of your FBML.

Listing 9.
<a href=”#” onclick=”showform()”>Subscribe</a>

<fb:js-string var=”subscribePopup”>

    <div class=”newsLetterControl”>

    <form id=”subscribeForm”>

        <p>

            <span>Email:</span><input name=”email” id=”txtEmail” /></p>

        <p>

            <span>First Name:</span><input name=”firstName” id=”txtFName” /></p>

        <p>

            <span>Last Name:</span><input name=”lastName” id=”txtLName” /></p>

            </form>

    </div>

    </fb:js-string>

As you see in Listing 9 we have a tag that starts with “fb:”, that just denotes that it is one of Facebook’s custom elements. In this case, the element takes whatever it contains and converts it to an object for use within your Javascript instead of displaying it.

Now we need to add logic:

Listing 10.
<script>

<!–

    function showform() {

        new Dialog().showChoice(‘Demo Newsletter Subscription’, subscribePopup).onconfirm = function() {

            var params = document.getElementById(‘subscribeForm’).serialize();

            var ajax = new Ajax();

            ajax.responseType = Ajax.JSON;

            ajax.ondone = SubscribeCallback;

            ajax.post(‘http://urlToYourService.asmx/SubscribeUser’, params);

        };

        return false;

    }

    function SubscribeCallback() {

        new Dialog().showMessage(“Demo Newsletter Subscription”, “You have been successfully subscribed.”);

    }

//–>

</script>

The code in Listing 10 will display a Facebook Dialog box with the contents of the <fb:js-string> tag as it’s contents. When the user fills out the form and clicks “Okay” it pulls out the form data and sends it to the web service you created earlier. When the AJAX call is successful it calls the method SubscribeCallback and displays a message to the user that they are subscribe to the newsletter.

Like this post? Share it!
Free WordPress Themes, Free Android Games