Monday, October 6, 2008

Consuming a WCF service in MS Dynamics CRM 4.0 Workflow

So I was facing a bit of a challenge:

I had created a workflow for CRM 4.0 which consumed a WCF service (In my case I had exposed a BizTalk schema as a WCF service). I added a reference to the service, and did my coding. Everything was looking great until I deployed the custom Workflow via the plugin manager and tried it out: Nothing happened. I tried to debug it, and got the message:
"Could not find default endpoint element that references contract 'XXX' in the ServiceModel client configuration section."

I've seen this problem before with assemblies when trying to read a connection string from its config file. You could input these settings in the host's app.config or web.config, but this is not always desirable or even possible. As for the CRM's async service which is running the workflow, this was not an option. For regular configuration settings, I've used Mike Woodring's approach in the past. However, when it comes to WCF settings, .Net writes a whole lot of configuration in the config-file, but it also generates the code which creates the client based on these settings...

The solution:

The credit for the solution goes mainly to Pablo M. Cibraro, who has written code to load the WCF configuration from a different file than the standard config file. See his blogpost here
.
What I did different was using Visual Studio's "Reference Service..."-wizard to consume my WCF service. Then, to be able to use the custom config-file, I had to create a new channel instead of using the auto-generated service client.
CustomClientChannel<IMyServiceInterface> channel = new CustomClientChannel<IMyServiceInterface>("C:\Program Files\Microsoft CRM\Server\bin\assembly\myworkflow.dll.config");
IMyServiceInterface client = channel.CreateChannel();

where "IMyServiceInterface" is one of the interfaces that has been auto-generated by VS (In my case CrmCustomerService). So what you in reality is doing, is using most of the auto-generated code classes/interfaces, but scrapping the ServiceClient class.

Finally, if you're using the code sample, remember to modify the CreateDiscription()-method in the Bindings-section to:
if (serviceEndpoint.Behaviors.Count == 0 && !string.IsNullOrEmpty(selectedEndpoint.BehaviorConfiguration))

to make sure it doesn't fail if you don't have binding-info in the config file.
The sample code includes a lot of overloaded constructors for creating a channel. For me, the best bet was just specifying the file path for the custom config file as input parameter (Remember to specify the absolute path, in most cases "C:\Program Files\Microsoft CRM\Server\bin\assembly\myworkflow.dll.config" if you want the config file in the same folder as the workflow).

Hope this helps other people in the same situation!

No comments: