Archiv für den Monat: August 2009

Error 0x80044a08: ‚invalid character in file name‘

If you try to upload a file to a note in your crm system, you have to make sure that the property filename of the annotation only contains the filename. If it contains for example the drive letters you will receive the error 0x80044a08.

The easiest way to ensure that the filename contains only the file name is to use Path.GetFileName( … );

See the ‚corrected‘ sdk example below

// Open a file and read the contents into a byte array.
FileStream stream = File.OpenRead("some-path-pointing-to-a-file-in-here");
byte[] byteData = new byte[stream.Length];
stream.Read(byteData, 0, byteData.Length);
stream.Close();
 
// Encode the data using base64.
string encodedData = System.Convert.ToBase64String(byteData);
 
// Now update the note.
annotation updateNote = new annotation();
updateNote.annotationid = new Key();
updateNote.annotationid.Value = createdNoteId;
updateNote.documentbody = encodedData;
updateNote.filename = Path.GetFileName("some-path-pointing-to-a-file-in-here");
updateNote.mimetype = @"application\ms-word";
 
service.Update(updateNote);

Howto: Debugging CRM errors

Today I had a service call with a customer who got an error on creating appointments. The error message was General Failure in Scheduling Engine

A quick search in the internet revealed that this error message is not an unknown one (at least for Dynamics CRM 3)

Because the description of the articles were not suitable for the customers environment and the CRM system is a newer one ( Dynamics CRM 4), we had to dig further.

We enabled the tracing on the crm application server and set the TraceCategories to *:Error which writes only the message with TraceLevel Error to the trace file.

The generated trace file contained following error
...
Crm Exception: Message: SecLib::CrmCheckPrivilege failed. Returned hr = -2147220960 on UserId: bcf9bb2e-6070-de11-a4a6-000c29abeb6c and PrivilegeId: b5f2ee06-d359-4495-bbda-312aae1c6b1e, ErrorCode: -2147220960
...
MessageProcessor fail to process message 'Book' for 'appointment'.
...

A quick search for the name of the denied privilege showed that the security role of the user doesn’t give him the right to share appointments. Apparently, this right is needed for creating an appointment. After adjusting the security role the error was gone and the customer was happy.

RetrieveMultiple Gotchas

This article is only relevant if you use the assemblies which are provided in the crm sdk

The crm webservice provides multiple ways for querying data. One of them uses the QueryExpression for selecting the data.

A QueryExpression can be used for retrieving data of any crm entity. However, if you use it to query the entities activitypointer or queueitem your crm webservice proxy will throw an InvalidOperationException with the message There is an error in XML document

So what are you doing wrong? Nothing.

This problem is (poorly) described in the sdkreadme.htm in the crm sdk.

Possible failure using the CrmService.RetrieveMultiple method found in SdkTypeProxy.dll (32227)

Calling this method may result in an InvalidOperationException.

Workaround: Use the CrmService.Execute method with the RetrieveMultiple message instead.

The described workaround leads to the same error. The only way to request data from these entities is to use DynamicEntities.
This requires a small change at your existing query: you only have to tell the CRM to return the results as DynamicEntities

RetrieveMultipleRequest request = new RetrieveMultipleRequest 
{ 
  Query = query, 
  ReturnDynamicEntities = true 
};

OpenThreadToken failed with hr = 1008

The crm sdk includes the class CrmImpersonator which allows to execute code with the crm user credentials instead the website credentials.

If you have used this class, you may have come into situations in which the constructor has thrown an InvalidOperationException with the message OpenThreadToken failed with hr = 1008. A little research shows, that the most common reason of this exception is that the CrmImpersonator only works if your website is executed in the context of the crm.

But even if the application runs in the context of crm there is a gotcha which leads to this exception. If you use a generic handler in your application and you are creating a new instance of the CrmImpersonator in the constructor of this handler, it will throw the same exception. See this example for reference

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Handler1 : IHttpHandler, IDisposable
{
  private CrmImpersonator _impersonator;
 
  public Handler1()
  {
    _impersonator = new CrmImpersonator();
  }
 
  public void ProcessRequest(HttpContext context)
  {
    context.Response.ContentType = "text/plain";
    context.Response.Write("Hello World");
  }
 
  public bool IsReusable
  {
    get{ return false; }
  }
 
  public void Dispose()
  {
    if (_impersonator != null)
    {
       _impersonator.Dispose();
       _impersonator = null;
    }
  }
}

It seems that the thread which processes the request is not properly initialized at this point. The solution of this problem is simple. You have to create the CrmImpersonator in the ProcessRequest method of your handler.