Archive

Posts Tagged ‘Biztalk’

Call REST services from BizTalk Server 2010

March 14, 2011 LeandroDG 7 comments

I was having some trouble consuming REST services from Biztalk Server 2010.

The first and easy thing to try is creating a Send Port with WCF-Custom adapter and configuring webHttpBinding as the binding and webHttpBehavior as the behavior.

But it doesn’t work inmediately, when you send a message with this configuration, you’ll get the following error:

The adapter failed to transmit message going to send port "SampleSendPort" with URL "http://localhost/SampleSite". It will be retransmitted after the retry interval specified for this Send Port. Details:"System.InvalidOperationException: Manual addressing is enabled on this factory, so all messages sent must be pre-addressed."

So, I tried another solution that I read around, use webHttpBehavior but instead of webHttpBinding, use a custom binding just like webHttpBinding but with manual addressing turned off. This looks like this:

The problem is that webHttpBehavior expects ManualAddressing to be turned on, so it throws this error:

The adapter failed to transmit message going to send port "SampleSendPort" with URL "http://localhost/SampleSite". It will be retransmitted after the retry interval specified for this Send Port. Details:"System.InvalidOperationException: In the endpoint at 'http://localhost/SampleSite', in order to use 'System.ServiceModel.Description.WebHttpBehavior', the 'HttpTransportBindingElement' of the binding must have ManualAddressing set to true."

So, I got rid of webHttpBehavior, and the messages were being sent without issues. If the endpoint couldn’t be reached, it would throw an error correctly in Biztalk and the message instance would get suspended. But when the server threw a 500 error (Internal Server Error), the message would dissappear and no error would show up.

Finally I decided to use webHttpBinding, webHttpBehavior but also add a custom behavior that configures the address and the method for the call. I took the code for this from here: http://social.msdn.microsoft.com/Forums/eu/biztalkesb/thread/c19d7486-0705-433f-8e1a-a9088d076ed7. And it ends up looking like this:

WebManualAddressingBehavior.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel;
using System.ServiceModel.Configuration;
using System.Configuration;

namespace Logue.Library.WebManualAddressingBehavior
{
    public class WebManualAddressingBehavior : IEndpointBehavior, IClientMessageInspector
    {
        public string Method { get; set; }
        public Uri ManualAddress { get; set; }

        public WebManualAddressingBehavior()
        {
        }

        public WebManualAddressingBehavior(string _method, Uri manualAddress)
        {
            Method = _method;
            ManualAddress = manualAddress;
        }

        public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(this);
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
        {
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }

        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
        }

        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            request.Headers.To = ManualAddress;
            HttpRequestMessageProperty property = new HttpRequestMessageProperty();
            property.Method = Method;
            property.SuppressEntityBody = true;
            request.Properties.Add(HttpRequestMessageProperty.Name, property);

            return request;
        }
    }
}

WebManualAddressingBehaviorExtensionElement.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel;
using System.ServiceModel.Configuration;
using System.Configuration;

namespace Logue.Library.WebManualAddressingBehavior
{
    public class WebManualAddressingBehaviorExtensionElement : BehaviorExtensionElement
    {
        //Constructor to create instance of endpoint behavior and initialize with two property values.
        protected override object CreateBehavior()
        {
            return new WebManualAddressingBehavior(Method, ManualAddress);
        }

        public override Type BehaviorType
        {
            //Return configuration element type to be used in the behavior.
            get
            {
                return typeof(WebManualAddressingBehavior);
            }
        }

        [ConfigurationProperty("Method", DefaultValue = "GET", IsRequired = true)]
        public string Method
        {
            get
            {
                return (string)base["Method"];
            }
            set { base["Method"] = value; }
        }

        [ConfigurationProperty("ManualAddress", DefaultValue = "", IsRequired = true)]
        public Uri ManualAddress
        {
            get
            {
                return (Uri)base["ManualAddress"];
            }
            set { base["ManualAddress"] = value; }
        }

        //Copies the content of the specified configuration element to this configuration element
        public override void CopyFrom(ServiceModelExtensionElement extFrom)
        {
            base.CopyFrom(extFrom);
            WebManualAddressingBehaviorExtensionElement element = (WebManualAddressingBehaviorExtensionElement)extFrom;
            Method = element.Method;
        }

        //Represents a collection of configuration-element properties
        private ConfigurationPropertyCollection _properties;

        /// Both properties are returned as a collection.
        protected override ConfigurationPropertyCollection Properties
        {
            get
            {
                if (_properties == null)
                {
                    _properties = new ConfigurationPropertyCollection();
                    _properties.Add(new ConfigurationProperty("Method", typeof(string), "", ConfigurationPropertyOptions.IsRequired));
                    _properties.Add(new ConfigurationProperty("ManualAddress", typeof(Uri), "", ConfigurationPropertyOptions.IsRequired));
                }
                return _properties;
            }
        }
    }
}

