April 12, 2012 at 1:42 PM

This is a post, describing an issue we recently had on the Azure Service Bus. 

 

Situation description

When a single appdomain is opening two (or more) service bus relay endpoints that have the same path (what is added after the servicebus.windows.net), but have a different namespace, the following exception is raised:

System.InvalidOperationException: The ChannelDispatcher at 'sb://repro2.servicebus.windows.net/ordersvc' with contract(s) 'ICustomerService' is unable to open its IChannelListener. ---> System.InvalidOperationException: A registration already exists for URI 'sb://repro2.servicebus.windows.net/ordersvc'.

The following is the configuration of my endpoints (not including the TokenProvider, etc, just the endpoints.

        <endpoint address="http://repro1.servicebus.windows.net/ordersvc"
            binding="basicHttpRelayBinding"
            bindingConfiguration="httpRelayBinding"
            contract="Demo1.Relay.ICustomerService"
            behaviorConfiguration="repro1Behavior" />
        <endpoint address="http://repro2.servicebus.windows.net/ordersvc"
            binding="basicHttpRelayBinding"
            bindingConfiguration="httpRelayBinding"
            contract="Demo1.Relay.ICustomerService"
            behaviorConfiguration="repro2Behavior" />

Why do we need the same services exposed on different namespaces?

Environment seperation

For Codit Integration Cloud, our azure-based integration platform, we are consuming some on-premises web services, exposed over the Azure Service Bus relay binding.  We do this for different services that make part of our runtime.  We also have a deployment cycle where we have different environments (a development, a test, a demo and off course the production environment(s)).

To isolate services, we make sure that every environment has a specific service bus namespace.  This allows for security segregation and to move services on premises, without touching other environments.  So this means that for our EdiFactParser service, we have the following endpoints (different names are being used here):

  • sb://intcloud-dev.servicebus.windows.net/onprem/parse
  • sb://intcloud-test.servicebus.windows.net/onprem/parse
  • sb://intcloud-demo.servicebus.windows.net/onprem/parse
  • sb://intcloud-prod.servicebus.windows.net/onprem/parse

As you can see the only difference in the above mentioned endpoints are the service bus namespaces.  As mentioned, these services are hosted on different servers on premises, but in some cases, we host them together.  (for example: dev & test are sharing the same local server).  In our cases, these services are hosted in BizTalk Server receive locations.

Disaster recovery

In the rare case where an Azure center would be out of the air, all service bus namespaces (hosted in that data center) are unavailable.  (There might be something like service bus federation in the future, but that’s not there yet).  To make sure that our on premises services are still available, we could expose these services on multiple service bus namespaces.  (hosted in different data centers).

In the case of a namespace being unavailable, the client that consumes the service could failover and try to consume the service over the second namespace.

How to work around this

This seems to be a bug in the Service Bus dll implementation, but we didn’t got a confirmation of this by product team yet.  (there might be a good reason for this, allthough I don’t see it).  Anyway, to workaround this, you need to open the different endpoints in separate service hosts.  The following describes how to do this.

In BizTalk Server

We initially had the issue on BizTalk Server, where we expose these services over the service bus.  Both receive locations were hosted in the same BizTalk host.  Just moving both locations to a different BizTalk host, solved the problem. 

In regular .NET applications

If you open the service host yourself, it as easy as creating two instances of the ServiceHost class and have them opening the endpoints seperately.

 

Just wanted to share this one

Sam Vanhoutte


April 11, 2012 at 9:46 AM

SCOM (System Center Operations Manager) 2007 R2 comes with a very handy utility to create reports.
In this blogpost I will explain how you can create a detailed report concerning the CPU usage for a particular BizTalk Host Instance.

So let's get started!

The first thing you need to do is open the Operations Console.
Navigate to "Reporting > Microsoft Generic Report Library" in the left navigation bar. There you can double-click the report "Performance":

 

A new window will appear where you can enter some criteria. Here you can enter the timespan of the performance details you want to have. Let's say we want the stats starting from a week ago. To do this you need to modify the "From" date.

The next step you need to do is select the objects you want to visualize in your chart. You will notice a button named "Change" in the upper right corner. If you click on that button a window will appear where you can modify the settings of the chart.

 

To create a new chart, simply hit the button "New Chart". You can give the chart a meaningful name by setting this in the details pane.
After that you need to set the different series (these are the different objects inside your chart). Click on the button "New Series".

 

In the series, you can add a group/object. In our case this would be the particular server for which we want to see the CPU usage. Click on "Add Group.." and another window will appear. In the search pane, type a part of the computername and hit the search button. Select the computer you want to add.

Once that object is added, you still need to define the performance counter. You can define this in the "Rule" section. Click the browse button.
In the search pane type "CPU" and select the counter "BizTalk: CPU Usage Server Processes".

In the rule section you will see that you can choose a specific host instance (or all host instances) to which the rule will be applied. 

 

Now here's the tricky part. The UI only shows the Process name, not the actual host instance name. To know the actual host instance name you need to execute the steps below:

Go to the server that you have added in the object menu (so the server of which you want to see the performance details).
In the server, press start > Run > perfmon, this will open the built-in performance monitor of that server.
Navigate to "Monitoring Tools  > Performance Monitor" and right click in the window > "Add Counters".

Search for the counter "Process > ID Process" and select the process name of which you want to know the actual host instance name (in our case "BTSNTSvc").
Switch the current view to the "Report" view. In this view you can see the current "Process ID" of that host instance.

To link the Process ID to the host instance name, you have to execute following command in the cmd utility of windows:

TASKLIST /SVC /FI "IMAGENAME eq btsnt*"

This will give you a list of all the BizTalk host instances and their Process ID. Be aware that whenever you restart a host instance, the Process ID will change!
Now simply search for the Process ID that you retrieved from the performance monitor and you know which host instance you selected in the SCOM rule (in our case the host instance "CIPGW_ReceiveHost").

 

When everything is configured simply press the "Run" button at the top left of the window and SCOM will generate a nice chart. You can export the chart as pdf, excel,.. If you like to run this performance report again, you can save all your settings by clicking "File > Publish". This will allow you to save all the settings and run the report at a later time. The report will be available in the section "Authored Reports".

Here is a screenshot of such a report:

 

I had some trouble with linking the host instance name with the process name, so that's the main reason why I wrote this blog item.

I hope this saves you a lot of trouble :)

