Microsoft Dynamics CRM 3.0: Extending Marketing Automation

Inna Agranov
Microsoft Corporation
June 2007

Applies to:
Microsoft Dynamics™ CRM 3.0

Requires:
Microsoft Dynamics CRM 3.0
Microsoft® Visual Studio® 2003

Summary

Learn how to programmatically manage marketing or sales events, such as seminars, using Microsoft Dynamics CRM 3.0 Software Development Kit (SDK). Also, learn how to create and integrate a .NET Framework 2.0 Web application into Microsoft Dynamics CRM.

Download the Visual Studio 2003 Visual C# code sample for this article: MarketingAutomation.exe.

The Readme.doc that is included with the sample code contains information about how to set up, build, and test the sample application.

Content

  • Introduction
  • Implementation
    • Defining Custom Entity Types
    • Defining Custom Toolbar Buttons
    • Processing the ConfirmAttendance Web Page
    • Processing the SolicitFeedback.aspx Web Page

 

Introduction

Conducting a seminar involves a lot of planning, time and resources. You have to determine the seminar objectives, the material to present, who your desired audience is and how to let your customers know about the upcoming event. Automating the marketing processes that are associated with planning, organizing, and monitoring the results of the seminar is very important in making you more efficient, competitive, and successful in meeting the business goals.

This sample application shows you how to automate your marketing activities related to managing a seminar. Specifically, it shows you how to use Microsoft Dynamics CRM SDK to retrieve campaign responses that indicate whether the customers will attend the seminar and to create a marketing list that contains seminar attendees.  It launches a campaign to evaluate the results of the seminar and creates a campaign activity, such as sending e-mail messages to the seminar attendees to ask for a feedback on the seminar.

The sample is implemented as an ASP.NET Web application that you can use as a seminar automation add-in for the Microsoft Dynamics CRM Web application. The customization data that is provided with the sample includes two custom entities, seminar and attendee, that are used to track seminar activities and seminar attendees. It also includes two custom toolbar buttons, Qualify Response and Solicit Feedback. The Qualify Response button is used to qualify customer responses to the seminar invitations. The Solicit Feedback button is used to launch a post-seminar campaign to solicit a feedback from all customers who attended the seminar.

An example of a Campaign Response record that contains a customer response to the seminar invitation and illustrates the Qualify Response button is shown here.

Figure 1 – The customer response to the invitation to the seminar

The following is an example of a Seminar record that contains a list of attendees and illustrates the Solicit Feedback button.

Figure 2 – The request for a feedback on the seminar

 

Implementation

The MarketingAutomation Web application contains two ASP.NET Web pages: ConfirmAttendance.aspx and SolicitFeedback.aspx.

The ConfirmAttendance.aspx page includes the Yes and No buttons to confirm the seminar attendance. The code-behind creates attendees from the customers who responded with the Yes using the customer information that is associated with the campaign response.

Figure 3 — The Qualify Response ConfirmAttendance Web Page dialog 

Figure 3 – The Qualify Response ConfirmAttendance Web page dialog

The SolicitFeedback.aspx page contains the OK button. When the OK button is clicked, the code-behind creates a new campaign to solicit a feedback on the seminar. It also creates a marketing list that contains seminar attendees and an e-mail campaign activity to distribute the e-mail messages to all attendees on the marketing list.

The customization data for the sample is contained in the AllCustomizations.xml and ISVCustomizations.xml files. You can easily add customizations to Microsoft Dynamics CRM by using Import Customizations feature that is available in the Microsoft Dynamics CRM Web application. Another way of creating custom entities is by going to Setting, Customizations, and Customize Entities in the Microsoft Dynamics CRM Web application.

Defining Custom Entity Types

The AllCustomizations.xml file defines two new custom entities, seminar and attendee, their attributes, and their relationships with other entities.

The seminar entity represents a container for campaigns, marketing lists, attendees and various activities, such as tasks, e-mails, appointments and other activities associated with the seminar. Each of these entities is linked to a seminar for which it is created.

The attendee entity represents a contact who attended a seminar. Each attendee is linked to a specific contact from which it is created and to a seminar.

The following diagram shows the relationships among the seminar, attendee, campaign, and list entities:

Note This sample uses the default customization prefix "new_". To avoid possible conflicts with other customizations that you may install in the future, it is recommended that you modify the default prefix. To do this, in the Microsoft Dynamics CRM Web application, in the Navigation Pane, click Settings. In the Settings area, click Organization Settings, and then click System Settings. On the Customization tab, modify the default prefix before you create custom entities and attributes.

