Posts Tagged ‘crm 2011’

CRM 2013 & Chrome: Browser Upgrade Woes

Beginning with CRM 2011 and continuing with CRM 2013, Microsoft has made some major strides in supporting Dynamics with non-IE browsers, but a couple recent Chrome updates have thrown a wrench in the works.

With Google Chrome 37, an error displays when changing Status Reasons. As mentioned in this KB article, An error occurs in Microsoft Dynamics CRM when adding or editing Status Reasons using Google Chrome, the cause for this is because showModalDialog() has been turned off. Fortunately, the article lists the steps to re-enable the JavaScript function, providing a workaround for the issue.

However, with Google Chrome 38, Lookups began to have problems. As described in the KB article, Microsoft Dynamics CRM lookup fields fail to save or provide results when using Chrome 38, you receive “An error occurred” message in CRM 2013 when clicking on a Lookup and a different error in CRM 2011 when trying to save the form where a Lookup has been changed. While there is currently no fix or workaround for this problem, Aaron Richards has mentioned on his MS Dynamics CRM Community blog in the post Dynamics CRM lookup fields fail with Chrome 38 that CRM Online will be fixed in Service Update 6, while On-Premise should be addressed in the next few weeks.

Tags: , , , , , ,


Need to import complex data into CRM 2013? It may be easier than you think!

While CRM 2013’s Import Wizard can provide a quick-and-dirty way to get data into the system, there’s a limit to what you can do and how much you can control how the wizard responds to missing data. Sometimes you just happen to have a huge table of historical data that you need in CRM, which may or may not be referencing records that already exist in the system, but will definitely need to be referencing something once they’re imported. Or maybe that historical data will need to reference something like a Contact or Account, but you’d like the lookup logic to be more complex than a simple “do any of these fields contain the value from this column?” condition.

The words “custom app” or “one-time use” tend to send up red flags, but that’s no excuse to try to force a square peg into a round hole. While you could always export data from CRM and import it into a database temporarily, allowing you to analyze it and craft a series of Excel files for import, it may actually be more cost-effective to go ahead and write that one-time use custom app. The truth is, as long as you know how to knock the logic out in C# and you have the connection info for both the source and the destination, it’s very easy to do.

MSDN provides a handy guide on how to set up a barebones version of such an app: Walkthrough: Build a console application that connects to Microsoft Dynamics CRM using developer extensions. All that’s left is to add code to pull your source data, logic to perform lookups, and populate CRM Entity objects to your heart’s content!

Tags: , , , , , ,


Getting the Current User Information in a Plugin

I was working with MS CRM 2011 and I had a situation where I needed to get the information about the current user in the middle of plugin execution. When you start digging around the documentation in MS CRM you’ll find that there are two properties that look like they might have the information you need:

  • InitiatingUserId
  • UserId

Here’s an example of the code you’ll see in a plugin:

public void Execute(IServiceProvider serviceProvider)
{
    IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
        IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

    // Which one is correct?
    var initiatingUserId = context.InitiatingUserId;
    var userId = context.UserId;
}

How do you know which one you need? What’s the difference? The difference is that the UserId property may or may not be the same as the InitiatingUserId. If in your plugin step registration “Run in User’s Context” field has the value “Calling User” then the UserId and InitiatingUserId will match. If you specify a user in the “Run in User’s Context” field, then the UserId field will contain the user ID of the person you specify and the InitiatingUserId will be the actual CRM user whose action triggered the plugin.

My bet is that most people are usually looking for the InitiatingUserId, so it probably makes sense to use that property even if you specify “Calling User” for the “Run in User’s Context” field. That way, if the “Run in User’s Context” value ever changes, InitiatingUserId will still have the correct value. If you use “UserID”, it’s possible you’ll get a different value than what you expect.

Hopefully this helps someone figure out which value is the correct one for your situation.

Tags: , , , , ,


CRM 2013 Online and On-Premise: Handy Dev Tools

