Customer Care Accelerator (CCA) for CRM 2011 (Part 4 – Simple Automation example using Bing Search)

Please refer the earlier posts for understanding basics of configuring CCA

1. Customer Care Accelerator – Part 1

2. Customer Care Accelerator – Part 2

3. Customer Care Accelerator – Part 3

Here let us take a scenario where we would be hosting the Bing search page using Hosted Control and then entering a search term in the search box and clicking Enter to see the results.

All this we will configure to happen without any user interaction i.e. we will automate it.

To begin with, add a new class library project to the Agent Desktop Solution.

Add a new User Control class to the project

Add references to the following assemblies

 

 

Extend the following classes HostedControl, IDesktopUserActionsConsumer

Source code for the BingHostedControl class. Please check the comments within code to understand things better.


using System;
using System.Windows.Automation;
using System.Windows.Forms;
using Microsoft.Uii.Common.Logging;
using Microsoft.Uii.Csr;
using Microsoft.Uii.Csr.Browser.Web;
using Microsoft.Uii.Desktop.Core;

namespace MyHostedControl
{
 /// <summary>
 /// Class BingHostedControl
 /// </summary>
 public partial class BingHostedControl : HostedControl, IDesktopUserActionsConsumer
 {
 /// <summary>
 /// The navigation URL
 /// </summary>
 private readonly string _navigationUrl;

/// <summary>
 /// Represents the web page dom
 /// </summary>
 private HtmlDocument _doc;

/// <summary>
 /// The web browser extension
 /// </summary>
 private WebBrowserExtended _webBrowser;

/// <summary>
 /// The application name being hosted
 /// </summary>
 private string applicationName;

/// <summary>
 /// The bing window after set parent
 /// </summary>
 private AutomationElement bingWindowAfterSetParent;

/// <summary>
 /// The desktop access
 /// </summary>
 private IDesktopUserActions desktopAccess;

 /// <summary>
 /// Initializes a new instance of the <see cref="BingHostedControl" /> class.
 /// </summary>
 public BingHostedControl()
 {
 InitializeComponent();
 }

 /// <summary>
 /// Initializes a new instance of the <see cref="BingHostedControl" /> class.
 /// </summary>
 /// <param name="appId">The app id.</param>
 /// <param name="appName">Name of the app.</param>
 /// <param name="extensionXml">The extension XML.</param>
 public BingHostedControl(Guid appId, string appName, string extensionXml)
 : base(appId, appName, extensionXml)
 {
 _navigationUrl = "http://www.bing.com";
 applicationName = appName;
 InitializeComponent();
 }

/// <summary>
 /// Sets the desktop user actions access.
 /// </summary>
 /// <param name="desktopAccess">The desktop access.</param>
 public void SetDesktopUserActionsAccess(IDesktopUserActions desktopAccess)
 {
 this.desktopAccess = desktopAccess;
 }

/// <summary>
 /// Initializes this instance.
 /// </summary>
 public override void Initialize()
 {
 try
 {
 InitializeBrowser();
 base.Initialize();
 }
 catch (Exception exception)
 {
 Logging.Error("Bing Hosted App", "Error occurred initializing the Bing control", exception);
 throw;
 }
 }

/// <summary>
 /// Initialize Browser
 /// </summary>
 private void InitializeBrowser()
 {
 _webBrowser = new WebBrowserExtended(false, true, true);
 _webBrowser.Dock = DockStyle.Fill;
 _webBrowser.Visible = true;
 Controls.Add(_webBrowser);
 }

 /// <summary>
 /// Method is used to perform automation
 /// </summary>
 /// <param name="args">event arguments</param>
 protected override void DoAction(RequestActionEventArgs args)
 {
 try
 {
 if (args == null)
 {
 return;
 }

if (args.Action.Equals("default"))
 {
 _webBrowser.DocumentComplete += WebBrowser_DocumentComplete;
 _webBrowser.Navigate(_navigationUrl);
 //BingSearch();
 }

base.DoAction(args);
 }
 catch (Exception exception)
 {
 Logging.Error("Bing Hosted App", "Error occurred in Do Action method of the Bing control", exception);
 throw;
 }
 }

