@michaelLipscombe 

Tuesday
Nov062012

BizTalk MQSeries adapter cross domain Authentication

Had a requirement for BizTalk to communicate with a Websphere MQ server running on Windows 2008 R2 but in a separate domain. The domains were trusted which is important to note as I can’t see this working without the trust.

The domain that the BizTalk servers were in is called AMERICAS-BIZ and the MQ domain AMERICAS-CIB. Both operating systems are Windows Server 2008 R2 sp1 and all 64-bit. The MQ version is 7 or greater and BizTalk 2010.

BizTalk

We decided to use the MQSeries BizTalk MQ Adapter over the MQSC adapter although after we started having issues I did try the MQSC adapter but had similar problems. Strangely enough it seems the the MQSC adapter is using MSDTC, doesn’t make a lot of sense to me as that adapter uses the IBM MQ client and is meant to enable BizTalk to connect to MQ running on non windows operating systems.

The BizTalk configuration is pretty standard, we had a dedicated MQ BizTalk host which was using the service account AMERICAS-BIZ\SRV_BTSAppHost. The only component that needs configuring on the BizTalk side is MSDTC which should be setup as follows:

clip_image002

MQ

On the MQ Server you have to install the MQSAgent

Good documentation can be found here: http://msdn.microsoft.com/en-us/library/aa561858.aspx

For this environment we used a service account in the AMERICAS-CIB domain called SRV_BTS_WMQS.

Once the agent is in place Make sure MSDTC is configured the same as BizTalk.

clip_image002[6]

The next step is to grant the BIZ domains BizTalk service account access to the MQSAgent COM+ application. This is done in the Component Services MMC. You might have to enable changes which is done on the Advanced tab of the MQSAgent’s properties.

image

Notice the different domains, the MQSAgent will run on the MQ server as AMERICAS-CIB\SRV_BTS_WMQS and BizTalk will connect using AMERICAS-BIZ\SRV_BTSAppHost. All the MQ access will be performed by SRV_BTS_WMQS.

SRV_BTS_WMQS will need logon as a batch and service rights in the GPO.

These sorts of errors are fairly easy to see as you get security audit failures in the eventlog.

Make sure the COM+ Network Access role is installed.

image

Then add the BizTalk Domain service account to the local Distributed COM Users group

image

Add the MQSAgent and Network Service to the local mqm group for Websphere MQ. Not entirely convinced the Network Service is needed but haven’t tested it without it.

image

At this point you can create a queue in MQ and setup a BizTalk receive location making sure Transaction Support is enabled.

image

If there are no messages in the queue you should see BizTalk connecting in MQ.

image

Now PUT a test message on the queue.

image

If it works, great. For us we got this error on the BizTalk server:

The adapter "MQSeries" raised an error message. Details "Creating an instance of the COM component with CLSID {EEEF8325-B385-420D-A8A9-EABA4F51AF5C} from the IClassFactory failed due to the following error: 8004d01b."

We then noticed an error on the component services mmc on the MQ server.

There’s lots of information out there about this problem and most seem to narrow in on reinstalling MSDTC. Do it properly you have to delete registry keys. This didn’t help.

Found this excellent post.

http://blogs.msdn.com/b/distributedservices/archive/2009/03/13/troubleshooting-msdtc-permission-issues-when-a-distributed-transaction-starts.aspx

Given MQ was not clustered on this server (preproduction) we focused on permission for MSDTC and SCMANAGER.

Sc sdshow msdtc

D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCLCSWLOCRRC;;;IU)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)

Sc sdshow SCManager

Just as the article explained in both cases Authenticated Users did not have required permissions to MSDTC.

sc sdset msdtc D:(A;;CCLCSWRPLOCRRC;;;S-1-2-0)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCCR;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)(A;;CCLCSWRPRC;;;WD)(A;;CCLCSWRPLORC;;;NS)S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)