Posted in: BizTalk | Monitoring | SCOM

Tags:


April 3, 2012 at 11:52 AM

Many of us at Codit already installed the WCF LOB SDK multiple times. And in the process we have learned to know the caveats that come with the installation:
- 32 bit vs 64 bit
- Adapter Pack installation (again, 32 bit vs 64 bit)
- Enterprise application installation

Now since BizTalk 2010, there is a great wizard added to the installation screen if you click “Install Microsoft BizTalk Adapters”:

image 

The screen shows up like this once you go through the entire installation:

image

Please note that the above screenshot is from a production server where I don’t have Visual Studio installed, so I could not install the developer tools (hence the warning)

It is a very welcome change, because before BizTalk 2010, people did not know exactly what they needed to install and in which order.
Now the screen gives you a very handy wizard-style interface.

Now recently I had a strange error: on a 64-bit machine I went through the installation.
I was sure that everything was installed correctly and in the right order!

I checked all machine.config files (for framework 2.0 and 4.0, both 32-bit and 64-bit) and all had the necessary entries added.
However, there was no way I could see/add the WCF LOB Adapters in the BizTalk console:

image

I went through a lot of online searching until I accidently stumbled upon the BizTalk modify wizard:

image

It happens that the WCF Adapter components in BizTalk were not installed, so the WCF adapters were not showing up for a good reason!

When I checked both checkboxes (WCF for BizTalk Runtime and Administration Tools And Monitoring), installed it on both nodes and re-opened the BizTalk consoles, I could add the WCF adapters I needed.

image

I hope this helps at least someone!

Posted in: BizTalk | LOB | WCF

Tags: , , ,


February 24, 2012 at 1:14 PM

Recently, I encountered a strange problem at a customer. MSDN blogs warned us about the leap year date 2/29/2012 when using EDI in BizTalk Server 2006 R2 or 2009, as you can see on this blogpost. It was during the install of this hotfix on a BizTalk 2006 R2 server I was encountering the problem. I’ll explain the problem over here and show you the easy work around.


EDIT: Apparently Microsoft has solved this error. A more recent version of the hotfix download does autodetect Cumulative Update 3, without using a version number. The latest version of the hotfix can be found over here.

However, I will show you how I worked around the problem (because the newer version was not yet available at that time).

Prerequisites

 

MSDN blog is indicating that the install of the EDI leap year hotfix on BizTalk Server 2006 R2 requires some prerequisites.

Since BizTalk 2006 R2 Service Pack 1 was already installed in this particular case, I only still needed to execute step 2 and 3. Installing the Cumulative Update 3 gave me no problems. So far, so good.

 

Install of the leap year date hotfix itself

 

However, when installing the leap year hotfix, I encountered following error:


 

“The patch 861c5534-6cfa-4dcf-ba70-cbf01129b646 in the package Microsoft BizTalk Server 2006 R2 Hotfix [See KB article 2435900 for detail] cannot be applied.  The minimum installed version of Microsoft BizTalk Server 2006 must be 3.6.2222.12.  The installed version on this computer is 3.6.1404.0.”

 

This was quite strange to me, since MSDN blog was indicating that Service Pack 1 and Cumulative Update 3 should be sufficient as prerequisites to install the hotfix. A little investigation led to the following.

