Microsoft & .NET.NETIntegrating Your Web Site into Microsoft CRM

Integrating Your Web Site into Microsoft CRM

One of the challenging things about being CTO for a small company is that you have no choice but to wear many different hats and solve a smattering of problems that you wouldn’t normally deal with as CTO of a larger organization. The benefits that this brings—besides giving you more control—is the opportunity to learn about tools and technologies in greater depth than you normally would. Recently, this has been the case for me with Microsoft’s CRM software.

(For those of you not using Microsoft’s CRM software, you can find out all about it here.)

Our Process

At Knowledge Relay, we have been using Microsoft CRM for quite a while now (since its first release). Among other things, we use it to keep track of potential contacts (CRM Leads) that have registered with us on our Web site to download the software products we sell. Once we have a lead in the system, a sales person can make the decision when to convert the lead into a CRM Contact or CRM Customer based on other criteria (such as the lead downloading or purchasing our software). Despite achieving this customer-to-Web site tracking, we were not achieving the kind of efficiency and automation goals to make the product really simple and effective for our small sales staff to use. Sales persons were having to manually copy information out of e-mails generated by our Web site and paste that information into forms within the CRM system. Obviously, this is not a model of efficiency. So, we decided to look into the possibility of having our Web site automatically generate both leads and activities associated with those leads. Then, any sales person logging into CRM would see the items appear in their activity list.

Knowing that Microsoft CRM is an ASP.NET Web application powered by XML Web Services at the back-end, I had a hunch that either I’d need to call the appropriate Web Services from my code, or use the CRM API which, in turn, would call the appropriate Web Services. Because the latter is the approach I found used in the CRM SDK, I went with that. Now that I knew how to programmatically access the CRM, I set out to accomplish the following:

Web Site Action(s) CRM Action(s)
1. User Registration 1. CRM Lead Creation
2. CRM Activity referencing new Lead
2. User confirms e-mail/registration 1. CRM Activity referencing new Lead
3. User downloads a product 1. CRM Activity referencing new Lead
4. User requests a product demo 1. CRM Activity referencing new Lead

Developing the Solution

With my developer hat on, I went to the Class Library section of the CRM SDK Reference. The first page reads:

“This class library is a library of classes, interfaces, and enumerations that are included in the Microsoft CRM SDK. These are found in the Microsoft.Crm.Platform.Proxy.dll assembly. This library provides access to system functionality and is designed to be the foundation on which custom Microsoft CRM applications are built.

The Microsoft.Crm.Platform.Types.dll assembly contains the value types used to build XML strings for the APIs found in the proxy assembly.”

Eureka! Okay, so I found the names of the two assemblies I need to reference to have access to the CRM system functionality. Now, all I need to do is go find these two assemblies. My first thought was to go look in the bin directory beneath the root of the CRM virtual directory where the CRM was installed on our server. I found many assemblies there, but neither of the two I was looking for. Strangely enough, it turns out that these two assemblies are not copied from the CRM disc as part of the installation process. To get them, you’ll have to locate the wwwrootbin directory on your installation CD. This wasn’t mentioned anywhere that I could find in the CRM SDK Documentation, but the Microsoft.public.crm.developer newsgroup produced the answer without much trouble. Now that I had these two assemblies, I created a new ASP.NET project in Visual Studio.NET 2003 and referenced them from the /bin subdirectory of my project virtual directory.

In the small corner of the CRM I worked in (Leads and Activities), creating CRM objects generally followed the same pattern:

  1. Construct a string that points to the CRM platform server’s virtual directory. For example, http://myservername/mscrmservices/. This directory should contain the .srf files that will be referenced in the URL property of various CRM objects. You’ll see more about this in the code samples listed later.
  2. Create a Microsoft.Crm.Platform.Proxy.BizUser object and assign it the necessary credentials using a System.Net.CredentialCache object. Add credentials using the URI of the .srf files that the CRM Objects need access to.
  3. Use the BizUser.WhoAmI() method to return a Microsoft.Crm.Platform.Proxy.CUserAuth object that will contain the GUID representing the System User Id for the BizUser object. You’ll need this GUID value to inject into the <owner> node of the XML text you submit to the CRMLead.Create() method.
  4. Construct an XML string that describes the CRM Object you want to create. The CRM SDK Documentation conveniently provides links to .xsd files that describe the XML schemas for the various CRM Objects.
  5. Optionally, you can capture the GUID value for the created CRMLead or CRMActivity object returned by their respective Create() methods. You may or may not need to store this GUID somewhere for later use.