sc sdset SCMANAGER D:(A;;CCGR;;;AU)(A;;CCLCRPWPRC;;;SY)(A;;KA;;;BA)S:(AU;FA;KA;;;WD)(AU;OIIOFA;GA;;;WD)

Running these commands resolved the issue. However once the servers the permissions were lost and we subsequently discovered the GPO was overriding our permissions.

Running gpresult /h <outputfilename.html>  showed the problem:

clip_image001

Authenticated Users is missing

clip_image001[7]

Resolved!

Wednesday
Aug012012

Amazon Marketplace Web Service (MWS) BizTalk WCF Adapter

Amazon’s Marketplace Web Service (MWS) is a is an integrated Web service API that helps Amazon sellers to programmatically exchange data on listings, orders, payments, reports, and more. XML data integration with Amazon enables higher levels of selling automation, which helps sellers grow their business. By using Amazon MWS, sellers can increase selling efficiency, reduce labor requirements, and improve response time to customers.

The API has some nice documentation, C# libraries and samples you can download from the site.

Basically they give you 8 different interfaces.

  • Orders
  • Feeds
  • Reports
  • Inbound Shipments
  • Outbound Shipments
  • Inventory
  • Products
  • Sellers

Most are self-explanatory.  Feeds and reports enable you to request or schedule a report/data feed to be generated.

MWS and BizTalk

Unfortunately BizTalk doesn’t really support REST at the moment, there are a couple of workarounds but they are a little clunky. I’ve worked with the MWS service in the past and for various reasons we went with a windows service that pulled reports down and submitted the flat files to BizTalk. This worked well and I really learnt a lot about the MWS API’s. I’ve since been thinking about a Custom WCF Adapter. So here it is….

I think there’s great opportunity for larger Amazon sellers that want to integrate with MWS. This could be with existing ERP’s like Dynamics AX, SAP or Oracle eBusiness Suite etc which BizTalk already supports. BizTalk also has strong EDI capabilities so I could imagine integrating vendors\customers with MWS using EDI or RosettaNet. Hopefully this adapter will make that easier and allow firms to leverage a proven middleware platform.

The adapter isn’t really an adapter, strictly speaking it’s a WCF binding but we’ll call it an adapter for simplicity and coolness.

Of the list above currently the Adapter only supports the following interfaces:

  • Orders
  • Inbound Shipments
  • Outbound Shipments
  • Inventory
  • Products
  • Sellers

You’ll notice only Feeds and Reports are missing. Feeds and Reports would make more sense to be a Receive Adapter in my opinion. You have to request the data to be generated, keep checking if it’s ready and then pull down the data and away you go. It still requires more mountain bike thinking time as to the best way to implement it. Currently I’m thinking about developing an interface that the user could select which reports/feeds they want and define a schedule. BizTalk would request the reports and wait (poll) for them to be available, but as I said it requires more thought.

Each API has about 10 or so methods, for example InboundShipment supports the following:

  • CreateInboundShipmentPlan
  • CreateInboundShipment
  • GetServiceStatus
  • ListInboundShipmentItemsByNextToken
  • ListInboundShipmentItems
  • ListInboundShipmentsByNextToken
  • ListInboundShipments
  • UpdateInboundShipment

 

Schemas

With the Adapter you’ll get several DLL’s containing all the Request & Response schemas for the support API’s. For example, InboundShipment:

  • CreateInboundShipmentPlanRequest
  • CreateInboundShipmentPlanResponse
  • CreateInboundShipmentRequest
  • CreateInboundShipmentResponse
  • GetServiceStatusRequest
  • GetServiceStatusResponse
  • ListInboundShipmentItemsByNextTokenRequest
  • ListInboundShipmentItemsByNextTokenResponse
  • ListInboundShipmentItemsRequest
  • ListInboundShipmentItemsResponse
  • ListInboundShipmentsByNextTokenRequest
  • ListInboundShipmentsByNextTokenResponse
  • ListInboundShipmentsRequest
  • ListInboundShipmentsResponse
  • UpdateInboundShipmentRequest
  • UpdateInboundShipmentResponse

In all the schemas I’ve promoted SellerId, MarketPlace and NextToken so these can be populated via property demotion.

Example Request Message, CreateInboundShipmentPlanRequest:

<ns0:CreateInboundShipmentPlanRequest 
xmlns:ns0="http://mws.amazonaws.com/FulfillmentInboundShipment/2010-10-01/">
<ns0:SellerId>SellerId_0</ns0:SellerId>
<ns0:Marketplace>Marketplace_0</ns0:Marketplace>
<ns0:ShipFromAddress>
<ns0:Name>Name_0</ns0:Name>
<ns0:AddressLine1>AddressLine1_0</ns0:AddressLine1>
<ns0:AddressLine2>AddressLine2_0</ns0:AddressLine2>
<ns0:DistrictOrCounty>DistrictOrCounty_0</ns0:DistrictOrCounty>
<ns0:City>City_0</ns0:City>
<ns0:StateOrProvinceCode>StateOrProvinceCode_0</ns0:StateOrProvinceCode>
<ns0:CountryCode>CountryCode_0</ns0:CountryCode>
<ns0:PostalCode>PostalCode_0</ns0:PostalCode>
</ns0:ShipFromAddress>
<ns0:LabelPrepPreference>LabelPrepPreference_0</ns0:LabelPrepPreference>
<ns0:InboundShipmentPlanRequestItems>
<ns0:member>
<ns0:SellerSKU>SellerSKU_0</ns0:SellerSKU>
<ns0:ASIN>ASIN_0</ns0:ASIN>
<ns0:Condition>Condition_0</ns0:Condition>
<ns0:Quantity>10.4</ns0:Quantity>
</ns0:member>
<ns0:member>
<ns0:SellerSKU>SellerSKU_0</ns0:SellerSKU>
<ns0:ASIN>ASIN_0</ns0:ASIN>
<ns0:Condition>Condition_0</ns0:Condition>
<ns0:Quantity>10.4</ns0:Quantity>
</ns0:member>
<ns0:member>
<ns0:SellerSKU>SellerSKU_0</ns0:SellerSKU>
<ns0:ASIN>ASIN_0</ns0:ASIN>
<ns0:Condition>Condition_0</ns0:Condition>
<ns0:Quantity>10.4</ns0:Quantity>
</ns0:member>
</ns0:InboundShipmentPlanRequestItems>
</ns0:CreateInboundShipmentPlanRequest>
 
Response:
 