 /// <summary>
 /// Gets the window UI automation element after setting parent window.
 /// </summary>
 /// <param name="name">The name.</param>
 /// <returns>AutomationElement.</returns>
 private AutomationElement GetWindowUIAutomationElementAfterSetParentWindow(object name)
 {
 try
 {
 AutomationElementCollection automationElementCollection = AutomationElement.RootElement.FindAll(
 TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "AgentDesktop"));
 foreach (AutomationElement automationElement in automationElementCollection)
 {
 if (automationElement.Current.ControlType == ControlType.Window)
 {
 return automationElement;
 }
 }
 }
 catch (Exception ex)
 {
 Logging.Error("Bing Hosted App", "Error occurred in GetWindowUIAutomationElementAfterSetParentWindow method of the Bing control", ex);
 throw;
 }
 return null;
 }

 /// <summary>
 /// TypeTextBoxSearch functions sets the text box with the search term and inputs the Return key to display search results
 /// </summary>
 /// <param name="textBoxName">Name of the text box.</param>
 /// <param name="textBoxValue">The text box value.</param>
 public void TypeTextBoxSearch(string textBoxName, string textBoxValue)
 {
 try
 {
 bingWindowAfterSetParent = GetWindowUIAutomationElementAfterSetParentWindow("AgentDesktop");
 AutomationElementCollection bingWindowChildItems =
 bingWindowAfterSetParent.FindAll(TreeScope.Descendants,
 new PropertyCondition(AutomationElement.NameProperty, textBoxName));

 foreach (AutomationElement bingWindowChildItem in bingWindowChildItems)
 {
 if (bingWindowChildItem.Current.Name.Equals(textBoxName) &&
 bingWindowChildItem.Current.ControlType == ControlType.Edit)
 {
 AutomationElement textBox = bingWindowChildItem;
 var valuePattern = (ValuePattern) textBox.GetCurrentPattern(ValuePattern.Pattern);
 valuePattern.SetValue(textBoxValue);
 Win32HelperMethods.KeyBoardEntry(Win32HelperMethods.KeyboardInput.SpecialKeys.RETURN);
 break;
 }
 }
 }
 catch (Exception ex)
 {
 Logging.Error("Bing Hosted App", "Error occurred in TypeTextBoxSearch method of the Bing control", ex);
 throw;
 }
 }

 /// <summary>
 /// Called when web application is completely loaded
 /// </summary>
 /// <param name="sender">sender object</param>
 /// <param name="e">event arguments</param>
 private void WebBrowser_DocumentComplete(object sender, DocumentCompleteEventArgs e)
 {
 try
 {
 if (_webBrowser != null &&
 (_webBrowser.ReadyState == WebBrowserReadyState.Complete ||
 _webBrowser.ReadyState == WebBrowserReadyState.Loaded))
 {
 _doc = _webBrowser.Document as HtmlDocument;
 if (_doc != null)
 {
 // perform DOM operation as reuquired
 //_document = _doc.GetElementsByTagName("FRAME");
 }
 }
 }
 catch (InvalidOperationException exception)
 {
 Close();
 Logging.Error("Bing Hosted App", "Error occurred while loading Bing control", exception);
 throw;
 }
 catch (Exception exception)
 {
 Close();
 Logging.Error("Bing Hosted App", "Error occurred while loading Bing control", exception);
 throw;
 }
 }

/// <summary>
 /// Desktops the loading complete.
 /// </summary>
 public void DesktopLoadingComplete()
 {
 TypeTextBoxSearch("Enter your search term", "CCA R1");
 }

 /// <summary>
 /// Close the web browser process before closing the hosted control
 /// </summary>
 public override void Close()
 {
 try
 {
 if (_webBrowser != null)
 {
 _webBrowser.CloseBrowser();
 _webBrowser.Dispose();
 }

base.Close();
 }
 catch (Exception exception)
 {
 Logging.Error("Bing Hosted App", "Error occurred closing the Bing control", exception);
 throw;
 }
 }

 }
}