I’ve always believed that most anything is possible, as long as you have the right tools. The holds true with Dynamics as much as it does with home repair or car maintenance, and having the right tools at your disposal can turn time-consuming dev tasks into trivial ones.

Daren Turner’s roundup of Dynamics CRM 2011 and 2013 useful Tools and Features bears reblogging, as he lists indispensable resources, such as the CRM SDK, tools that can help your everyday web development, like IE’s Developer Tools, and solutions that you can import into Dynamics to significantly speed up your dev time.

I’ve found two of those solutions particularly useful in my own development: the Ribbon Workbench and the OData Query Designer. Sure, you can mess around with the ribbon XML directly, if you like; the various nodes and attributes are well-documented in the Dynamics SDK. However, the Ribbon Workbench provides you with a WYSIWYG interface that can take the pain out of manually customizing the ribbon. As for the OData Query Designer, it’s just a quick and easy way to generate the strings needed to query the CRM web service from JavaScript, and is part of the Dynamics XRM Tools solution, which contains other handy tools as well.

Tags: , ,


CRM 2011 Plug-ins 101: Be Careful Where You Put That Service!

When I first started playing around with CRM 2011 plug-ins, I pretty much dove in headfirst to see what I could do. Sure, I browsed the SDK and modeled my code after the examples, but I ended up running into a nasty issue with one of my embellishments. What I thought was an innocuous method of handling the IOrganizationService proved to be problematic, considering how CRM 2011 plug-ins function.

I was creating the service like you usually do:

IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
IOrganizationServiceFactory serviceFactory = 
executionContext.GetExtension<IOrganizationServiceFactory>();
IOrganizationService service = 
serviceFactory.CreateOrganizationService(context.UserId);

Then I made a horrible mistake:

CrmData.Service = service;

At the time, I thought: “It sure is nice and clean, keeping all my data access methods in a separate class! Why don’t I just plop the service into some variable so I don’t have to pass it for each method call?” Little did I know that my choice to not RTFM would’ve told me exactly why I shouldn’t do that.

From MSDN’s Write a Plug-In article:

For improved performance, Microsoft Dynamics CRM caches plug-in instances. The plug-in’s Execute method should be written to be stateless because the constructor is not called for every invocation of the plug-in. Also, multiple system threads could execute the plug-in at the same time. All per invocation state information is stored in the context, so you should not use global variables in plug-ins or attempt to store any data in member variables for use during the next plug-in invocation.

The worst part about this is that it works great, up until you have the plug-in firing more than once, simultaneously. Various errors will be logged, from messages about the service already being in use to errors exclaiming that basic interal CRM functionality, such as RetrieveMultiple, cannot be found.

So, for anyone else out there who has a CRM 2011 plug-in that’s failing in strange and inconsistent ways, you may want to see if you’re keeping your IOrganizationService on a short leash. Sending it away to another class to be used indiscriminately by any ol’ plug-in execution is a surefire way to pad the server error logs!

Tags: , , , , , ,


CRM 2011 Quirk: Field-level Security & Updates

We’ve recently received a request to set up some field-level security in a CRM instance that has already had a ton of customizations developed for it and we ran into an issue that I did not expect to see. When setting up a Field Security Profile with Read permissions, but no Update or Create permissions, one of our Silverlight Web Resources was throwing the dreaded “Need to start a transaction before commit” error:

After doing some digging, it turned out that it wasn’t the “Work Item” custom entity that was the issue; the error was a result of an earlier web service call failing on another entity with a field that had one of the new Field Security Profiles. Only, the field we were updating wasn’t the one with the profile; we just wanted to set new_ProjectCompleteDate and new_InstallCompleteDate, not new_UpdateFromSlx, which is a field that’s not referenced anywhere in the code.

// If the Work Item Type has "Set Install Complete Date" = "Yes", set the Install Complete Date to the Work Item's Complete Date.
if (setInstallComplete != null)
{
  if(setInstallComplete.new_SetInstallCompleteDate.Value == true)
  {
    _retrievedProject.new_InstallCompleteDate = (DateTime)dtpScheduledDate.SelectedDate;

    saveProject = true;
  }
}

