Archive
Tellago Technology Updates
Tellago Studios SO-Aware at Microsoft TechReady!
Tellago Studios’ Chief Architect Jesus Rodriguez will be presenting a session about SOA Governance on the Microsoft platform using SO-Aware at Microsoft TechReady.
This week Microsoft is hosting the first edition of their annual TechReady conference. Even though TechReady is an internal conference, Microsoft invited us to present a session about how to enable Agile SOA Governance on the Microsoft platform using our recently release product: SO-Aware.
As part of our session, we will take a look at the current challenges that organizations face when enabling SOA governance capabilities on the Microsoft platform and how organizations can benefit from more agile, lightweight and modern SOA governance models.
The session will provide a practical view to the role of Tellago Studios’ SO-Aware as an essential technology to enable native SOA governance on the Microsoft platform. We will explore in detail important capabilities of SO-Aware such as
- Centralized service repository
- Centralized configuration management
- Service testing
- Monitoring
- Transparent integration with technologies such as Visual Studio, BizTalk Server, Windows Server & Azure AppFabric among many others
But the fun doesn’t stop there…..
As part of this session, we will showcase for the first time our upcoming SO-Aware Test Workbench product which enables load and functional web service testing capabilities on the Microsoft technology stack.
SO-Aware Test Workbench provides developers with a visually rich environment to model and control the execution of load and functional tests in a SOA infrastructure. This tool includes the first native WCF load testing engine allowing developers to transparently load test applications built on Microsoft’s service oriented technologies such as WCF, BizTalk Server or the Windows Server or Azure AppFabric.
Encryption and decryption with X.509 certificates (with MIME Base64 Encoding)
We’ve been working on the last months with encyption and decryption using certificates for Biztalk, I haven’t found enough documentation out there but after some time we were able to encrypt and decrypt messages with a very little amount of code.
Messages are encrypted using a certificate’s public key, and decrypted using their private key. This way, to send a message to a particular recipient, he needs to have a certificate with a private key deployed on their side, and you need to have the certificate (only the public key is necessary) deployed on your side. No one will be able to decrypt the message without the private key (it’s an asymmetric encryption/decryption method).
We use this code to encrypt/decrypt messages inside Biztalk Server components, so the code we developed for encryption/decryption uses MIME Base64 Encoding, for example:
Content-ID: {F5BBE1D4-D0E3-4CD7-9B51-1129FA3077E1}
Content-Description: body
Bcc:
MIME-Version: 1.0
Content-type: application/x-pkcs7-mime; smime-type=enveloped-data; name="smime.p7m"
Content-Transfer-Encoding: base64
MIAGCSqGSIb3DQEHA6CAMIACAQAxgZEwgY4CAQAwODAkMSIwIAYDVQQDExlSQ0NMIEJpelRhbGsg
q49kxusLITM1r982n2MgZaa8vdgkLBLATSUWDEyDu/B57PZxxxU/AhEyIUppI5fsaxpI7NT+2QPW
8/HT7vfgH0t3ch3AUVglspS/NRYCuaOwG5lIpw9IAAAAAAAAAAAAAA==
How to use the Encrypt method
string messageToEncrypt = "message"; string certificateName = "MyCertificate"; string encryptedMessage = CryptographyHelper.Encrypt(messageToEncrypt, certificateName);
The certificate needs to be deployed on the Personal store inside your Local Machine (the code can be modified in the GetCertificate method to use another store).
To do this deployment, you may want to check this link: http://technet.microsoft.com/en-us/library/cc740068%28WS.10%29.aspx
How to use the Decrypt method
string decryptedMessage = CryptographyHelper.Decrypt(messageToDecrypt);
This time, the certificate needs to be deployed at the same store but it’ll be necessary to deploy it including the private key. If the method throws an exception “the enveloped data-message does not contain the specified recipient”, this is because the certificate with the private key is not correctly deployed into the current account/local machine personal store.
Source code (download at the bottom)
using System;
using System.Linq;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.IO;
namespace Logue.Library.Cryptography
{
public static class CryptographyHelper
{
#region Public methods
public static string Encrypt(string fullMessage, string certificateName)
{
X509Certificate2 certificate = GetCertificate(certificateName);
string base64DecryptedContent = Convert.ToBase64String(Encoding.UTF8.GetBytes(fullMessage));
base64DecryptedContent = ChunkContent(base64DecryptedContent, 76);
base64DecryptedContent = EnvelopeBase64(base64DecryptedContent);
byte[] contentBytes = Encoding.ASCII.GetBytes(base64DecryptedContent);
Oid contentOid = new Oid("1.2.840.113549.1.7.1", "PKCS 7 Data");
Oid algorithmOid = new Oid("1.2.840.113549.3.2", "rc2");
AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(algorithmOid);
ContentInfo content = new ContentInfo(contentOid, contentBytes);
EnvelopedCms envelope = new EnvelopedCms(SubjectIdentifierType.NoSignature, content, algorithmIdentifier);
envelope.Encrypt(new CmsRecipient(certificate));
byte[] encryptedBytes = envelope.Encode();
string encryptedContent = Convert.ToBase64String(encryptedBytes);
encryptedContent = ChunkContent(encryptedContent, 76);
string result = EnvelopEncryptedContent(encryptedContent);
return result;
}
public static string Decrypt(string fullMessage)
{
string messageContent = GetContentInBase64(fullMessage);
// Load envelope and decrypt
EnvelopedCms envelope = new EnvelopedCms();
envelope.Decode(Convert.FromBase64String(messageContent));
envelope.Decrypt();
// Get original bytes
byte[] decryptedBytes = envelope.ContentInfo.Content;
string decryptedText = Encoding.ASCII.GetString(decryptedBytes);
// Get processed Base64 content
byte[] decryptedContentBytes = Convert.FromBase64String(GetContentInBase64(decryptedText));
string decryptedContentText = Encoding.UTF8.GetString(decryptedContentBytes);
return decryptedContentText;
}
#endregion
#region Private Methods
private static string ChunkContent(string encryptedContent, int chunkSize)
{
StringBuilder sb = new StringBuilder();
StringReader sr = new StringReader(encryptedContent);
int position = 0;
char[] buffer = new char[chunkSize];
while (position < encryptedContent.Length)
{
if (encryptedContent.Length - (position + chunkSize) < 0)
chunkSize = encryptedContent.Length - position;
sb.Append(encryptedContent.Substring(position, chunkSize));
sb.Append("rn");
position += chunkSize;
}
return sb.ToString();
}
private static string EnvelopEncryptedContent(string encryptedContent)
{
return CryptographyResources.ENCRYPTED_TEMPLATE.Replace("[REPLACE]", encryptedContent);
}
private static string EnvelopeBase64(string content)
{
return CryptographyResources.BASE64_TEMPLATE.Replace("[REPLACE]", content);
}
private static X509Certificate2 GetCertificate(string certificateName)
{
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
X509Certificate2 certificate = store.Certificates.Cast<X509Certificate2>().Where(cert => cert.Subject.IndexOf(certificateName) >= 0).FirstOrDefault();
if (certificate == null)
throw new Exception("Certificate " + certificateName + " not found.");
return certificate;
}
private static string GetContentInBase64(string fullMessage)
{
string contentSeparator = Environment.NewLine + Environment.NewLine;
int startIndex = fullMessage.IndexOf(contentSeparator) + contentSeparator.Length;
int endIndex = fullMessage.Length - 1;
StringBuilder sb = new StringBuilder();
string[] lines = fullMessage.Substring(startIndex, endIndex - startIndex).Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
sb.Append(line);
return sb.ToString();
}
#endregion
}
}
Download
Cryptography Helper Source Code (249)
Biztalk Custom Functoid Wizard for Biztalk 2004 & 2006
First, this release got delayed about 3 years!. But, it still works fine and I’ve used it in many Biztalk Project over the last years, so I think it may be of use for every other BTS developer out there.
The idea behind this project is to be able to build custom Biztalk Functoids through a wizard. When this was built, there was not much information on the web about developing custom functoids, so it was a little hard to work on it. It’s based on Boudewijn van der Zwan and Scott Woodgate‘s Biztalk Adapter Wizard. I’ve also based this development in Martijn Hoogendoorn‘s Biztalk Pipeline Component Wizard. These are the original releases for this components: Adapter Wizard, Pipeline Wizard.
Basically a custom functoid is very similar to a Scripting Functoid with the same code copied once and again. The idea of developing a custom functoid instead of a Scripting Functoid is to avoid code repetition and to be able to modify it in every map that uses it simultaneously. This concept is known as DRY (Don’t repeat yourself).
I’ve built an original version for 2004 for an enormous project which required around 50 custom functoids to be built, of course building them by hand would be very time consuming. Adrian Lopez helped me adapt this version to Biztalk Server 2006, special thanks to him for the help!.
I’m posting both versions here, for Biztalk 2004 (and Visual Studio .NET 2003) and Biztalk 2006 (and Visual Studio .NET 2005).
Installation and usage is quite simple but I’ll show the usage step by step in a simple “Hello world” functoid sample.
- Start up Visual Studio, go to File, New Project, and select Biztalk Projects:
- Splash screen

Biztalk Functoid Wizard Initial wizard splash
- Now you must select some general properties: class name, namespace, assembly name and assembly key file (.snk), which can be generated by clicking on New or selected by clicking on the browse button. You must select either a key file or a key name (the last one if you’ll be using the Crypto Service Provider).

Biztalk Functoid Wizard General project properties
- In this screen you must choose the functoid id (this is a unique id that cannot be repeated among functoids, so be careful not to repeat yourself), name, tooltip and description.

Biztalk Functoid Wizard Functoid properties 1/2
- You can choose the category where the functoid will be shown and a default exception message. Also you can select the icon for the functoid (by double clicking on the predefined icon), and select VB.NET or C# as the implementation languages.

Biztalk Functoid Wizard Functoid properties 2/2
- Then it’s time to select the incoming parameters for the functoid, the return type and the allowed input and output connections for the functoid. Also you can re-order the parameters and define minimum and maximum amount of parameters.

Biztalk Functoid Wizard Functoid parameters & connection types
- We are ready, functoid definition is finished.

Biztalk Functoid Wizard Completion splash
- Now, into some code. A functoid is nothing more than a function that can be used inside a map. We defined the interface with the wizard, but we need to edit the source code for the implementation. The wizard will have autogenerated the following code:
public System.String Execute() { ResourceManager resmgr = new ResourceManager(ResourceName, Assembly.GetExecutingAssembly()); try { // TODO: Implement Functoid Logic } catch (Exception e) { throw new Exception(resmgr.GetString("FunctoidException"), e); } } - We add the basic “Hello world” implementation:
public System.String Execute() { ResourceManager resmgr = new ResourceManager(ResourceName, Assembly.GetExecutingAssembly()); try { return "Hello world!"; } catch (Exception e) { throw new Exception(resmgr.GetString("FunctoidException"), e); } } - Now we just build the whole solution, it will automatically generate our file Logue.Biztalk.Functoids.dll inside of Microsoft BizTalk Server 2006Developer ToolsMapper Extensions in the program files folder. We open a map inside of Visual Studio and right-click on the functoids toolbox, and we select “Choose Items”. The following screen appears:

Functoid toolbox item selection
- We browse for the file. As explained before, it will be inside of Microsoft BizTalk Server 2006Developer ToolsMapper Extensions in the program files folder.

Browsing for custom functoid assembly
- Now the functoid appears in the item selection box, so we check it and click on Ok.

Our functoid in the toolbox item selection
- Now it appears in the toolbox:

Functoid toolbox with our functoid
- And now we drag&drop it, link it, and we can test the map!

Our functoid used in a map
I hope you find it useful! Please report any bugs or information you think it would be useful to share.
Downloads:
Biztalk Functoid Wizard 2006 Source Code (62)
Biztalk Functoid Wizard 2006 Installer (79)
Biztalk Functoid Wizard 2004 Source Code (27)
Update (2010/01/24): I’ve fixed the download module after moving to a new hosting provider, they are now working again.
.NET C#: Recycle current Application Pool programmatically (for IIS 6+)
I’ve been working on how to recycle the current application pool for my ASP .NET application.
There are 3 steps for doing this:
- Verify if application is running on IIS that supports application pools (if not, there’s nothing to recycle).
- Get application pool name (obtained from the DirectoryServices entry corresponding to our virtual directory).
- Invoke Recycle method in the DirectoryServices entry corresponding to the application pool.
I divided the code into this 3 steps, the RecycleApplicationPool method can be used separately for recycling any application pool (by knowing only its name). The RecycleCurrentApplicationPool method returns a boolean value indicating if the application pool was recycled.
public static class ApplicationPoolRecycle
{
/// <summary>Attempts to recycle current application pool</summary>
/// <returns>Boolean indicating if application pool was successfully recycled</returns>
public static bool RecycleCurrentApplicationPool()
{
try
{
// Application hosted on IIS that supports App Pools, like 6.0 and 7.0
if (IsApplicationRunningOnAppPool())
{
// Get current application pool name
string appPoolId = GetCurrentApplicationPoolId();
// Recycle current application pool
RecycleApplicationPool(appPoolId);
return true;
}
else
return false;
}
catch
{
return false;
}
}
private static bool IsApplicationRunningOnAppPool()
{
// Application is not hosted on IIS
if (!AppDomain.CurrentDomain.FriendlyName.StartsWith("/LM/"))
return false;
// Application hosted on IIS that doesn't support App Pools, like 5.1
else if (!DirectoryEntry.Exists("IIS://Localhost/W3SVC/AppPools"))
return false;
else
return true;
}
private static string GetCurrentApplicationPoolId()
{
string virtualDirPath = AppDomain.CurrentDomain.FriendlyName;
virtualDirPath = virtualDirPath.Substring(4);
int index = virtualDirPath.Length + 1;
index = virtualDirPath.LastIndexOf("-", index - 1, index - 1);
index = virtualDirPath.LastIndexOf("-", index - 1, index - 1);
virtualDirPath = "IIS://localhost/" + virtualDirPath.Remove(index);
DirectoryEntry virtualDirEntry = new DirectoryEntry(virtualDirPath);
return virtualDirEntry.Properties["AppPoolId"].Value.ToString();
}
private static void RecycleApplicationPool(string appPoolId)
{
string appPoolPath = "IIS://localhost/W3SVC/AppPools/" + appPoolId;
DirectoryEntry appPoolEntry = new DirectoryEntry(appPoolPath);
appPoolEntry.Invoke("Recycle");
}
}