<ns0:CreateInboundShipmentPlanResponse 
xmlns:ns0="http://mws.amazonaws.com/FulfillmentInboundShipment/2010-10-01/">
<ns0:CreateInboundShipmentPlanResult>
<ns0:InboundShipmentPlans>
<ns0:member>
<ns0:ShipmentId>ShipmentId_0</ns0:ShipmentId>
<ns0:DestinationFulfillmentCenterId>DestinationFulfillmentCenterId_0
</ns0:DestinationFulfillmentCenterId>
<ns0:ShipToAddress>
<ns0:Name>Name_0</ns0:Name>
<ns0:AddressLine1>AddressLine1_0</ns0:AddressLine1>
<ns0:AddressLine2>AddressLine2_0</ns0:AddressLine2>
<ns0:DistrictOrCounty>DistrictOrCounty_0</ns0:DistrictOrCounty>
<ns0:City>City_0</ns0:City>
<ns0:StateOrProvinceCode>StateOrProvinceCode_0</ns0:StateOrProvinceCode>
<ns0:CountryCode>CountryCode_0</ns0:CountryCode>
<ns0:PostalCode>PostalCode_0</ns0:PostalCode>
</ns0:ShipToAddress>
<ns0:LabelPrepType>LabelPrepType_0</ns0:LabelPrepType>
<ns0:Items>
<ns0:member>
<ns0:SellerSKU>SellerSKU_0</ns0:SellerSKU>
<ns0:FulfillmentNetworkSKU>FulfillmentNetworkSKU_0</ns0:FulfillmentNetworkSKU>
<ns0:Quantity>10.4</ns0:Quantity>
</ns0:member>
<ns0:member>
<ns0:SellerSKU>SellerSKU_0</ns0:SellerSKU>
<ns0:FulfillmentNetworkSKU>FulfillmentNetworkSKU_0</ns0:FulfillmentNetworkSKU>
<ns0:Quantity>10.4</ns0:Quantity>
</ns0:member>
<ns0:member>
<ns0:SellerSKU>SellerSKU_0</ns0:SellerSKU>
<ns0:FulfillmentNetworkSKU>FulfillmentNetworkSKU_0</ns0:FulfillmentNetworkSKU>
<ns0:Quantity>10.4</ns0:Quantity>
</ns0:member>
</ns0:Items>
</ns0:member>
<ns0:member>
<ns0:ShipmentId>ShipmentId_0</ns0:ShipmentId>
<ns0:DestinationFulfillmentCenterId>DestinationFulfillmentCenterId_0
</ns0:DestinationFulfillmentCenterId>
<ns0:ShipToAddress>
<ns0:Name>Name_0</ns0:Name>
<ns0:AddressLine1>AddressLine1_0</ns0:AddressLine1>
<ns0:AddressLine2>AddressLine2_0</ns0:AddressLine2>
<ns0:DistrictOrCounty>DistrictOrCounty_0</ns0:DistrictOrCounty>
<ns0:City>City_0</ns0:City>
<ns0:StateOrProvinceCode>StateOrProvinceCode_0</ns0:StateOrProvinceCode>
<ns0:CountryCode>CountryCode_0</ns0:CountryCode>
<ns0:PostalCode>PostalCode_0</ns0:PostalCode>
</ns0:ShipToAddress>
<ns0:LabelPrepType>LabelPrepType_0</ns0:LabelPrepType>
<ns0:Items>
<ns0:member>
<ns0:SellerSKU>SellerSKU_0</ns0:SellerSKU>
<ns0:FulfillmentNetworkSKU>FulfillmentNetworkSKU_0</ns0:FulfillmentNetworkSKU>
<ns0:Quantity>10.4</ns0:Quantity>
</ns0:member>
<ns0:member>
<ns0:SellerSKU>SellerSKU_0</ns0:SellerSKU>
<ns0:FulfillmentNetworkSKU>FulfillmentNetworkSKU_0</ns0:FulfillmentNetworkSKU>
<ns0:Quantity>10.4</ns0:Quantity>
</ns0:member>
<ns0:member>
<ns0:SellerSKU>SellerSKU_0</ns0:SellerSKU>
<ns0:FulfillmentNetworkSKU>FulfillmentNetworkSKU_0</ns0:FulfillmentNetworkSKU>
<ns0:Quantity>10.4</ns0:Quantity>
</ns0:member>
</ns0:Items>
</ns0:member>
</ns0:InboundShipmentPlans>
</ns0:CreateInboundShipmentPlanResult>
<ns0:ResponseMetadata>
<ns0:RequestId>RequestId_0</ns0:RequestId>
</ns0:ResponseMetadata>
</ns0:CreateInboundShipmentPlanResponse>
 
To use the MWSAdapter just reference the schema and promoted property DLL’s and configure the send port. Obviously it will be a solicit response send port.

image

 

On the Endpoint Address tab you must configure it as follows:

Address URI: The schema is mws:// then enter the host and port for the MWS API server. The Adapter will only support https so the port isn’t required.

Action: The normal Operation/Action mapping for WCF adapters except the Action must be defined as follows:

[ServiceAPI]/[ServicePath]/[ServiceMethod]

e.g. InboundShipment/FulfillmentInboundShipment/CreateInboundShipmentPlan

