Thursday, July 19, 2012

Kick Your Business Up a Notch: All The Way To AWESOME!!

Learn how you can kick your business up a notch with Microsoft Dynamics.  This is a pretty cool little AD campaign by Microsoft that hopefully can be used to introduce Microsoft's "Dynamic Business" concept that I think could really help a lot of people.

Fun YouTube Video Promotion: http://www.youtube.com/watch?v=iO8HZLR8-G4

The Meat and Potatoes: http://www.microsoft.com/en-us/dynamics/dynamic-business.aspx

- Check it out!

Thursday, July 12, 2012

How to Build an HTML/JScript Configuration Web Resource for Microsoft Dynamics CRM 2011


Web Resources can be used to create an interface to allow end-users to easily configure your solution after it's been installed.  This is ideal for storing keys and other sorts of registration or configuration information related to the solution.

Download the Sample here: http://code.msdn.microsoft.com/Sample-HTMLJScript-172cd74e

For step-by-step instructions on how to install a configuration page (this one is already installed) and work with it from an end-user standpoint you can visit Mahender Pal's blog here:
http://mahenderpal.wordpress.com/2011/07/26/step-by-step-adding-configuration-page-in-solution-ms-crm-2011/

Building the Sample

1. First you must unzip the download file and install the included zip file SampleConfiguredSolution_1_0.zip
2. Next you must Import and Publish the  SampleConfiguredSolution_1_0.zip into your Microsoft Dynamics CRM 2011 instance.  Your instance can be On-Premise or Online.


Description

After you install the solution there are only two main components worth noting.  
1. A custom entity used to store configuration data.  I chose to use a custom entity instead of an XML file or other mechanism due to the ease of securing and manipulating the data.  The data is easy to secure because, as a custom entity, it uses the standard role-based security already included in CRM and by default will only be available to administrators.  The data is also easier to manipulate because if stored as an XML web resource it is stored in the content attribute of the webresource entity.  This means that you have to follow these steps to work with the data.
- un-encode the content attribute (it is stored as a base-64 encoded string)
- parse the XML 
- update the values
- re-encode the attribute data in base-64
- make an update call
It's just more complicated.

2. An HTML webresource that includes jscript that contains the GUI for working with the configuration data and also has jscript web service calls wired up inside that facilitate saving and retrieving the data.
The logic is easy:
When page loads it checks for a configuration record with a specific name.  If it finds the record it will load the data into the GUI.  
When the update button is pressed it checks if the record existed or not and creates it if it didn't exist otherwise it will update the record.


Source Code Files

  • SampleConfiguredSolution.zip - Download Zip File
  • SampleConfiguredSolution_1_0.zip - CRM 2011 Unmanaged Solution File

Tuesday, July 10, 2012

Using the Dynamic Type in Silverlight to Easily Access The Client-Side API in Microsoft Dynamics CRM 2011

This is a neat little trick to be able to easily work with the client-side API in CRM 2011 from within Silverlight using the "Dynamic" type.

1. Add a reference to Microsoft.CSharp from the .NET tab in your project.

2. Now you are ready to go.  The Dynamic type is one that allows you to write your code but allow it to not be evaluated until runtime.  This means that the compiler won't throw an error if your syntax is bad though so you will want to be precise.

The example given below illustrates getting the form type and verifying it is an update form and then if it is we are calling a function from a jscript webresource attached to the form (that is part of a namespace).  I also embedded a little call to get the entity ID in there also.  It makes it hard to remember that you are working in C# sometimes.

dynamic xrm = (ScriptObject)HtmlPage.Window.GetProperty("Xrm");
var formType = xrm.Page.ui.getFormType();
string strFormID = xrm.Page.data.entity.getId();
if (formType == 2)
{
    dynamic sdk = (ScriptObject)HtmlPage.Window.GetProperty("SDK");
    sdk.SAMPLES.TriggerActionsRequest();
}


- I hope this helps!

Sunday, July 8, 2012

Cross-Browser Support for CRM 2011 Delayed Till Q4 Service Update

I was kind of disappointed to learn that long-awaited cross-browser support for Microsoft Dynamics CRM 2011 will be delayed until the Q4 service update.