var setProjectComplete = (from wi in _retrievedWorkItemDefinitions
                          where wi.new_SetCompleteDate.HasValue
                          orderby wi.new_ProjectPercentComplete descending
                          select wi).FirstOrDefault();

// If the Work Item Type has "Set Complete Date" = "Yes", set the Project Complete Date to the Work Item's Complete Date.
if (setProjectComplete != null)
{
  if(setProjectComplete.new_SetCompleteDate.Value == true)
  {
    _retrievedProject.new_ProjectCompleteDate = (DateTime)dtpScheduledDate.SelectedDate;

    saveProject = true;
  }
}

if (saveProject)
{
  _context.UpdateObject(_retrievedProject);
  _context.BeginSaveChanges(OnSchedulingComplete_Project, _retrievedProject);
}
else
{
  OnSchedulingComplete_Project(null);
}

This was throwing a permissions error, as if we were trying to update every field on the entity’s form. It also happened in a custom plug-in, where we wanted to update a field on the Account, which was another entity with a Field Security Profile. Again, the field being updated was not the field with the profile:

account.new_IntegrationStatus = new OptionSetValue(1);
context.UpdateObject(account);
context.SaveChanges();

However, if we set the Read permission to “No” on these profiles, the errors went away; they were no longer considered a field available to update. I don’t know if things were set up this way by Microsoft by design or if this is a bug, but, if you run into that vague “Need to start a transaction before commit” message, you may want to consider reviewing any recent security changes. From where I stand, it doesn’t make sense that the system would require a user to have update permissions for a field to make a change to the record, even when they’re not even interested in touching that field at all. Still, it’s another quirk to consider when planning your security and customizations.

Tags: , , , , ,


CRM 2011: Issue with Opening a New Window from Outlook with ADFS Enabled

With CRM 2011, ribbon customization requests are fairly common, and it doesn’t take much to create a custom button that will generate an entity record of some type, then pop open the finished product. It’s just a matter of editing the RibbonDiffXml in an exported solution’s customizations.xml file, pointing the button to a JavaScript web resource, and handling everything else with OData. Once the record’s created and the guid is returned, we simply build the URL and fire off a window.open().

However, while this works just fine when accessing CRM via the browser, there’s an issue if the user is accessing it via the Outlook client when CRM is using ADFS. When the new record is opened, the user is redirected to the ADFS login page. Even if they’ve logged in for one popup, they’ll be prompted again on subsequent popups. This doesn’t happen when the user clicks the out-of-the-box “New” button, so what’s the deal? The Outlook authentication doesn’t pass over automatically with window.open(), so, when in doubt, use what’s already working!

It’s important to note that the following solution is unsupported by Microsoft. This means that a future update could possibly change things in such a way that this fix is no longer valid, so, just like with any other unsupported change to CRM, make a note to test it after updates are applied and always have a backup plan.

With that out of the way, on to openObj(), a function in ..\Microsoft Dynamics CRM\CRMWeb\_static\_common\scripts:

function openObj(type, id, parameters, urlPrefix, mode, extraParams) {
    try {
        var $v_0 = openObject(type, id, parameters, urlPrefix, mode, extraParams);

        if ($v_0 || !$v_0) return $v_0;

        return !IsNull($v_0)
    } catch ($$e_1_0) {
        return false
    }
}


Not much to it and there’s no documentation available to explain what all the parameters are used for, but that’s okay; we’re only concerned with the first two. “type” refers to the entity’s TypeCode and “id” refers to its guid, both of which we should already have available for the window.open() we were previously using. If you’re not sure of what an entity’s TypeCode is, a quick and easy way to get it is to open up a record and use the “Copy a Link” button:





Which should get you something like the following, where you’ll want to be looking at the “etc” number:

[Record Name]
<http://[ServerName]/[OrgName]/main.aspx?etc=10009&extraqs=formid%3d80cb9582-2560-4dad-a0e0-a1acdcb8d114&id=%7bE1134832-40AB-E111-8E5E-005056BC4F66%7d&pagetype=entityrecord>