The adapter takes the ServiceAPI and loads the appropriate Amazon API library, the ServicePath is used in the URI e.g. https://mws.amazonservices.com:443/FulfillmentInboundShipment/

The ServiceMethod clearly relates to the actual method being called.

Example Action Mapping XML:

<BtsActionMapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Operation Name="createInboundShipmentPlan"
Action="InboundShipment/FulfillmentInboundServiceMWS/CreateInboundShipmentPlan" />
<Operation Name="createInboundShipment"
Action="InboundShipment/FulfillmentInboundServiceMWS/CreateInboundShipment" />
</BtsActionMapping>

image

 

The binding is called mwsAdapter and has the following properties which all relate to your Amazon credentials. The Adapter will use these when it constructs the request message.

image

 

That’s it really, fairly simple. Using BizTalk you can then create your Amazon Request messages as you want depending on what you’re integrating it with.

If you’re interested in using this adapter get in contact with us. I’m still testing at this point so not quite ready to release code just yet.

I’ll post an actual demo of the adapter after I get through some more testing.

Monday
Jun252012

Contract First Development and BizTalk Server

Got asked to setup a demo to show how BizTalk handles contract first development within a service orientated architecture. If BizTalk consumes a web service there isn’t really much to talk about, it’s easy enough provided the published contract or WSDL adheres to a couple of minor considerations, granted they’re not so minor if you bump into one.

The client was looking to define WSDL files using a tool like Eclipse or SOAPUI which they could then distribute so all relevant parties could get coding. The BizTalk developers would take that file and build a service that conforms to the contract. If you’re familiar with BizTalk you could probably start to see the challenge. There’s a chapter in Richard Seroter’ book SOA Patterns with BizTalk 2009 which has a section on one way to do this, for this post I’ve used his approach on exposing the WSDL but decided do something different regarding the schemas.

When you generate a WCF service rather than choose all the schemas you want to expose it’s possible to just select the “Any” message type from the Microsoft.XLANGs.BaseTypes.dll assembly. This basically means your service will accept messages and not care about the type. This enables BizTalk to receive the messages defined in the contract without having to worry about getting the schemas to match in the service. You’ll still have message type validation when the message is published into BizTalk so the client could not send just any old message without getting an exception. What you would lose is the field level validation that a strongly typed service would provide, but you could get the similar behavior by adding a validation pipeline component to the receive location. All we’re really doing is delaying the message validation until it hits BizTalk when a traditional service would do that in IIS.

To the client the only difference would be the metadata endpoint as the messages would be of type Any rather than Order or OrderResponse. Again this isn’t a big deal as the client is using the contract. Having said that the workaround from SOA Patterns enabled BizTalk WCF Service to use our handcrafted WSDL rather than generate one, so really our BizTalk service will behave and look just like it should.

The requirements

The requirements for the demo were pretty simple. I had to use the distributed WSDL to define types in BizTalk and they wanted BizTalk to publish the WSDL for discovery so the metadata endpoint had to match the contract.

The Contract

Obviously I needed a contract. Given they were going to use Eclipse I figured that’s a good place to start. One of the concerns I had were those considerations mentioned earlier when BizTalk consumes a web service. Using the same tool the client will use to craft the WSDL would ensure there aren’t as many gotchas for the client later on. Couple of downloads, a 64-bit java issue and a few clicks later I had my contract. Just a basic PlaceOrder method that took in an Order request and returned OrderResponse.

image

 

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.demo.org/ContractFirst/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
name="ContractFirst" targetNamespace="http://www.demo.org/ContractFirst/">
<wsdl:types>
<xsd:schema targetNamespace="http://www.demo.org/ContractFirst/">
<xsd:element name="Order" type="tns:Order">
</xsd:element>
<xsd:element name="OrderResponse" type="tns:OrderResponse">
</xsd:element>
<xsd:complexType name="Order">
<xsd:sequence>
<xsd:element name="PONumber" type="xsd:int"></xsd:element>
<xsd:element name="CustomerID" type="xsd:string"></xsd:element>


