Showing posts with label WCF. Show all posts
Showing posts with label WCF. Show all posts

Thursday, November 4, 2010

Following up on the BizTalk Adapter Pack on Framework 4.0

In this post, I mused about whether the BizTalk Adapter Pack 2.0 would actually work in Framework 4.0 applications -- not just in design-time. As it turns out, the answer is yes, albeit with two caveats and a potential issue.

These things you must do, or it won't work at all:

  1. You must add the useLegacyV2RuntimeActivationPolicy="true" attribute to the startup node of your app.config file. Without this, you'll get an exception at runtime indicating that the mixed-mode assembly can't be loaded without additional configuration. This setting changes the way the Framework loads assemblies in side-by-side mode when they use APIs such as COM interop; marklio explains this better than I.
  2. You must apply the machine.config changes in my prior post to the machine.config for both the 32 and 64 bit versions of the Framework, or you must change your build configuration to target a specific CPU architecture. You need to do this so the WCF architecture used by the Adapter Pack can see its binding extensions in the appropriate architecture.
The potential issue is that the Adapter Pack seems to be slower when run under Framework 4.0. The performance hit, based on my instrumentation in an application that I've just migrated, is about 20% or so for the SAP RFC adapter. I suspect this is because of changes between the 2.0 and 4.0 CLRs. Depending on what you use the Adapter Pack for, this may or may not have a major impact. SAP, for instance, is often slow enough on the RFC interface that a 20% increase is hardly noticeable.

Oh, and this trick works for both the full and client profiles of the Framework, again assuming you do both 1 and 2 above. 2 will usually be taken care of for you as most of the time, you'll be using architecture-specific DLLs for your ERP system's interface and you'll have already addressed this when you built the application.

Thursday, April 15, 2010

Adding the BizTalk Adapter Pack "Add Adapter Service Reference" plugin to Visual Studio 2010

Visual Studio 2010 is out at last, and it's awesome. It's got a slick new interface design, support for C# 4.0, and impressive integration with Team Foundation Server. What it doesn't have, however, is backwards compatibility out of the box with certain key components -- such as the BizTalk Adapter Pack and its required component, the WCF LOB Adapter. This means that you lose the ability to consume adapters with the Add Adapter Service Reference wizard. Now, you could wait for an official release that's compatible with VS 2010, or you can follow my instructions here and magically enable the Adapter Pack for 2010! Please note that these instructions involve editing machine.config and the registry, so remember to back things up first. They work for me, but they could break something on your machine.

Phase 1: The Registry
 
The WCF LOB Adapter registers the Visual Studio add-in through the registry. It actually does it in an "unofficial" way, which is to say that it adds itself as
a Visual Studio feature package, then adds a reference to itself in the Menus key. To get the menu option to appear, you need to copy these registration entries from your Visual Studio 2008 registry tree to your Visual Studio 2010 one. Luckily for you, I've written a registry script that'll do that very thing.
 Copy the script below into a file with a .reg extension, then double-click on it to import it into the Registry (elevating, of course, if you're on Vista or 7). You may need to perform a few checks before importing it, such as:
  • Removing the Wow6432Node and SysWOW64 references from the script if you're using a 32-bit operating system.
  • Making sure you have the 64-bit version of the WCF LOB Adapter installed if you're using a 64-bit OS (which, I should note, is the only supported configuration)
The script follows.

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\Packages\{fff9759c-767b-4327-b8c2-f2ff2e36144d}]

@="Microsoft.ServiceModel.Channels.Tools.PlugInPackage.PlugInPackage, Microsoft.Channels.Tools.PlugInPackage,Version=2.0.0.0,
Culture=neutral, PublicKeyToken=null"
"InprocServer32"="C:\\Windows\\SysWOW64\\mscoree.dll" "Class"="Microsoft.ServiceModel.Channels.Tools.PlugInPackage.PlugInPackage"
"CodeBase"="C:\\Program Files\\WCF LOB Adapter SDK\\Tools\\Microsoft.ServiceModel.Channels.Tools.PlugInPackage.dll"

"ID"=dword:00000001
"MinEdition"="Standard"
"ProductVersion"="2.0.0.0"
"ProductName"="Add Adapter Service Reference" "CompanyName"="Microsoft"


[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\Menus]

"{fff9759c-767b-4327-b8c2-f2ff2e36144d}"=", 1000, 1"

Once this script is imported, when you run VS 2010, you'll now see the Add Adapter Service Reference menu item in the context menu of Solution Explorer. However, when you click on it, you'll be told there are no valid adapters installed. To solve this, we need to proceed to... 

Phase 2: machine.config 
Because VS 2010 runs as a Framework 4.0 application, the plugin binds using the 4.0 configuration files.You can verify this yourself by turning on assembly binding logging (http://msdn.microsoft.com/en-us/library/e74a18c4.aspx) and viewing the logs for devenv.exe's binds to Microsoft.ServiceModel.Channels.Tools.PlugInPackage.

Here's what that looks like in VS 2008, emphasis added:

*** Assembly Binder Log Entry (4/15/2010 @ 11:35:25 AM) ***
The operation was successful.
Bind result: hr = 0x0. The operation completed successfully.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
Running under executable C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe
--- A detailed error log follows.
=== Pre-bind state information ===
LOG: User = APIMEM\pchipman
LOG: Where-ref bind. Location = C:\Program Files\WCF LOB Adapter SDK\Tools\Microsoft.ServiceModel.Channels.Tools.PlugInPackage.dll
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Visual Studio 9.0/Common7/IDE/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = NULL
Calling assembly : (Unknown).
===
LOG: This bind starts in LoadFrom load context.
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load().
LOG: Using application configuration file: C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exe.Config
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
LOG: Attempting download of new URL file:///C:/Program Files/WCF LOB Adapter SDK/Tools/Microsoft.ServiceModel.Channels.Tools.PlugInPackage.dll.
LOG: Assembly download was successful. Attempting setup of file: C:\Program Files\WCF LOB Adapter\SDK\Tools\Microsoft.ServiceModel.Channels.Tools.PlugInPackage.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: Microsoft.ServiceModel.Channels.Tools.PlugInPackage, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
LOG: Re-apply policy for where-ref bind.
LOG: Post-policy reference: Microsoft.ServiceModel.Channels.Tools.PlugInPackage, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
LOG: Found assembly by looking in the GAC.
LOG: Switch from LoadFrom context to default context.
LOG: Binding succeeds. Returns assembly from C:\Windows\assembly\GAC_MSIL\Microsoft.ServiceModel.Channels.Tools.PlugInPackage\3.0.0.0__31bf3856ad364e35\Microsoft.ServiceModel.Channels.Tools.PlugInPackage.dll.
LOG: Assembly is loaded in default load context.

And what it looks like in VS 2010:

*** Assembly Binder Log Entry (4/15/2010 @ 10:53:05 AM) ***
The operation was successful.
Bind result: hr = 0x0. The operation completed successfully.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe
--- A detailed error log follows.
       
=== Pre-bind state information ===
LOG: Where-ref bind. Location = C:\Program Files\WCF LOB Adapter SDK\Tools\Microsoft.ServiceModel.Channels.Tools.PlugInPackage.dll
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Visual Studio 10.0/Common7/IDE/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = devenv.exe
Calling assembly : (Unknown).
===
LOG: This bind starts in LoadFrom load context.
WRN: Native image will not be probed in LoadFrom context. Native image will only be probed in default load context, like with Assembly.Load().
LOG: Using application configuration file: C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe.Config
LOG: Using host configuration file:
       
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Attempting download of new URL file:///C:/Program Files/WCF LOB Adapter SDK/Tools/Microsoft.ServiceModel.Channels.Tools.PlugInPackage.dll.
LOG: Assembly download was successful. Attempting setup of file: C:\Program Files\WCF LOB Adapter\SDK\Tools\Microsoft.ServiceModel.Channels.Tools.PlugInPackage.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: Microsoft.ServiceModel.Channels.Tools.PlugInPackage, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
LOG: Re-apply policy for where-ref bind.
LOG: Post-policy reference: Microsoft.ServiceModel.Channels.Tools.PlugInPackage,            Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
LOG: Found assembly by looking in the GAC.
LOG: Switch from LoadFrom context to default context.
LOG: Binding succeeds. Returns assembly from C:\Windows\assembly\GAC_MSIL\Microsoft.ServiceModel.Channels.Tools.PlugInPackage\3.0.0.0__31bf3856ad364e35\Microsoft.ServiceModel.Channels.Tools.PlugInPackage.dll.
LOG: Assembly is loaded in default load context.

As you can see, we're using the 4.0 configuration file in 2010, which means we need to copy the magic words from our 2.0 configuration file so our plugin can see the valid adapters. Note that this doesn't necessarily mean that 4.0 programs will be able to consume adapters -- that's an investigation for another day.

The magic words, in this case, happen to be located in the system.servicemodel part of the machine.config tree. You want to copy any Microsoft.Adapters references in the extensions/bindingElementExtensions and extensions/bindingExtensions nodes. You'll also need to copy any client/endpoint nodes that make similar references. For example, to get SAP bindings to work, you need to merge the following XML into your 4.0 machine.config file:

<system.serviceModel>
    <extensions>
        <bindingElementExtensions>
            <add name="sapAdapter" type="Microsoft.Adapters.SAP.SAPAdapterExtensionElement, Microsoft.Adapters.SAP, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
        </bindingElementExtensions>
        <bindingExtensions>
            <add name="sapBinding" type="Microsoft.Adapters.SAP.SAPAdapterBindingSection, Microsoft.Adapters.SAP, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
        </bindingExtensions>
    <client>
        <endpoint binding="sapBinding" contract="IMetadataExchange" name="sap"/>
    </client>


         
Now, you can use the Add Adapter Service Reference wizard in VS 2010 with your older Framework projects.

(Oh, and by the way, I want you to know how much effort it took to make this look pretty. Stupid HTML editor...)