Figure 4 — The entities relationship diagram 

Figure 4 – The entities relationship diagram

DefiningCustom Toolbar Buttons

The ISVCustomizations.xml file contains the definitions of the two custom toolbar buttons, Qualify Response and Solicit Feedback. The XML configuration code for the buttons is shown here.


 <Button Title="Qualify Response" 
     ToolTip="Qualify the campaign response." 
     Url="https://localhost:31040/MarketingAutomation/ConfirmAttendance.aspx"
     PassParams="1" 
     WinParams="dialogWidth=400px;dialogHeight=200px;center:yes;status:no;help:no;"
     WinMode="2" />
 
 <Button Title="Solicit Feedback" 
     ToolTip="Solicit feedback for the seminar from its attendees." 
     Url="https://localhost:31040/MarketingAutomation/SolicitFeedback.aspx"
     PassParams="1" 
     WinParams="dialogWidth=200px;dialogHeight=100px;" WinMode="1" />

The following table identifies the attributes used in the XML configuration code.

Attribute

Description

Title

Specifies the name that appears on the button.

Tooltip

Specifies the ToolTip that appears for the button.

Url

Specifies the URL to be opened when the button is clicked.

WinParams

Specifies the parameters to be passed to the window. The format of this parameter is different depending on the value of the WinMode parameter. In the example code, the dialog width and height in pixels are specified.

PassParams

Specifies whether the entity type and entity instance ID parameters are to be passed to the URL. A value of 1 indicates "true".

WinMode

Specifies the window mode.

0 = Window [default]

1 = Modal Dialog

2 = Modeless Dialog

 

For more information about the configuration format for a button, see the Button topic in the Microsoft Dynamics CRM 3.0 SDK.

 

Processing the ConfirmAttendance Web Page

The ConfirmAttendance.aspx page qualifies a customer response to an invitation to attend a seminar.

It performs the following functions:

  1. Validates that the campaign response is open and it is a response to a seminar invitation.
  2. Displays the Yes/No buttons to indicate if the customer will attend the seminar.
  3. If the answer is Yes, it creates an attendee for the seminar using the customer information that is associated with the campaign response.
  4. Closes the campaign response.

 

Page_Load Event Handler

When you click the Qualify Response button that is located on the campaign response toolbar, you issue a request for the ConfirmAttendance.aspx page. The ConfirmAttendance.aspx page is specified in the Url attribute of the Qualify Response button in the ISVCustomizations.xml file. The ConfirmAttendance code-behind contains the Page_Load event handler that is invoked when a request for the ConfirmAttendance.aspx page is issued and the code inside the handler is executed.

The Page_Load event handler validates that the campaign response is open and it is a response to the seminar invitation by verifying that the campaign response ID obtained from the query string is valid. It also adds the event handlers for the Yes and No buttons.


  protected void Page_Load(object sender, EventArgs e)
  {
      // Set up the standard Microsoft Dynamics CRM 3.0 service.
      _service = new CrmService.CrmService();
      // Set credentials to avoid access denied errors.
      _service.Credentials = System.Net.CredentialCache.DefaultCredentials;
  
      // Verify that the campaign response is open 
      // and a part of a seminar before continuing.
      IsValidResponse = false;
      
      // Obtain the campaign response GUID from the query string.
      if (IsGuid(Request.QueryString["oId"]))
      {
          // Retrieve the campaign response in question 
          // from Microsoft Dynamics CRM 3.0.
          _campaignResponseId = new Guid(Request.QueryString["oId"]);
          campaignresponse response = 
              (campaignresponse) _service.Retrieve(EntityName.campaignresponse.ToString(),
              _campaignResponseId, new AllColumns());
              
          // Verify that the campaign response is open.
          if (response.statecode.Value == CampaignResponseState.Open)
          {
              // Retrieve the campaign for the response from Microsoft Dynamics CRM 3.0.
              campaign campaign = 
                  (campaign)_service.Retrieve(EntityName.campaign.ToString(), 
                  response.regardingobjectid.Value, new AllColumns());
                  
              // Verify that the campaign is for the seminar.
              if ((campaign.new_seminarid != null) && (!campaign.new_seminarid.IsNull))
              {
                  IsValidResponse = true;
              }
          }
      }
      
      // Add the event handlers for the Yes and No buttons.
      this.confirmButton.ServerClick += new EventHandler(this.confirmButton_ServerClick);
      this.noButton.ServerClick += new EventHandler(this.noButton_ServerClick);
      this.cancelButton.ServerClick += new EventHandler(this.cancelButton_ServerClick);
  }