You need to GAC this behavior assembly and modify both 32-bit and 64-bit machine.configs, in the following paths: “%WINDIR%Microsoft.NETFrameworkv4.0.30319Configmachine.config” and “%WINDIR%Microsoft.NETFramework64v4.0.30319Configmachine.config”.

In the system.serviceModel/extensions/behaviorExtensions section, add the following line:

<add name="webManualAddressingBehavior" type="Logue.Library.WebManualAddressingBehavior.WebManualAddressingBehaviorExtensionElement, Logue.Library.WebManualAddressingBehavior, Version=1.0.0.0, Culture=neutral, PublicKeyToken=be30eb01119b89a8" />

It should look like this:

And then, you should be able to add it to the send port configuration, so you can set the method and the address:

When configured like this, an error on server side will generate an exception on Biztalk send port as expected, like this:

The adapter failed to transmit message going to send port "SampleSendPort" with URL "http://localhost/SampleSite". It will be retransmitted after the retry interval specified for this Send Port. Details:"System.ServiceModel.CommunicationException: Internal Server Error

Downloads:
WebManualAddressingBehavior Source Code (242)
WebManualAddressingBehavior Binaries (172)

VN:F [1.9.11_1134]
Rating: 3.7/5 (3 votes cast)
Categories: Development Tags: , ,

Tellago Studios SO-Aware at Microsoft TechReady!

February 15, 2011 adglopez No comments

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.

VN:F [1.9.11_1134]
Rating: 0.0/5 (0 votes cast)

Encryption and decryption with X.509 certificates (with MIME Base64 Encoding)

March 29, 2010 LeandroDG and adglopez 6 comments

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 (467)

VN:F [1.9.11_1134]
Rating: 5.0/5 (1 vote cast)
Categories: Development Tags: , , ,

Tellago Devlabs on Codeplex

March 2, 2010 LeandroDG No comments

At Tellago have opened a new codeplex workspace, the Tellago DevLabs.

We’ll be posting there all the open source projects we work on, we’ve already posted a second version of the Biztalk Data Services project, a RESTful API to manage and operate MS Biztalk Server 2009.

A couple of related posts by Tellago’s Chief Architect, Jesus Rodriguez:

VN:F [1.9.11_1134]
Rating: 0.0/5 (0 votes cast)
Categories: Development Tags: ,

Service Configuration Editor with 64-Bit OS error: An extension of name ‘persistenceProvider’ already appears…

November 3, 2009 LeandroDG No comments

I’m working on developing some WCF-Custom adapters for Biztalk 2009, so I needed to add some binding configuration to machine.config.

If you are trying to modify the computer WCF Configuration with the Service Configuration Editor to add a binding extension, behavior, binding element extension, etc., and you are working in a 64 bit environment, this error may occur:

An extension of name ‘persistenceProvider’ already appears in extension collection. Extension names must be unique. (C:WINDOWSMicrosoft.NETFrameworkv2.0.50727CONFIGmachine.config (line 224)

If you open the configuration file (C:WINDOWSMicrosoft.NETFrameworkv2.0.50727CONFIGmachine.config), you’ll probably find that it’s not repeated in that file. But it actually appears in another machine.config file.

If you check C:WINDOWSMicrosoft.NETFramework64v2.0.50727CONFIGmachine.config, it will probably contain the following:

<system.serviceModel>
 <extensions>
 <behaviorExtensions>
 <add name="persistenceProvider" type="System.ServiceModel.Configuration.PersistenceProviderElement, System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
 <add name="workflowRuntime" type="System.ServiceModel.Configuration.WorkflowRuntimeElement, System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
 <add name="enableWebScript" type="System.ServiceModel.Configuration.WebScriptEnablingElement, System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
 <add name="webHttp" type="System.ServiceModel.Configuration.WebHttpElement, System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
 <add name="Microsoft.VisualStudio.Diagnostics.ServiceModelSink.Behavior"
 type="Microsoft.VisualStudio.Diagnostics.ServiceModelSink.Behavior, Microsoft.VisualStudio.Diagnostics.ServiceModelSink, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
 </behaviorExtensions>
 <bindingElementExtensions>
 <add name="webMessageEncoding" type="System.ServiceModel.Configuration.WebMessageEncodingElement, System.ServiceModel.Web, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
 ...

Notice the Framework64 part in the path, this configuration is specific for 64-bit .NET applications.

So, to be able to correctly modify your machine.config using the Service Configuration Editor, you’ll need to temporarily comment the whole <system.servicemodel> in the <em>C:WINDOWSMicrosoft.NETFramework64v2.0.50727CONFIGmachine.config</em>  and save the file. Then use the Service Configuration Editor with your machine.config, edit and save. Finally, open the Framework64 machine.config again, uncomment the section, and save again.

Be very careful when modifying the machine.config files, it contains configuration that can affect every .NET application that you run in your PC.

VN:F [1.9.11_1134]
Rating: 5.0/5 (1 vote cast)