March 28, 2014 at 3:45 PM

Recently, I needed to send a message from BizTalk to an external WCF service with Windows Authentication.

For easy testing, I created a Windows console application that will act as the client. I used basicHttpBinding with the security-mode set to TransportCredentialOnly. In the transport-node I chose for Windows as clientCredentialType.

The web.config file looks like this:

<basicHttpBinding>
	<binding name="DemoWebService_Binding"  textEncoding="utf-16">
		<security mode="TransportCredentialOnly">
			<transport clientCredentialType="Windows" />
		</security>
	</binding>
</basicHttpBinding>

 Before sending the test message, I needed to authenticate myself and insert the Windows Credentials:

proxy.ClientCredentials.Windows.ClientCredential.Domain = "xxx";
proxy.ClientCredentials.Windows.ClientCredential.UserName = "xxx";
proxy.ClientCredentials.Windows.ClientCredential.Password = "xxx";

This works, so now to get it right in BizTalk!

Problem:

Nothing special, just a Send Port, WCF-Custom with basicHttpBinding as Binding Type and the same binding configuration as in the console application:

 

I thought I just needed to add the credentials to the Credentials-tab in BizTalk to be able to do proper authentication.

Unfortunately, this does not work!

Apparently, when "Windows" is chosen as clientCredentialType, the Credentials-tab is ignored and the credentials of the Host-Instance running the Send Port are used instead.

Solution:

After some searching, I found the answer thanks to Patrick Wellink's blog post on the Axon Olympos blog: http://axonolympus.nl/?page_id=186&post_id=1852&cat_id=6.

 

The credentials of the Host Instance can't be right, because the web-service is from an external party.

To use the Windows Credentials, a custom Endpoint Behaviour has to be created.

So I've created a new Class Library in Visual Studio with a class that inherits from both BehaviorExtensionElement and IEndpointBehavior:

public class WindowsCredentialsBehaviour : BehaviorExtensionElement, IEndpointBehavior

For extensibility, the class needs to have these public properties:

[ConfigurationProperty("Username", DefaultValue = "xxx")]
public string Username
{
	get { return (string)base["Username"]; }
	set { base["Username"] = value; }
}

[ConfigurationProperty("Password", DefaultValue = "xxx")]
public string Password
{
	get { return (string)base["Password"]; }
	set { base["Password"] = value; }
}

[ConfigurationProperty("Domain", DefaultValue = "xxx")]
public string Domain
{
	get { return (string)base["Domain"]; }
	set { base["Domain"] = value; }
}

In the function "AddBindingParameters", I've added this piece of code that sets the Windows Credentials:

public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
	if (bindingParameters != null)
	{
		SecurityCredentialsManager manager = bindingParameters.Find<ClientCredentials>();

		var cc = endpoint.Behaviors.Find<ClientCredentials>();
		cc.UserName.UserName = this.Domain + @"\" + this.Username;
		cc.UserName.Password = this.Password;
		cc.Windows.ClientCredential.UserName = this.Username;
		cc.Windows.ClientCredential.Password = this.Password;
		cc.Windows.ClientCredential.Domain = this.Domain;

		if (manager == null)
			bindingParameters.Add(this);
	}
	else
	{
		throw new ArgumentNullException("bindingParameters cannot be null.");
	}
}

Now after building and putting the assembly in the GAC, we need to let BizTalk know that it can use this custom Endpoint Behavior:


We need to add this line below to the behaviorExtensions (system.serviceModel - extensions) in the machine.config (32-bit and 64-bit):

<add name="WindowsCredentialsBehaviour" type="BizTalk.WCF.WindowsCredentials.WindowsCredentialsBehaviour, BizTalk.WCF.WindowsCredentials, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1de22c2808f4ac2e" />

Restart the host instance that runs the send port and you will be able to select the custom EndpointBehavior:

 


March 12, 2014 at 4:00 PM

On new environments, Codit always runs benchmark tests to check whether that new environment behaves as expected and to find any anomalies.
This week, these simple tests proved their value yet again:

One of the components of the benchmark test is a simple WCF echo service. A client WCF console application calls this service (also hosted in a console application). The service simply echoes back the request message.

When launching both console applications we experienced extreme delays.
The service host took more than 8 minutes to launch and the client console application took more than 3 minutes to launch.
Because the launch of the console applications typically takes under one second, this demanded for a deeper look.

To get a clearer picture of where the time is lost, I enabled WCF tracing.
This shows that constructing the servicehost and channelfactory takes a lot of time:



