401 Unauthorized when accessing the webservice

While there are many situations in which you can retrieve the error message 401: Unauthorized, there are some more difficult to find than others. Of course you have After you have checked the basic settings including:
- Are the default credentials used
- Does the user have an account in CRM
- Does the user have enough priviledges in CRM
- Is Windows Authentication enabled for the CRM website
- Is anonymous access disabled for the CRM website

If these settings do not solve the issue, then it's getting intereseting. One of the reasons I have experienced, has to do with two steps. In the first step, I've been using the CrmDiscoveryService to find the url's for the CrmService as well as the CrmMetadataService. The second step was using SPN's to allow the server to pass on the kerberos ticket to the server, even though it is a single server install.

Let me get a bit more in detail. The code which I used for the first step is:


CrmDiscoveryService disco = new CrmDiscoveryService();
disco.Credentials = cred;
disco.Url = server + "/MSCRMServices/2007/AD/CrmDiscoveryService.asmx";
RetrieveOrganizationsRequest orgRequest = new RetrieveOrganizationsRequest();
RetrieveOrganizationsResponse orgResponse = (RetrieveOrganizationsResponse)disco.Execute(orgRequest);
foreach (OrganizationDetail orgdetail in orgResponse.OrganizationDetails)
{
if (orgdetail.OrganizationName == org)
{
orgdetail.CrmServiceUrl;
}
}

This returns the CrmServiceUrl. Apparently the URL for the web service can have different servername than the url you have used in the code for accessing the CrmDiscoveryService. In my particular example there was the servername (srv-crm01), a dns name (crm) and of course the localhost that could be used to access the server. For accessing the CrmDiscoveryService the dns name was used. The service did return the servername as url for the crm web service.