Checking the Registry Editor (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\BizTalk Server\3.0), showed us that the current product version is ‘3.6.1404.0’. 


 

This is just like the error indicated, while it expects a version of 3.6.2222.12 or higher. So I started searching the web to check if that Product Version Key was correct and related to BizTalk Server 2006 R2 SP1.

 

BizTalk Server 2006 R2 SP1 Product Version Key

 

On a Microsoft Technet wiki page I found following table with the all product version key’s correlated to the product name:


 

 

What you can see over there, is that the Product Version Key is not adapted when Service Pack 1 of BizTalk Server 2006 R2 is installed. This is not consistent if you compare it with the other version of BizTalk Server.

Strange thing, BizTalk 2006 R2 SP1 comes with Product Version Key 3.6.1404.0, while the install of the hotfix needs a version of 3.6.2222.0 or higher. Because the prerequisites for the hotfix (BizTalk 2006 R2 SP1 and CU3) were correctly installed and yet the Product Version Key seemed not to be right, I started thinking about a possible solution to fix this little error.

 

Workaround for the error

 

Since installing the hotfix for the leap year date is all about just running a ‘Setup’ and there’s also a Setup.xml file in the folder, I had a look over there.

As you can see in the print screen below, there indeed is a field ‘MinProductVersion’ indicating the version should be at least 3.6.2222.12. This is why we encountered the error.


 

So what about changing this value to a Product Version lower than 3.6.1404.0, the one that is installed on the server now? Let’s give it a try.

NOTE: make a copy of the original Setup.xml, in case the change would not be effective.

As you can see below, I changed that one value in the xml document to ‘MinProductVersion = “3.6.1.12” ‘.


 

Before executing the Setup again, and hoping it will not fail on the Product Version again, we need to find a way to check if the setup will be executed effectively.

In the Setup xml file we can see some assemblies that will be adjusted to a newer version when executing the hotfix. Therefore we can check the current file version of a specific assembly and see if the file version has been changed after the execution of the Setup.

For example, we can see in the setup xml file that ‘Microsoft.BizTalk.Edi.Shared.dll’ should have version 3.6.2230.12 after the execution.


 

A quick lookup shows us that the file version of that assembly is ‘3.6.2224.12’ right now.


 

If we now execute the Setup and check this file version of the assembly again afterwards, we should see it’s changed to ‘3.6.2230.12’ if the Setup was successful. Let’s try this!

I executed the Setup again and did not encounter the same error again, indicating the product version is too low. So that’s a good start. Now that the wizard indicates the execution has successfully ended, let’s have a look at the file version again.


 

And yes, the file version was changed to 3.6.2230.12 and therefore the assembly was updated. Together with the fact that our newly installed hotfix is shown in the ‘Installed programs and updates’-overview (as you can see below), we can conclude that our workaround for the error and therefore the installation of the hotfix itself has been successful!


 

 


February 22, 2012 at 10:10 PM

Recently, I was asked by Microsoft to give a presentation on how to integrate CRM online with on premises applications, on the Techdays in Belgium.  While hybrid integration was totally not new for me, the challenge here was to learn the extensibility capabilities and integration aspects of CRM online.  And I have to say, I was happily surprised with the extensibility framework that Dynamics CRM Online provides, especially with the Plugin mechanism.

All code of this article will be added with the second blog post of this series.

Extending CRM Online

There are different ways to extend CRM Online.  This is possible through forms customization, or by injecting Ajax/Silverlight controls.  However, these customizations are only applied on changes and events that happen through the front end.  Knowing that more and more actions of a CRM applications (especially data creation) are getting automated, I believe that customization should be injected in the actual ‘processing pipeline’ of CRM.  And that is where custom plugins come into the picture.

Getting started

Getting started is very straightforward.

  1. If you don’t have a CRM online account, it is very easy to create a trial account (which is only valid for 30 days).  Just browse to http://www.crmonline.com and register for a trial account, using your Windows Live Id (WLID).
  2. After this, you need to get the CRM SDK.  This one can be downloaded here.
  3. Once you have the SDK downloaded, you should build the PluginRegistration project, that can be found in %sdk%\tools\pluginregistration directory.  You will use this tool to inject plugins and create endpoints on your CRM system.

Writing custom plugins

Every plugin you create, needs to implement the IPlugin interface, which has one method; Execute.  These plugins should then be linked with the corresponding CRM event, through the PluginRegistrationTool.

using Microsoft.Xrm.Sdk;
 
namespace CRMPlugins
{      
  public class MyPlugin : IPlugin       
  {             
     public void Execute(IServiceProvider serviceProvider)             
     {    }  
   }
}

Implementing a ‘Base plugin’