Trace when launching the Service

clip_image001



Trace when launching the Client

clip_image002

 

Digging deeper - and using my favorite search engine - revealed this is probably due to assembly load times.

By default, .NET 3.5 will generate so-called ‘publisher evidence’ for code access security (CAS). Verifying the assembly publishers signature can be very costly, and it is indeed very costly on the new environment.
The generation of this publisher evidence can be disabled: so, let's disable publisher evidence generation and measure the startup time again after that.

Publisher evidence generation is disabled by adding this Xml snippet to your application configuration file, or to the machine.config file (whatever suits your needs):

<runtime>
    <generatePublisherEvidence enabled="false"/>
</runtime>

After I applied this change, I started my 2 console applications again, and ‘eureka’ they are done in less than one second!

Please note that this change will only apply to .NET 3.5!



Trace when launching the Service

clip_image001[6]



Trace when launching the Client

clip_image001[8]

 

This MSDN link on the generatePublisherEveidence element contains more info about publisher evidence.

The moral of the story is, if you setup a new environment,  test it well!

 

 

Peter Borremans


November 21, 2013 at 4:00 PM

According to MSDN, the WCF Adapter copies SOAP headers to the ‘InboundHeaders’ context properties:
“The WCF adapters copy custom SOAP headers and standard SOAP headers in the inbound messages to the WCF.InboundHeaders property.”

This is true in most cases, but as I learned during the past days, this doesn’t work as described in all cases.

Let’s try with a very basic scenario – A client application sends a custom header with each call:

using (var scope = new OperationContextScope(proxy.InnerChannel)) 
{
    var header = MessageHeader.CreateHeader("peterheader", "http://peter.com", "myvalue", false);
                        
    OperationContext.Current.OutgoingMessageHeaders.Add(header);


    BTSServcieHttp.Request req = new BTSServcieHttp.Request();
    req.Param1 = "1";

    var resp = proxy.GetInfo(req);

    MessageBox.Show(resp.Result);
}

In BizTalk the incoming messages are tracked to monitor the content of 'InboundHeaders' as it is set by the WCF adapter.
A call from the client with the code shown above results in the following content for 'InboundHeaders':

<headers>
	<a:Action>GetInfo</a:Action>
	<peterheader xmlns="http://peter.com">myvalue</peterheader>
	<a:MessageID>urn:uuid:bb6d87cc-90b5-4ea7-8995-c5cd9060f74b</a:MessageID>
	<ActivityId CorrelationId="507d4c75-9d64-49f5-a095-f227437251fd">bbb9f44e-65b5-4d95-b238-493f4b54b0b3</ActivityId>
	<a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo>
	<a:To>replyaddress</a:To>
</headers>

*** Note: For the sake of readability, I removed all namespaces and security headers from the 'headers' section.

The behavior above is exactly as expected, the WCF adapter writes our header to the InboundHeaders property.

Let's slightly change our basic scenario to this:

using (var scope = new OperationContextScope(proxy.InnerChannel)) 
{
    var header = MessageHeader.CreateHeader("peterheader", "http://peter.com", "myvalue", false, "myActor");
                        
    OperationContext.Current.OutgoingMessageHeaders.Add(header);


    BTSServcieHttp.Request req = new BTSServcieHttp.Request();
    req.Param1 = "1";

    var resp = proxy.GetInfo(req);

    MessageBox.Show(resp.Result);
} 

The only thing I added was an extra parameter to the 'CreateHeader' method. This added parameter represents the 'Actor' for the SOAP header.

This is the content of 'InboundHeaders' for the call with an Actor set:

<headers>
	<a:Action>GetInfo</a:Action>
	<a:MessageID>urn:uuid:5c4c50f8-76dd-4bf9-83dc-7af7cc9af164</a:MessageID>
	<ActivityId CorrelationId="15cf87f2-6bb0-4b5e-aefb-a644d55836b7">f548f1b7-bc29-4102-a986-2f9dacb92202</ActivityId>
	<a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo>
	<a:To>replyaddress</a:To>
</headers>

As you can see, the custom header is now not written to the 'InboundHeaders' property.
This is not exactly what is documented on MSDN about 'InboundHeaders'. All standard and custom headers should be written to 'InboundHeaders'. Just adding an 'Actor' to our header will break this behavior.

This observation made me very curious to know why exactly this is happening.
To find the exact reason, I started digging in the WCF Adapter by decompiling the 'Microsoft.BizTalk.Adapter.Wcf.Runtime' assembly.

