Tag Archives: Dynamics

Using an ERD tool to create CRM entities

I get asked this now and then:

“I want to use Erwin [or Visio or Visual Studio or…] to graphically design the CRM entity model, then have the actual CRM entities generated off of the tool I used to design the entities.”

While I am not aware of a direct way to do this with any ERD tools, there is a multi-step process you can use as long as your ERD designer can generate a SQL or Access database:

  • Use your ERD designer to model your entities, fields and relationships
  • Generate a SQL or Access database from the designer
  • Use https://xrmspeedy.codeplex.com/ to generate the CRM entities from the database

Of course, you’ll need to make sure you don’t pick data types in your diagram that the xrmspeedy tool can’t translate to CRM types, but this approach can be used as a productivity enhancement to those who prefer to diagram out their entities and generated them.  Since this is an open source tool, you might consider contributing feedback if you have ideas for improvement.  After a little trial and error, I’ve found I get value out of using Visual Studio’s Entity Framework Designer plus this tool when brainstorming data models and building POCs.  Your Mileage May Vary (YMMV).

@devkeydet

Batch updating fields with crmsvcutil generated code

Scenario:

“I love early bound code because of compile time checking, LINQ query enablement, etc.  I want to batch update a bunch of records, but OrganizationServiceContext.SaveChanges() executes under the hood as one web service call per entity.  How do I batch update?  Also, how do I make sure that only the fields I change are updated?”

The answer is that you basically have to combine your crmsvcutil.exe generated code with ExecuteMultipleResults.  Here’s an example:

var conn = CrmConnection.Parse("USE A VALID connection string using appropriate format documented at https://msdn.microsoft.com/en-us/library/jj602970.aspx");
var ctx = new marcsctest1Context(new OrganizationService(conn));

// NOTE: The query below uses LINQ projection.  The CRM LINQ provider will translate this to a query that only returns ID & Name
var query = 
    from a in ctx.AccountSet
    select new Account
    {
        Id = a.Id,
        Name = a.Name
    };

var executeMultipleRequest = new ExecuteMultipleRequest()
{
    Settings = new ExecuteMultipleSettings(){
        ContinueOnError = false,
        ReturnResponses = true
    },
    Requests = new OrganizationRequestCollection()
};

foreach (var account in query)
{
    account.Name += " - Updated";
    //UpdateObject is required to set the EntityState to Changed because it is readonly through crmsvcutil generated entities
    ctx.UpdateObject(account); 

    executeMultipleRequest.Requests.Add(new UpdateRequest()
    {
        Target = account
    });
}

//Don't forget to check response.IsFaulted and handle appropriately
var response = ctx.Execute(executeMultipleRequest) as ExecuteMultipleResponse;

@devkeydet

Using LINQPad with the CRM Online OData service

I’ve been a longtime fan of LINQPad (www.linqpad.net) as a general purpose tool for executing LINQ queries with various LINQ enabled technologies as well as a general purpose scratchpad for testing out .NET code without having to fire up Visual Studio.  I’ve already blogged about how to use LINQPad to work with the CRM Online SOAP service:

http://blogs.msdn.com/b/devkeydet/archive/2012/12/04/linqpad-crm-2011-and-using-office-365-accounts.aspx

One thing that may not be obvious is how to use LINQPad to query the OData service that comes with Dynamics CRM Online.  Using the same basic concept that I showed with the SOAP service, I created a video walkthrough of how to interact with the OData service from LINQPad:

 

Here’s the LINQPad starter code I showed in the video:

var clientId = "[YOUR_CLIENT_ID]";
var resource = "https://[YOUR_INSTANCE].crm.dynamics.com";
var redirectUri = new Uri("http://linqpad"); //replace with your redirect uri

var authContext = new AuthenticationContext("https://login.windows.net/common/oauth2/authorize", false);
var authResult = authContext.AcquireToken(resource, clientId, redirectUri, PromptBehavior.Auto);
Util.ClearResults();

var ctx = new marcsctest1Context(new Uri(resource + "/XRMServices/2011/OrganizationData.svc/"));

ctx.SendingRequest2 +=
 (o, eventArgs) => eventArgs.RequestMessage.SetHeader("Authorization", "Bearer " + authResult.AccessToken);

var query = 
     from a in ctx.AccountSet
     where a.Name.Contains("sample")
     select new
     {
          a.AccountId,
          a.Name,
          a.Address1_City,
          a.Address1_StateOrProvince
     };

query.ToString().Dump("OData Query Url");
query.Dump("Query Results");

One of the things I did, after creating the video, was to write a reusable helper method in the LINQPad MyExtensions class so I can reuse the code to get the access token across multiple LINQPad query sessions.  Here’s the code for the extension:

void Main()
{
     // Write code to test your extensions here. Press F5 to compile and run.
}

public static class MyExtensions
{
     // Write custom extension methods here. They will be available to all queries.
     static string LINQPadAccessToken = null;
     