<xsd:element name="OrderDate" type="xsd:date"></xsd:element>
<xsd:element name="Lines" type="tns:Line" maxOccurs="unbounded"
minOccurs="1">
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="OrderResponse">

<xsd:sequence>
<xsd:element name="Status">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Success"></xsd:enumeration>
<xsd:enumeration value="Failed"></xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="OrderNumber" type="xsd:string"></xsd:element>
<xsd:element name="Message" type="xsd:string"></xsd:element>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="Line">
<xsd:sequence>
<xsd:element name="ItemNumber" type="xsd:int"></xsd:element>
<xsd:element name="Quantity" type="xsd:int"></xsd:element>
<xsd:element name="Price" type="xsd:double"></xsd:element>
</xsd:sequence>
<xsd:attribute name="LineNumber" type="xsd:string"></xsd:attribute>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="PlaceOrderRequest">
<wsdl:part name="part" element="tns:Order" />
</wsdl:message>
<wsdl:message name="PlaceOrderResponse">
<wsdl:part name="part" element="tns:OrderResponse" />
</wsdl:message>
<wsdl:portType name="ContractFirst">
<wsdl:operation name="PlaceOrder">
<wsdl:input message="tns:PlaceOrderRequest"/>
<wsdl:output message="tns:PlaceOrderResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ContractFirstSOAP" type="tns:ContractFirst">

<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="PlaceOrder">

<soap:operation
soapAction="http://www.demo.org/ContractFirst/PlaceOrder" />
<wsdl:input>

<soap:body use="literal" />
</wsdl:input>
<wsdl:output>

<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ContractFirst">
<wsdl:port binding="tns:ContractFirstSOAP" name="ContractFirstSOAP">
<soap:address location="http://www.demo.org/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

I saved the WSDL to common folder, contract done!

The Client

Next I created a test harness or client that will eventually be able to call BizTalk and submit an Order. For the client everything I need to know at this point is contained in the contract even though the service doesn’t exist. A simple console application will work, just have to add a service reference to the WSDL file I saved earlier.

image