In this assembly I located the 'CopyHeadersToContext' method. This method is responsible to copy the SOAP headers to the 'InboundHeaders' property.
This is the 'CopyHeadersToContext' method implementation:

private static void CopyHeadersToContext(Message wcfMessage, IBaseMessageContext btsMessageContext)
{
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.Append("<headers>");
    foreach (MessageHeaderInfo messageHeaderInfo in wcfMessage.Headers)
    {
        int header = wcfMessage.Headers.FindHeader(messageHeaderInfo.Name, messageHeaderInfo.Namespace);
        if (header >= 0)
        {
            using (XmlReader xmlReader = (XmlReader)wcfMessage.Headers.GetReaderAtHeader(header))
            {
                string str = xmlReader.ReadOuterXml();
                btsMessageContext.Write(messageHeaderInfo.Name, messageHeaderInfo.Namespace, (object)str);
                stringBuilder.Append(str);
            }
        }
    }
    stringBuilder.Append("</headers>");
    string str1 = ((object)stringBuilder).ToString();
    btsMessageContext.Write(WcfMarshaller.inboundHeadersProp.Name.Name, WcfMarshaller.inboundHeadersProp.Name.Namespace, (object)str1);
}

As you can see in the code above, the WCF Adapter loops over the wcfMessage.Headers collection and adds them to a stringbuilder. This stringbuilder is finally written to the 'InboundHeaders' property.
The key line here is the wcfMessage.Header.FindHeaders() method call. Only headers that return a non negative result are added to the 'InboundHeaders'.

Let's have a look at the implementation of FindHeader:

public int FindHeader(string name, string ns)
{
    //lines removed for readability
    return this.FindNonAddressingHeader(name, ns, this.version.Envelope.UltimateDestinationActorValues);
}

FindHeaders calls FindNonAddressingHeader. That method is implemented like this:

private int FindNonAddressingHeader(string name, string ns, string[] actors)
{
    int num = -1;
    for (int i = 0; i < this.headerCount; i++)
    {
        if (this.headers[i].HeaderKind == MessageHeaders.HeaderKind.Unknown)
        {
            MessageHeaderInfo headerInfo = this.headers[i].HeaderInfo;
            if (headerInfo.Name == name && headerInfo.Namespace == ns)
            {
                for (int j = 0; j < actors.Length; j++)
                {
                    if (actors[j] == headerInfo.Actor)
                    {
                        if (num >= 0)
                        {
                            if (actors.Length == 1)
                            {
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageHeaderException(SR.GetString("MultipleMessageHeadersWithActor", new object[]
                                                                                                                                {
                                                                                                                                                name,
                                                                                                                                                ns,
                                                                                                                                                actors[0]
                                                                                                                                }), name, ns, true));
                            }
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MessageHeaderException(SR.GetString("MultipleMessageHeaders", new object[]
                                                                                                                {
                                                                                                                                name,
                                                                                                                                ns
                                                                                                                }), name, ns, true));
                        }
                        else
                        {
                            num = i;
                        }
                    }
                }
            }
        }
    }
    return num;
}

What this function basically does is 'finding' a header based on its name, namespace AND actor! The actor of the namespace is compared with a collection of actors that is passed into the function as a parameter (string[] actors). Only headers that have an actor matching the actors collection will give a positive result.

So.. the next step is finding out what this collection of actors contains...
The parameter that was passed in by the 'FindHeader' method was 'this.version.Envelope.UltimateDestinationActorValues'.
The question is what is the content of that property. The only location where the content of that property is assigned is in the constructor of the EnvelopeVersion:

private EnvelopeVersion(string ultimateReceiverActor, string nextDestinationActorValue, string ns, XmlDictionaryString dictionaryNs, string actor, XmlDictionaryString dictionaryActor, string toStringFormat, string senderFaultName, string receiverFaultName)
{
   //code remove for readability
        this.ultimateDestinationActorValues = new string[]
        {
            "",
            ultimateReceiverActor,
            nextDestinationActorValue
        };
    }
}

Here we find the reason for what is happening in our two basic scenarios. The actors collection that is passed to the FindHeader function contains three strings: "", ultimateReceiverActor, nextDestinationActorValue.

Because "" is in this collection, having no actor in the header will make sure it is passed to 'InboundHeaders'.
But when an actor is set, and it doesn't matches the ultimateReceiverActor or nextDestinationActorValue, then the 'FindNonAddressingHeader' method return -1! This results in a lost SOAP header.

