Friday, August 26, 2011

Activity Party in Emails & Unresolved Email Addresses

Adjusting emails through custom code is a bit of a pain, but I managed to figure out how to modify the recipients of an email as well as force unresolved email addresses in there.

First, for unresolved emails, enable them in the CRM settings. Settings -> Administration -> System Settings -> Email Tab -> Allow messages with unresolved e-mail recipients to set -> Set to yes.

Now, onto the some code snippets. I know I learn best by looking at working code!

EntityCollection ec = new EntityCollection();
EntityCollection ccEC = new EntityCollection();

// Send to a CONTACT
Entity party = new Entity("activityparty");
party["partyid"] = new EntityReference("contact", contactId);                        party["participationtypemask"] = new OptionSetValue(2); // 2 for TO
ec.Entities.Add(party);

// Send to an EMAIL ADDRESS BY STRING
Entity ccParty = new Entity("activityparty");
ccParty["addressused"] = ccEmail.Trim(); // Raw email address string
ccParty["participationtypemask"] = new OptionSetValue(3); // 3 for CC
ccEC.Entities.Add(ccParty);

email["to"] = ec;
email["cc"] = ccEC;
crmService.Update(email); // I already had my email entity object prior to this

// Send the email!
SendEmailRequest ser = new SendEmailRequest();
ser.EmailId = email.Id;
ser.TrackingToken = "";
ser.IssueSend = true;
crmService.Execute(ser);

Hope this saves someone out there some pain! I know I beat my head against this for awhile before getting it all rolling.

Thursday, August 18, 2011

Disabling Lookup View Selector via Javascript

Sometimes you need to disable the View Selector after the fact via Javascript. In my case, I needed to add a custom view, set to to default, then disable the view picker. If you try to set the view picker as disabled from the form editor, it'll fail to change to the new view that you specify! Therefore, you *have* to disable it after the fact. Luckily, this can be done with one quick & effective line:

document.getElementById("new_product").disableViewPicker = 1;

In my case, new_product is the name of the lookup that I wanted to disable views for. In the bigger context, here is a working example of how to create a custom view then disable the view selector:


var viewId = "{00000000-0000-0000-0000-000000000001}";
    var entityName = "new_quoteproduct";
    var viewDisplayName = "Filtered Products";
    var viewIsDefault = true;

    fetchXml = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>" +
                   "<entity name='new_quoteproduct'>" +
                   "<attribute name='new_quoteproductid' />" +
                   "<attribute name='new_name' />" +
                   "<attribute name='new_category' />" +
                   "<attribute name='new_systemset' />" +
                   "<attribute name='new_productnumber' />" +
                   "<order attribute='new_category' descending='false' />" +
                   "<filter type='and'>" +
                   "<condition attribute='statecode' operator='eq' value='0' />";
    if (systemSet) {
        fetchXml += "<condition attribute='new_systemset' operator='eq' value='100000002' />";
    }
    if(categoryID != null) {
        fetchXml += "<condition attribute='new_category' operator='eq' value='" + categoryID + "' />";
    }
    fetchXml += "</filter>" +
                "</entity>" +
                "</fetch>";

    var layoutXml = "<grid name='resultset' object='1' jump='new_name' select='1' icon='1' preview='1'>" +
                    "<row name='result' id='new_quoteproductid'>" +
                    "<cell name='new_category' width='150' />" +
                    "<cell name='new_productnumber' width='150' />" +
                    "<cell name='new_systemset' width='75' />" +
                    "<cell name='new_name' width='200' />" +
                    "</row>" +
                    "</grid>";

    Xrm.Page.getControl("new_product").addCustomView(viewId, entityName, viewDisplayName, fetchXml, layoutXml, viewIsDefault);
    document.getElementById("new_product").disableViewPicker = 1;


Now, if only MS would fix the bug where custom lookup views don't respect your sorting, and we'd have a perfect solution! Hopefully this helps some of you out there.

Friday, July 8, 2011

CRM 2011 Boolean OnChange event not working properly

If you've used CRM 2011 bit fields with OnChange events, you've probably noticed some very annoying behavior: The event is only fired when you leave the checkbox, not when the box itself is checked. That is, you have to check the box then click elsewhere for the Javascript to fire.