The Yes Button Event Handler

The confirmButton_ServerClick event handler is invoked when you click the Yes button inside the ConfirmAttendance dialog box. It marks the response as Attending, creates a new attendee from a contact, and closes the campaign response.


 protected void confirmButton_ServerClick(object sender, EventArgs e)
 {
     if (_campaignResponseId != Guid.Empty)
     {
         // Mark the response as Attending.
         SetCampaignResponseAttending(_campaignResponseId, true);
     }
     
     // Close the dialog box.
     Response.Write(@"<script language=""javascript"">window.close();</script>");
 }

The SetAttending method creates a new attendee from a contact. If you wish to create attendees from accounts or leads, you can modify this code to support use of these entity types. After you do this, you will have choice of entity types in the Customer lookup field of the Campaign Response when you qualify a customer response. For more information, see "Create a campaign response and qualify it" in the Testing section of the Readme.doc file.

In the following code example, contactId is the ID of a contact that is converted into an attendee, seminarId is the ID of the seminar that the attendee is attending, and isAttending specifies whether to convert a contact into an attendee.


 private void SetAttending(Guid contactId, Guid seminarId)
 {
     // Retrieve the contact object from Microsoft Dynamics CRM 3.0.
     contact contact = 
         (contact)_service.Retrieve(EntityName.contact.ToString(),
                           contactId, new AllColumns());
     
     // Create a new attendee object.
     new_attendee attendee = new new_attendee();
     
     // Set the attendee's contact name to the contact's full name.
     attendee.new_contactname = contact.fullname;
     
     // Set the attendee's contact ID to the contact's ID.
     attendee.new_contactid = new Lookup();
     attendee.new_contactid.Value = contactId;
     
     // Associate the attendee with the campaign's seminar.
     attendee.new_seminarid = new Lookup();
     attendee.new_seminarid.Value = seminarId;
     
     // Create the attendee in Microsoft Dynamics CRM 3.0.
     _service.Create(attendee);
 }

The SetCampaignResponseAttending method creates a new attendee from a contact and closes the campaign response.

In the following code example, campaignResponseId is the ID of the campaign response, isAttending specifies whether the contact in the response is attending the seminar.


 private void SetCampaignResponseAttending(Guid campaignResponseId, bool isAttending)
 {
     // Retrieve the campaign response object from Microsoft Dynamics CRM 3.0.
     campaignresponse campaignResponse = 
         (campaignresponse)_service.Retrieve(EntityName.campaignresponse.ToString(), 
         campaignResponseId, new AllColumns());
         
     // Get the campaign ID and object associated with 
     // the campaign response from Microsoft Dynamics CRM 3.0.
     Guid campaignId = campaignResponse.regardingobjectid.Value;
     campaign campaign = 
         (campaign)_service.Retrieve(EntityName.campaign.ToString(), 
                           campaignId, new AllColumns());
                           
     // Get the seminar ID associated with the campaign.
     if (campaign.new_seminarid.IsNull == false)
     {
         Guid seminarId = campaign.new_seminarid.Value;
            
         if (isAttending)
         {
             // Create an attendee for the seminar using the customer 
             // that is associated with the campaign response.
             Guid customerId = campaignResponse.customer[0].partyid.Value;
             SetAttending(customerId, seminarId);
         }
                 
             // Close the campaign response.
             CloseCampaignResponse(campaignResponseId);
     }
 }

The No Button Event Handler

The noButton_ServerClick event handler is invoked when you click the No button inside the ConfirmAttendance dialog box. It marks the response as Not Attending and does not create a new attendee.


 protected void noButton_ServerClick(object sender, EventArgs e)
 {
     if (_campaignResponseId != Guid.Empty)
         {
         // Mark the response as Not Attending.
         SetCampaignResponseAttending(_campaignResponseId, false);
         }
         // Close the dialog box.
         Response.Write(@"<script language=""javascript"">window.close();</script>");
 }

Processing the SolicitFeedback.aspx Web Page

The SolicitFeedback.aspx page requests a feedback on a seminar from the seminar attendees. It performs the following functions:

  • Creates a campaign to solicit the feedback from the seminar attendees.
  • Creates a campaignactivity entity to distribute the feedback requests using e-mail.
  • Retrieves the BusinessEntityCollection class that contains the seminar attendees.
  • Creates a marketing list and populates it with the attendees contained in BusinessEntityCollection.
  • Adds the marketing list to the campaignactivity.
  • Distributes the campaignactivity to the marketing list members.