With the help of a system engineer we found out that this server did have kerberos as authentication method specified. In the list of service principal names (SPN's) the servername was not listed for the http protocol. After this has been added for the servername as well as the fully qualified domain name, the error was gone. To add the SPN's execute the following commands:

setspn -A http/servername
setspn -A http/servername.fullyqualified.name

Don't forget to change the servername and servername.fullyqualified.name to the correct values of your environment.

If you happen to have the same error but find another solution, please share this by adding a comment to help your peers.



Hiding elements: the next evolution

One of my colleagues, Richard McCormick, has written a blog post for the Avanade internal employees. He has asked me to make this post publically available since it might be interesting for more people. Read on and get great code samples on how to hide attributes, elements and sections.

Hiding Links & Controls in CRM 4

Before I go on, I should point out that this solution is technically unsupported by Microsoft as it goes outside the CRM SDK, however the customization is small and easy to reverse to get into a state where Microsoft is supported.

With that said, this post aims to provide a quick JavaScript solution for hiding both controls on a CRM page and links in the left-hand navigation page on an Entity Form.

The code below provides three functions that can be used to show/hide specific items on a CRM form:


var HIDE = 'none';
var SHOW = 'block';

// Function to show/hide CRM controls on a CRM form
// such as text boxes, lookups, pick-lists etc.
function SetCrmControlVisible(elementName, visibility)
{
SetElementVisible(elementName + '_c', visibility);
SetElementVisible(elementName + '_d', visibility);
}

// Fuction to show/hide specific elements on a CRM form
// such as the left-hand link items (More Addresses, Workflows
// and even custom ISV links
function SetElementVisible(elementId, visibility)
{
var elem = document.getElementById(elementId);
if (elem != null)
{
elem.style.display = visibility;
}
}

// Function to show/hide Navigation "Sections" in the left-hand
// links (Such as Sales, Marketing and Service)
function SetParentElementVisible(elementId, visibility)
{
var elem = document.getElementById(elementId);
if (elem != null && elem.parentElement != null)
{
elem.parentElement.style.display = visibility;
}
}

Add the above code to the Entity OnLoad (and ensure that you enable the event) and after that you are ready to show/hide elements on the CRM form.

By using the IE Developer toolbar, you can retrieve the id of the element to be hidden (note in IE 8 this come built in and is not a seperate download). Open an entity record (in this case a Contact), press CTRL+N to open it in a new window, and then select IE Developer Toolbar.

Using the controls, select the item you want to hide and get the element id. In this case I have selected the “Opportunities” link and the id is “navOpps”



Using this, I can call the SetElementVisible function like this to hide the Opportunities link:

SetElementVisible('navOpps', HIDE);

To hide the entire “Sales” section from the left-hand navigation pane, I can once again find the id, but this time is of the parent item which would result in the following call to hide it:

SetParentElementVisible('_NA_SFA', HIDE);

Lastly, to hide an element on the form such as the “Job Title” field, you once again should use the IE Developer Toolbar to retrieve the element id and then call the SetCrmControlVisible function:

SetCrmControlVisible('jobtitle', HIDE);

By selecting either the textbox or the label, for the Job Title, the returned id will be “jobtitle_c” or “jobtitle_d” – remove everything including and after the “_” and pass that to the SerCrmControlVisible function and you are done!

Happy coding!



CRMAsyncService using 100% CPU

With one of my projects I've experienced a situation in which the CRMAsyncService is requiring 99% CPU power. Since this doesn't leave much left for CRM, we needed to get this fixed. One of my colleagues, Maarten Smid, came up with the solution of installing the Service Pack 1 for .NET 3.0. But before this can be installed, some prerequisites needed to be installed.

The first step is to install Service Pack 1 for .NET 2.0:
NetFx20SP1_x86.exe: http://go.microsoft.com/fwlink/?LinkId=98103
NetFx20SP1_x64.exe: http://go.microsoft.com/fwlink/?LinkId=98104

The second step is to install Microsoft XML Paper Specification Essentials Pack (XPSEP): http://www.microsoft.com/downloads/details.aspx?FamilyId=B8DCFFDD-E3A5-44CC-8021-7649FD37FFEE&displaylang=en

And finally SP1 for .NET 3.0:
NetFx20SP1_x86.exe: http://go.microsoft.com/fwlink/?LinkId=98105
NetFx20SP1_x64.exe: http://go.microsoft.com/fwlink/?LinkId=98106



Plugin registration tools for Visual Studio 2005

The newest update of the SDK, version 4.0.8, includes updated projects for the plugin registration tool as well as the plugin developer tool. While I usually am pleased with updates, this update could cause some issues for some people. The updated projects are build in Visual Studio 2008 whereas they used to be build in Visual Studio 2005. This means that you will not be able anymore to run the projects on machines running VS2005 including the demo VPC.

I've luckily backupped the previous SDK and uploaded both the Visual Studio projects so that you can download them if neccesary:

Plugin Registration VS2005 (zip)
Plugin Developer VS2005 (zip)

Of course you could remove the solution file, create a new solution and add the current project as well, but the downloads work just as good.

Good luck with building your plugins!



Displaying inactive records in associated view

In some situations you do want to show the inactive records in an associated view as well. My fellow MVP George Doubinski wrote an article about how to solve this by using a plugin:
http://crm.georged.id.au/post/2008/03/07/Displaying-inactive-records-in-associated-view.aspx.

In this post I will show that there are more routes to Rome. I've looked into the option of editing the query which is being executed against CRM. This seemed to be more easy then expected. What I did is:
- Export Customizations for the specific entity
- Open the XML file with a text editor
- Look for the section ""
- Look for the saved query with the localized name of the associated view
- In that saved query look for the filter that is specified in the columnset
- Remove the filter
- Save the Customizations file
- Import the Customizations file
- Publish the Customizations

Here's an example:


<ImportExportXml version="4.0.0.0" languagecode="1043" generatedBy="OnPremise">
<Entities>
<Entity>
<Name .... />
....
<SavedQueries>
<savedquery>
<columnsetxml>
<columnset version="3.0">
<column>fullname</column>
<column>createdon</column>
<column>statuscode</column>
<column>subject</column>
<column>leadid</column>
<ascend>createdon</ascend>
<!-- Delete from here -->
<filter type="and">
<condition column="statecode" value="0" operator="eq" />
</filter>
<!-- Delete till here -->
</columnset>
</columnsetxml>
....
</savedquery>
</SavedQueries>
....
</Entity>
</Entities>
....
</ImportExportXml>

Keep in mind that you do add the attribute StateCode or StatusCode to the associated view as well, so that end users can see which records are current and which are inactive.

One of the locations that this is useful, is when you are looking into relationships. The out of the box entity does allow you to select party 1, party 2, role 1 and role 2, but no real extensibility options. You could recreate that entity and add useful attributes like startdate and enddate. As soon as the end date has passed, then the record can be deactivated by using workflow. The fact that a person had a professional relationship with a company is information that you do want to keep visible, especially in the associated view.



Read-only URL Addressable Form

The SDK does describe URL Addressable Forms, but one thing which I do miss on this page, is details around how to link to a form in readonly format. This is done by using the following URL:
http://server/orgname/_forms/readonly/readonly.aspx?objTypeCode=objectTypeCode.
Of course you need to change the server to servername, orgname to organization name and the objectTypeCode to the entity object type code. For instance 1 for account or 1024 for product.



New Statement of Direction paper

Microsoft has just release a new Statement of Direction document. Due to NDA restrictions I cannot share contents of this document (yet), but assuming that you are a partner or a customer, you can download this paper yourself from either of the following locations.
Partnersource: https://mbs.microsoft.com/partnersource/marketing/statementofdirection/MD_CRM_SOD.htm
Customersource: https://mbs.microsoft.com/customersource/documentation/whitepapers/MD_CRM_SOD.htm

There is a lot of interesting information in this document regarding mobility, additions to CRM 4.0 as well as new information about v.Next. Have fun reading this!