Archives for the month of: March, 2006

I've just uploaded a new sample showing the use of WSE 3.0 from C++/CLI. The sample consists of a C++/CLI ASMX Service which allows users to upload/download files, query file information and list available files, and a simple C++/CLI Winforms client.

SimpleFileServer_Client.png The sample illustrates the following features:

  • UsernameToken-based authentication
  • Use of a simple UsernameTokenManager class for authentication (password==username)
  • MTOM use for upload/download of files between client and server

Some useful tips when creating WSE applications with C++/CLI are:

  1. To create the client-side proxy, don't use the Add Web Reference wizard in Visual Studio, instead use WSDL.EXE with the /language:CPP option and then add the generated .H file into your project. This is because you'll want to modify the generated code (to have the proxy class derive from WebServicesClientProtocol instead of the usual HttpClientProtocol), and the Add Web Reference wizard is not good for that: It actually compiles code to a separate DLL, and it also will re-generate the proxy code from the WSDL when you do a Rebuild-All.
  2. You can use policy files for both client- and server-side security policy configuration; the sample uses a very simple policy requesting UsernameToken based authentication. What you cannot do is use the WSE Settings wizard to edit the policy file directly. However, you can easily start with basic policy by copy-pasting it from the WSE documentation (watch out, errors abound!) or from one created in a sample C# project.
  3. Make sure you manually add a reference to Microsoft.Web.Services3.dll to your C++/CLI projects. You will also need to manually modify the Web.Config and app.config files to include the relevant WSE3 sections to them. For example, here's the web.config lines added for the service:

   <configSections>

      <section name="microsoft.web.services3"

         type="Microsoft.Web.Services3.Configuration.WebServicesConfiguration, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

   </configSections>

   ...

   <system.web>

      ...

      <webServices>

         <soapServerProtocolFactory type="Microsoft.Web.Services3.WseProtocolFactory, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

      </webServices>

   </system.web>

 

   <microsoft.web.services3>

      <messaging>

         <mtom serverMode="always" />

      </messaging>

      <security>

         <securityTokenManager>

            <add localName="UsernameToken"

                 type="SimpleFileServer.CustomUsernameTokenManager, SimpleFileServer"

                 namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"/>

         </securityTokenManager>

      </security>

      <policy fileName="policy.config"/>

   </microsoft.web.services3>

 

Hope someone finds this useful!

 

My good friend Sam Gentile has posted links to some of the articles and posts he has written in the past throughout the several incarnations of his weblog. There is some incredible stuff over there, so make sure you read it.

I've always been impressed with how versatile and knowledgeable Sam is on everything he works on since I first met him online back in 2002 or so, and you owe it to yourself to check everything Sam has written about; you'll be sure to learn a thing or two! My personal favourites are the ones on Agile development and architecture :-)

My friend Carlos Medina has posted a BizTalk functoid that lets you get the value of a context property of a given message from inside a map when it is executed inside an orchestration context. It's a fairly obscure, ugly, unsupported hack  :-), but a cool piece of code nonetheless!

Moustafa Khalil Ahmed (from the Windows Workflow Foundation Team) recently blogged about how the SqlTrackingService included in WF does data partitioning across tables to keep data partitioned to smaller subsets for completed workflows.

Moustafa was kind enough to answer some extra questions about how it worked on the WF forums, and this was his answer, which I believe completements the stuff on his weblog:

"The partition is done on the completion of the workflow instance. That is your records will be in your regular tables until the instance completes and this is when the records are going to move to the added tables. This is designed for applications that have no downtime do not want to incur downtime. We do have an offline scheme as well, so if you have a downtime and want to do partitioning during that time or you want to avoid moving records around when the instances complete or for any other reason you can schedule a task that runs PartitionCompletedWorkflowInstances stored proc which will move all currently completed instances from the live tables to the partitions. Host applications don’t need special privileges to create those tables, the user should be part of the tracking_ roles that are defined in the SqlTrackingService database.

 