Win32Helper Class

public static class Win32HelperMethods
 {
 /// <summary>
 /// Win32 SendInput Method
 /// </summary>
 /// <param name="numberOfInputs">The number of inputs</param>
 /// <param name="input">The input sent</param>
 /// <param name="structSize">the size of the input structure</param>
 /// <returns>returns exit code</returns>
 [DllImport("user32.dll")]
 private static extern int SendInput(int numberOfInputs, ref Input input, int structSize);

/// <summary>
 /// Win32 GetMessageExtraInfo Method
 /// </summary>
 /// <returns>Message Pointer</returns>
 [DllImport("user32.dll")]
 private static extern IntPtr GetMessageExtraInfo();

/// <summary>
 /// Win32 SetCursorPosition Method.
 /// </summary>
 /// <param name="cursorInfo">The cursor position point.</param>
 /// <returns></returns>
 [DllImport("user32.dll")]
 private static extern bool SetCursorPos(System.Drawing.Point cursorInfo);

/// <summary>
 /// Win32 GetKeyState Method
 /// </summary>
 /// <param name="virtKey">The key for which state is retrieved.</param>
 /// <returns>state of the key.</returns>
 [DllImport("user32.dll")]
 private static extern ushort GetKeyState(uint virtKey);

/// <summary>
 /// Win32 VkKeyScan Method
 /// </summary>
 /// <param name="ch">The key to be scanned.</param>
 /// <returns></returns>
 [DllImport("user32.dll")]
 private static extern short VkKeyScan(char ch);

/// <summary>
 /// The structure for Mouse Input Details
 /// </summary>
 [StructLayout(LayoutKind.Sequential)]
 public struct MouseInput
 {
 private int dx;
 private int dy;
 private int mouseData;
 private int dwFlags;
 private int time;
 private IntPtr dwExtraInfo;
 public MouseInput(int dwFlags, IntPtr dwExtraInfo)
 {
 this.dwFlags = dwFlags;
 this.dwExtraInfo = dwExtraInfo;
 this.dx = 0;
 this.dy = 0;
 this.time = 0;
 this.mouseData = 0;
 }
 }

/// <summary>
 /// The structure for Hardware Input Details
 /// </summary>
 [StructLayout(LayoutKind.Sequential)]
 private struct HardwareInput
 {
 private int uMsg;
 private short wParamL;
 private short wParamH;
 }

/// <summary>
 /// The structure for Keyboard Input Details
 /// </summary>
 [StructLayout(LayoutKind.Sequential)]
 public struct KeyboardInput
 {
 private short wVk;
 private short wScan;
 private KeyUpDown dwFlags;
 private int time;
 private IntPtr dwExtraInfo;
 public KeyboardInput(short wVk, KeyUpDown dwFlags, IntPtr dwExtraInfo)
 {
 this.wVk = wVk;
 this.wScan = 0;
 this.dwFlags = dwFlags;
 this.time = 0;
 this.dwExtraInfo = dwExtraInfo;
 }
 // Nested Types
 public enum KeyUpDown
 {
 KEYEVENTF_KEYDOWN,
 KEYEVENTF_EXTENDEDKEY,
 KEYEVENTF_KEYUP
 }

public enum SpecialKeys
 {
 ALT = 0x12,
 BACKSPACE = 8,
 CAPS = 20,
 CONTROL = 0x11,
 DELETE = 0x2e,
 DOWN = 40,
 END = 0x23,
 ESCAPE = 0x1b,
 F1 = 0x70,
 F10 = 0x79,
 F11 = 0x7a,
 F12 = 0x7b,
 F2 = 0x71,
 F3 = 0x72,
 F4 = 0x73,
 F5 = 0x74,
 F6 = 0x75,
 F7 = 0x76,
 F8 = 0x77,
 F9 = 120,
 HOME = 0x24,
 INSERT = 0x2d,
 LEFT = 0x25,
 LEFT_ALT = 0xa4,
 PAGEDOWN = 0x22,
 PAGEUP = 0x21,
 PRINT = 0x2a,
 PRINTSCREEN = 0x2c,
 RETURN = 13,
 RIGHT = 0x27,
 RIGHT_ALT = 0xa5,
 SHIFT = 0x10,
 SPACE = 0x20,
 TAB = 9,
 UP = 0x26
 }
 }

/// <summary>
 /// The structure capturing the User Input Details
 /// </summary>
 [StructLayout(LayoutKind.Explicit)]
 public struct Input
 {
 // Fields
 [FieldOffset(4)]
 private HardwareInput hi;
 [FieldOffset(4)]
 private KeyboardInput ki;
 [FieldOffset(4)]
 private MouseInput mi;
 [FieldOffset(0)]
 private int type;

//// Methods

/// <summary>
 /// Returns User Input for Mouse Input
 /// </summary>
 /// <param name="mouseInput">The mouse input.</param>
 /// <returns>The user input structure</returns>
 public static Input Mouse(MouseInput mouseInput)
 {
 Input input = new Input();
 input.type = 0;
 input.mi = mouseInput;
 return input;
 }

/// <summary>
 /// Returns User Input for Keyboard Input
 /// </summary>
 /// <param name="keyboardInput">The keyboard input.</param>
 /// <returns>The user input structure</returns>
 public static Input Keyboard(KeyboardInput keyboardInput)
 {
 Input input = new Input();
 input.type = 1;
 input.ki = keyboardInput;
 return input;
 }

}

/// <summary>
 /// The Item Click Method.
 /// </summary>
 /// <param name="item">The automation element item to be clicked.</param>
 internal static void ItemClick(AutomationElement item)
 {
 System.Windows.Rect rect = item.Current.BoundingRectangle;
 System.Windows.Point center = new System.Windows.Point((double)((int)(rect.Left + ((rect.Right - rect.Left) / 2.0))), (double)((int)(rect.Top + ((rect.Bottom - rect.Top) / 2.0))));

if (SetCursorPos(new System.Drawing.Point((int)center.X, (int)center.Y)))
 {
 MouseLeftKeyPress();
 }
 }

/// <summary>
 /// The Left Mouse Click Method.
 /// </summary>
 private static void MouseLeftKeyPress()
 {
 MouseLeftKeyDown();
 MouseLeftKeyUp();
 }

/// <summary>
 /// The Left Mouse Key Down Method.
 /// </summary>
 private static void MouseLeftKeyDown()
 {
 Input input = Input.Mouse(new MouseInput(2, GetMessageExtraInfo()));//left key down
 SendInput(1, ref input, Marshal.SizeOf(input));
 }

/// <summary>
 /// The Left Mouse Key Up Method.
 /// </summary>
 private static void MouseLeftKeyUp()
 {
 Input input = Input.Mouse(new MouseInput(4, GetMessageExtraInfo()));//left key up
 SendInput(1, ref input, Marshal.SizeOf(input));
 }

/// <summary>
 /// The method to enter text using Keyboard input.
 /// </summary>
 /// <param name="text">The input text.</param>
 internal static void EnterText(string text)
 {
 KeyPress((short)KeyboardInput.SpecialKeys.HOME, true);
 KeyHold((short)KeyboardInput.SpecialKeys.SHIFT, true);
 KeyPress((short)KeyboardInput.SpecialKeys.END, true);
 KeyLeave((short)KeyboardInput.SpecialKeys.SHIFT, true);
 KeyPress((short)KeyboardInput.SpecialKeys.DELETE, true);

if (CapsLockIsOn())//set caps lock to false
 {
 KeyPress((short)KeyboardInput.SpecialKeys.CAPS, true);
 }

foreach (char c in text)
 {
 short key = VkKeyScan(c);
 if (!c.Equals('\r'))
 {
 if (ShiftKeyIsNeeded(key))
 {
 SendKeyDown(0x10, false);
 }
 KeyPress(key, false);
 if (ShiftKeyIsNeeded(key))
 {
 SendKeyUp(0x10, false);
 }
 }
 }

}

/// <summary>
 /// Sends a special key entry from keyboard
 /// </summary>
 /// <param name="key">the special key input</param>
 internal static void KeyBoardEntry(KeyboardInput.SpecialKeys key)
 {
 KeyPress((short)key, true);
 }

/// <summary>
 /// Checks if Caps Lock is on.
 /// </summary>
 /// <returns>state if caps lock key.</returns>
 private static bool CapsLockIsOn()
 {
 return (GetKeyState(20) != 0);
 }

/// <summary>
 /// Checks if Shift Key is needed.
 /// </summary>
 /// <param name="key">the input key.</param>
 /// <returns>result</returns>
 private static bool ShiftKeyIsNeeded(short key)
 {
 return (((key >> 8) & 1) == 1);
 }

/// <summary>
 /// Keyboard key press Method.
 /// </summary>
 /// <param name="key">the input key</param>
 /// <param name="specialKey">flag if special key.</param>
 private static void KeyPress(short key, bool specialKey)
 {
 SendKeyDown(key, specialKey);
 SendKeyUp(key, specialKey);
 }

/// <summary>
 /// Method to hold the key pressed.
 /// </summary>
 /// <param name="key">The input key.</param>
 /// <param name="specialKey">flag if special key.</param>
 private static void KeyHold(short key, bool specialKey)
 {
 SendKeyDown(key, specialKey);
 }

/// <summary>
 /// Method to leave the held key.
 /// </summary>
 /// <param name="key">The input key.</param>
 /// <param name="specialKey">flag if special key.</param>
 private static void KeyLeave(short key, bool specialKey)
 {
 SendKeyUp(key, specialKey);
 }

/// <summary>
 /// Method for key down.
 /// </summary>
 /// <param name="key">The input key.</param>
 /// <param name="specialKey">flag if special key.</param>
 private static void SendKeyDown(short key, bool specialKey)
 {
 KeyboardInput.KeyUpDown keyUpDown = KeyboardInput.KeyUpDown.KEYEVENTF_KEYDOWN;
 if (specialKey)
 {
 keyUpDown |= KeyboardInput.KeyUpDown.KEYEVENTF_EXTENDEDKEY;
 }
 Input input = Input.Keyboard(new KeyboardInput(key, keyUpDown, GetMessageExtraInfo()));
 SendInput(1, ref input, Marshal.SizeOf(typeof(Input)));
 }

/// <summary>
 /// Method for key up.
 /// </summary>
 /// <param name="key">The input key.</param>
 /// <param name="specialKey">flag if special key.</param>
 private static void SendKeyUp(short key, bool specialKey)
 {
 KeyboardInput.KeyUpDown keyUpDown = KeyboardInput.KeyUpDown.KEYEVENTF_KEYUP;
 if (specialKey)
 {
 keyUpDown |= KeyboardInput.KeyUpDown.KEYEVENTF_EXTENDEDKEY;
 }
 Input input = Input.Keyboard(new KeyboardInput(key, keyUpDown, GetMessageExtraInfo()));
 SendInput(1, ref input, Marshal.SizeOf(typeof(Input)));
 }
 }

