Monday, December 21, 2015

CRM OData (REST) queries and special characters

In this blog, we will discuss "How to handle special characters in CRM OData queries". Every now an then we have to query the data based on the fields other than entity Ids. Most of the time OData queries works as expected except if the filtering parameter conatins special characters. OData queries does not support special characters as a filter parameters.

For example, if you are searching for a customer with an apostrophe in the  name (“Simon O’ Donnel”),  the OData query will throw a following error message.












If you try to search for a customers with special characters in the email address (abc#123@test.com) , we  encountered the following error message.











The reason is that these special characters has different meaning when used in URLs. The JavaScript “encodeUri” or  “encodeUriComponent” does not solve this problem. Here is the list of the special characters that needs to be replaced when used in the OData queries.
https://msdn.microsoft.com/en-us/library/aa226544(SQL.80).aspx

Special character Special meaning Hexadecimal value
+ Indicates a space (spaces cannot be used in a URL). %2B
/ Separates directories and subdirectories. %2F
? Separates the actual URL and the parameters. %3F
% Specifies special characters. %25
# Indicates bookmarks. %23
& Separator between parameters specified in the URL. %26

The apostrophe is not mentioned in the table. The apostrophe needs to be replaced with double apostrophes.
Now you can write a separate function to replace these characters with the appropriate hexadecimal value.

Note: Do not use the “JavaScript String replace() Method”. It will replace the first occurrence of the special characters. if you  have 2 occurence of the same special characters in the filtering parameter, it will fail. So use the regular expression to replace the characters.

You can create a  separate function and call it for all the filtering parameter before you pass it to the query.

function replaceSpecialCharacters(attribute) {
  // replace the single quotes
     attribute = attribute.replace(/'/g, "''");

     attribute = attribute.replace(/"+"/g, "%2B");
     attribute = attribute.replace(/\//g, "%2F");
     attribute = attribute.replace(/"?"/g, "%3F");
     attribute = attribute.replace(/%/g, "%25");
     attribute = attribute.replace(/#/g, "%23");
     attribute = attribute.replace(/&/g, "%26");
     return attribute;
}


Happy Coding…

Friday, October 30, 2015

CRM SOAP Library- Part 3 (Testing CRM web resources for CRM Online in Visual Studio)

This is a part 3 of the CRM Soap Library series. This blog covers how to test the web resources that make CRM web services calls  from visual studio for MSCRM Online.

If you run the CRM soap library sample or "StartUp.htm" page from my last blog CRM SOAP Library - Part 2 (Project Structure) , you will get the following  error.

“Sdk.Util.getClientUrl Unable to get clientUrl. Context not available.”

This is a straight forward error. The library is trying to get the CRM URL from global context or Xrm.page.Context. For development purposes,  you can replace the “GetGlobalContext().getClientUrl()” line in “Sdk.Soap.min.js” with your  CRM Online URL.


Now if you try to run the code after making the change,  code will throw the following error.

“status: 401: Unauthorized”

It becomes a pain when you have to keep deploying Java Script resources to CRM to test them. There are hundreds of forums/blogs that talk about this problem but you can’t not see any solution.

I figured out a way around this problem with the help of “Fiddler”.So, here is hack that will allow you to run/test you web resources without deploying them in CRM.

Here is the step by step tutorial to achieve this.
  1. If you don't have fiddler installed already, install it.you can download it from http://www.telerik.com/download/fiddler.
  2. Start the fiddler and make sure “Capture Traffic” is selected  in the “File” menu as shown in the screen shot below.
     image
  3. Logon to your CRM organisation. I am using CRM Online for this tutorial.
  4. Switch to fiddler and double click on  a CRM URL from the session pane as shown in the screen shot.
    image
  5. In the second pane, select “Inspectors>>Cookies” as shown in the screen shot below. if the contents of cookies for the selected request does not look the same try some other URL from the session list.
    image
  6. Look for “MSISAuth” in the contents and select everything from that text onwards and paste it notepad.
  7. Select “Tools>>Customize Rules” as shown in the screen shot below. It will open the “CustomRules.js” file.
    image
  8. Search for  “OnBeforeRequest(oSession: Session) function in the file and add the following code to it.

    1:  if (oSession.PathAndQuery=="/XRMServices/2011/Organization.svc/web")  
    2:   {  
    3:               //appending the cookie data for the request  
    4:            oSession.oRequest["Cookie"] = (oSession.oRequest["Cookie"] + "; text copied in step 6" );  
    5:  }  
    
    

  9. Replace the highlighted text with the text copied in step 6. Save the changes to the file.
  10. Open up your HTML page in VS and test it. You won’t get the unauthorised error  anymore.

Thursday, October 22, 2015

CRM SOAP Library - Part 2 (Project Structure)

This is the second part of my blog www.mscrmshop.blogspot.com.au/2015/10/crm-soap-library-sdksoapjs-part-1.html. In this blog I will discuss the Visual Studio project structure for JavaScript(SOAP endpoints) projects. The sample project provided by Microsoft has the following structure.

image

All the code is contained in the folder '_samples'. There are 3 sub folders in that folder.
  • min:
    This folder contains the minified version of Sdk.soap.min.js, jquery_1.9.1.min.js and folders for actions, entities and messages.
  • sampleCode:
    This is working folder where developers will write their html and JavaScript  web resources. This folders contains 3 subfolders to organise the images, pages(html), and scripts.
  • vsdoc:This folder contains all the same files and folders as the 'min' folder but they are not min-ified. Libraries in this folder contains comments etc. for the developer. Script files from this folder will be used in sampleCode scripts to provide IntelliSense.

Project Template

I think development teams should use project templates if they are doing similar work all the time. It brings consistency onto the project structure. I have changed a few things around in the sample project and turned it into a project template. My project structure looks like the following screen shot.

 image

I got rid of the '_sample' folder. I have renamed the 'min' folder to 'libs' as this folder also contains the SOAP library as well as the jquery library. I have renamed 'sampleCode' to 'webresources' and left the vsdoc as it is. I have deleted most of the sample files from this solution as I want to use this project as a project template. I have kept a few files from the sample solution to use as templates if required.

You can download my project template from: Project Template.

Now when developers will starts a webresource project using the soap endpoint. They will select a project type of “CRM SOAP JavaScript” project as shown in the following screen shot.

image

By doing that you  have same folder structure for all webresource projects using SOAP endpoints.

The following screen shot displays the structure of the new project created using the template.

image

Working with the files

  1. libs folder
    The following screen shot displays all the files and sub folders in the libs folder. The most important thing to remember is to use the min-ified version of all the JavaScript files to reduce the size. 
    image

    • the root folder contains the Sdk.soap.min.js and jquery_1.9.1.min.js files

    • the 'actions' folder contains all the custom action classes. The custom action will be created using Sdk.Soap.js Action Message Generator.

    • the 'entities' folder contains all the CRM entity classes. These classes will be used for early binding.

    • the 'message' folder contains all the other messages supported by the library. The library supports 202 different messages. You can add and remove the messages required by your project.

  2. vsdocs folder
    This folder contains all the files and folders as the 'libs' folder. The only difference is that the JavaScript files in this folders are not min-ified. These files will be used just for IntelliSense and won’t be uploaded into CRM.

  3. webresources folder
    This is the real working folder. This folder contains the following files and folders:
    image

    • the 'images' folder contains all the images used in the HTML web resources.

    • the 'pages' folder contains all the HTML websesources

    • the 'scripts' folder contains all the JavaScript files that will be called by the html webresources/CRM forms.

      I have added a StartUp.htm and StartUp.js to the project template as starting webresources. You can modify them for your project or use as reference.
      The following section displays the source code for StartUp.htm

      1:  <html>  
      2:  <head>  
      3:   <title>StartUp Page</title>  
      4:   <script src="../../../ClientGlobalContext.js.aspx" type="text/javascript"></script>  
      5:   <script src="../../libs/Sdk.Soap.min.js"></script>  
      6:   <script src="../../libs/jquery_1.9.1.min.js"></script>  
      7:   <script src="../../libs/entities/Sdk.Account.min.js"></script>  
      8:   <script src="../scripts/StartUp.js"></script>  
      9:   <!--<script src="../../libs/messages/Sdk.WhoAmI.min.js"></script>   
      10:   <script src="../../libs/actions/Sdk.sample_SimpleAction.min.js"></script>-->  
      11:   <script type="text/javascript">  
      12:   "use strict";  
      13:   document.onreadystatechange = function () {  
      14:    if (document.readyState == "complete") {  
      15:    }  
      16:   }  
      17:   function clearMessages() {  
      18:    document.getElementById("messages").innerHTML = "";  
      19:   }  
      20:   function earlyBindingSample() {  
      21:    clearMessages();  
      22:    writeToPage("Starting 'Early Binding' Sample");  
      23:    try {  
      24:    startEarlyBindingSample();  
      25:    }  
      26:    catch (e) {  
      27:    writeToPage(e.message);  
      28:    }  
      29:   }  
      30:   </script>  
      31:   <style type="text/css">  
      32:   body  
      33:   {  
      34:    font-family: "Segoe UI";  
      35:   }  
      36:   </style>  
      37:  </head>  
      38:  <body>  
      39:   <button onclick="earlyBindingSample()">&quot;Early Binding&quot; Sample</button>  
      40:   <ol id="messages" />  
      41:  </body>  
      42:  </html>  
      

      The script section highlighted in yellow lists all the JavaScript files required for this webresource. You can add the reference to your custom actions, entities and messages as required.
      • ClientGlobalContext.js.aspx:
        This file will get the context for the webresource

      • scripts/Sdk.Startup.js:
        This file contains the startEarlyBindingSample() function that the StartUp.htm webresource will call.

      The following code displays the reference directive from the StartUp.js. 

      1:  /// <reference path="../../vsdoc/Sdk.Soap.vsdoc.js" />  
      2:  /// <reference path="../../vsdoc/entities/Sdk.Account.vsdoc.js" />  
      3:  /// <reference path="../../vsdoc/jquery_1.9.1_vsdoc.js" />  
      
      These directives are used to provide IntelliSense. You can read the following article to get detail information on JavaScript IntelliSense. https://msdn.microsoft.com/en-us/library/bb385682.aspx  As you can see the code above references “Sdk.Account.vsdoc.js”. It will add the IntelliSence for the account entity as shown in the screen shot below.

      image
    That is all about the project structure. I hope this will give you enough information on how to setup a project structure for the Sdk.soap.js library.

    Another feature that would be nice, would be a one click deployment into CRM...

Monday, October 19, 2015

CRM SOAP Library – sdk.soap.js Part 1

This blog post is related to the CRM soap library created by the CRM SDK team last year. This library helps with writing JavaScript for web resources using SOAP endpoints just like C# code.  I am surprised that it only has 2600 downloads. I believe more people should use it. It provides a lot of functionality and will help to reduce code duplication in a project.
The library includes 2 files:
  • Sdk.Soap.min.js This is the minified version of the library. The size of the file is around 164kb.
  • Sdk.Soap.vsdoc.jsThis file should be used at design time to add IntelliSense to JavaScript

Advantages/Benefits

The following lists some of the benefits/advantages of using this library.
  1. Writing JavaScript like C#
    The library helps you to write JavaScript like C# code. It provides object models, methods and messages like C#. It is more productive if you are a C# developer.

  2. IntelliSense
    The Sdk.Soap.vsdoc.js file contains comments for the developers. It will be used at design time to provide IntelliSense. You just need to add a reference directive on the top of your .js file as shown below:
    /// <reference path="..path/Sdk.Soap.vsdoc.js" />

  3. Choice of Early Bound and Late Bound Classes
    The library provides the option to chose early binding and late binding in your code. I prefer the late binding but other people may prefer early binding classes as it provides the IntelliSense at design time for CRM entities. The solution also provides an early binding class entities generator to generate early bind classes for CRM entities. It is an equivalent of  crmserviceutil.exe

  4. Choice of Namespaces
    The library supports the following 8 core IOrganisationService methods.
    Associate,Create, Delete, Disassociate, Execute, Retrieve, RetrieveMultiple and Update.

    The library provides the 4 different namespaces that implement these core methods:


    • Sdk.Async:  It executes the methods asynchronously. The method signatures provide the  successCallBack and errorCallBack parameters.
    • Sdk.Sync:  It executes the methods synchronously.
    • Sdk.jQ:  It is an alternative approach to implementing asynchronous operations. It returns a jQuery.Deferred object/Promise. The initial state of the object is pending. The code will wait until the promise is resolved or rejected to execute the next line of the code.  In short, it is like writing synchronous code for asynchronous calls. I will post some sample code to explain the difference between callbacks and promises at a later date.

      This namespace depends on the existence of the jQuery.
                 
    • Sdk.Q:This is also the implementation of the “Promise” concept discussed above in Sdk.JQ.

  5. Messages/Actions
    Apart from the 8 core methods, the library supports 202 different methods. The library also provides a utility to create methods for custom action methods.

  6. Supported Queries
    The Sdk.Soap.js library supports the three main query styles used with retrieve operations:

Things to consider

  1. The library was originally written for CRM2013. The Sdk.Xml.getEnvelopeHeader function specifies an SdkClientVersion value of 6.0. It does work for CRM2013 and CRM2015. It may change in future.
  2. It does not contain all the messages.Please check the documentation on the libarary page.
  3. Delete the messages that are not required for your project to reduce the size of the JavaScript file.
  4. Delete the namespaces that are not required
Downloads
    Here is the list of the downloads for the library:
  1. Sdk.Soap.js (contains the core libraries)

  2. Sdk.Soap.js Entity Class Generator (tool to create libraries for CRM entities for ‘early binding’ and IntelliSense)

  3. Sdk.Soap.js Action Message Generator (tool to generate the support libraries for custom actions in your organization.
  4. Sdk.Soap.js Samples (code sample using the library)

 

Monday, September 7, 2015

Creating CRM apps with Project Siena

In my last blog, I used Project Siena to create a mobile app for my blog. While going through all the samples and tutorials, I came across this sample Project Siena: Dynamics CRM Online sample. The sample also contains a step by step guide to connect to CRM Online in Project Siena.

This is the link “Step by Step guide to connect to CRM Online” to the guide.

I followed all the steps but I was not able to retrieve any data from the CRM.

When I tried to test the functions listed in the WADL file, I got the following error after
authentication.

“There was an error in retrieving sample data. Error : The resource owner or authorization server denied the request”
image

The problem is that one step is missing in the step by step guide. After adding the app in “Windows Azure”, we need to add “Dynamic CRM Online” in “permissions to other applications” as shown in the screen shot below.

image

After you done that. You can retest the function and this time you will get the results as shown in the screen shot below.

image

Now you can test your sample application.

Monday, August 31, 2015

Building Mobile Apps using Project Siena

Project Siena is a Microsoft initiative that enables business users to create mobile apps without any programming skills. Project Siena was released at the end of 2013. The Project Siena team have been adding new features and functionality ever since. It's only downside is that it only allows the creation of applications for the Windows platform. 
  • It lets you drag and drop controls onto the canvas.
  • It lets you manipulate the mobile device features including camera, touch and pen input, and voice annotation etc.
  • It provides the functionality to connect to SharePoint, Bing APIs, REST endpoints and RSS feeds.
You can download “Project Siena” from “https://www.microsoft.com/en-us/projectsiena/”.

I have created a Windows app for my blog. It took me a less than an hour to create this app.

image

I have added the following 3 “On Select” events to this app.
  1. On select of the blog title, the app will open that blog in the web browser.
  2. On select of the “Amreek Singh”, the app will open my linkedin profile in the web browser.
  3. On select of the logo image, the app will open my blog “mscrmshop.blogspot.com” in the web browser.
This is the first time I have done a video tutorial for the blog.



Click here to download the project file.

Wednesday, July 15, 2015

Restrict customer lookup to select a specific entity records in CRM 2013/2015

A few years ago, I wrote a blog addCustomFilter method for lookup control in CRM2013. Some of the readers asked if “addCustomFilter” can be used to restrict/default the customer lookup to a specific entity. The answer to the question is that you can restrict the customer lookup to return the results for a specific entity, but you can’t default it to the contact entity.
Here is an example on how to restrict the customer lookup on the case entity to display contact records. I am using the same code that I have used in my original blog with a few changes.

Code

 function addEventHandler() {  
   // add the event handler for PreSearch Event  
   Xrm.Page.getControl("customerid").addPreSearch(addFilter);  
 }  
 function addFilter() {  
   //create a filter xml  
    var filter ="<filter type='and'>" +  
            "<condition attribute='accountid' operator='null'/>" +  
            "</filter>";   
     //apply the filter  
     Xrm.Page.getControl("customerid").addCustomFilter(filter,"account");  
 }  


In the above code, I am using the filter where accountid is null and applying it to the account entity. The account record will always have an accountid, therefore no account records will be returned.

Results

The following screen shot displays the customer lookup returning only contact records.
image

If the user clicks on the “Look Up More Records”, CRM will display the following screen.
image

The customer lookup does not return any account records as shown in the screen shot above.
The user can change the “Look for” entity to contact and choose the contact record.

.....

Wednesday, June 10, 2015

Branding in CRM2015 SP1

How many times do customers ask to add branding to their dynamics CRM solution? The answer is that they have been asking for this from the good old CRM 1.2 days. At last it is here in CRM2015 SP1. It still does not provide full fledged branding functionality, but is a good start.
To add branding to your CRM solution, follow the following steps:
  1. Go to Setting>>customization>> as shown in the following screen shot

    image
  2. Click on “Themes”. The system will display “CRM Default Theme” in the grid. As the name suggests, it is the default theme for the CRM.

    image
  3. Open the “CRM Default Theme” and click the Clone button on the command bar. The system will clone the default theme.
  4. Make the changes to the theme and click save. There are a few options available in the theme. I have made 3-4 changes to my theme for this blog.

    image
  5. Click on “Preview” button to preview the changes.
  6. If you are happy with the changes, click “Publish Theme” to push the changes to all the users.

CRM Screen shot of with default theme

image

CRM Screen shot of with my theme

image

Note

  1. Themes are not solution aware. To deploy the theme to other environments, use export to excel functionality and import it in the target environment.
  2. A new field named color is added to the entity customization screen. This color is used to represent the entities in the navigation bar as shown below.

    image

Limitations

You will not be able to change the color of the entity forms, they are still white as I write this blog.

Best Practices

Check the following link for the best practices and color contrasts.
https://technet.microsoft.com/library/21a166a0-d25e-4260-a1e4-2ddc528787c2

CTI integration between CRM USD and Microsoft Lync - Part 2

This is the second part of the blog CTI integration between CRM USD and Microsoft Lync - Part 1. The last blog covered how to receive the CTI event in USD. In this blog we will use the telephone number provided by the CTI system to pop up a customer record in USD.  To achieve this we have to create a windows navigation rule record.

Creating a Window Navigation Rule

  1. Logon to CRM.
  2. Navigate to Settings>>Window Navigation Rules
  3. Click “New” and fill in the following fields

    Field Name Value
    Name LyncIntegration Route
    Order 1
    Hosted Control LyncCTIManager
    Direction Both

    image
  4. Save the record.
  5. Click + in the CTI search section of the form, as shown below, to create a new CTI Search record.

    image
  6. Fill the form with the following values as shown below.

    Field Name Value
    Name LyncIntegration ContactSearch
    Order 1
    FetchXML <fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
      <entity name="contact">
        <attribute name="fullname" />
        <attribute name="parentcustomerid" />
        <attribute name="telephone1" />
        <attribute name="emailaddress1" />
        <attribute name="contactid" />
        <order attribute="fullname" descending="false" />
        <filter type="and">
          <condition attribute="telephone1" operator="eq" value="[[cti.telephone1]]" />
        </filter>
      </entity>
    </fetch>

    To create the fetchxml use the advance find functionality in CRM and then download the xml. The highlighted part in the xml [[cti.telephone1]] represents the parameter passed as a query string by the LyncConnector middleware application

    image
  7. Save the record and return back to windows navigation rule.
Based on the result of the CTI Search, we can configure the behaviour of the windows navigation rule.

Single Match (Single contact is found)

  1. Under Single Match, in the Decision field, select Create Session, Load Match then Do Action.
  2. Under Single Match, in the Action field, click the search icon to select a value, and then click New.

    image
  3. It will open up a new “Action Call” record. Fill this form with the following values:

    Field Name Value
    Name LyncIntegration Open Contact
    Hosted Control CRM Global Manager
    Action Open CRM Page
    Data Id=[[$Context.Id]]
    LogicalName=[[$Context.LogicalName]]

    image
  4. Save the "Action Call” record and return back to the windows navigation rule record.
  5. Under the Result area, fill the Destination, Target Tab and Show Tab field as shown in the screen shot below.

    image
  6. Save the window navigation rule record.

No Matches (No contact is found)

  1. Under No Matches, in the Decision field, select Do Action.
  2. Under No Matches, in the Action field, click the search icon to select a value, and then click New.

    image
  3. It will open up a new “Action Call” record. Fill this form with the following values:

    Field Name Value
    Name Search Contact Action Call
    Hosted Control Search
    Action Find
    Data contact

    image
  4. Save the "Action Call” record and return back to the windows navigation rule record. This action will open a USD search screen with the contact tab selected.
  5. Save the windows navigation rule.

Multiple Matches

I did not find a way to display multiple results. I will try to come up with a custom hosted control in the future. If anyone has any idea please let me know.

Testing the Integration

  1. Logon to USD.
  2. Ring the Lync number.
  3. If everything is working properly and system has found the matching contact, the system will then display the contact record and it will start a session as shown in the screen shot below

    image
  4. If no contact is found with the matching number USD will display the search screen with the contact tab selected as shown in the screen shot below. There is an issue with this solution; USD does not set the focus on the “Search” tab.

    image
     

Where to From Here

This is the simplest example of the integration. The middleware built in this blog is just posting the URL on a generic listener port. It can be modified to send Lync chat and contact information.
Going forward, middleware can be used to retrieve the interaction history from Lync and create CRM records as required.
Some people suggested to process the call in the LyncConnector, pass the customer id to USD, and create the session.  I am just exploring USD and would rather create my custom search control in USD.
Please keep the suggestions coming.

Sunday, May 10, 2015

CTI integration between CRM USD and Microsoft Lync - Part 1

Last year, Microsoft released USD (Unified Service Desk) for CRM 2013. USD is a framework to build contact centre applications to provides a unified view of customer data stored in CRM and other applications.
It provides the adapters and modules to manipulate CRM UI elements, agent scripting, configuration toolbars and a CTI adapter.  For more information on USD please check https://technet.microsoft.com/en-us/library/dn646899(v=crm.6).aspx
For this tutorial, we are only interested in CTI adapters. The following 2 types of adapters can be used to integrate USD with CTI systems.
  • Generic listener adapter:
    USD provides this adapter out of the box. This adapter listens for HTTP request on a port 5000 ( http://localhost:5000/). On receiving a request, the generic listener adapter extracts a query string from the URL and uses the query string as parameters to raise a CTI screen pop up in USD.


  • Custom CTI adapter:
    User Interface Integration(UII) CTI framework provides the component to build custom CTI adapters. The customer adapter can provide a lot of functionality to manage calls and agent state. Here is the link on how to build a custom CTI adapter for USD.

  • We will be using the generic listener adapter to achieve USD and Lync integration.

    Prerequisite

    1. Access to CRM2013 (I m using a on premise CRM)
    2. Lync client installed on the development machine 
    3. Microsoft Lync  2013 SDK installed on the development machine (Download)
    4. USD (Unified Service Desk) installed on the development machine
      The following article lists the step by step instructions to install USD.
      https://technet.microsoft.com/en-au/library/dn646908.aspx.  The USD installation involves:
      • Installing USD client (UnifiedServiceDesk.msi)
      • Deploying USD Solution using Package Deployer (CRM2013-USD-PackageDeployer.exe) For this tutorial, deploy “CRM 2013 SP1” solution

    Process Flow Diagram


    image
    1. Customer makes a phone call
    2. Phone call pop up appears in the Lync Client
    3. A custom middleware application receives the conversation event and posts a HTTP request on “http://localhost:5000” with customer phone number.
      http://localhost:5000/?phone=+61456564323
    4. USD generic listener pickup the event, extract the query parameter and use these parameters to pop contact record

    Configuring the generic listener adapter in CRM

    Make sure that all the prerequisite steps have been completed
    1. Logon to CRM  and navigate to “Settings>>Hosted Controls”
    2. Click “New” enter the fields as shown in the screen shot below

      image
      USD component, Display Group,Assembly URL and Assembly Type are the important fields and should contain the exactly same values.
      Assembly URL : Microsoft.Crm.UnifiedServiceDesk.GenericListener
      Assembly Type: Microsoft.Crm.UnifiedServiceDesk.GenericListener.DesktopManager
    3. Save the record.

    Creating a Lync Connector (Middleware application)

    A Lync connector application will capture the conversation event of the Lync client when a phone call is made or received.  This application is a client side application.
    I am creating the Lync connector as a WPF application.  I don’t need a user interface for the connector for this blog but may use it add more functionality to it in future.
    1. Create a new WPF application project and name it “LyncConnector”.

      image
    2. Add “Microsoft.Lync.Model.dll” as reference to the project. The file will be available in the following location.
      \Microsoft Lync\SDK\Assemblies\Desktop

      image
    3. The following code is going in the “MainWindow.xaml.cs file.
      Code:
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Windows;
      using System.Windows.Controls;
      using System.Windows.Data;
      using System.Windows.Documents;
      using System.Windows.Input;
      using System.Windows.Media;
      using System.Windows.Media.Imaging;
      using System.Windows.Navigation;
      using System.Windows.Shapes;
      using Microsoft.Lync.Model;
      using Microsoft.Lync.Model.Conversation;
      using System.Net;
      using System.Text.RegularExpressions;
      using System.Collections.Specialized;
      
      namespace LyncConnector
      {
          /// <summary>
          /// Interaction logic for MainWindow.xaml
          /// </summary>
          public partial class MainWindow : Window
          {
              private LyncClient _lyncClient;
      
              public MainWindow()
              {
                  InitializeComponent();
      
                  //Get the link client- Make sure Lync client is running
                  _lyncClient = LyncClient.GetClient();
      
                  // Invoke the conversation event when the conversation starts in Lync Client
                  _lyncClient.ConversationManager.ConversationAdded +=
                      new EventHandler<Microsoft.Lync.Model.Conversation.ConversationManagerEventArgs>(
                          OnConversationAdded);
      
              }
              void OnConversationAdded(object sender, Microsoft.Lync.Model.ConversationConversationManagerEventArgs e)
              {
                  // Get the properties for this conversation.
                  IDictionary<ConversationProperty, object> properties = e.Conversation.Properties;
      
                  // Get the Contact object for the person initiating the conversation.
                  Contact inviterContact = properties[ConversationProperty.Inviter] as Contact;
      
                  // Get the URI of the inviter.
                  string inviterUri = inviterContact.Uri;
      
                  // Try to match a phone number in the URI.
                  Regex phoneRegex = new Regex(@"\+(\d+)");
                  Match phoneMatch = phoneRegex.Match(inviterUri);
      
                  string callerId = string.Empty;
                  
                  if (phoneMatch.Success)
                  {
                      // Load the data only if the caller is from a PSTN number.
                      callerId = phoneMatch.ToString();
                      LoadDataForCaller(callerId);
                  }
              }
              private void LoadDataForCaller(string callerId)
              {
                            
                  string UsdLocalAddress = "http://localhost:5000";
      
                  using (var wb = new WebClient())
                  {
                      var data = new NameValueCollection();
                      
                      // By default generic listener pass the follwing 3 parameters to USD/
                      //You can use them to post some data. If you don't use them then generic listener will still post the empty values for these parameters. 
      
                      /*
                      data["ani"] = Ani;
                      data["dnis"] = Dnis;
                      data["type"] = CallType;
                       */
                      
                      data["telephone1"] = callerId;
      
      
                      try
                      {
                          if (Uri.IsWellFormedUriString(UsdLocalAddress, UriKind.RelativeOrAbsolute))
                              wb.UploadValues(new Uri(UsdLocalAddress), "POST", data);
                      }
                      catch (SystemException ex)
                      {
                          //System.Windows.MessageBox.Show(ex.Message, "Failed to send call event");
                      }
                  }
                 
              }
          }
      }
      

    4. Compile  and Run the code



    Test the integration



    1. Make sure Lync client is running
    2. Make sure Lync Connector application is running.
    3. Logon to USD and click on the setting >>Debug

      image

    4. Delete all the entries in the “Action Calls” tab by clicking the delete button as shown in the screen shot below.

      image

    5. Make a phone call or ask someone to ring you on Lync. If everything is working properly,  a new event will appear in Action Calls tab as shown in the screen shot.

       image



    So here you go, we have successfully passed the caller's phone number to USD.
    That is it for today. In the next tutorial we will use this phone number to pop up the contact record.

    Tuesday, March 31, 2015

    How to create a message in a Scribe Insight queue using C#

    If you are familiar with Scribe Insight then you would know that “queue” based integration is the preferred integration method. The reason for that is performance. Multiple message processors can be allocated to process the queues. For more information please read this blog on the “Message Processor”.

    Scribe Adapters can create the queue message automatically, but, what if we need to create the queue message from the portal or a custom program? This blog will show you how to create a MSMQ message using C#.

    The code below will create a message with the label "PortalCustomer" and put it in the ScribeIn queue.

    using System;
    using System.Messaging;
    
    namespace MSMQ
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Initiating MSMQ object");
               
               // queue address
                string queueAddress = @"FormatName:Direct=OS:machinename\private$\scribein";
                
                Console.WriteLine("Queue Path: {0}", queueAddress);
    
                //Create an instance of MSMQ Manager
                MSMQManager msmq = new MSMQManager(queueAddress);
                msmq.SendMessageToQueue();
    
                Console.WriteLine("Message sent successfully");
                Console.ReadLine();
            }
        }
    
        // Class that initiate the message queue and send the message
        class MSMQManager
        {
            private string queueAddress;
    
            public MSMQManager(string queueAddress)
            {
                this.queueAddress = queueAddress;
            }
    
    
            //Creating and sending the message
            public void SendMessageToQueue()
            {
                MessageQueue msMq = new MessageQueue(queueAddress);
    
                try
                {
                   //create an instance of customer class
                    Customer req = new Customer()
                    {
                        FirstName="John",
                        LastName="Smith",
                        ReceivedDate=DateTime.Now
    
                    };
                    
                    Console.WriteLine("Creating customer request: {0}", req.ToString());
    
                    //create the message
                    Message m = new Message()
                    {
                        
                        Body = req,
                        Label = "PortalCustomer",
                        Recoverable = true,
                       
                    };
               
                    Console.WriteLine("Initialising message: {0}", m.Label);
    
                    Console.WriteLine("Sending...");
                    msMq.Send(m);
                }
    
                catch (MessageQueueException e)
                {
                    Console.Write(e.Message);
                }
                catch (Exception e)
                {
                    Console.Write("Error Message: {0}. Trace: {1}", e.Message, e.StackTrace);
                }
                finally
                {
                    msMq.Close();
                }
            }
                  
        }
    }
    
     
    Here is the code for the customer class.

    using System;
    
    namespace MSMQ
    {
        [Serializable]
        public class Customer
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public DateTime ReceivedDate { get; set; }
    
            public override string ToString()
            {
                return string.Format("Link: {0} - Response: {1} - ReceivedDate: {2}", FirstName, LastName , ReceivedDate.ToString());
            }
        }
    }
    
    

    Run the code and look in the ScribeIn queue or in the Dead Message queue (if you don’t have any integration using label “PortalCustomer”).

    image

    Make sure that MSMQ are installed on the machine where the code is hosted, and can communicate  with Scribe server on port 1801.

    Thursday, February 5, 2015

    Microsoft CRM publisher stuck on “Initializing” in Scribe Insight

    If you are trying to create a CRM publisher in Scribe Insight and it is stuck on “Initializing” as shown in the screen shot below:
    image
    It means that there is something wrong.

    Cause

    If you check in the event viewer, you may find the following error:
    An unexpected error occurred.
    Microsoft Dynamics CRM Publisher
    http://fwocrm2013.edc.hosts.devnetwork/
    Error setting publisher settings: System.Messaging.MessageQueueException (0x80004005): Invalid queue path name.
       at System.Messaging.MessageQueue.ResolveFormatNameFromQueuePath(String queuePath, Boolean throwException)
       at System.Messaging.MessageQueue.Exists(String path)
       at Scribe.AdapterBase.Publisher.QueueService.InitPublisherQueues(String pubInQueueName, String pubSucceededQueueName, String pubFailedQueueName)
       at Scribe.AdapterBase.Publisher.ScribePubWorkerBase.InitPublisherQueues()
       at Scribe.AdapterBase.Publisher.ScribePubWorkerBase.setSettings(String settingsXML, String entitiesXML, Object lastRunTime, Object lastRunTimeUTC)
    The error suggests that there is problem with the path of the queue

    Solution

    Compare the queue names in the CRM publisher and message queues in component services as shown in the following screen shots.
    image image
    If the queue names are different then we have to update the queue names in the internal database.
    Note: I don’t know if this is a supported solution.
    1. Backup your ScribeInternal database.
    2. Look into the scribe.bridges table and find the bridgeid of your CRM publisher. All the publisher settings including the queues are stored in the settings column.
      image
    3. Now update the settings column with the proper queue paths.
    Note: Settings column stores the data as XML. Please be careful when updating the column.

    Wednesday, January 28, 2015

    'Security Negotiation Exception' during plug-in execution in CRM2013

    A few months ago, we experienced an issue during a plugin execution in the dev. environment. We were using Scribe Insight for integration. We were using the “Microsoft Dynamics CRM publisher” for scribe that registered a plugin on the contact entity. Everything was working perfectly until we received the following error:

    Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=6.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: The following error has occurred in the Scribe Change History plug-in: System.ServiceModel.Security.SecurityNegotiationException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #0CCC3255  

    Cause


    During troubleshooting we found the following entry in the event viewer of the backend server. 

    The Kerberos client received a KRB_AP_ERR_MODIFIED error from the server serviceaccountname. The target name used was HTTP/CRMFrontEndServer. This indicates that the target server failed to decrypt the ticket provided by the client. This can occur when the target server principal name (SPN) is registered on an account other than the account the target service is using. Ensure that the target SPN is only registered on the account used by the server. This error can also happen if the target service account password is different than what is configured on the Kerberos Key Distribution Center for that target service. Ensure that the service on the server and the KDC are both configured to use the same password. If the server name is not fully qualified, and the target domain (DomainName) is different from the client domain (DomainName), check if there are identically named server accounts in these two domains, or use the fully-qualified name to identify the server 

    The “EventSourceName” was Kerberos.

    Looking at the error we hypothesised that there was an SPN issue for the CRMFrontEndServer server.

    You can receive this error for any plugin published in the sandbox. It will only happen if the sandbox service is not installed on the same server as CRM web site and kerberos authentication is enabled for the website.
     

    Resolution


    We used the following account to list all the SPNs registered for the serviceaccountname.
    setspn –l domain\serviceaccountname

    The command displays only the SPN registered on the HTTP/CRMfrontEndServer.CRM.domainname.com  (Fully Qualified domain name of the CRM front end server).

    We added a new SPN on the servername using the following command setspn –a http/CRMFrontEndServer domain\serviceaccountname That was it. We restarted the sandbox service and the error was gone.

    For more information on SPNs and their configuration you can check out this KB article from Microsoft. http://support.microsoft.com/kb/929650