Or you can use SQL:

SELECT ObjectTypeCode FROM ENTITYVIEW WHERE Name = [EntityName]



Also make sure you include the global.ashx file in the CommandDefinition RibbonDiffXml for the custom button, like in the following example. “FunctionName” is being passed a dummy value, just because we want to include a reference to the resource, but don’t want the button to directly call any function in it:

<CommandDefinitions>
	<CommandDefinition Id="Custom.sse_customerjob.grid.ScheduleAppointment.Command">
		<EnableRules></EnableRules>
		<DisplayRules></DisplayRules>
		<Actions>
			<JavaScriptFunction FunctionName="General_ValidateGuids" Library="/WebResources/sse_NewAppointmentButton">
				<CrmParameter Value="SelectedControlSelectedItemIds"></CrmParameter>
				<StringParameter Value="Customer Job Site" />
			</JavaScriptFunction>
			<JavaScriptFunction FunctionName="isNaN" Library="/_common/global.ashx"></JavaScriptFunction>
		</Actions>
	</CommandDefinition>
</CommandDefinitions>



Once you have that, it’s as simple as replacing the window.open() with:

openObj(typeCode, recordGuid);


Now the new record’s window should pop up without any trouble, no matter how the user is accessing CRM!

Tags: , , , ,


CRM 2011: Error when Deleting an Audited Entity with a Plug-in

Normally, auditing in CRM 2011 doesn’t cause any issues. A user can easily delete an audited entity manually, via OData, or a .NET plug-in. However, I’ve recently run into an issue when attempting to delete during the SetStateDynamicEntity step for the Quote.

The requirement was to delete a set of associated Assets on a closed Quote during the “Activate Quote” process for the revised copy of the closed Quote. My first pass at the deletion code was as simple and straightforward as the following:

public static void DeleteAsset(new_asset assetToDelete)
{
   try
   {
      using (var ctx = new OrgContext(_service))
      {
         ctx.Delete(&quot;new_asset&quot;, assetToDelete.Id);
         ctx.SaveChanges();
      }

   }
   catch (Exception ex)
   {
   }
}

I’ve deleted entities in plug-ins before, but this was throwing an error when saving, for some reason I could not determine. The Microsoft.Crm.AuditMonikerMessagesPlugin was throwing a null reference exception, despite the context and entity object being populated:

The Web Service plug-in failed in OrganizationId: 8fa8e23a-2083-e111-9161-005056bc4f66; SdkMessageProcessingStepId: b92673ed-dc92-442b-a6c6-82f2fce14585; EntityName: new_asset; Stage: 25; MessageName: Delete; AssemblyName: Microsoft.Crm.AuditMonikerMessagesPlugin, Microsoft.Crm.Audit, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35; ClassName: Microsoft.Crm.AuditMonikerMessagesPlugin; Exception: Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.Crm.AuditLib.GetAction(IPluginExecutionContext context, Entity entity, Boolean useParentMessageName)
   at Microsoft.Crm.AuditBase.LogAuditData(IPluginExecutionContext context, Guid objectId, Boolean allowEntityOnlyAudit, Entity entity, EntityMetadata entityMetadata)
   at Microsoft.Crm.AuditMonikerMessagesPlugin.Execute(IServiceProvider serviceProvider)
   at Microsoft.Crm.Extensibility.V5PluginProxyStep.ExecuteInternal(PipelineExecutionContext context)
   at Microsoft.Crm.Extensibility.VersionedPluginProxyStepBase.Execute(PipelineExecutionContext context)
.
.

Doing a bit of Googling, the closest article I could find was “Can’t Delete an Email From Microsoft Dynamics CRM 2011″, where the situation wasn’t quite like mine, but I gave his suggestion a shot anyway and disabled auditing on the Asset entity.

To my surprise, that actually worked perfectly. Unfortunately, while the records were being deleted as expected, we needed auditing to be enabled for the entity, so this wasn’t a suitable fix. In the end, I simply hooked up a JavaScript function to the “Activate Quote” ribbon button that used OData to delete the Asset records.

