Schlagwort-Archive: SDK

Who triggered my plugin?

Do you ever want to know who triggered the execution of a plugin? This knowledge is handy, if you have to do some operation if the user entered data, but not if an external application made an update with the SDK.

The IPluginExecutionContext contains the property CallerOrigin which will tell us more about the origin which triggered the plugin execution.

The CallerOrigin is populated with one of these four types

  • Application – The user has triggered the event (by creating or editing a record).
  • AsyncService – The async service triggered the event (by workflow execution).
  • WebServiceApi – An application which makes use of the crm web service triggered the event.
  • OfflineOrigin – The event was triggered by replaying offline actions while going online.

This sample shows how to make use of this property (the sample is part of the sdk article Online vs. Offline Plug-ins)

using System;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
public class OnlinePlugin : IPlugin
   public void Execute(IPluginExecutionContext context)
      // Check to see if this is a playback context.
      CallerOrigin callerOrigin = context.CallerOrigin;
      if (callerOrigin is OfflineOrigin)
         // This plug-in was fired from the playback queue after the user
         // selected to go online within Microsoft Dynamics CRM for Outlook.
         // Do something here.

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);
// 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";

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 = "")]
[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 = 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.