The Code

The following code demonstrates the concept of creating CRMLead and CRMActivity objects. I’ve removed some of the code related to the custom requirements for our Web pages so the code can apply generally to any implementation.

Listing 1: Generate a CRMLead and CRMActivity upon user registration

public class ConfirmRegistration : System.Web.UI.Page
{
  private string FirstName;
   private string LastName;

   private string ServerName;
   private string VirtualDirectory;
   private string Dir;

   private string CRMLeadGUID;

   private Microsoft.Crm.Platform.Proxy.CRMLead Lead;
   private Microsoft.Crm.Platform.Proxy.CRMActivity Activity;
   private Microsoft.Crm.Platform.Proxy.CUserAuth UserAuth;
   private Microsoft.Crm.Platform.Proxy.BizUser bizUser;

   private void Page_Load(object sender, System.EventArgs e)
   {
      if(Request.QueryString["firstname"] != null)
      {
         FirstName = Request.QueryString["firstname"];
      }
      if(Request.QueryString["lastname"] != null)
      {
         LastName = Request.QueryString["lastname"];
      }

      ServerName = "MyServer";
      VirtualDirectory = "mscrmservices";
      Dir = http:// + ServerName + @"/" + VirtualDirectory + @"/";

      System.Net.CredentialCache MyCredentials =
         new System.Net.CredentialCache();

      System.Net.NetworkCredential MyNetCred =
         new System.Net.NetworkCredential(
         @"johndoe",
         @"somepassword",
         @"ourdomain.com");

      MyCredentials.Add
         (new Uri(Dir + "BizUser.srf"), "NTLM", MyNetCred);
      MyCredentials.Add
         (new Uri(Dir + "CRMLead.srf"), "NTLM", MyNetCred);
      MyCredentials.Add
         (new Uri(Dir + "CRMActivity.srf"), "NTLM", MyNetCred);

      //BizUser object
      bizUser = new Microsoft.Crm.Platform.Proxy.BizUser();
      bizUser.Credentials = MyCredentials;
      bizUser.Url = Dir + "BizUser.srf";

      //CRMLead object
      Lead = new Microsoft.Crm.Platform.Proxy.CRMLead();
      Lead.Credentials = MyCredentials;
      Lead.Url = Dir + "CRMLead.srf";

      try
      {
         UserAuth = bizUser.WhoAmI();

         String LeadXml = @"<lead>";
         LeadXml += @"<lastname>";
         LeadXml += LastName;
         LeadXml += @"</lastname>";
         LeadXml += @"<firstname>";
         LeadXml += FirstName;
         LeadXml += @"</lastname>";
         LeadXml += @"<ownerid type=""" +
            Microsoft.Crm.Platform.Types.ObjectType.otSystemUser.
                      ToString();
         LeadXml += @""">";
         LeadXml += UserAuth.UserId ;
         LeadXml += @"</ownerid>";
         LeadXml += @"</lead>";

         CRMLeadGUID = Lead.Create(UserAuth, LeadXml);
      }
      catch(System.Web.Services.Protocols.SoapException)
      {
         //error handling logic here
         throw;
      }
      catch(Exception)
      {
         //error handling logic here
         throw;
      }

      //Create the CRM Activity
      try
      {
         Activity = new CRMActivity();
         Activity.Credentials = MyCredentials;
         Activity.Url = Dir + "CRMActivity.srf";

         string ActivityXML = "<activity>";
         ActivityXML += @"<subject>Registration for";
         ActivityXML += FirstName + " " + LastName;
         ActivityXML += @"</subject>";
         ActivityXML += @"<description>";
         ActivityXML += "Here is the description";
         ActivityXML += @"</description>";
         ActivityXML += @"<activitytypecode>134";
         ActivityXML += @"</activitytypecode>";
         ActivityXML += @"<objecttypecode>4"; //4 = CRMLead
         ActivityXML += @"</objecttypecode>";
         ActivityXML += @"<objectid>" + CRMLeadGUID;
         ActivityXML += @"</objectid>";
         ActivityXML += @"<prioritycode>1";
         ActivityXML += @"</prioritycode>";
         ActivityXML += @"<scheduledstart>";
         ActivityXML += DateTime.Now.ToString("s",
            DateTimeFormatInfo.InvariantInfo);
         ActivityXML += @"<ownerid type=""" +
            Microsoft.Crm.Platform.Types.ObjectType.otSystemUser.
                      ToString();
         ActivityXML += @""">";
         ActivityXML += UserAuth.UserId + @"</ownerid>";
         ActivityXML += @"</activity>";

         //Create the "Activity Party" XML
         String ActPartyXml = @"<activityparties>";
         ActPartyXml += @"<activityparty><partyid>";
         ActPartyXml += CRMLeadGUID + @"</partyid>";
         ActPartyXml += @"<partyobjecttypecode>" +
            Microsoft.Crm.Platform.Types.ObjectType.otLead.ToString();
         ActPartyXml += @"</partyobjecttypecode>";
         ActPartyXml += @"<participationtypemask>" +
            Microsoft.Crm.Platform.Types.ACTIVITY_PARTY_TYPE.
                      ACTIVITY_PARTY_REGARDING.ToString();
         ActPartyXml += @"</participationtypemask>";
         ActPartyXml += @"</activityparty>";
         ActPartyXml += @"</activityparties>";

         //Create the Activity
         string CRMActivityGUID =
            Activity.Create(UserAuth, ActivityXML, ActPartyXML);
      }
      catch(System.Web.Services.Protocols.SoapException)
      {
         //error handling logic
         throw;
      }
      catch(Exception)
      {
         //error handling logic
         throw;
      }
   }
}

As you can very easily tell, the CRM API involves creating a lot of XML text to pass to the CRM Web Service end point.

Additional Considerations

As you can see in the code sample, GUID values are returned by some methods and also passed as parameters in the XML text. What you don’t see in the code sample is the CRMLeadGUID value being stored in our database with the registration information. We added this value to our database so that we could retrieve it for a user in the event that we want to generate a CRM Activity for them for a download or information request that occurred on our Web site.

It’s also likely that you’ll want different users as the owner of the CRM Lead or CRM Activity depending on certain data (Product downloaded, geographical region, type of request, and so forth). As you may recall from the code sample, this is the user account used with the NetworkCredential. Storing these user names and passwords in a secure yet accessible location is important. For reasonable security and accessibility, I would recommend storing them in your Web.Config file and using the System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile() method for password storage.

In the code sample you may notice the parameters passed to the DateTime.Now.ToString() method. The lowercase “s” denotes a sortable date/time pattern (based on ISO 8601) using the local machine time. The DateTimeFormatInfo class is under the System.Globalization namespace and implements the IFormatProvider interface—and also returns the default read-only DateTimeFormatInfo that is culture independent using the InvariantInfo property. This is the date format that the CRM expects to see within the XML you pass to its APIs.

Because the intent of the code sample was to demonstrate the basic schema members of the XML for CRMLead and CRMActivity objects, it’s worth mentioning that CRMLead and CRMActivity objects both have dozens of elements that you can populate with information in your XML to more concisely and full define attributes of your CRMLead or CRMActivity objects. See the .xsd files for additional schema information. The more you explore the CRM SDK Documentation, you’ll find how widely applicable the patterns discussed here are across the objects in the CRM class libraries.

Conclusion

As this article demonstrates, Microsoft CRM has a very powerful XML-based API that allows Web Services to be invoked from a variety of different application platforms. This open architecture allows for businesses of all kinds to integrate their Web sites, applications, and processes with CRM data and reduce the amount of busy work required by CRM users. With a little bit of exploration into the CRM API, there is a good chance you’ll be able to find features that will allow you to automate common business practices within your organization.

About the Author

Jason Mauss is Chief Technology Officer for Knowledge Relay, Inc – a business intelligence visualization company, providing tools and resources at all levels of the enterprise. In addition to writing technical articles, he keeps a weblog at http://weblogs.asp.net/jamauss. You can contact him at Jason.Mauss@KnowledgeRelay.com or through his weblog.

Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.
Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.

Latest Posts

Related Stories