Tags: , ,


CRM 2011: Custom Reports & the rsProcessingAborted Error

I created a custom report for CRM 2011 in BIDS months ago for a client, but was recently notified that it had stopped working after some significant changes were made to their environment. Out-of-the-box reports would display just fine, but the one I wrote displayed a vague “The report cannot be displayed. (rsProcessingAborted)” message and there was nothing useful in the Event Viewer to shed more light on the problem.

After confirming that the data source and credentials my report was using were still valid, I started poking around and discovered that other custom reports, even those created through the CRM 2011 Report Wizard, were failing with the same error. I tried a few solutions that I found online, but the one that fixed it is covered in When CRM 2011 Custom Reports Don’t Work.

Turns out all I needed to do was look up which account was being used for the CRM Application account by checking the CRMAppPool in IIS, then add an SPN for it with “setspn –a HTTP/NETBIOSNAME DOMAINSERVICEACCOUNT”. Such a quick and easy solution for something I was beginning to worry would end up being a real headache to fix! 

Tags: , , ,


Microsoft CRM 2011: Immediately Open a Record That Was Updated Using oData

This is a quick modification to the Microsoft CRM 2011: Update oData Examples article we posted a while ago. In the event that you would prefer to just pop up a record that you’ve updated or created using oData instead of making your user find it on their own, you can use the AJAX “success” attribute to execute whatever code you want when the update/create is complete.

For instance, in the following “updateContact” function from the previous article, I’ve added code to build a URL, then open a window:

function updateContact(id, contactObject) {

  //Parse the entity object into JSON
  var jsonEntity = window.JSON.stringify(contactObject);

  //Asynchronous AJAX function to Update a CRM record using OData
 $.ajax({
    type: &quot;POST&quot;,
    contentType: &quot;application/json; charset=utf-8&quot;,
    datatype: &quot;json&quot;,
    data: jsonEntity,
    url: Xrm.Page.context.getServerUrl() + &quot;/XRMServices/2011/OrganizationData.svc/ContactSet(guid'&quot; + id + &quot;')&quot;,
    beforeSend: function (XMLHttpRequest) {
      //Specifying this header ensures that the results will be returned as JSON.             
      XMLHttpRequest.setRequestHeader(&quot;Accept&quot;, &quot;application/json&quot;);

      //Specify the HTTP method MERGE to update just the changes you are submitting.             
      XMLHttpRequest.setRequestHeader(&quot;X-HTTP-Method&quot;, &quot;MERGE&quot;);
    },
    success: function (data, textStatus, XmlHttpRequest) {
      if(Xrm.Page.getAttribute('new_opencontactonsave').getValue() == true) {
        var linkUrl = Xrm.Page.context.getServerUrl() + &quot;/main.aspx?etc=2&amp;extraqs=formid%3d894cc46a-b0cb-4ab0-8bf6-200544e46a2d&amp;id=%7b&quot; + id + &quot;%7d&amp;pagetype=entityrecord&quot;;

        var windowWidth = screen.width * .5;
        var windowLeft = windowWidth * .5;

        var windowHeight = screen.height * .75;
        var windowTop = (screen.height - windowHeight) * .5;

        var options = &quot;left=&quot; + windowLeft + &quot;,width=&quot; + windowWidth + &quot;,top=&quot; + windowTop + &quot;,height=&quot; + windowHeight;

        window.open(linkUrl,&quot;_blank&quot;,options);
      }
    }
  });
}

In this case, we’re using the GUID for the Contact we just updated when building the URL, but, if we inserted a Contact record, we could use the result data to find the GUID of the record with something like “data.d.ContactId”. The quickest way to get the values for the other querystring variables, “etc” and “extraqs”, is to open a record of whatever entity you’re interested in, click “Copy a Link”, then pull the values from there. All that’s left is to set the window options that you want and open it up!

Contact Header

The updated CRM 2011 solution file can be downloaded here!

Tags: , , , , ,