Add the reference to this assembly inside the AgentDesktop project.

Here TypeTextBoxSearch(“Enter your search term”, “CCA R1”); is the function which accepts the Name of the Search Box Control and the search term.

To get the Name of the Search Box Control of bing, we can make use of UiSpy tool

http://msdn.microsoft.com/en-us/library/ms727247.aspx

  • Run the UiSpy tool.
  • Set Mode as Focus Tracking

  • Open Bing
  • Put the foucs on the Bing Search Box and get its name and other details from the UISpy window.

Create a new UII Hosted Application record in CRM

Run the Agent Desktop.exe

When we run the Agent Desktop we can see the Bing search page hosted inside the Agent Desktop as a Hosted Control. And the search box being auto populated with CCA R1 text, followed by Click on Enter to display search results.

Hope it helps.

Customer Care Accelerator (CCA) for CRM 2011 (Part 3 – Hosting Bing as Hosted Control)

Please refer the earlier post

1. Customer Care Accelerator – Part 1

2. Customer Care Accelerator – Part 2

Here we would be hosting the Bing search page using Hosted Control.

Add a new class library project to the Agent Desktop Solution.

Add a new User Control class to the project

Add references to the following assemblies

Inherit the HostedControl class

And override the implement the Hosted Control class in the following manner