Soon, I noticed that almost every plugin has some generic code that is applicable to almost all plugins.  For that, I created an abstract class BasePlugin, that every plugin will implement.  This BasePlugin takes care of a lot of common aspects:

  • Tracking: plugins can now easily track events and logging info, in case exceptions occur.
  • Configuration: plugins can receive external configuration, when linked with an event (example: connection strings, passwords, service bus settings…)  This configuration is then passed as a string to the plugin constructor, where one can parse it.
  • Entity filtering: some plugins should only be executed against specific entities (for example: only for invoices, only for salesorders…).  It is possible in the BasePlugin to filter out the entity, just by passing in the entity logical name with the constructor.
  • OrganizationService: the organization service allows to query and lookup entities that are configured on the CRM system.  This service is made available to every executing plugin.
  • Entity handling: reading and updating attributes on entities is made generic now.
  • Exception handling: all exceptions are caught and handled in a consistent way.

Implementing a plugin now just comes down to writing the specific logic and not bothering about the general logic that is always the same.  The only things left are the following:

  • Define the constructors: a constructor should exist with two string parameters as arguments.  These are the secured and unsecured configuration settings that get passed in from the plugin registration.  If you want to make sure the plugin only gets executed for certain entity types, you can easily pass in the entity type name to the base constructor, like here (only execute on invoice entities)
    public MyPlugin(string unsecure, string secure) : 
        base(unsecure, secure, "invoice") 
    { 
    } 
  • Implement the InternalExecute method: this is the abstract method that gets called by the BasePlugin and that is wrapped in the exception handling and is preceeded with the EntityType check.  This method will contain the actual logic of the plugin.
public override void InternalExecute(IServiceProvider serviceProvider, Microsoft.Xrm.Sdk.Entity entity)
{}

All the following plugins are using this Base Plugin class, in order to focus on the actual logic and abstract away all CRM specific logic.  (for that, you can easily find resources and blogs online).

Writing a plugin: sending a text message to the invoicee

As a first test, I created a plugin that sends a Text message, when an invoice gets created. For this, it looks up the phone number of the account, linked with that invoice. To send the plugin, we just use an existing online service (www.smsbox.be), that exposes the texting functionality through an HTTP endpoint.

Execution logic

The execution logic for the plugin is pasted below.  The following steps take place

  • First, the invoice number and amount are read from the Entity.  (the entity is of type “invoice”, because we have passed the “invoice” as an argument to the BasePlugin constructor).  To read these values, we call the base method ReadAttribute.
  • If the customerId attribute is available, we make an EntityReference, using the customerId value and we retrieve that account through the OrganizationService (provided by the BasePlugin).  We also specify (for performance reasons) that we only want to receive the telephone number attribute.
  • If that attribute is available, we send the Text message to the right phone number.  Full code is available in the provided zip file.
// Obtain the target entity from the input parmameters.
string invoiceNr = ReadAttribute(entity, "invoicenumber", "(unknown)");
string amount = ReadAttribute(entity, "totalamount", "0");
if (entity.Attributes.Contains("customerid"))
{
  EntityReference Customer = (EntityReference)entity["customerid"];
  if (Customer.LogicalName == "account")     
  {        
    Entity Account = OrganizationService.Retrieve("account", Customer.Id, new ColumnSet(new string[] { "address1_telephone1" }));         
    string phoneNr = ReadAttribute(Account, "address1_telephone1", null);         
    if (phoneNr != null)         
    {            
      SendSms(phoneNr, string.Format("Invoice {0} has been created for you with the amount of {1}", invoiceNr, amount), null);         
    }     
  }
}

Sending the SMS

For those who are interested, the code to do the HTTP post to the smsbox.be endpoint is pasted below:

private void SendSms(string phoneNumber, string text, ITracingService tracingService) 
{ 
  try   
  {    
    phoneNumber = phoneNumber.Replace("+", "");      
    string prefix = phoneNumber.Substring(0, 2);      
    string phoneNr = phoneNumber.Substring(2);     
    WebRequest request = WebRequest.Create(string.Format("http://www.smsbox.be/scripts/sendsms.php?login=####&pwd=####&prefix={0}&number={1}&message={2}", prefix, phoneNr, text));     
    request.Method = "POST";     
    var response = request.GetResponse();     
    response.Close();   
  } 
  catch (Exception ex)   
  {     
    if (tracingService != null)      
      tracingService.Trace(ex.Message);     
    throw;   
  } 
}

 

Registering the plugin with the PluginRegistration tool.

