I did it so you don't have to: Connecting to Dynamics CRM Online from BizTalk Server
If you’re a consultant like me, you’ve probably got similar calls from some key account manager, as I did yesterday:
KAM: Hi Mikael. I’m just about to close this super big deal, with this super important Customer.
Me: Really! Good for you.
KAM: Yeah, we’re really close. But to rap it up, I was wondering if you could help me out a bit…
Me: Sure. What do you have in mind?
KAM: Could you come with me to meeting with the customer on Monday? (this happens on Thursday 6PM)
Me (getting suspicious): mmm…What do you want me to do?
KAM: A demo!
Me: Demo of what?
KAM: The customer want us to show how to integrate Dynamics CRM Online with SAP using BizTalk.
KAM: Yes, yes. The customer wants us to show it live! You know, they want to see you do it…
Me: ARE YOU HIGH? (I didn’t actually say that, but I was thinking it)
Me: It will not happen! I haven't worked with SAP since 3-4 year ago. I’ve never worked with CRM Online (or off-line for that matter). I’m fully booked tomorrow, and I want to spend the weekend with my family as X-mas is coming up.
KAM: But we need to close this deal…
Me: No way!
(Yada, yada, yada)
Me: Ok, I’ll give it a try (I’M SUCH AN IDIOT!!!!!)
So here it is: How to connect to Dynamics CRM Online from BizTalk Server
To begin with, if you want to integrate with CRM Online, you have two options. Either use an un-typed web-service API or use a tool called CrmSvcUtil.exe to create a proxy class for you. Each of these comes with some challenges and limitations:
Using an un-typed web service, can of course be somewhat messy, but the SDK provides you with the schemas you need (more on that later). The biggest challenge, however, is to authenticate to the service as it assumes you’re using Windows Live Id. Authenticating against the service would require an additional four calls to the service to finally get the authentication tokens needed to create the security header. An then figure out a way to to add the headers in a pipeline. The steps needed are described by Girish Raja here.
The proxy created using the CrmSvcUtil is quite nice, since it’s typed, but of course I can’t use it in a send port. I would have to make the call using the inline-send approach from within an expression shape in an orchestration. And thereby loose the built in re-send functionality and more, that ships with BizTalk.
As none of these approaches was acceptable, I begun looking for other alternatives. What I really wanted was an authentication behavior, that I could add to my WCF-Custom send port adapter.
Building the Custom WCF Behavior
What I needed was a Message Inspector that would build up the security header as Girish Raja did in his sample, and then add that header to the SOAP envelope. This class is called LiveIdAuthenticationMessageInspector and inherits from IClientMessageInspector. This gives two methods to my class: BeforeSendRequest and AfterReceiveReply.
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request,
string securityHeader = HeaderHelper.GetSecurityHeader(this._username, this._password, this._crmUri);
In the BeforeSendRequest method is where I can add the security header to the message before the message is sent out. The the BeforeSendRequest method I call a helper class returning the actual header. The GetSecurityHeader method is going through four steps to build up the header:
- Get Windows Live Device Credentials
- Register Device Credentials and get binaryDAToken
- Get Security Token by sending WLID username, password and device binaryDAToken
- Build up the security header with the token from previous step.
(This sample does not cache the tokens! I strongly suggest you add some caching logic before you run this in production)
After the header is created it is added to the request, using a custom serializer, as it would otherwise be HTML encoded.
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
Trace.WriteLine("[bLogical] LiveIdAuthenticationMessageInspector:AfterReceiveReply called");
int index = reply.Headers.FindHeader("Security", WSSecurityUsernameTokenProfileNamespace);
When BizTalk (or any other WCF client) receives the response it will throw an exception, as it doesn’t understand the Security header. I might have gone away with adding the http:http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd schema to BizTalk, but as I don’t need it, I just removed it from the header on the way back.
Part from the Message Inspector, I also added an EndpointBehavior and a BehaviorExtensionElement. The LiveIdAuthenticationBehaviorExtensionElement needs to be registered in the configuration using the behavior in BizTalk
After you have registered the behavior, you can focus on the normal BizTalk tasks like building orchestrations and mappings. To get started with consuming the CRM Services, have a look at Richards post. The only thing I’d like to emphasis is that the correct schemas are part of the SDK (sdk\schemas). After you run the Consume WCF Service Wizard, remove all schemas and replace them with the the once in the SDK. Better yet, put all those schemas in a separate schema project, and reference that project from other projects where you’re using them.
1. Add the behavior to the Global Assembly Cache
Open up the LiveIdAuthentication project, build and add it to the global assembly cache.
2. Register the behavior in the configuration
(sorry about the formatting).
<add name="liveIdAuthentication" type="LiveIdAuthentication.LiveIdAuthenticationBehaviorExtensionElement, LiveIdAuthentication, Version=18.104.22.168, Culture=neutral, PublicKeyToken=698ceec8cebc73ae"/>
You can do this either in a config file (machine.config or BTSNTSvc.exe.config) or in BizTalk (WCF-Custom Send handler):
I prefer the later as I would otherwise need to make the changes to all the servers in the group. Just copy the extension element above, into a config file, and import the file from the Transport Properties dialog above. Or you can point to the app.config file in the sample.
3. Add the Endpoint Behavior
Open the send port and click the Configure button to open the WCF Transport Porperties. Select the Behavior tab and right-click the Endpoint behavior node, and select Add extension. Select the liveAuthentication extensions. Select the extension and set the properties.
Use this code as you like, and on your own risk. If you make improvements, I’d appreciate if you notify me. One thing I know could be done better, would be to cache the tokens and re-use them for the next call.
Download the Dynamics CRM LiveId Authentication Behavior sample here.