     public static string GetAccessToken()
     {
          if (LINQPadAccessToken != null)
          {
               return LINQPadAccessToken;
          }
          
          var clientId = "[YOUR_CLIENT_ID]";
          var resource = "https://[YOUR_INSTANCE].crm.dynamics.com";
          var redirectUri = new Uri("http://linqpad"); //your redirect uri

          var authContext = new AuthenticationContext("https://login.windows.net/common/oauth2/authorize", false);
          var authResult = authContext.AcquireToken(resource, clientId, redirectUri, PromptBehavior.Auto);
          Util.ClearResults();
          
          LINQPadAccessToken = authResult.AccessToken;
          
          return LINQPadAccessToken;
     }     
}

Here’s a version of the code in my query tab that is simplified, after writing and leveraging the helper method:

var ctx = new marcsctest1Context(
     new Uri("https://[YOUR_INSTANCE].crm.dynamics.com/XRMServices/2011/OrganizationData.svc/")
);
ctx.SendingRequest2 += 
     (o, eventArgs) => eventArgs.RequestMessage.SetHeader("Authorization", "Bearer " + MyExtensions.GetAccessToken());

var query =      
     from a in ctx.AccountSet
        where a.Name.Contains("sample")
     select new
     {
          a.AccountId,
          a.Name,
          a.Address1_City,
          a.Address1_StateOrProvince
     };

query.ToString().Dump("OData Query Url");
query.Dump("Query Results");

Note the call to MyExtensions.GetAccessToken() above.  You could obviously refactor the GetAccessToken() method more to make it even more reusable, but I will leave that as an exercise for you.

This approach will become even more powerful once Dynamics CRM introduces the new OData v4 service endpoint:

https://msdn.microsoft.com/en-us/dynamics/crm/webapipreview

As I mention in the video, once that happens, you’ll want to perform the codgen with the OData Client Code Generator instead of “Add Service Reference”:

http://blogs.msdn.com/b/odatateam/archive/2014/03/11/how-to-use-odata-client-code-generator-to-generate-client-side-proxy-class.aspx

@devkeydet

Setting up a Microsoft Cloud trial

CRM Online based solutions often run across the broader Microsoft Cloud, not just CRM Online alone.  As they say, a picture is worth a thousand words.  So here’s a picture that hits home this point at a high level.

image

To help people get started trying this environment out, I’ve created a video that walks you through setting up a trial for CRM Online, Office 365, and Microsoft Azure where all the services are provisioned for Single Sign On (SSO) under a single Azure Active Directory tenant and provide shared administration. 

@devkeydet

Microsoft Dynamics Technical Conference

February 2-4, 2015, Seattle WA

Hear from Jujhar Singh, General Manager of Program Management for Microsoft Dynamics CRM, about why you should be a part of the Microsoft Dynamics Technical Conference.
clip_image004
Equal parts education, networking, and fun, the Microsoft Dynamics Technical Conference brings together Microsoft Dynamics CRM professional and developer communities in a technical readiness experience designed to inspire you and help you take your business further. This is our first-ever such event for Microsoft Dynamics CRM partners. Don’t miss it!
We want to see you there!

Register now!

clip_image006

Time is running out: Register today for the Microsoft Dynamics Technical Conference!
Your conference pass—priced at $1,595—gives you access to keynotes, general and breakout sessions, and evening functions, where you’ll get in on knowledge and conversations that can only happen in a live event atmosphere.
Check out the Session Catalog now.
All of our Breakout Sessions and Instructor-led Labs are focused on Microsoft Dynamics CRM 2015. Don’t miss your chance to meet the members of the R&D team and speak directly to the experts!
Looking for more hands-on training?
Check out the Deep Dive Workshops. Scheduled around the Microsoft Dynamics Technical Conference and offered at half the usual price (use code HaLF007), these intensive workshops help you maximize your learning and make the most of your trip to Seattle.

Register now!

clip_image007

See you in Seattle!
The Microsoft Dynamics Technical Conference Team

© Microsoft Corporation. All Rights Reserved.

Doing CSS the right way with Dynamics CRM

One of a few practices I see when people customize Dynamics CRM that usually comes back to haunt them during update rollups or upgrades is directly referencing the CSS files and classes that come with the product.  It’s an innocent enough mistake, but the CSS files which ship with Dynamics CRM are intentionally not documented in the SDK.  Directly referencing them is not supported.  The Dynamics CRM team reserves the right to change them at any point, just like they reserve the right to change the structure of their html.  That’s why direct HTML DOM manipulation of the UI the server creates isn’t supported either.  Of course, you can manipulate the DOM of the web resources you author as much as you like.  If you think about it, this makes perfect sense.  I am not aware of any product out there that shield you from future changes if you hardcode your extensibility code to html/css structures.  So what should you do?  Well, you should create your own CSS files which mimic the CRM look and feel and reference those from your web resources.  That way, when anything changes with the Dynamics CRM codebase, you are shielded from any ripple effect.  You’re customizations may look out of place if major colors or fonts change.  However, if you structure your CSS right (i.e. don’t copy paste, reuse), then you should be able to adjust to those changes with less impact.  Ok, but how?  Here’s a great article from the Dynamics CRM in the Field blog which walks you through the fundamentals:

http://blogs.msdn.com/b/crminthefield/archive/2014/07/03/css-style-reference-using-developer-tools.aspx

@devkeydet

Capturing a signature in a CRM form using html5

Scenario:

“I have a touchscreen.  I want to capture a signature in a Dynamics CRM form.  If the signature hasn’t been saved, then I want to allow a user to provide their signature.  The next time the record is loaded, after the signature has been saved, I want to load an imagine of the signature to prevent ‘resigning’.”

This is a relatively simple thing with Dynamics CRM thanks to web resources and Xrm.Page.  The general concept is to embed an html web resource in the form that captures the signature using the html5 canvas (preferably using an existing control vs. low level canvas programming).  Before saving, you want to copy the data from the canvas control into a Multiple Lines of Text type hidden field on the form so the data is stored when the record is saved.  Finally, when the web resource is loaded, you want to check if the field has data in it.  If so, you can assume a signature was previously recorded and just show the data as an image. 

Here’s the entire source code for a basic implementation:

1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title>Signature</title> 5 <script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.1.min.js"></script> 6 <script src="scripts/jSignature.min.js"></script><!-- download from http://willowsystems.github.io/jSignature/#/about/ --> 7 </head> 8 <body> 9 <img id="sigImage" alt="This is an image of the persons signature." style="display:none"/> 10 <div id="sigPanel" style="display:none"> 11 <div id="signature"></div> 12 <button id="clear">Clear</button> 13 </div> 14 <script type="text/javascript"> 15 $(function () { 16 var sigImage = $("#sigImage"); 17 var sigPanel = $("#sigPanel"); 18 var sig = $("#signature"); 19 20 var Xrm = window.parent.Xrm; 21 var sigBase64Attribute = Xrm.Page.getAttribute("msftpoc_esigbase64"); //replace this with your hidden "multiple lines of text" field with a max length of 1,048,576 22 var sigBase64Value = sigBase64Attribute.getValue(); 23 24 sig.bind("change", function (e) { 25 sigBase64Attribute.setValue(sig.jSignature("getData")); 26 }); 27 28 29 if (sigBase64Value != null) { 30 sigImage.css("display", "inline"); 31 sigImage.attr("src", sigBase64Value); 32 } else { 33 sigPanel.css("display", "inline"); 34 sig.jSignature(); 35 $("#clear").click(function() { 36 sig.jSignature("clear"); 37 }); 38 } 39 }); 40 </script> 41 </body> 42 </html> 43

All you have to do is add this web resource to your form (make sure you read instructions in the comments) and update the code to reference your field name.  A few things to note:

  • There are many controls out there, but I chose http://willowsystems.github.io/jSignature/#/about/.  It met all my requirements.  Feel free to use another.
  • The hidden field on the form for my entity is called msftpoc_esigbase64 and uses the Multiple Lines of Text type of Dynamics CRM.  Make sure to change the code to match your field name.
  • For simplicity, I chose to use the default data format of the jSignature control which is a base64 encoded string (hence my field name).  Since base64 encoded strings can be big, I set the max length field to 1,048,576 which is the largest Dynamics CRM allows.  The jSignature control supports other formats.  You could clearly improve on performance of this sample by using one of the smaller string formats.
  • My code doesn’t handle save/autosave side effects.  I simply copy the signature date to the hidden field using the change event of the jSignature control.   A more robust implementation would perhaps wire up to Xrm.Page.data.entity.addOnSave() and intelligently determine whether to copy the data into the field based on save state.  You might also want to consider switching to the image after as successful OnSave with signature if that makes the most sense for your requirements.  I’ll leave that up to you as an exercise for improvement.

Here are a couple screenshots for a quick visualization.

Before Save (signature capable canvas with clear button):

image

After Save (fixed image of signature):

image

@devkeydet

Tools to make sure you are writing upgradeable CRM customizations

With the release of CRM 2011 UR12, which introduced cross browser support, and the release of CRM 2013, there were two tools made available to you to check both your JavaScript code and your server side code for unsupported customizations:

Microsoft Dynamics CRM 2013 Custom Code Validation Tool

Legacy Feature Check Tool

There’s an excellent blog post about these tools with video walkthroughs here.

I’ve spoken with many customers/partners lately about these tools in the context of verifying where they stand for upgradability and creating a remediation plan for any unsupported customizations that might break after upgrading.  One of the things I have also been emphasizing is how these tools can continued to be used in your development cycles to run a sanity check scan on new customizations.  By introducing this approach into your testing process, you decrease the probability you are implementing unsupported customizations that can break during upgrades.

@devkeydet