Read more about this here:
https://community.dynamics.com/product/crm/crmnontechnical/b/crmconnection/archive/2012/07/06/q2-2012-service-update-new-delivery-schedule.aspx


-

Wednesday, June 20, 2012

Check Out the New SSIS Integration Toolkit for Microsoft Dynamics CRM 2011 from KingswaySoft!

I had the privilege over the last month or two to test out KingswaySoft's new SSIS Integration Toolkit for Microsoft Dynamics CRM.  It works for both CRM 4.0 and CRM 2011 and does a great job.

It gives you an easy to use and hook up CRM destination and CRM source that can be used to easily unleash the full force of SSIS combined with CRM without having to use script tasks or web service tasks.

It's free to try and is currently $895 to buy for a perpetual license or $495 for a one year subscription license.  The trial is fully functional.

I have put together a small sample SSIS package that inserts into CRM accounts and related contacts into CRM from flat files.  This sample is available below.

Keep in mind that I am definitely not an SSIS guru but I did manage to get this sample to work.  Please do not ask me questions related to SSIS as it makes my head hurt.  Please deflect all such questions to the maker of this program Daniel Cai (https://plus.google.com/115440641969940382242/posts).



Get My Sample Package Here:


Get The Tool Here!: http://www.kingswaysoft.com/products/ssis-integration-toolkit-for-microsoft-dynamics-crm

-

Thursday, June 14, 2012

Export a Data Import Map in Microsoft Dynamics CRM 2011 Using VB.NET

This illustration shows how to export a data import map in Microsoft Dynamics CRM 2011 in code using VB.NET.   This example will be given in SOAP (JScript) and in C# (.NET).

Ok, here is what the code look like!
In VB.NET:

Dim req As New ExportMappingsImportMapRequest()
req.ExportIds = False
req.ImportMapId = New Guid("455B72E2-9863-4984-AEF2-A26C16AFBAD6")
Dim resp As ExportMappingsImportMapResponse = DirectCast(service.Execute(req), ExportMappingsImportMapResponse)


Thats all there is to it!

I hope this helps!

Tuesday, June 12, 2012

Export a Saved Import Map in Microsoft Dynamics CRM 2011 Using C# or JScript

This illustration shows how to export a saved import map in Microsoft Dynamics CRM 2011 with ExportMappingsImportMapRequest.  This example will be given in Jscript (SOAP) and in C# (.NET).
    Ok, here is what the code looks like!
    First in C#:

    ExportMappingsImportMapRequest req = new ExportMappingsImportMapRequest();
    req.ExportIds = false;
    req.ImportMapId = new Guid("455B72E2-9863-4984-AEF2-A26C16AFBAD6");
    ExportMappingsImportMapResponse resp = (ExportMappingsImportMapResponse)service.Execute(req);
    

    If you need help instantiating a service object in .NET within a plugin check out this post:
    http://mileyja.blogspot.com/2011/04/instantiating-service-object-within.html

    Now here is the Jscript nicely formatted by the CRM 2011 SOAP formatter. Available at: http://crm2011soap.codeplex.com/

    Now in Jscript


    This example is asynchronous, if you want to learn how to make JScript SOAP calls synchronously please visit this post: http://mileyja.blogspot.com/2011/07/using-jscript-to-access-soap-web.html

    
    if (typeof (SDK) == "undefined")
       { SDK = { __namespace: true }; }
           //This will establish a more unique namespace for functions in this library. This will reduce the 
           // potential for functions to be overwritten due to a duplicate name when the library is loaded.
           SDK.SAMPLES = {
               _getServerUrl: function () {
                   ///<summary>
                   /// Returns the URL for the SOAP endpoint using the context information available in the form
                   /// or HTML Web resource.
                   ///</summary>
                   var ServicePath = "/XRMServices/2011/Organization.svc/web";
                   var serverUrl = "";
                   if (typeof GetGlobalContext == "function") {
                       var context = GetGlobalContext();
                       serverUrl = context.getServerUrl();
                   }
                   else {
                       if (typeof Xrm.Page.context == "object") {
                             serverUrl = Xrm.Page.context.getServerUrl();
                       }
                       else
                       { throw new Error("Unable to access the server URL"); }
                       }
                      if (serverUrl.match(/\/$/)) {
                           serverUrl = serverUrl.substring(0, serverUrl.length - 1);
                       } 
                       return serverUrl + ServicePath;
                   }, 
               ExportMappingsImportMapRequest: function () {
                   var requestMain = ""
                   requestMain += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
                   requestMain += "  <s:Body>";
                   requestMain += "    <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
                   requestMain += "      <request i:type=\"b:ExportMappingsImportMapRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">";
                   requestMain += "        <a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
                   requestMain += "          <a:KeyValuePairOfstringanyType>";
                   requestMain += "            <c:key>ImportMapId</c:key>";
                   requestMain += "            <c:value i:type=\"d:guid\" xmlns:d=\"http://schemas.microsoft.com/2003/10/Serialization/\">455b72e2-9863-4984-aef2-a26c16afbad6</c:value>";
                   requestMain += "          </a:KeyValuePairOfstringanyType>";
                   requestMain += "          <a:KeyValuePairOfstringanyType>";
                   requestMain += "            <c:key>ExportIds</c:key>";
                   requestMain += "            <c:value i:type=\"d:boolean\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">false</c:value>";
                   requestMain += "          </a:KeyValuePairOfstringanyType>";
                   requestMain += "        </a:Parameters>";
                   requestMain += "        <a:RequestId i:nil=\"true\" />";
                   requestMain += "        <a:RequestName>ExportMappingsImportMap</a:RequestName>";
                   requestMain += "      </request>";
                   requestMain += "    </Execute>";
                   requestMain += "  </s:Body>";
                   requestMain += "</s:Envelope>";
                   var req = new XMLHttpRequest();
                   req.open("POST", SDK.SAMPLES._getServerUrl(), true)
                   req.setRequestHeader("Accept", "application/xml, text/xml, */*");
                   req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
                   req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
                   var successCallback = null;
                   var errorCallback = null;
                   req.onreadystatechange = function () { SDK.SAMPLES.ExportMappingsImportMapResponse(req, successCallback, errorCallback); };
                   req.send(requestMain);
               },
           ExportMappingsImportMapResponse: function (req, successCallback, errorCallback) {
                   ///<summary>
                   /// Recieves the assign response
                   ///</summary>
                   ///<param name="req" Type="XMLHttpRequest">
                   /// The XMLHttpRequest response
                   ///</param>
                   ///<param name="successCallback" Type="Function">
                   /// The function to perform when an successfult response is returned.
                   /// For this message no data is returned so a success callback is not really necessary.
                   ///</param>
                   ///<param name="errorCallback" Type="Function">
                   /// The function to perform when an error is returned.
                   /// This function accepts a JScript error returned by the _getError function
                   ///</param>
                   if (req.readyState == 4) {
                   if (req.status == 200) {
                   if (successCallback != null)
                   { successCallback(); }
                   }
                   else {
                       errorCallback(SDK.SAMPLES._getError(req.responseXML));
                   }
               }
           },
           _getError: function (faultXml) {
               ///<summary>
               /// Parses the WCF fault returned in the event of an error.
               ///</summary>
               ///<param name="faultXml" Type="XML">
               /// The responseXML property of the XMLHttpRequest response.
               ///</param>
               var errorMessage = "Unknown Error (Unable to parse the fault)";
               if (typeof faultXml == "object") {
                   try {
                       var bodyNode = faultXml.firstChild.firstChild;
                       //Retrieve the fault node
                       for (var i = 0; i < bodyNode.childNodes.length; i++) {
                           var node = bodyNode.childNodes[i];
                           //NOTE: This comparison does not handle the case where the XML namespace changes
                           if ("s:Fault" == node.nodeName) {
                           for (var j = 0; j < node.childNodes.length; j++) {
                               var faultStringNode = node.childNodes[j];
                               if ("faultstring" == faultStringNode.nodeName) {
                                   errorMessage = faultStringNode.text;
                                   break;
                               }
                           }
                           break;
                       }
                   }
               }
               catch (e) { };
            }
            return new Error(errorMessage);
         },
     __namespace: true
    };
    


    To understand how to parse the response please review my post on using the DOM parser.
    Now you can call the SDK.SAMPLES.ExportMappingsImportMapRequest function from your form jscript handler.


    Thats all there is to it!
    -