October 30, 2012 at 3:01 PM

It’s a common practice to reuse schemas / types within your BizTalk solution.  Lately, I’ve encountered an issue regarding this.  Here you can find a simplified example and a solution to the problem.

 

Assume you have two reusable schemas (no dependencies between them):

-   http://schemas.codit.eu/common#Address

-   http://schemas.codit.eu/common#ContactInformation

 

Now you want to create a “Person’ schema in the http://schemas.codit.eu namespace, by reusing the previous schemas.

-   First you need to import the Address schema

-   Secondly you need to import also the ContactInformation schema.  This results in the error:

 
 The namespace of the schema you are trying to add clashes with one of the namespaces already declared.  Please choose another schema.

 image

 

Although, in XSD this is not a limitation.  So I’ve tried to work around the BizTalk Schema Editor and opened the XSD as an XML file.  I’ve manually added the XSD import of the ContractInformation schema:

 

image

 

After this workaround, I’ve opened the schema again with the BizTalk Schema Editor, without any errors.  It just seems to be a limitation of the BizTalk Schema Editor.

 

image

Posted in: BizTalk | General | Schemas

Tags:


October 24, 2012 at 4:19 PM

For a recent project I needed to send messages to BizTalk through an ASP.NET application.
The purpose of the ASP.NET website was to provide a simple user interface to send messages to BizTalk, where people can download / upload messages (with validation).

The users can first validate their message, this is done through a BizTalk pipeline that parses the message and does several checks to see if it is valid.

I exposed a request-response receive location using net named pipe binding that executes the validation.
The BizTalk pipelines parses the message and converts it to a “Validator Message” that contains the errors / warnings of the message.

Some of the files that are uploaded are pretty huge ( > 100 mb as a flatfile).
That is one of the reasons why I opted for the net.pipe binding, because this binding can implement streaming (note: not all bindings can implement streaming mode!).
Another reason why I opted for that binding is because this binding is perfect for communication between WCF applications on the same machine.

BizTalk

Here is how I set-up the BizTalk side.

I created one request-response receive port and added a receive location. I route the message I receive from the receive pipeline directly back to the send pipeline of that port, so I don’t need additional send ports.
You can see how to do this in another blogpost
The receive location uses the WCF-Custom adapter with the netnamedBinding.

I changed some default values, like the maxReceivedMessageSize, and made sure that “transferMode” is set to “Streamed”.

image

I also needed to change some settings in the “Messages” section.
I had to change the inbound and outbound message body, this is dependent on how you name the WCF interface in your .NET application (see section “.NET application” below).

Inbound Message Body

Extract the stream by selecting the xpath, in my case the xpath looks like following:

/*[local-name()='SubmitMessage' and namespace-uri()='http://App.services/BizTalk']/*[local-name()='Message' and namespace-uri()='http://App.services/BizTalk']

Also make sure that you set the Node Encoding to “Base64”, since we are sending a stream.

Outbound Message body

You also need the “wrap” the stream we receive back, so it is a valid response message according the interface of the WCF service we setup in the .NET application.

You can do this by setting the template. In my case I had to set it like following:

<ns0:SubmitMessageResponse xmlns:ns0="http://App.services/BizTalk">     
     <ns0:SubmitMessageResult xmlns:ns0="http://App.services/BizTalk">         
          <bts-msg-body xmlns="http://www.microsoft.com/schemas/bts2007" encoding="base64"/>     
     </ns0:SubmitMessageResult> 
</ns0:SubmitMessageResponse>

Be sure to include the “encoding” parameter so it encodes the message as base64.

image

Only thing left to do is set the uri of the receive location, example:  net.pipe://localhost/App/ValidatePricat

.NET Application

First thing to do is create the WCF interface.

I implemented the “IClientChannel” so I could use an OperationContextScope in my client to add a custom WCF header.

[ServiceContract(Namespace = "http://App.services/BizTalk")]
public interface IBizTalkSubmitService : IClientChannel {         
   [OperationContract(Action = "*", ReplyAction = "*")]         
   Stream SubmitMessage(Stream Message);  
}

 

Now for sending the stream to BizTalk.

FIrst create a channelfactory of the interface above, using the correct binding.
Make sure you set the transferMode to “Streamed”.

NetNamedPipeBinding b = new NetNamedPipeBinding("NetNamedPipeBinding_BizTalkService"); 
EndpointAddress epa = new EndpointAddress("net.pipe://localhost/App/" + operation); 
var myChannelFactory = new ChannelFactory<IBizTalkSubmitService>(b, epa);

Next create the client. You will see I am using an OperationContextScope. This is for adding a custom WCF header.
The reason why I need to add a custom WCF header is because the site is multilingual, so I implemented multiple languages in the BizTalk solution for returning error / warning messages concerning the validity of the message in the correct language.

You will see following line of code:

header.GetUntypedHeader("PropertyContainer", "https://R4A.Properties");

BizTalk will automatically promote the messageheader in the context. For this to work, you will need to create (and deploy) a propertyschema containing the property “PropertyContainer” (the one you defined in the above line of code) in the correct namespace.
The value of the “propertycontainer” is an XML document that has been encoded (but this could also be a simple string), I did this because I have multiple properties (language, some codes for validation, ..) and this way I can easily extract it in a custom pipelinecomponent in BizTalk.

This is the full code:

public Stream SendMessage(string operation, Dictionary<string, string> contextProperties, Stream message)        
{            
     NetNamedPipeBinding b = new NetNamedPipeBinding("NetNamedPipeBinding_BizTalkService");            
     EndpointAddress epa = new EndpointAddress("net.pipe://localhost/App/" + operation);           
     var myChannelFactory = new ChannelFactory<IBizTalkSubmitService>(b, epa);           
     
     IBizTalkSubmitService client = null;            
     Stream response = null; 
           
     try
     {                 
          client = myChannelFactory.CreateChannel();                
          using (OperationContextScope contextScope = new OperationContextScope(client))                 
          {                     
               if (contextProperties != null)                     
               {                         
                    XmlDocument xDoc = new XmlDocument();                         
                    XmlElement rootNode = xDoc.CreateElement("PropertyContainer");                        
                    foreach (KeyValuePair<string, string> pair in contextProperties)                         
                    {                             
                              XmlElement prop = xDoc.CreateElement(pair.Key, "https://R4A.Properties");                             
                              prop.InnerText = pair.Value;                            
                              rootNode.AppendChild(prop);                         
                    }                        
                    xDoc.AppendChild(rootNode);                        
                    var header = new MessageHeader<string>(HttpUtility.HtmlEncode(xDoc.InnerXml));                         
                    var untyped = header.GetUntypedHeader("PropertyContainer", "https://R4A.Properties");                         
                    OperationContext.Current.OutgoingMessageHeaders.Add(untyped);                    
               }                    
               
               response = client.SubmitMessage(message);                 
          }                
          
          ((IClientChannel)client).Close();   
          
     }catch(Exception ex)             
     {                     
          ((IClientChannel)client).Abort();             
     }            

     return response;   
      
}

That’s it!
Now simply call the “SendMessage” method and you can send a stream to BizTalk and receive a stream back.
This way my website doesn’t need to read the message and no memory problems can be encountered, because everything works streaming.
And using the custom WCF header, I can still add some extra information to the message.

I couldn’t find a similar blogpost about this subject, so hopefully this will help you :)

Posted in: BizTalk | WCF

Tags: , ,


October 10, 2012 at 3:42 PM

On one of the projects we were doing, we needed to migrate the BizTalk 2006 R2 applications to BizTalk 2010.
This gave us the chance to change the running SOAP BizTalk services to WCF services. These services have more capabilities and are easier to configure.
We only had one restriction: the clients may not be forced to change. After some searching on the web, I found following post:

http://maximelabelle.wordpress.com/2010/08/12/creating-soap-compatible-biztalk-wcf-services/ and I like to share it with you.

First of all, I will explain how to expose a schema as a WCF Service;

Expose a Schema as a WCF Service

To create a WCF-service, use the BizTalk WCF Service Publishing Wizard. You can find it in the BizTalk Server 2010 folder at the Windows start menu.

clip_image001[5]

With this wizard you can set up the service endpoint.
You can choose between WCF-BasicHttp, WCF-WSHttp and WCF-CustomIsolated as a transport type and choose the application where you want to create the receive location in BizTalk.

clip_image002[2]

At the next step you get the choice to choose if you want to expose an orchestration or a schema as a WCF Service. In our case we will choose the schema choice.
The wizard gives you a tree of service methods, operations and request-response. Here you can add methods and one- or two-way operations. Define the schema type for your request and/or response from an assembly.

clip_image003[2]clip_image004[3]

clip_image005[2]clip_image006[2]

Fill in the target namespace of the WCF Service and choose the host and web directory where the service will be reachable.

The last step is a summary of the service you are going to create.... congratulations, you have created a WCF Service in BizTalk!

A new site is created in IIS and a receive location has been created for this service. The URI property refers to the address of the site in IIS.

Look also at the Receive Handler which is the BizTalkServerIsolatedHost. This means that this port is running under IIS.

clip_image007[2]

clip_image008[2]

Check if the receive location is started and if the Application pool of the site has the correct identity to work with BizTalk.

clip_image009[1]

If you try to browse to the site and receive a login error then you have to give the application pool the correct identity.

If after browsing to the site and you receive the following screen, you have created a WCF service with success.

clip_image010[1]

Change the Service to be able to communicate with the old SOAP-clients

First thing you need to do, is download the WSDL of the old SOAP Service and store it in the same folder of your SVC-file.

Open the WSDL and change the address location to the URI of the SVC-service.

When you look in the folder where the SVC-file is situated, there is also a web.config file of the service.

Load this web.config file in the WCF Service Configuration Editor for easy modifying.

clip_image011[1]

Go to the advanced tab and open the Service Behavior. Open the configuration and in the Service Metadata\ExternalMetadataLocation you have to add the path to the old WSDL. Save the config and close the configuration editor.

Now if you go to the service you will see that the URL of the WSDL has changed, also the WSDL itself now refers to the old one.

For the last step, you will need to change the Inbound BizTalk message body and the outbound WCF message Body.

The old ASMX message has one node more than a WCF envelope. You have to tell BizTalk were to get the find the message in the received envelope.

Open the settings of the receive location and click on configure, go to the message Tab. In the Inbound BizTalk message body check the path option and use the xpath '”/*/*” to go to the child node of the received message.