A blogger over at PowerObjects.com has a great CRM4 solution:
http://www.powerobjects.com/blog/2009/09/10/crm-bit-field-onchange-event-not-firing-as-expected/

The idea is that, instead of firing on the onchange event, we fire on onclick such as:

crmForm.all.checkbox.onclick = functionName;

This works great, and the function will fire the moment the checkbox is interacted with. However, we need to make sure that we use the old-style CRM4 method of accessing the bit rather than the new CRM2011 Xrm model. For whatever reason, attempting to access the Xrm model during onclick returns very erratic values -- in my experience, it would report false for several straight clicks, then true when the box was unchecked at one point! So, be sure to access the field in your function as such:

if(crmForm.all.checkbox.DataValue) {
  // Do something if true
} else {
  // Do something if false / null
}

Hopefully this helps you avoid the confusion I ran into!

Sunday, July 3, 2011

CRM error when opening a form due to invalid role

One of my clients was running into a particularly nasty issue earlier this week. They were unable to open any kinds of forms related to contacts, opportunities, or accounts. Trying to do so gave a generic error - it wouldn't even start to open.

After some investigation, it turns out they had deleted a role which had been assigned access to several forms. For whatever reason, CRM did not clean this up, and it left a bad reference in the customizations. This led to an odd error; anyone who had access to the form was able to open their forms without issue. Anyone who did *not* have access to the form would be given a generic error when opening any other form for the same entity. Unfortunately, attempting to reassign the security for the form or import a copy with the role stripped out generates errors - it appears that we have a circular error!

Luckily there is still a way to fix this. Simply perform the following:
  1. Open up the form with the bad assignment and save a copy.
  2. On the copy, set up assignment as normal.
  3. Delete the old form.
  4. Rename the copied form to be the same as the old form.
This will forcibly remove all references to the bad role, and allow users access to the system again! Note that if a dev/QA system is in place, the next push to the live server will create another copy of the form due to a GUID mismatch. In this case, be sure to delete the correct form.

Saturday, April 16, 2011

Javascript inconsistency with Xrm.Page model

While doing ribbon customization today I found an interesting issue with how the new Xrm.Page model introducted in CRM 2011.

I have a ribbon button which simply fires a javascript function:

function lookup_form() {
    alert(Xrm.Page.getAttribute("dc_openform").getValue());
    alert(crmForm.all.dc_openform.DataValue);
}

I would type a value into my dc_openform field, and click the ribbon button. The first alert would show what was *previously* in the field, while the second alert showed what is *currently* in the field. If I clicked off the field then click the button again, the values match up.

Thus, it appears the the Xrm.Page model is only updated onChange, and that onChange is not fired between typing into a field and clicking the Ribbon button.

Thursday, April 7, 2011

Odd Currency Symbols returned from FetchXML

While working with CRM2011 FetchXML, I came across a nasty issue when retrieving a currency field. I have done this successfully many times before, but for some reason this time I was getting multiple currency symbols in my raw XML result, ie:

$‎5,000

instead of the desired:

$5,000

Adding transactioncurrencyid to the fetch did not help, and replacing "$‎" with "$" directly also did not work. However, after toying about with the string in unicode for a bit, I came up with:

value = Regex.Replace(value, "\u200e", "");

This properly removed the funky symbols, leaving me with "$5,000". Likely something under the hood is causing an issue elsewhere, but this is a great workaround if you just need to get a properly formatted currency field without hacking deeper into the CRM platform.

Friday, April 1, 2011

No Calendar when Enabling DateTime fields via Javascript

I ran into an annoying problem today. I was enabling and disabling a DateTime field via Javascript via the following code:

Xrm.Page.getControl("new_datetimefield").setDisabled(true/false);

However, even when enabled, the calendar button did not function and I couldn't put any dates in the text box.

It turns out that this is a bug in CRM2011 - The fix is to ensure that the DateTime field is enabled by default on the form, then disable or enable via Javascript. If it is initially disabled, it will not be properly editable even when enabled via Javascript.

Tuesday, March 8, 2011

Assembly must be registered in isolation

While attempting to register plug-ins on our new CRM2011 box today, I ran into this error message, "Assembly must be registered in isolation." This was driving me nuts -- I could register in the Sandbox without issue, but I needed access to system Mutexes and data logs on the hard drive which are unavailable in Sandbox.