</pre>
using System;
using System.Windows.Forms;
using Microsoft.Uii.Common.Logging;
using Microsoft.Uii.Csr;
using Microsoft.Uii.Csr.Browser.Web;

namespace MyHostedControl
{
 /// <summary>
 /// Class BingHostedControl
 /// </summary>
 public partial class BingHostedControl : HostedControl
 {
 /// <summary>
 /// The navigation URL
 /// </summary>
 private readonly string _navigationUrl;

/// <summary>
 /// Represents the web page dom
 /// </summary>
 private HtmlDocument _doc;

/// <summary>
 /// The web browser
 /// </summary>
 private WebBrowserExtended _webBrowser;

/// <summary>
 /// Initializes a new instance of the <see cref="BingHostedControl"/> class.
 /// </summary>
 public BingHostedControl()
 {
 InitializeComponent();
 }


 /// <summary>
 /// Initializes a new instance of the <see cref="BingHostedControl"/> class.
 /// </summary>
 /// <param name="appId">The app id.</param>
 /// <param name="appName">Name of the app.</param>
 /// <param name="extensionXml">The extension XML.</param>
 public BingHostedControl(Guid appId, string appName, string extensionXml)
 : base(appId, appName, extensionXml)
 {
 _navigationUrl = "http://www.bing.com";
 InitializeComponent();
 }

/// <summary>
 /// Initializes this instance.
 /// </summary>
 public override void Initialize()
 {
 try
 {
 InitializeBrowser();
 base.Initialize();
 }
 catch (Exception exception)
 {
 Logging.Error("Bing Hosted App", "Error occurred initializing the Bing control", exception);
 throw;
 }
 }

/// <summary>
 /// Initialize Browser
 /// </summary>
 private void InitializeBrowser()
 {
 _webBrowser = new WebBrowserExtended(false, true, true);
 _webBrowser.Dock = DockStyle.Fill;
 _webBrowser.Visible = true;
 Controls.Add(_webBrowser);
 }


 /// <summary>
 /// Close the web browser process before closing the hosted control
 /// </summary>
 public override void Close()
 {
 try
 {
 if (_webBrowser != null)
 {
 _webBrowser.CloseBrowser();
 _webBrowser.Dispose();
 }

base.Close();
 }
 catch (Exception exception)
 {
 Logging.Error("Bing Hosted App", "Error occurred initializing the Bing control", exception);
 throw;
 }
 }


 /// <summary>
 /// Method is used to perform automation
 /// </summary>
 /// <param name="args">event arguments</param>
 protected override void DoAction(RequestActionEventArgs args)
 {
 try
 {
 if (args == null)
 {
 return;
 }

if (args.Action.Equals("default"))
 {
 _webBrowser.DocumentComplete += WebBrowser_DocumentComplete;
 _webBrowser.Navigate(_navigationUrl);
 }

base.DoAction(args);
 }
 catch (Exception exception)
 {
 Logging.Error("Bing Hosted App", "Error occurred initializing the Bing control", exception);
 throw;
 }
 }


 /// <summary>
 /// Called when web application is completely loaded
 /// </summary>
 /// <param name="sender">sender object</param>
 /// <param name="e">event arguments</param>
 private void WebBrowser_DocumentComplete(object sender, DocumentCompleteEventArgs e)
 {
 try
 {
 if (_webBrowser != null &&
 (_webBrowser.ReadyState == WebBrowserReadyState.Complete ||
 _webBrowser.ReadyState == WebBrowserReadyState.Loaded))
 {
 _doc = _webBrowser.Document as HtmlDocument;
 if (_doc != null)
 {
 // perform DOM operation as reuquired
 //_document = _doc.GetElementsByTagName("FRAME");
 }
 }
 }
 catch (InvalidOperationException exception)
 {
 Close();
 Logging.Error("Bing Hosted App", "Error occurred while loading Bing control", exception);
 throw;
 }
 catch (Exception exception)
 {
 Close();
 Logging.Error("Bing Hosted App", "Error occurred while loading Bing control", exception);
 throw;
 }
 }
 }
}
<pre>