SqlTrackingQuery will look at the partitioned tables as well. You can look at the PartitionCompletedWorkflowInstances stored proc as a starting point if you want to have your own Archiving and Purging story other than the one we provide out of box. We are working on documenting the SqlTrackingService schema in WF’s help."


I've just uploaded a version of my Fix Encoding Pipeline Component I had written for BizTalk Server 2006 that has been retro-ported to BizTalk Server 2004.

The code is not exactly the same and it is not so pretty, but mostly because  the .NET Frramework 1.1 does not have functionality to enumerate supported encodings (not even half baked like v2.0), so I hardcoded a list of encodings for the dropdown, which I hope are supported :-).

Keep in mind you'll need to GAC the component in order for the custom UITypeEditor to work!. Enjoy.

Steve Simpson has graciously provided a patch for my FileMap library that supports one possible implementation of dynamic paging. That is, it supports automatic mapping/unmapping of views of the memory mapped file as you seek/read/write through a virtual stream that covers the entire size of the memory mapped file. Steve let me know that he has been using it successfully with files > 800MB in size!

Steve let me repost his files here on my site, for which I'm very greatful; I'm sure others will find his work just as useful! You can download the patched files here. I'd like to publicly thank Steve again for this valuable contribution!

Scott Hanselman posts a set of intriguing questions on the nature of open source on his latest "Is Open Source a Crap Idea?" post. One of the things he mentions from this article is that most people contribute to Open Source software out of self-interest, and I think I would agree with it.

I know at least that all of my participation in Open Source projects (not that there have been many) were motivated by self-interest:

  • When I contributed to NAnt and NAntContrib, I did it because I liked NAnt, but needed a few things to improve in order to use it for the project I was working on at the time. Pretty much all tasks and core changes I submitted were motivated by a specific problem or difficulty we were encountering when automating our build.
  • When I contributed to Felix Kazsa's FKSEC library, I did it because I was already familiar with some of the security APIs, but there were some that I really wanted to learn in more depth, and this was an excellent opportunity for that. Besides, I really was getting tired of writing almost the same code all the time I needed to fool around with access tokens.

Really, there's nothing wrong with this (it's not supposed to be a charity, after all). In fact, I believe this is probably one of the core ideas in Open Source development, and a good thing altogether, as it helps ensure you get useful things put into the product, things someone actually needed.