This ended up being a simple fix -- I needed to add my user to the "Deployment Managers" group, in addition to the System Administrator group he was already in. With that done, registering went off without a hitch!

Monday, February 28, 2011

Unable to Select Header when Modifying View

While working earlier today on a client server (Windows Server 2008 R2) in CRM4, I came across an incredibly annoying issue: I was unable to select a header in a view in order to move or delete it. It turns out, the client machine had IE Enhanced Security Configuration enabled, which was causing this very peculiar bug!

To disable IE ESC:

1) Open up the Server Manager.
2) On the bottom right of the Manager, under Security Information, click "Configure IE ESC".
3) Set both options to Off.

Now that these are disabled, you should be able to select your column headers!

Friday, February 25, 2011

Error Accessing CRM 2011 Online Plugin-Registration Tool

This can be a frustrating error when trying to access CRM 2011 Online via the plugin registration tool:


Unhandled Exception: System.ServiceModel.Security.MessageSecurityException: An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.

Server stack trace:
   at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.ProcessReply(Message reply, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
   at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]:
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at Microsoft.IdentityModel.Protocols.WSTrust.IWSTrustContract.Issue(Message message)
   at Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannel.Issue(RequestSecurityToken rst, RequestSecurityTokenResponse& rstr)
   at Microsoft.Xrm.Sdk.Client.ServiceConfiguration`1.AuthenticateLiveIdInternal(ClientCredentials clientCredentials, SecurityTokenResponse deviceToken, String keyType)
   at Microsoft.Xrm.Sdk.Client.ServiceConfiguration`1.AuthenticateDevice(ClientCredentials clientCredentials)
   at Microsoft.Xrm.Sdk.Client.DiscoveryServiceConfiguration.AuthenticateDevice(ClientCredentials clientCredentials)
   at PluginRegistrationTool.CrmConnection.get_DiscoveryService() in C:\Projects\CRM 2011 SDK\sdk\tools\pluginregistration\CrmConnection.cs:line 272
   at PluginRegistrationTool.CrmConnection.RetrieveOrganizations() in C:\Projects\CRM 2011 SDK\sdk\tools\pluginregistration\CrmConnection.cs:line 367
   at PluginRegistrationTool.ConnectionsForm.OpenConnection(CrmConnection con) in C:\Projects\CRM 2011 SDK\sdk\tools\pluginregistration\ConnectionsForm.cs:line 940
Inner Exception: System.ServiceModel.FaultException: Invalid Request

Luckily, there is a pretty simple fix. Open up your %userprofile%\LiveDeviceID\ folder, and delete LiveDevice.xml (back it up in case something goes wrong!).

Restart the plugin registration tool, and it should now connect properly!

Monday, January 24, 2011

Javascript & Read-Only Picklists

So you've got this great bit of Javascript that changes a read-only picklist field. Great! The only problem is, when the code fires on an update form, the picklist that you set doesn't get saved! It'll work on create, so whats the deal?

What you need to do is go back into your Javascript and enable the "ForceSubmit" attribute of the picklist. For example (from CRM 2011, changing one picklist based on the value of another picklist onchange):

function CheckType() {
  if(crmForm.all.new_type.DataValue == 100000001) {
    crmForm.all.new_readonlypicklist.DataValue = 100000001;
    crmForm.all.new_readonlypicklist.ForceSubmit = true;
  }
}

Your picklist field should now update and save properly!

Sunday, January 23, 2011

Simple CRM FetchXML in C#

Need to use some FetchXML in C# to pull some data? Normally you would have to write your FetchXML, then worry about paging since you may have more than 5,000 records. Luckily, there's an easy way to speed up both of these processes.

Use this tip from Rockstar Bits & Ronald Lemmen to generate your FetchXML automatically from an advanced find:
http://rockstarbits.blogspot.com/2010/02/using-advanced-find-to-generate.html

Next, use this sample from Phil's CRM Blog which gets rid of the paging hassle:
http://blog.expertsoftware.co.uk/post/2009/03/19/Retrieving-All-Records-with-Fetch-XML.aspx

Now that you've got your results, load them into an XmlDocument for parsing and away you go!