Create a new UII Hosted Application record in CRM

Here we will see a default UII Actions defined for the Hosted Control which we can access in the DoAction method of the Hosted Control.

Run the Agent Desktop.exe

We can see the Bing search page hosted inside the Agent Desktop as a Hosted Control. We will get into details of the Hosted Control and other stuffs and will see more real world examples in the future posts.

Customer Care Accelerator (CCA) for CRM 2011 (Part 2 – Hosting Bing as Web Hosted Control)

As I have already covered installation and configuration in part 1 of the post, let’s take a little step further with a simple example in which we will host Bing inside Agent Desktop in a new tab as a Web Hosted Control.

Open the CRM organization.

Go to UII Settings à Create a new UII Hosted Applications

Specify the following values for the new UII hosted application record

Hosted Application Type
à Web Hosted Application

Application is Global
à Checked (To make it appear in the Agent desktop when it loads)

URL
à URL of the Bing search page.

Save the record and run the AgentDesktop.exe.

We can see the Bing search page hosted inside the Agent Desktop.

This was very simple example. As we move forward we’d look into more complex and real world scenarios.

Hope it helps.

Customer Care Accelerator (CCA) for CRM 2011 (Part 1 – Installation)

I have been playing around with CCA for quite some time now for few of my recent projects. So just thought of sharing some of my learnings. Will try to cover as much as possible in different parts. For the part 1 let us start with the installation.

The first step to which is to download it. We can get the CCA components from the market place.

http://pinpoint.microsoft.com/en-IN/applications/Customer-Care-Accelerator-for-Microsoft-Dynamics-CRM-2011-12884949176

Which would be CCA.cab file which we need to extract. It will have one more cab file in it. CustomerCareAccelerator.zip.cab which also needs to be extracted.

It will contain following files and folders in it

Open the Accelerator folder and execute run the 32 bit or 64 bit Customer Care Accelerator exe.

It would have following files and folders in it.

Open the source code folder and open the Agent Desktop solution therein.

If we try to build the solution it will fail as it would be expecting references to certain assemblies that will be missing

To get those assemblies open the UII folder and run the executable inside.

The executable will install the following folders

The Framework folder will contain all the required assemblies.

Replace the CRM 2011 dlls with the latest one otherwise we would face authentication errors.

Here download the hotfix for CCA and replace the following assemblies in the framework folder

http://dynamics-crm.pinpoint.microsoft.com/en-us/applications/customer-care-accelerator-for-microsoft-dynamics-crm-2011-12884914795

Add the required references to the projects in the AgentDesktop Solution.

There is one assembly Microsoft.Practices.CompositeUI.Windows which we can get from the following url

http://blogs.msdn.com/b/ukcrm/archive/2011/05/11/getting-started-with-cca-for-crm-2011.aspx

Adding references to it will let us finally build the solution.

Next import the following solutions and the csv files in the CRM organization.

Once the import is successful, open the Microsoft.Crm.Accelerator.Cca.RIConfigLoader.exe of the solution just built.

Create a new connection.

For CRM Service URL, specify the discovery service url and check CRM Online if connection to the Online instance.

Once connected Click Deploy

Create a TEMP folder on the C Drive which Agent Desktop will user for logging.

Next open the AgentDesktop.exe.config and specify the connection information.

And Run the AgentDesktop.exe.

Hope it helps.