The code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestHarness
{
class Program
{
static void Main(string[] args)
{
try
{
ServiceReference1.ContractFirstClient client =
new ServiceReference1.ContractFirstClient();

ServiceReference1.Line line1 = new ServiceReference1.Line{
ItemNumber = 1234,
LineNumber ="1",
Price = 100,
Quantity = 10};

ServiceReference1.Line line2 = new ServiceReference1.Line{
ItemNumber = 1234,
LineNumber ="2",
Price = 100,
Quantity = 10};

ServiceReference1.Order order = new ServiceReference1.Order
{
CustomerID = "12345",
OrderDate = DateTime.Now,
PONumber = 998877,
Lines = new[] { line1, line2 }
};

Console.WriteLine("Sending PlaceOrder...");

ServiceReference1.OrderResponse response = client.PlaceOrder(order);

Console.WriteLine("Received response: {0}", response.Status);
Console.WriteLine("Order Number: {0}", response.OrderNumber);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
finally
{
Console.Read();
}
}
}
}

The app.config that will get created is good to go, you’ll just have to change the endpoint address when the BizTalk service is finally published.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ContractFirstSOAP" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://www.demo.org/contractfirst" binding="basicHttpBinding"
bindingConfiguration="ContractFirstSOAP" contract="ServiceReference1.ContractFirst"
name="ContractFirstSOAP" />
</client>
</system.serviceModel>
</configuration>

The Service

Everything up until this point has been fairly straightforward as in no workarounds or pitfalls, now we need to create the service. I created a simple orchestration that’s going to subscribe to the Order message, construct an OrderResponse and send it back out. 

image

 

Frist we’ll have to add a Web Reference to bring in my contract.

image

 

This will create all my message types and ports. They’ll be the web variety but that’s okay.

image

 

Back in the orchestration we want to add a port that will receive the Order message and send out the OrderResponse. First issue. The Web PortTypes have their direction predefined, as in they can only send a request and receive a response. This is fine for most instances when you add a web reference but this won’t work in this scenario as we want to receive the request and send a response even though we’re referencing a WSDL.

image

 

It’s probably possible to get into the Reference.odx that’s generated by adding a web reference and change it but I wouldn’t advise that. You’ll have to change it every time you update the contract. The workaround is to just define your own port types and use the web message types from the web reference. This way you can control the direction and still use the types as defined in the contract.

image

 

Next we’ll create the actual SOAP endpoint that our client will call. To do this you’ll have to deploy the project and open the WCF Publishing Wizard. On the first screen make sure you choose WCF-CustomIsolated as the adapter. CustomIsolated will enable us to use a custom or external metadata file via the servieMetadata behavior.

image

 

Publish Schemas.

image

 

Here we get to the next workaround.

image

 

On this screen we’re expected to select the schemas from our project. We could in theory select the web message types that get generated by the web reference but I suspect that’ll get nasty. As explained at the top of the post I decided to use the Any message types to create generic service. It still isn’t really generic as BizTalk will still validate the message types so a client could not send an unknown message type without getting an exception. Having said that if you don’t add a validation pipeline component it would be possible to receive a message that doesn’t conform to the contract as BizTalk does not validate against the schema by default.

image   

   image

 

Now you can finish the wizard and create the service. You’ll probably have to add the basicHttpBinding to the receive location but you can now bind your orchestration and start everything up. Change the Testharness app.config to have the correct endpoint address and an Order should get submitted.

image

Metadata Endpoint

The final step is to get the WSDL or contract to be discoverable from the BizTalk Service URL. If you instructed the WCF publishing wizard to create a mex endpoint it will currently look something like this.

image

This is clearly a lot different to the contract we developed in the beginning, notice the xsd:anyType part definitions. There is workaround! First, copy the WSDL file to the virtual directory of your BizTalk WCF Service and note the URL i.e. http://localhost/DemoService/ContractFirst.wsdl it can also be a relative path. Open up the WCF-CustomIsolated receive location and add a serviceMetadata service behavior, set httpGetEnabled to true and enter the URL in the externalMetadataLocation property . 

image

 

This will override the metadata endpoint of the service and add a link to the contract. Now we have a service that not only accepts the types defined in the contract but it’s also discoverable. As the contract changes you don’t even need to change your WCF service just update the web reference in the BizTalk project and copy the contract to the virtual directory.

The code needs to be scrubbed of any client names so I’ll have to add that later.

Wednesday
Jun132012

Automating the BizTalk WCF Service Publishing Wizard

Download it here.

Documentation here.

Example:

BtsWcfServicePublishing.exe WCF.xml 
-EnableMetaData
-Anonymous
-TargetNamespace:"http://Mike.POD.Schemas/"
-Location:"http://localhost/BrewBusIntegration"
-Overwrite

 

Probably should mention that you’ll have to run the wizard once to get the XML (WCF.xml in the example). It displays it on the last step.

Tuesday
May222012

BizTalk Send Port Filters and Binding Files

Helping a client that uses the BizTalk Deployment Framework and noticed a rather annoying issue with the Filters not being imported from the Bindings. Found this post that says it’s due to auto formatting in Visual Studio.

Did some testing and found that if you remove the XML declaration from the encoded filter it doesn’t matter how it’s formatted. When using the Deployment Framework just don’t copy that line into your master bindings file and you’ll be good to go.

image

 

You can also get the Deployment Framework to do the decoding/encoding for you. Location this file where ever you installed the BTDF.

C:\Program Files\Deployment Framework for BizTalk\5.0\Framework\DeployTools\adapterXPaths.txt

Add a line for SendPort/Filter and you should be able to put properly encoded XML in the Master Bindings file and the framework will take care of it for you.

image