On the other hand, this also means that, inherently, Open Source developers will tend to work on what they want (which is what makes it fun for them), and not on what regular users of the product need/want. If you want an Open Source project to go someplace, chances are you might need to jump in sooner or later and do the work yourself if no one else is interested (or you can't convince someone that they are interested in it as well), which really doesn't work for a lot of people.

BizTalk Server 2006 offers some tools that can make it easier to diagnose routing failures in your BizTalk deployments, with the help of the new query facilities in the BizTalk Server 2006 Administration Console. Imagine for example that you've got an incoming message through a receive location that failed routing and was suspended.

The first thing you'll want to do is open up the BizTalk Server 2006 Administration Console, go to the Group Hub page and create a new query. To diagnose a routing failure, you can do two different queries.

Querying for Messages
The first possible query is to query for messages. If a routing failure occurred, you will find the message listed in the results pane in the "Suspended (resumable)" state, as the following screenshot shows:

The first record you see in the screenshot above (the one where the MessageType field is empty) is the actual message that failed routing. If you double click on it, you will see a new dialog window open where you can see the message details, as well as the message context and even the content of each part associated with the message. This is one of my favourite windows in the new UI because it is much more usable than the old HAT windows.

The second record you see in the results pane, however, is far more interesting. This one is actually a Routing Failure Report pseudo-message, which has no actual body, but contains the real state (and message context) of the message at the point the routing failure occurred. You can always recognize an RFR because its Service Class field contains the value "Routing Failure Report".

Since the Routing Failure Report contains the real message context, you can use it to check if the expected context properties were promoted, and what the values of them were. So this is the place to look for if you feel that perhaps the routing problem occurred because your pipeline or adapter didn't promote the right values or the right properties.

Querying for services
You can also start by querying for suspended service instances (message receives/sends are also service instances):

The Messaging Service Instance is the actual instance that was suspended. By opening up the Service Details window, you can look at the exact error message that was logged in the Error Information tab:

The published message could not be routed because no subscribers were found. This error occurs if the subscribing orchestration or send port has not been enlisted, or if some of the message properties necessary for subscription evaluation have not been promoted. Please use the Biztalk Administration console to troubleshoot this failure.

You can also see the list of messages associated with this service instance (in this case only one) in the Messages tab of the window.

By analogy, the Routing Failure Report instance is a service instance associated with the routing failure report; from here you can get access to the Routing Failure Report message as well.

Troubleshooting the routing failure
One really interesting option here is that you can right-click on either of the suspended service instances in the Query Results pane and you'll see a new "Troubleshoot Routing Failure" submenu with some options to help you diagnose why the routing failure happened:

  • The Find failed service instance option will run a new query that will find you the specific service instance that failed. It is not as useful in the above example because we already new exactly what service instance it was (it had been already returned in the original query), but in cases where you have hundreds of service instances, this can make it a lot easier to find the relevant instance.
  • The Show all subscriptions option will open a new query window that queries for all subscriptions defined in the message box.
  • The Show all active subscriptions option is the same as above, but it filters the results so that only subscriptions in an Active state are returned.
  • The How to troubleshoot routing failures option will open up the help topic on troubleshooting routing failures in the BizTalk help.

As you can see, BizTalk Server 2006 makes it much easier to see what’s going on in your environment and does offer a few new options integrated into the management console itself; instead of having to go through HAT to view all this stuff. Also, the new UI is great, far more usable than what HAT provided (though you still need to go to HAT for some scenarios including orchestration debugging), and gives you a much more integrated view of how subscriptions, service instances and messages relate to each other.

In BizTalk Server 2006, the BTSSubscriptionViewer.exe tool that was in the 2004 SDK is no more. Instead, the functionality to query the subscriptions defined in the MessageBox is included in the new BizTalk Server Administration Console. To find it, do the following:

  1. Open up the BizTalk Server Administration Console
  2. Select in the left-side tree view your BizTalk group node (for example "BizTalk Group [KEPLER:BizTalkMgmtDb]" in my machine).
  3. Click on the New Query tab that appears on the right side or use the context menu to create a new query window. In the query expression pane, select "Search For - Equals - Subscriptions", and click the Run Query button.

After that, the Query Results pane will contain all the subscriptions defined in your group's MessageBox. To find more details about a particular subscription, you can double click on it, or right click and select "Subscription Properties" from the context menu. A new dialog will pop up: the General Tab will contain some basic information about the subscription, but the most interesting information will be in the Expression tab, which contains the filter expression that defines this subscription.

When using the MIME/SMIME Decoder Pipeline Component in BizTalk Server 2004 and 2006, you might get an error at runtime saying that "The revocation status of the certificate used to sign the message is unknown" or something to that effect.

The cause of this error is that BizTalk is trying to check for certificate revocation against the Certificate Revocation List (CRL) of the certificate authority that generated the certificate used. There are two ways to fix this problem:

The first one (and I would say preferred one in some scenarios) would be to configure things so that BizTalk can actually query the CRL. How this is done will depend on who your certificate authority is.

The second option is the easiest, though most insecure one, and is to disable CRL checking altogether. You do this by setting the "Check Certificate Revocation" property of the MIME/SMIME Decoder component to false, like this:

Once you've done this, just recompile and re-gac (or redeploy) your pipeline and you'll be all set. I would also recommend checking the BizTalk Server 2004 Technical Guide for Certificate Management document, which should provide some good practices for working with X.509 certificates in BizTalk Server.