As indicated earlier, you need the PluginRegistrationTool to register the plugin on the CRM system and to link it with the corresponding events.  To do that, follow these steps:

  1. Open the PluginRegistrationTool
    • Enter the discovery URL of your CRM account.  This can be found in the CRM portal, in the resources section.
    • Enter the WLID that is linked with your CRM online subscription and click connect, to enter the password.
      image
  2. In the left pane, you now can see all CRM subscriptions that belong to your WLID.  Double clicking one of them will retrieve the entire customization profile.
    • Now you can add assemblies, plugins and endpoints and save them to your CRM instance.
      image
  3. Now it’s time to upload our assembly with the plugin.  For that, it’s as easy as clicking the Register new assembly button in the toolbar and selecting the plugin.
    • For CRM Online, the only Isolation Mode that is available, is the Sandbox mode, meaning you have reduced functionality.
    • The assembly should be deployed to the database, since the Disk or GAC is not available in CRM Online.
    • Once everything is configured, clicking the Register Selected Plugins will upload and register the plugin on the CRM Online system.
      image
  4. The plugin we have created, should be executed, when a new invoice is created.  To do that, we need to register a new step for the plugin. 
    • Select the plugin and click Register new step. This pops up a new window, where we need to provide the following information.
    • Message: this is the type of event.  In this case, we type Create (notice the intellisense, while typing)
    • Primary Entity: the logical name of the entity to which the event will be linked.  In this case, we select invoice. (case sensitive)
    • Then we can specify the execution order and security context in which the plugin should be executed.
    • The plugin can be executed at a specific time in the processing pipeline.  Pre-validation, Pre-operation and Post-operation.  In this case, we will execute the action, when the invoice has been saved in the system.  Therefore, we select the post-operation stage.
    • The execution mode defines if the user will be waiting during the exeuction of the pipeline (synchronous mode).  Asynchronous mode will increase the user experience, but when this action fails, it is not visible to the end user and only visible to the administrators through the CRM portal.
    • On the right, it is possible to specify configuration values that will be passed to the constructor of the plugin.  (we handle this in the BasePlugin)
      image
  5. That’s all that is needed to link our custom action with the right event on CRM Online.  Straight forward and easy, isn’t it?

CRM out of the box service bus connectivity

Dynamics CRM provides some out of the box capabilities to integrate events with the Azure Service Bus on different levels: Messaging and Relay.  For that you first need to configure the Access Control Service (ACS).  This is typically a complex step, but the registration tool makes this extremely easy and shows a perfect example of how Microsoft is using its own components and capabilities in a good way.

To do this, you need to register a new service bus endpoint through the PluginRegistrationTool.  (Register New Service Endpoint). 

  • Here we need to provide the following settings:
    • Now we need to specify our service bus namespace and the path to our queue/topic or service endpoint.
    • It’s also needed to specify the type of endpoint in the Contract drop down: Oneway, Queue, TwoWay, Rest.
      image
  • Secondly, we need to configure the ACS settings for this endpoint, so that the CRM online system has access to the service bus endpoint.
    • Clicking on Save & Configure ACS opens a new tool window, where we need to specify the management key and the issuer name for that key.
    • We also need to upload a certificate.  This public certificate key can be downloaded from the CRM online portal by clicking on Settings > Customizations > Developer Resources and Download Certificate.
      image
    • After clicking the Configure ACS button, we get a nice log, indicating what this wizard has done for us.  The highlights are pasted below:
      Trying to find out the ACS Version.
      ACS Version is: V2
      Creating ManagementService for codittest-sb
      Created RelyingParty with Name: testqueue, RealmName:
      http://codittest.servicebus.windows.net/testqueue, ID: 10004406
      Created RuleGroup with Name: Rule group for testqueue
      Assigned RuleGroup to RelyingParty
      Created Rule: sampleorgsendrule
      Created Rule: sampleownersendrule
      Created Rule: sampleownerlistenrule
      Created Rule: sampleownermanagerule
    • To test if the ACS was configured successfully, it is possible to click on the Save & Verify Authentication button.

Messaging capabilities

It is possible to use the Plugin Registration tool to register a service bus messaging endpoint.  This endpoint can then be of type queue, but it also works with topics (since both topics and queues are exposing the same REST interface).  On this endpoint, it is also possible to register a step, linked with an event.  When this event is fired, the entity will be serialized and written to the messaging endpoint.  From then on, it is possible to use the receiver functionality to receive these entities from the messaging endpoint. 

There is one downside, however.  No properties are being added to the BrokeredMessage, which makes it hard to use the publish/subscribe pattern through subscriptions that are using a routing filter.

Relay service capabilities

The Relay service capabilities can also be leveraged through these endpoints, but then it is required that the on premises service, exposed over the service bus relaying endpoint implements the specific contract (Microsoft.Xrm.Sdk.IServiceEndpointPlugin), as indicated in the SDK documentation.  A sample service can be found in the SDK (%SDK%\samplecode\cs\azure\onewaylistener).  This application exposes itself on the service bus endpoint through WsHttpRelayBinding.

Conclusion

Microsoft Dynamics CRM Online is truly a good and well-designed product that leverages the various capabilities and components that the Microsoft platform is offering.  It provides a very extensible plugin model and application concepts in order to configure and customize the application.  Next to that, it also provides some out of the box capabilities to integrate with the various Azure Service Bus capabilities, including relaying and messaging.