*** Note: ultimateReceiverActor and nexDestinationActorValue are assigned a fixed value by the parameter less constructor of MessageVersion.

Conclusion

After digging into the implementation of the WCF Adapter, we can perfectly explain why SOAP headers containing an actor are not written to 'InboundHeaders'. However, this strange behavior doesn't seem to be like intended. I would love to get Microsoft feedback on this issue.

Peter Borremans

Posted in: .NET | BizTalk | WCF

Tags: , , ,


August 30, 2013 at 4:00 PM

In my current environment, we have a service router built in BizTalk providing generic endpoints for client applications and central security between clients and services.

A new service was added to the router that performs some complex tasks and replies after 30 minutes. I know that long running services like this should be avoided as much as possible, but in this case, we needed to add this one as well to the service router.

 

After adding the new service to the service router configuration, shorter calls worked out fine, but longer calls resulted in this error:

 

A request-response for the "CustomRLConfig" adapter at receive location "***service.svc" has timed out before a response could be delivered.

 

After having a look at the timestamp, I saw that the timeout that is hit is 20 minutes. This timeout immediately rang a bell: it is the default idle timeout on AppPools and BizTalk AppDomains.

So I decided to test the impact of these timeouts:

clip_image002[8]

 

After having set these timeouts to 60 minutes (or disabling them on the AppPool), the same error occurred again. I double checked the receive timeout and send timeout on the receive location and send port. Both are set to 60 minutes and are ok.

 

After doing some research, I learned that the WCF adapter itself has another built-in timeout that is set to 20 minutes by default!

This timeout tells BizTalk when to send a NACK to the WCF adapter. If a request-response doesn’t receive any response within 20 minutes (default) a NACK will be send to the WCF adapter instead of the response message.

The default of 20 minutes is not enough for my scenario, and luckily this timeout can be changed by adding a registry value (DWORD).

 

For in-process adapters, use the following registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\BTSSvc{Host Guid}\MessagingReqRespTTL

 

For isolated adapters, use the following registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\BTSSvc.3.0\MessagingReqRespTTL

 

The values of both keys should be expressed in minutes (decimal type).

When using BizTalk 2006 R2, you need at least this hotfix when you want to change the default timeout (or a more recent version of the WCF runtime dll via a Service Pack or Cumulative Update higher than the one specified in the hotfix).

 

After applying the registry modification and restarting the host instance hosting the service, the long running call succeeded! No more timeouts.

 

Peter Borremans

Posted in: BizTalk | IIS | WCF

Tags: , ,


August 26, 2013 at 4:52 PM

Here at Codit we try to be proactive and regularly check the health of BizTalk environments at our customers.
Part of that habit involves upgrading BizTalk environments regularly, a task which is handled by our Managed Services team.

Some of these updates involve installing CU (Cumulative Update) packages when they have been released for a while.

In one scenario one of those environments needed upgrading to BizTalk 2010 CU5.
During the same update procedure, CU2 of the BizTalk 2010 Adapter Pack (Adapter Pack 2010) was also released and as such we decided to take this CU into account as well.

 

After installing this on a test environment and after rebooting, things seemed to be working perfectly.
Only the day after we came to several of these errors in several of our flows:

A message sent to adapter "WCF-SQL" on send port "SP_SendPort_SQL" with URI "mssql://server//database?" is suspended.
Error details: System.FormatException: Failed to convert parameter value from a String to a Int32. ---> System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   at System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType)
   --- End of inner exception stack trace ---
Server stack trace:
   at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
   at System.ServiceModel.Channels.ServiceChannel.EndRequest(IAsyncResult result)
Exception rethrown at [0]:
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at System.ServiceModel.Channels.IRequestChannel.EndRequest(IAsyncResult result)
   at Microsoft.BizTalk.Adapter.Wcf.Runtime.WcfClient`2.RequestCallback(IAsyncResult result)

 

The error occurred in several flows and seems to be a problem in the send port.
Our send port uses a WCF-SQL adapter (sqlBinding) so this was our first indication of an issue with the CU2 of the adapter pack.

After some searching, I came accross this blog post which states the issue very clearly:

 

 

Situation before Adapter Pack 2010 CU2

If an empty element is specified for a stored procedure argument in the instance XML, the WCF-Custom adapter will specify DBNull as the parameter value.
However, this is not the case for table operations(such as table insert), an empty string will be specified as the parameter value unless the "nil" attribute is present in the instance XML.
If the “nil” attribute is set as true in the instance XML for table operation, then DBNull will be used as the parameter value, the FormatException won’t be thrown out.
That’s why we didn’t see any exception reported previously.

 

 

Situation after Adapter Pack 2010 CU2

We made the code paths consistent between table operations and stored procedure invocation.  
That is, when the element is empty, the DBNull will be used as parameter value if “nil” attribute is set as “true”, Otherwise an empty string will be used as the parameter value.
Please note that using DBNull always can cause problems if the parameter is used to populate a table column that is marked as not nullable. This is the right behavior after Adapter Pack 2010 CU2.

 

 

As such, this is a breaking change!

Off course, it makes a lot of sense to streamline behavior for the WCF-SQL adapter and to be honest, the behavior for stored procedure invocation was not optimal.

However, it might force any BizTalk developers that have relied on the current behavior of the adapter to face the consequences of this change.
Developers have relied on the “old” behavior and the same error (listed above) might occur when upgrading their environments to CU2 or even CU3 (whenever it comes out).

 

I hope this saves someone a bit of time in case they bounce into the problem.

 

Now I’m not sure if the same already applies to the BizTalk Adapter Pack 2013, but once I find the time to test this, I will surely update this blog post.
If you have any information that might help us and our readers on the 2013 adapter pack behavior, please let me know here in the comments.

 

- Pieter Vandenheede


April 30, 2013 at 4:30 PM

On the latest version of BizTalk (2013): a new adapter was introduced for natively working with REST endpoints, using WCF technology: the WCF-WebHttp Adapter. 

After the beta version was released we could find some very good articles about this adapter, but since it is a new adapter there's a lot of ground to cover.
At the moment of my writing, the  MSDN website has very few information about it, so time to give something to the community... 

 


On this small article I will focus on using HTTP headers with the new adapter.

In this scenario I wanted to set HTTP content type at the header level. This could be done in two ways: using the adapter properties or writing in the message context. 

 

Adapter properties 

Using the adapter properties is a fairly simple task, we just need to go to our port properties and then adapter properties. On the last tab "Messages" we have a text area destined to Outbound HTTP Headers. Every HTTP header that we place here will be included on the message that will be sent (I'm using a send port for this example).

 

 

By default, WCF-WebHttp sends your message with as "Content-Type: application/xml; charset=utf-8", if you want to invoke a REST service with a GET request, for instance, you will have to insert the following code in the HTTP Outbound Headers:

Content-Type: application/http

And use a PassThruTransmit pipeline component, or another component that doesn't validate XML.


Message Context

If we need to set the HTTP headers at runtime we could do this mainly on orchestrations or pipeline components by writing the property on context.

 

We have two properties available to set in the headers: 

Property Name

Property Schema

Adapter

UserHttpHeaders

http://schemas.microsoft.com/BizTalk/2003/http-properties

HTTP

OutboundCustomHeaders

http://schemas.microsoft.com/BizTalk/2006/01/Adapters/WCF-properties

WCF-*


Both options will not raise any error if you try to write/promote them, but it won't work!
UserHttpHeaders is for HTTP adapter only, if you use it you will send the message as application/xml since the property isn't read by the adapter and since we are assuming that there is no HTTP header configured on the adapter properties.
The same goes for the OutboundCustomHeaders, it's for SOAP messages only (and using an XML structure), if you try to use it you will have the following error:
 

System.InvalidOperationException: Envelope Version 'EnvelopeNone (http://schemas.microsoft.com/ws/2005/05/envelope/none)' does not support adding Message Headers. 

If you happen to have an XML error it's probably because OutboundCustomHeaders is expecting an XML structure and you are not passing one.

 

So after dwelling on this issue for some time I inspected the new Biztalk 2013 property schema for WCF, and we can clearly  see some new properties related to the WCF-WebHttp adapter: 
 

Name

Type

Description

InboundHttpHeaders

xs:string

The HTTP headers present in the inbound message received over a HTTP transport

InboundHttpStatusCode

xs:string

The HTTP status code of the response message

InboundHttpStatusDescription

xs:string

The HTTP status description of the response message

InboundHttpMethod

xs:string

The HTTP Verb of the request message

OutboundHttpStatusCode

xs:string

The HTTP status code of the response message

OutboundHttpStatusDescription

xs:string

The HTTP status description of the response message

SuppressMessageBodyForHttpVerbs

xs:string

Removes the Message Body from the outbound request message, for the specified HTTP Verbs

HttpHeaders

xs:string

Sets HTTP headers for the outbound message

VariablePropertyMapping

xs:string

Provides the URL Template Variables and Message Context Properties mapping configuration

HttpMethodAndUrl

xs:string

Provides the HTTP Method and URL mapping configuration

 

In my scenario I wanted to use a send port, so the property that suits my purpose was HttpHeaders
All I had to do was write the content type into the property, without the need of promoting it. 

Here's part of my Execute() method of the custom pipeline component, where I set the message content type to application/atom+xml.


public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(IPipelineContext pContext, Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg)
{
    // Some non important logic here

    pInMsg.Context.Write("HttpHeaders", "http://schemas.microsoft.com/BizTalk/2006/01/Adapters/WCF-properties","content-type: application/atom+xml");

    return pInMsg;
}


Another important note that I should add, is about the adapter HTTP header limitations:
If you are planning to change the HttpHeader per message it won't work with a standard port, since by "design" the adapter uses the properties by port and not by message. If you need to change the header at runtime (per message) you will need to use a dynamic port instead.


And that’s it Smile

Ricardo Marques

 

 

 

Posted in: BizTalk | REST | WCF

Tags: , ,


April 3, 2013 at 4:05 PM

Some months ago, I was asked for an intervention regarding a SSL client certificate issue. There was a problem related to the setup of transport security (SSL) of a WCF service hosted in IIS 7.0, using client certificates that are mapped to a local account.  Let’s have a look.

 

The Setup

Server Setup

  • Wild card server certificate is installed in IIS (server level). Wild card is required, because we’re using multiple host names are configured.

          image

        image

 

  • The Certificate Authority is added to the Trusted Root Certification Authorities store (Local Machine)

        image

 

  • Website binding is configured to use https with the server certificate for SSL

        image

 

  • Website is configured to require SSL and to require client certificates

       image

 

  • Client certificate mapping is configured in order to map an individual client certificate to a specific Windows account. Configurable via this extension.

         image

       image

 

       This extension actually changes this configuration:

      image

 

  • An Allow authorization rule is configured for this Windows account

        image

 

  • Anonymous Authentication is enabled (Client Certificate is anonymous authentication)

        image

 

  • WCF service is configured for transport security

          image

 

Client Setup

  • The Certificate Authority is added to the Trusted Root Certification Authorities store (Local Machine)

           image

 

  • Client Certificate (containing private key) is added to the Personal certificate store (Local Machine).  This is required for the WCF client

          image

 

  • Client Certificate (containing private key) is added to the Personal certificate store (Current User).  This is required for browsing to the service via IE

         image

 

  • WCF Client is configured for transport security, providing Client Certificates:

          image

 

Problem Solving

The issue

When browsing to the service, for a particular web server, we’re not prompted to select a client certificate. Instead, we get this exception:

The page you are attempting to access requires your browser to have a Secure Sockets Layer (SSL) client certificate that the Web Server recognizes.

image

 

Troubleshooting

We configured another web server with exactly the same setup, which worked fine.  But still it didn’t work on that particular web server. Handy tools / commands during troubleshooting:

  • netsh http show sslcert
  • SSL Diagnostics

 

At the end, a warning in the System Event Log gave the solution. This entry is only written to the Event Log for the first call after the IIS service is restarted. That’s why we didn’t discover this Event Log warning earlier.

When asking for client authentication, this server sends a list of trusted certificate authorities to the client.  The client uses this list to choose a client certificate that is trusted by the server.  Currently, this server trusts so many certificate authorities that the list has grown too long.  This list has thus been truncated.

image

 

Root cause

During the handshake protocol for client certificate authorization, the server sends a list of Trusted Root Certification Authorities to the client.  The client will in this case only provide Client Certificates, issued by one of these Trusted Root Certification Authorities.  The problem was that the Trusted Root Certification Authorities list was too long on that particular server, so it was truncated before sent to the client.  Unluckily, our Root Certificate Authority was truncated from the list, so the handshake failed.

 

Solutions

There are two solutions to solve this issue:

  • The first solution is to clean up the Trusted Root Certification Authorities store (Local Machine) and remove all unnecessary certificates. Be aware that you don’t remove certificates that are required by Windows.

 

  • A second solution is to configure Schannel to no longer send the list of trusted root certification authorities during the TLS/SSL handshake process.  This can be done by adding this registry entry on the web server:

        HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL

        Value name: SendTrustedIssuerList
        Value type: REG_DWORD
        Value data: 0 (False)

 

Result

When browsing to the service, we’re now promoted for our Client Certificate. Now we can access the service:

         image

         image


March 6, 2013 at 4:05 PM

In many scenarios, it could be required to have a send port with a dynamic behavior:

  • Send messages to a FILE location, containing the date of today
  • Send a notification mail to many different recipients
  • Dynamically change the URL of the backend web service, depending on the incoming request

 

Many developers would solve this by using dynamic send ports.  These ports allow you to configure all adapter properties, even the adapter type, at runtime.  I’m not a big fan of dynamic send ports, because it introduces some drawbacks:

  • Dynamic send ports are very difficult to troubleshoot (a hell for your operations team)
  • Dynamic send ports require your port configuration to be stored in a secure way (custom SSO application)
  • Dynamic send ports have a bigger performance hit (solved in BTS 2013)
  • Dynamic send ports don’t allow to specify an adapter handler (solved in BTS 2013)

 

That’s why I prefer using static send ports.  With a very easy trick, you can make static send ports partially dynamic.  Mostly it’s only the connectionstring, URI, path that must be changed at runtime.  This can be achieved in a custom pipeline component in the send pipeline:

 

 

This dynamic behavior works smooth for FILE and FTP adapters.  However, when using this mechanism on WCF send ports, there’s a caveat.  You will find out that the BTS.OutboundTransportLocation of the first message will be cached on the WCF send port.  So all subsequent messages will be sent to the same location.  This port configuration is cached until your send port configuration is modified or until your adapter send handler is restarted.  Luckily: there’s a way to disable this caching:

 

 

By setting the BTS.IsDynamicSend property to true, you force the WCF send adapter not to use the cache, but the runtime value instead.  More information on this setting can be found on MSDN.

Posted in: BizTalk | WCF

Tags: ,


January 28, 2013 at 2:41 PM

The BizTalk Server 2013 Beta release comes with the SB-Messaging adapter.  This adapter allows our on-premise BizTalk environment to integrate seamlessly with the Windows Azure Service Bus queues, topics and subscriptions.  Together with my colleague Mathieu, I had a look at these new capabilities.

 

Adapter Configuration

The configuration of SB-Messaging receive and send ports is really straightforward.  BizTalk just needs these properties in order to establish a connection to the Azure cloud:

  • Service Bus URL of the queue, topic or subscription:

        sb://<namespace>.servicebus.windows.net/<queue_name>

  • Access Control Service STS URI:

        https://<namespace>-sb.accesscontrol.windows.net/

  • Issuer name and key for the Service Bus Namespace

 

Content Based Routing

Both Service Bus and BizTalk messaging layer offer a publish-subscribe engine, which allows for content based routing.  In BizTalk, content based routing is done through context properties, the Azure Service Bus uses Brokered Message properties.  A BizTalk context property is a combination of the propertyName and propertyNamespace.  In Azure Service Bus, context properties are only defined by a propertyName.  How are these metadata properties passed from the cloud to BizTalk and vice versa?

 

Sending from BizTalk to Service Bus topic

In order to pass context properties to the Service Bus topic, there’s the capability to provide the Namespace for the user defined Brokered Message Properties.  The SB-Messaging send adapter will add all BizTalk context properties from this propertyNamespace as properties to the Brokered Message.  Thereby, white space is ignored.

image

 

Receiving from Service Bus subscription to BizTalk

Also at the receive adapter, there’s the possibility to pass properties to the BizTalk message context.  You can specify the Namespace for Brokered Message Properties, so the SB-Messaging adapter will write (not promote) all Brokered Message properties to the BizTalk message context, within the specified propertyNamespace.  Be aware when checking the option Promote Brokered Message Properties, because this requires that a propertySchema is deployed which contains all Brokered Message properties.

 

image

 

Receive Port Message Handling

I was interested in the error handling when an error occurs in the receive adapter or pipeline.  Will the message be roll backed to the Azure subscription or suspended in BizTalk?  Two fault scenarios were investigated.

 

Receive adapter unable to promote property in BizTalk context

In this case, we configured the receive port to promote the context properties to a propertyNamespace that did not contain all properties of the Brokered Message.  As expected, the BizTalk adapter threw an exception:

  • The adapter "SB-Messaging" raised an error message. Details "System.Exception: Loading property information list by namespace failed or property not found in the list. Verify that the schema is deployed properly.

The adapter retried 10 times in total and moved afterwards the Brokered Message to the dead letter queue of the Service Bus subscription.  Afterwards, BizTalk started processing the next message.

 

Receive pipeline unable to parse message body

In this simulation we tried to receive an invalid XML message with the XMLReceive pipeline.  After the error occurred, we discovered that the message was suspended (persisted) in BizTalk.

 

WCF-Adapter Framework

It’s a pity to see that this new adapter is not implemented as a WCF-binding.  Due to this limitation, we can’t make use of the great extensibility capabilities of the WCF-Custom adapter.  The NetMessagingBinding could be used, but I assume some extensibility will be required in order to transform BizTalk context properties into BrokeredMessageProperty objects and vice versa.  Worthwhile investigating…

 

Conclusion

The BizTalk product team did a great job with the introduction of the SB-Messaging adapter!  It creates a lot of new opportunities for hybrid applications.

Posted in: Azure | BizTalk | Service Bus | WCF

Tags: , , ,


December 14, 2012 at 2:23 PM

In more advanced WCF scenarios, the BizTalk standard functionality can be insufficient.  In those cases, WCF extensibility can help us to overcome the limitations of the standard BizTalk WCF adapters.  Typical examples are custom MessageInspectors, ErrorHandlers, Decoders and AuthorizationBehaviors.

 

Once you have registered the extensibility, you can configure it on the WCF-Custom or WCF-CustomIsolated receive and send ports:

 

      image

 

When the WCF send or receive port is executed, your WCF extensibility objects will be injected into the WCF channel stack.

 

But how can we register these WCF extensions?

 

BizTalk 2006 R2 and BizTalk 2010

In the previous versions of BizTalk, there was only one way to register WCF extensions: the machine.config.

 

-   The C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config is needed for 32-bit processes:

  • BizTalk 32-bit host instances
  • IIS 32-bit applications
  • BizTalk Administration Console

 

-   The C:\Windows\Microsoft.NET\Framework64\v2.0.50727\CONFIG\machine.config is needed for 64-bit processes

  • BizTalk 64-bit host instances
  • IIS 64-bit applications

 

        image

 

BizTalk 2010: The new feature

BizTalk Server 2010 comes with a nice new feature for registering your WCF extensibility assemblies. The new feature allows you to avoid the machine.config and to register them in BizTalk itself. Let’s have a look!

 

  • Browse to the WCF-Custom adapter handlers.

 

        image

 

  • Open the receive or send handler.  Choose Properties.

 

        image

 

  • Here you can import a web.config / app.config that contains your WCF extensions.

         

       image

 

BizTalk 2010: The caveat

Unfortunately, this doesn’t work if your receive port is hosted in IIS.  You can register the WCF extensions on the WCF-CustomIsolated adapter handlers. However, when the WCF-CustomIsolated receive port is called, you get an activation error:

 

“WebHost failed to process a request.

Sender Information: System.ServiceModel.ServiceHostingEnvironment+HostingManager/45653674

Exception: System.ServiceModel.ServiceActivationException: The service '/ApplicationName/Service.svc' cannot be activated due to an exception during compilation. The exception message is: Unable to create endpoint behavior configuration element from XML configuration.

Check the following:

1. Verify behavior element extensions in machine.config are correctly configured.
2. Restart the application if machine.config was recently updated.
3. Ensure the configuration is valid XML that conforms to the configuration schema.”

 

Adding the WCF extensions in the corresponding web.config of IIS also doesn’t solve this issue.  The only solution I’ve found is to register them again in the machine.config.  Remember that BizTalk 2010 is .NET 4.0.

 

- The C:\Windows\Microsoft.NET\Framework\v4.0.30319\CONFIG\machine.config is needed for 32-bit processes:

  • BizTalk 32-bit host instances
  • IIS 32-bit applications
  • BizTalk Administration Console

 

- The C:\Windows\Microsoft.NET\Framework64\v4.0.30319\CONFIG\machine.config is needed for 64-bit processes

  • BizTalk 64-bit host instances
  • IIS 64-bit applications

 

Conclusion

-   Only when using the WCF-Custom adapter in BizTalk 2010, you can register WCF extensions in BizTalk itself.

-   In all other scenarios, you need to register them in the corresponding machine.config.  This has the drawback that this also influences other applications on the server.

 

Please get in touch if you managed to get this working!

Posted in: BizTalk | WCF

Tags: , ,