Page_Load Event Handler

When you click the Solicit Feedback button that is located on the Marketing Automation seminar toolbar, you issue a request for the SolicitFeedback.aspx page. The SolicitFeedback.aspx page is specified in the Url attribute of the Solicit Feedback button in the ISVCustomizations.xml file. The SolicitFeedback code-behind contains the Page_Load event handler that is invoked when a request for the SolicitFeedback.aspx page is issued and the code inside the handler is executed.

The Page_Load event handler retrieves the seminar ID from the query string, creates a feedback request campaign, and distributes it, as shown in the following code example.


 protected void Page_Load(object sender, EventArgs e)
 {
     string seminarIdStr = Request.QueryString["oId"];
     if ((seminarIdStr != null) && (seminarIdStr.Length > 0))
     {
         Guid seminarId = new Guid(seminarIdStr);
         SendFeedbackRequest(seminarId);
     }
 }

The SendFeedbackRequest method creates a feedback request campaign for a seminar and a campaign activity that distributes the e-mail messages to the attendees, as shown in the following code example.

In the following code example, seminarId is an ID of the seminar for which the feedback campaign is created.


 public void SendFeedbackRequest(Guid seminarId)
 {
     // In a real-world implementation, you would set up a Web site 
     // to collect the attendee's feedback for the seminar,
     // and send the feedback URL in the e-mail.
     
     const string EMAIL_BODY = "Thank you for attending our seminar. " 
                  + "We'd like to hear from you. "
                  + "Please visit us by clicking on the following link to share your feedback:\n\n"
           + "http://www.adventureworkscycle.com/SeminarFeedback?seminarID={0}";
           
     // Set up the standard Microsoft Dynamics CRM service.
     CrmService.CrmService service = new CrmService.CrmService();
     
     // Set the credentials to avoid access denied errors.
     service.Credentials = System.Net.CredentialCache.DefaultCredentials;
     
     // Retrieve the seminar for which to solicit feedback.
     new_seminar seminar = 
             (new_seminar)service.Retrieve(EntityName.new_seminar.ToString(), 
             seminarId, new AllColumns());
     
     // Check that feedback has not been already solicited for this seminar.
     if ((seminar.new_hassolicitedfeedback == null) || (seminar.new_hassolicitedfeedback.Value == false))
     
     {
         #region Create a campaign to facilitate the feedback request distribution
             campaign feedbackCampaign = new campaign();
             feedbackCampaign.name = "Feedback for " + seminar.new_name;
             
             feedbackCampaign.new_seminarid = new Lookup();
             feedbackCampaign.new_seminarid.Value = seminarId;
             
             Guid feedbackCampaignId = service.Create(feedbackCampaign);
             #endregion
             
             #region Create a campaignactivity to distribute the feedback requests using e-mail
             campaignactivity distributeFeedback = new campaignactivity();
             
             //Set the parent campaign.
             distributeFeedback.regardingobjectid = new Lookup();
             distributeFeedback.regardingobjectid.Value = feedbackCampaignId;
             distributeFeedback.regardingobjectid.type = EntityName.campaign.ToString();
             
             distributeFeedback.subject = "Feedback for " + seminar.new_name;
             distributeFeedback.description = 
                 String.Format(EMAIL_BODY, seminarId.ToString("B"));
             
             //Set the channel to e-mail.
             const int EMAIL = 7;
             distributeFeedback.channeltypecode = new Picklist();
             distributeFeedback.channeltypecode.Value = EMAIL;
             
             Guid distributeFeedbackId = service.Create(distributeFeedback);
             #endregion
             
         #region Get a BusinessEntityCollection containing the seminar attendees
             QueryByAttribute query = new QueryByAttribute();
             query.ColumnSet = new AllColumns();
             query.EntityName = EntityName.new_attendee.ToString();
             query.Attributes = new string[] { "new_seminarid" };
             query.Values = new object[] { seminarId };
             
             BusinessEntityCollection attendees = service.RetrieveMultiple(query);
             #endregion
             
         #region Create a marketing list to contain the seminar attendees
             list attendeeList = new list();
             
             attendeeList.new_seminarid = new Lookup();
             attendeeList.new_seminarid.Value = seminarId;
             attendeeList.new_seminarid.type = EntityName.new_seminar.ToString();
             
             attendeeList.listname = "Feedback Request Recipients for " + seminar.new_name;
             
             // Set the type of list members to contact.
             const int CONTACT = 2;
             attendeeList.membertype = new CrmNumber();
             attendeeList.membertype.Value = CONTACT;
             
             // Set the allowed list member type to contact.
             attendeeList.createdfromcode = new Picklist();
             attendeeList.createdfromcode.Value = CONTACT;
             
             Guid attendeeListId = service.Create(attendeeList);
             #endregion
             
         #region Add the attendees in the BusinessEntityCollection to the marketing list
         
             foreach (BusinessEntity attendee in attendees.BusinessEntities)
             {
                 Guid contactId = ((new_attendee)attendee).new_contactid.Value;
                 
                 AddMemberListRequest addContact = new AddMemberListRequest();
                 addContact.ListId = attendeeListId;
                 addContact.EntityId = contactId;
                 
                 service.Execute(addContact);
             }
             
             #endregion
             
         #region Add the marketing list to the campaignactivity
         
             // Create a Microsoft Dynamics CRM 3.0 request object
             // to add the marketing list to the feedback campaign
             AddItemCampaignRequest addMemberListToCampaign = new AddItemCampaignRequest();
             addMemberListToCampaign.CampaignId = feedbackCampaignId;
             addMemberListToCampaign.EntityId = attendeeListId;
             addMemberListToCampaign.EntityName = EntityName.list;
             
             // Execute the request.
             AddItemCampaignResponse addMemberListToCampaignResponse = 
                 (AddItemCampaignResponse)service.Execute(addMemberListToCampaign);
                 
             // Create a Microsoft Dynamics CRM 3.0 request object
             // to add the marketing list to the feedback request campaignactivity.
             AddItemCampaignActivityRequest addMemberListToCampaignActivity = 
                 new AddItemCampaignActivityRequest();
                 
             // Specify the campaign activity to modify.
             addMemberListToCampaignActivity.CampaignActivityId = distributeFeedbackId;
             
             // Specify the item to be added.
             addMemberListToCampaignActivity.ItemId = attendeeListId;
             
             // Specify the type of the item to be added.
             addMemberListToCampaignActivity.EntityName = EntityName.list;
             
             // Execute the request.
             AddItemCampaignActivityResponse addMemberListToCampaignActivityResponse = 
                 (AddItemCampaignActivityResponse)service.Execute(addMemberListToCampaignActivity);
                 
             #endregion
             
         #region Distribute the feedback request campaignactivity
         
             // Create a Microsoft Dynamics CRM 3.0 request object
             // to execute the feedback request distribution.
             ExecuteCampaignActivityRequest executeCampaignRequest = 
                 new ExecuteCampaignActivityRequest();
             executeCampaignRequest.CampaignActivityId = distributeFeedbackId;
             
             // Specify the campaign activity to be executed.
             executeCampaignRequest.Activity = new email();
             
             // Indicate that the campaign activity is to be executed,
             // not propagated.
             executeCampaignRequest.Propagate = false;
             executeCampaignRequest.OwnershipOptions = 
                 PropagationOwnershipOptions.ListMemberOwner;
                 
             // Execute the campaign activity.
             ExecuteCampaignActivityResponse executeCampaignResponse = 
                 (ExecuteCampaignActivityResponse)service.Execute(executeCampaignRequest);
                 
             // Mark that feedback has been solicited for the seminar.
             if (seminar.new_hassolicitedfeedback == null)
             {
                 seminar.new_hassolicitedfeedback = new CrmBoolean();
             }
             seminar.new_hassolicitedfeedback.Value = true;
             service.Update(seminar);
             
             #endregion
             
         // Let the user know the operation was successful.
         Response.Write(@"<script language=""javascript"" type=""text/javascript"">
             alert(""Feedback has been solicited for this seminar."");
         </script>");
         Response.Flush();
     }
     else
     {
         // Let the user know feedback has already been solicited.
         Response.Write(@"<script language=""javascript"" type=""text/javascript"">
             alert(""Feedback has already been solicited for this seminar."");
         </script>");
         Response.Flush();
     }
     
     // Always close the window after alerting the user.
     Response.Clear();
     Response.Write(@"
     <script language=""javascript"" type=""text/javascript"">
         window.close();
     </script>");
     Response.Flush();
 }

 

Additional Information

For more information, see the Microsoft Dynamics CRM 3.0 Software Development Kit (SDK) documentation.