However, these out of the box integration capabilities have some limitations and my next post will show how to work around these limitations.

Sam Vanhoutte, Codit

Posted in: CRM | Azure | Service Bus

Tags:


February 22, 2012 at 11:22 AM

Microsoft BizTalk Server 2010 ships with some assemblies that assist you with the administration and deployment of your BizTalk environment.  During the development of an automated deployment plan, we were able to perform most of the deployment tasks at a BizTalk application level, by using these assemblies:

 

Microsoft.BizTalk.ExplorerOM

 

-       Create/delete applications

-       Control receive locations

-       Control orchestrations

-       Control send ports

-       Control send port groups

-       Control application references

 

Microsoft.BizTalk.ApplicationDeployment

 

-       Add/remove resources

 

Microsoft.BizTalk.Deployment

 

-       Import/export bindings

 

Microsoft.BizTalk.Operations

 

-       Query for active service instances         

 

Remark that all of the used objects can be initialized by three parameters:

      -    SqlServerName

-    BizTalkMgmtDbName

-    ApplicationName

 

 

The object "BizTalk Group" is defined by the SqlServerName and the BizTalkMgmtDbName.  A "BizTalk Application" is defined by its BizTalk Group and the ApplicationName.  However, these assemblies have totally no notion of the object "BizTalk Server".  They only support operations at a database level (BizTalk Group), but some deployment tasks need to be executed on a BizTalk Server level:

 

- Install/uninstall assemblies to the Global Assembly Cache

- Control host instances

 

For both actions we needed to be able to dynamically determine which BizTalk Servers are part of the already defined BizTalk Group. After some research, we found two options to implement this logic:

 

Windows Management Instrumentation

 

WMI has some support for BizTalk via the WMI namespace “root\\MicrosoftBizTalkServer”.  We are able to loop though all configured host instances, by executing a query on the MSBTS_HostInstance class.  As each host instance runs on a BizTalk Server, it’s easy to implement some logic that retrieves all BizTalk Servers.

 

private List<string> GetBizTalkServers()
{
     List<string> btsServers = new List<string>();

     EnumerationOptions wmiEnumerationOptions = new EnumerationOptions { ReturnImmediately = false };
     ObjectQuery wmiQuery = new ObjectQuery("SELECT * FROM MSBTS_HostInstance");
     using (ManagementObjectSearcher wmiSearcher = new ManagementObjectSearcher("root\\MicrosoftBizTalkServer", wmiQuery.QueryString, wmiEnumerationOptions))
     {
          ManagementObjectCollection hostInstanceCollection = wmiSearcher.Get();
          foreach (ManagementObject hostInstance in hostInstanceCollection.Cast<ManagementObject>())
          {
                string btsServer = hostInstance["Name"].ToString().Split(' ').Last();
                if (btsServers.Contains(btsServer) == false)
                {
                     btsServers.Add(btsServer);
                }
          }
      } 

      return btsServers;
}

Custom SQL Server Query

 

Another option is to retrieve the information directly from the BizTalkMgmtDb.  The table adm_Server actually contains a list of all BizTalk Servers that are part of the BizTalk Group.  So this simple .NET code is able to return us the needed information:

 

 

private List<string> GetBizTalkServers()
{
     List<string> btsServers = new List<string>();

     SqlConnection sqlConnection = new SqlConnection(String.Format(CultureInfo.CurrentCulture, "Server={0};Database={1};Integrated Security=SSPI;", SqlServerName, MgmtDatabase));
     SqlCommand sqlCommand = new SqlCommand("SELECT Name FROM [dbo].[adm_Server]", sqlConnection);

     sqlConnection.Open();

     SqlDataReader sqlDataReader = sqlCommand.ExecuteReader();

     while (sqlDataReader.Read())
     {
          btsServers.Add(sqlDataReader["Name"].ToString());
     }

     sqlConnection.Close();

     return btsServers;
}

 

 

Conclusion

 

It's pretty easy to retrieve a list of all BizTalk Servers that are part of a BizTalk Group.  A limitation of the WMI approach is that this will only work when it's executed on one of the BizTalk Servers.  So I prefer the SQL approach, because this will also work for remote execution.

 

Toon Vanhoutte

Posted in: BizTalk | Cluster | Deployment | General | Infrastructure

Tags:


February 19, 2012 at 12:26 PM

A while ago I had a little surprise with a demo project.
The project consists of a client application, a claims aware WCF service and AD FS as token issuer.

This demo was working fine until now...
Without changing anything, authentication always fails with this error message (see WIF tracing):

ID4175: The issuer of the security token was not recognized by the IssuerNameRegistry. To accept security tokens from this issuer, configure the IssuerNameRegistry to return a valid name for this issuer.

Offcourse my token issuer certificate was added to the 'trustedissuers' collection on the WCF service, so something must have changed in AD FS.

The signing certificate in AD FS shows this:

As you can see, there are two signing certificates (I had one before). The second signing certificate was created by AD FS automatically because my signing certificate was reaching it's expiration date. This feature - AD FS creating a new self-signed certificate when the old one nears expiration - is called Auto Certificate Rollover.

When using self-signed certificates, auto certificate rollover is on by default.
AF FS will use the signing certificate marked as 'Primary' to sign issued tokens.
The only thing I need to do is adding the new certificate to the trusted issuers collection as shown below:

 

Note: The reason why my sample failed is that I use the out-of-the box 'ConfigurationBasedIssuerNameRegistry' class to resolve the trusted issuer. This class uses the certificate thumbprint to match certificates. Obviously the certificate thumbprint changed when auto certificate rollover issued a new signing certificate. You can avoid this by implementing you own class and for example use the subject name to match issuers.

After adding the thumbprint of the new signing certificate to the trustedIssuers section, the sample should work again ... unless ...

My signing certificate is a self-signed certificate, but the newly created certificate is not trusted on the WCF machine. This results in this error:

ID4257: X.509 certificate 'CN=ADFS Signing - WIN-BEJU5AI4TP7.pbdev.CODit.eu' validation failed by the token handler.

The self-signed signing certificate should be added to the trusted root store of the WCF machine. The action you need to take to make sure the certificate passes validation depends on the certificateValidation mode you use. Mine was set on chaintrust, so adding it to trusted root will do. If you use peertrust, add the certificate to the trusted people store. If you use custom it depends on your implementation.

 

Peter Borremans

Posted in: Security | WCF | WIF

Tags: , , , ,


February 16, 2012 at 7:00 PM

Recently, I had a project where full side-by-side deployment was required.  In a first test phase of the automated deployment, we used MSBuild together with the Codeplex MSBuild Extension Pack. We tried deploying assemblies side-by-side, but BizTalk threw errors when trying to deploy a new version of our Blog.Codit.BizTalk.Pipelines assembly:

 

Failed to add resource(s). Change requests failed for some resources. BizTalkAssemblyResourceManager failed to complete end type change request. SQL exception: "Violation of UNIQUE KEY constraint 'UQ__bts_pipe__DD425CAE7908F585'. Cannot insert duplicate key in object 'dbo.bts_pipeline'. The duplicate key value is (D6C53CD9-8466-4520-A85B-7BD887A57455)." 

 

I received this error when trying to deploy from Visual Studio, from MSBuild (using BTSTask.exe) and also when trying to deploy it manually via the Admin Console (Add Resource).  So the error is actually independent from the deployment source.  As BizTalk returned a SQL exception, I decided to run SQL Profiler and detected this call:

 

exec btm_CreatePipeline 
   @PipelineID='D6C53CD9-8466-4520-A85B-7BD887A57455',
   @Category=1,
   @Name=N'Blog.Codit.BizTalk.Pipelines.rcvSalesOrder',
   @FullyQualifiedName=N'Blog.Codit.BizTalk.Pipelines.rcvSalesOrder, Blog.Codit.BizTalk.Pipelines, Version=1.2.0.0, Culture=neutral, PublicKeyToken=xxx',
   @IsStreaming=0,
   @AssemblyID=265,
   @Release=2,
   @ID=@p8output

 

So the deployment logic tries to create a new entry in the bts_pipeline table, but it uses exactly the same (unique) ID of the pipeline of the older version.  This entry was already present in the bts_pipeline table: 

D6C53CD9-8466-4520-A85B-7BD887A57455 Blog.Codit.BizTalk.Pipelines.rcvSalesOrder, Blog.Codit.BizTalk.Pipelines, Version=1.1.0.0.  

 

We opened a case at Microsoft Support for this issue.  They forwarded the issue to the BizTalk Product Team and we received this answer:

 

The pipeline GUID is stored in the rcvSalesOrder.btp.cs  file. The GUID gets regenerated when either of the following occurs:
 
- The pipeline is saved from within Visual Studio.
- When REBUILD the BizTalk project.

 

As we executed a BUILD, instead of a REBUILD, a small change to our MSBuild script solved the issue:

<MSBuild Projects="@(ProjectsToBuild)" Targets="Rebuild" />

 

This behavior is rather inconsistent, because it only occurs when your assembly contains a pipeline object. 

 

Big thanks to Microsoft for the fast and accurate support.

Toon Vanhoutte


February 10, 2012 at 9:20 PM