clip_image012

For the outboundWCF message body you need to wrap your message in an extra node because the client is demanding an extra Operation node as a wrapper. You also have to give this node the service namespace.

Restrictions, this pattern can only be used when you have a service that only has one operation due to the wrapper element you have to declare in the outbound WCF message body.

Hope this helps.
 - Robert Maes


October 5, 2012 at 4:15 PM

This week I represented Codit at the Windows Server 2012 Launch event in Antwerpen. The Launch event had two separate tracks; a Windows Server track and an Azure track. Remarkable is that even on a Windows Server launch event, half of the sessions was about Azure.

In this post I will go over some nice features of Windows Server 2012 - in my personal point of view. This post is no attempt by any means to list all new features and changes in comparison with previous Windows Server versions.

Metro

The first thing you’ll notice is that even Windows Server 2012 uses the Metro ‘Start’ screen (or should we say Modern UI now?). Because Metro is primarily targeting touch-based devices, at first this feels a little odd for a server, but we will get used to it…

clip_image002

Server Manager

The new Server Manager screen is displayed automatically when you boot up your Windows Server 2012. The new Server Manager was a very pleasant surprise! The Server Manager has a dashboard screen with a ‘tile’ for each server role you added to your Windows Server machine:

clip_image004

Each tile gives an instantaneous overview about the state of that specific feature (IIS, DHCP, DNS, AD FS …). Errors are immediately visible because of the red tile. If you click the ‘events’ link displayed in a tile, you will get all events related to that Windows Server feature – very convenient.

That’s not it yet for the Server Manager, you can add other Windows Servers to this dashboard! This will give you a single screen overview of the state of your Windows Servers! Especially when you don’t have SCOM, this is a very useful feature.

Windows Servers can also be grouped in a Server Group. In this way you can perform operations on the group instead of on each server separately.

AppFabric?

Some people expected to get Windows Server AppFabric out of the box with Windows Server 2012. Guess what, it’s not!
Instead Windows Server 2012 ships with IIS8. IIS8 offers a lot of new features and I was very surprised that there wasn’t a single session about IIS8 during the launch event. IIS8 offers a Central Certificate Store; a shared store to manage your certificates in one place instead of on every node of your server farm.
IIS8 also supports WebSockets. WebSockets provide a full-duplex communication channel between the browser and the Web Server over a TCP connection. WebSockets allow pushing content to web clients without an incoming request from that client first! What is very interesting that all this works over port 80 (the TCP channel starts as a HTTP handshake that is then upgraded). All this enables you to push content to your clients over a TCP connection without modifying firewall settings.

.NET

Out of the box, Windows Server 2012 ships with .NET Framework 4.5. When you need .NET Framework 3.5 SP1 (e.g. for SQL Server 2012) you will have to install it separately. I advise you to do this up front, before installing SQL Server 2012. The SQL Server 2012 Installation Wizard fails when .NET framework 3.5 SP1 is not installed. It fails during installation not during the prerequisites check! This means you will need to go through the SQL Server 2012 Installation Wizard again…

 

 

Peter Borremans