Quick Tip: Don’t use underscore character in CRM webservices URL

Recently I was setting up CRM for Outlook client on a existing environment that we took over. CRM for Outlook would always display the following error after entering the organisation url details in the configuration screen.

The underlying cause seems to be the underscore character in all the crm service urls. The relevant KB316112 article says:
Security patch MS01-055 prevents servers with improper name syntax from setting cookies names. Domains that use cookies must use only alphanumeric characters (“-” or “.”) in the domain name and the server name. Internet Explorer blocks cookies from a server if the server name contains other characters, such as an underscore character (“_”).

Since CRM for Outlook cannot set the cookies, the client cannot be configured.
Advertisements

Executing QuickFind using CRM SDK

Global search in CRM for Tablets executes Quickfind view across the entities specified in the System Settings.

Internally the tablet client uses ExecuteQuickFindRequest to perform this quick find search. We can perform the same request using OrganizationRequest. Let’s look at the code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Tooling.Connector;
using System.Net;

namespace ExecuteQuickFind
{
    class Program
    {
        static void Main(string[] args)
        {
            var crmConnection = new CrmConnectionHelper(new NetworkCredential("[username]","[password]","CRM"),AuthenticationType.AD, "crm1","80","Contoso");
            if(crmConnection.IsReady)
            {
                var executeQuickFindRequest = new OrganizationRequest("ExecuteQuickFind");
                executeQuickFindRequest.Parameters = new ParameterCollection();
                var entities = new List<string> { "contact", "lead","opportunity","systemuser","competitor","activitypointer", "incident" };
                //specify search term
                executeQuickFindRequest.Parameters.Add(new KeyValuePair<string object="">("SearchText","maria"));
                //will cause serialisation exception if we don't convert to array
                executeQuickFindRequest.Parameters.Add(new KeyValuePair<string object="">("EntityNames", entities.ToArray()));
                
                var executeQuickFindResponse = crmConnection.OrganizationServiceProxy.Execute(executeQuickFindRequest);
                var result = executeQuickFindResponse.Results.FirstOrDefault();
                if (executeQuickFindResponse.Results.Any())
                {
                    var quickFindResults = result.Value as QuickFindResultCollection;

                    if (quickFindResults != null)
                    {
                        foreach (var quickFindResult in quickFindResults)
                        {
                            if (quickFindResult.ErrorCode != 0)
                            {
                                Console.WriteLine("Quickfind for {0} errored with code {1}",
                                                  quickFindResult.Data.EntityName,
                                                  quickFindResult.ErrorCode);
                                continue;
                            }
                            Console.WriteLine("***Entity {0} returned {1} record(s)***", quickFindResult.Data.EntityName,
                                              quickFindResult.Data.Entities.Count);
                            foreach (var entityRow in quickFindResult.Data.Entities)
                            {
                                foreach (
                                    var attribute in
                                        entityRow.Attributes.Where(
                                            attribute => !entityRow.FormattedValues.Any(x => x.Key == attribute.Key)))
                                {
                                    Console.WriteLine("{0} = {1}", attribute.Key, ExtractValue(attribute.Value));
                                }
                                foreach (var formattedAttributes in entityRow.FormattedValues)
                                {
                                    Console.WriteLine("Formatted: {0} = {1}", formattedAttributes.Key,
                                                      formattedAttributes.Value);
                                }
                                Console.WriteLine("-----------------------------------------");
                            }
                        }
                    }
                }               
            }
        }

        private static object ExtractValue(object attributeValue)
        {
            var attributeType = attributeValue.GetType().Name;
            object returnValue = attributeValue;
            switch (attributeType)
            {
                case "OptionSetValue":
                    returnValue = ((OptionSetValue) attributeValue).Value;
                    break;
                case "EntityReference":
                    returnValue = ((EntityReference)attributeValue).Name;
                    break;
                case "Money":
                    returnValue = ((Money)attributeValue).Value;
                    break;
            }
            return returnValue;
        }
    }
}

Here is the result after executing this code.

The maximum number of entities you can specify in the EntityNames parameter for this ExecuteQuickFindRequest is 10.