When developing applications that make use of Windows Identity Foundation - WIF (Microsoft's technology to deal with claims-based security in your services) you can encounter exceptions that are not very precise/clear.

In this blog post I will show the difference between WCF tracing and WIF tracing based upon a sample application that is made to fail. The sample application consists of a client calling a service by first obtaining a security token from AD FS 2.0 and then asking the service to enumerate the claims present in the security token. The client will show the claims enumeration as received from the service. 

When I run my application (both the host and the client) this is the result:

 

The window in the background is my ServiceHost, the window in the front is the client. When the client calls the service over transport security the presented claims are enumerated as expected, when doing the same over message security the communication fails.

We will try to find the root cause of the problem by looking into WCF and WIF tracing.

The first thing the seasoned .NET developer will think of is to go in the .config file of your service and enable WCF Tracing:

 

Let's have a look what helpful information we can find in the WCF tracelog and WCF message log after running the sample.

The trace log shows this exception:

 

The message log shows this SOAP fault:

 

Although we have some useful information, "Message security verification failed" and "Security token could not be authenticated" can have a lot of reasons. We are interested in more detailed information about what goes wrong in the communication between clients, AD FS 2.0 and the service.

To find more detailed information we can enable WIF Tracing. WIF tracing cannot be enabled by clicking 'enable' in the Service Configuration Editor tool like we did for WCF Trace. However the idea is similar.

We only need to add two things to our config file (can also be done via the Service Configuration Editor tool):
- A diagnostics source: Microsoft.IdentityModel
- A listener (shared or not)

 The Xml representation looks like this: 

<system.diagnostics>
    <sources>
...
      <source name="Microsoft.IdentityModel" switchValue="Verbose">
         <listeners>
           <add name="WIFListener" />
         </listeners>
      </source>
...
    </sources>
    <sharedListeners>
...
      <add initializeData="c:\...\wif.svclog" type ="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="WIFListener" />
    </sharedListeners>
</system.diagnostics>

The Service Configuration Editor tool view looks like this:

 

That't all you need to do to enable WIF tracing.

Let's re-run the sample app with WIF tracing enabled and hit against the same exception...

After opening the WIF trace-file, I can see this information:

 

As you can see, WIF Tracing gives us a much clearer exception message:

"ID1038: The AudienceRestrictionCondition was not valid because the specified Audience is not present in AudienceUris.
Audience: 'http://localhost:8733/ClaimsEnumeratorService/'"

After checking the service config file, I can see that WIF is exaclty right :)

The audienceUri for my endpoint that uses message security is commented out.
Thanks to WIF tracing I can troubleshoot problems like this in a reasonable time, with only WCF tracing the exception details are just not enough to point you to the right direction.

Both WCF and WIF tracing are priceless for .NET developers...

 

Peter Borremans

Posted in: Security | WCF | WIF

Tags:


January 23, 2012 at 4:42 PM

Recently a customer of ours asked us if it was possible to include versioning information into the title of the installed MSI.

These MSI files can be generated by right-clicking a BizTalk application and selecting "Export" and then "MSI file":

This generates the MSI file on disk.

Problem however is that the MSI file which gets generated always has version 1.0.0.0 assigned to it.
We can always use Microsoft's Orca tool to manually update the properties of the file, but this is very cumbersome to say the least.

I went on to search if there was an option to pass some parameters to BTSTask.exe.
This tool allows you to perform the "Export MSI" via the command line, allowing you to script it.
Unfortunately this tool does not allow you to set the version information at all. 

Luckily, BizTalk comes with a .NET API that allows you to update the properties of the MSI installer package.
For BizTalk 2010 this is the Microsoft.BizTalk.MSIManager assembly.

using Microsoft.BizTalk.ApplicationDeployment.MSIManager.WindowsInstaller;

This assembly allows you to query/update the MSI database structure contained within the MSI file.

Just provide the following code to update the name of the application for example:
msiPath = full path to your MSI
applicationName = your custom application name that will appear in your "Programs and Features" list under Windows.

static public void UpdateMSIApplicationName(string msiPath, string applicationName)
        {
            Database db = Installer.OpenDatabase(msiPath, DatabaseOpenMode.Transact);
            string query = @"UPDATE Property SET Property.Value = '" + applicationName + "' WHERE Property.Property = 'ProductName'";
            Microsoft.BizTalk.ApplicationDeployment.MSIManager.WindowsInstaller.View vw = db.OpenView(query);

            vw.Execute();
            vw.Close();

            db.Commit();
            db.Close();
            db.Dispose();
        }

You can also update your Manufacturer information to customize the directory where the MSI gets installed. By default this is "Generated by Biztalk".
Use this query to perform the update then:

string query = @"UPDATE Property SET Property.Value = '" + manufacturer + "' WHERE Property.Property = 'Manufacturer'";

I also tried updating the version information, but for some reason this will insert some minor errors during installation having to do with the registry.
I believe this has to do with the registry keys that are installed by default within the BizTalk MSI version. 

Incorporating all of this into a properly automated build/deployment scenario will allow you to publish your MSI files with customized versioning.

Good luck.

 

Posted in: BizTalk | Deployment

Tags: