A simpel test
There is quite a few steps involved in setting up a receive port/location for the http receive adapter on the server side, firewall and client side
It is nice to have a toolbox to test the connectivity
The following files should be stored in the root folder of the website added as the public address configured in the http transport properties dialog box
default.htm
After configuration in IIS and BizTalk access can be checked using a very simple html page, it could be index.htm or default.htm by preference
<!-- -->
<html>
<head>
<title>BizTalk Service - HTTP Receive</title>
</head>
<body>
<p>BizTalk Service - HTTP Receive</p>
<p><a href="form.htm">Connectivity test</a></p>
</body>
</html>
This page is used to test the firewall settings and https connectivity and whether the client certificate is properly installed on the client server
form.htm
On the page I have a link to a basic html form also to test BizTalk Server and IIS configuration. In BizTalk you should receive a basic document with content taking from the imput fields
<!-- -->
<html>
<head>
<title>BizTalk Service - HTTP Receive</title>
</head>
<body>
<form name="Test" method="post" action="BTSHTTPReceive.dll">
<p>Test BTSHTTPReceive port, please type a short message:</p>
<p>
<input type="text" name="message">
<input type="submit" value="Submit"> </p>
<p>You will receive a response with an correlationtoken if the post is successfull</p>
</form>
</body>
</html>
Very basic and will send the data "message=<value>" to BizTalk and return a correlation token if confgured
Scale-up
Next step is to test the complete flow, I have created a small console application as an example on how to send data files to BizTalk through the Http Receive Adapter
WebClient
I will use the WebClient class for sending the data
First we need to create a sub class to add a X.509 certificate to HttpWebRequest ClientCertificates collection
// --
class HttpsClient : WebClient
{
public X509Certificate2 Certificate { get; set; }
// Override GetWebRequest to add certificate to the request object
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
request.ClientCertificates.Add(this.Certificate);
return request;
}
}
Get Certificate
The certificate is retrieved from current user/address book certificate store using the thumbprint, the method is part of the console main program class
// --
static X509Certificate2 GetClientCertificateFromThumbPrint(string thumbPrint)
{
if (string.IsNullOrEmpty(thumbPrint))
throw new ArgumentException(
String.Format("Error: Thumbprint is empty"), "ThumbPrint"
);
X509Store _store = new X509Store(
StoreName.AddressBook, StoreLocation.CurrentUser
);
// Try to open the store.
_store.Open(OpenFlags.ReadOnly);
// Find the certificate that matches the thumbprint.
X509Certificate2Collection _certs = _store.Certificates.Find(
X509FindType.FindByThumbprint, thumbPrint, false
);
_store.Close();
// Check to see if our certificate was added to the collection.
// If no, throw an error, if yes, create a certificate using it.
if (_certs.Count == 0)
{
throw new ArgumentException(
String.Format(
"Error: No certificate found containing thumbprint: {0}",
thumbPrint
),
"ThumbPrint"
);
}
return _certs[0];
}
Main program
Code listing for the main program, get client certificate, open stram for sending data to the site and open another stream to the local file, use the copyto method and flush the stream to send the data across the boundaries
// --
// Main program
static void Main(string[] args)
{
byte[] _responseHeaders = null;
string _clientResponse = string.Empty;
X509Certificate2 _certificate = null;
try
{
string _thumbPrint = "1a 2b 3c 4d 5e 6f a1 b2 c3 d4 e5 f6 1a 2b 3c 4d 5e 6f a1 b2";
_certificate = GetClientCertificateFromThumbPrint(_thumbPrint);
}
catch (Exception exc)
{
Console.WriteLine(exc);
throw new Exception("Certificate exception", exc);
}
// Url to BizTalk Http Receive ISAPI dll
Uri _address = new Uri("https://biztalk.test.invalid/test/BTSHTTPReceive.dll");
// Load file from disk or other source
string _filePath = @"d:\data\test\Order.4b496d3c-6214-495b-bbce-1850516b6cf9.xml";
try
{
using (HttpsClient _client = new HttpsClient())
{
_client.Certificate = _certificate;
using (var _stream = _client.OpenWrite(_address))
{
using (FileStream _fileStream =
new FileStream(_filePath, FileMode.Open, FileAccess.Read))
{
_fileStream.CopyTo(_stream);
}
_stream.Flush();
}
Console.WriteLine("{0} at {1:F}", _client.StatusCodeDescription, _client.LastModified);
Console.WriteLine("");
_responseHeaders = _client.ResponseHeaders.ToByteArray();
_clientResponse = _client.Response;
}
}
catch (WebException exc)
{
Console.WriteLine(exc);
throw new Exception("WebClient exception", exc);
}
finally
{
if (!string.IsNullOrEmpty(_clientResponse))
Console.WriteLine(_clientResponse);
if (_responseHeaders != null && _responseHeaders.Length > 0)
// Decode and display the response.
Console.WriteLine(Encoding.ASCII.GetString(_responseHeaders));
}
}
Server Response
This is working ok but we are missing the correlation token received and status codes from the web server. From the content-length in the ReponseHeader we can see that we have the data
GetWebResponse
Override the GetWebResponse method in the WebClient class to read the reponse from WebRequest class as well as status code and description
// --
// Intercept the WebRequest object to get response data from host
protected override WebResponse GetWebResponse(WebRequest request)
{
this.StatusCode = HttpStatusCode.Accepted;
// Get response stream from web request
HttpWebResponse _webResponse = (HttpWebResponse)request.GetResponse();
this.StatusCode = _webResponse.StatusCode;
this.StatusCodeDescription = _webResponse.StatusDescription;
this.LastModified = _webResponse.LastModified;
// Is the stream readable?
if (this.StatusCode == HttpStatusCode.Accepted && _webResponse.GetResponseStream().CanRead)
{
using (StreamReader _reader = new StreamReader(_webResponse.GetResponseStream(), true))
{
// Get stream content
this.Response = _reader.ReadToEnd();
}
}
return base.GetWebResponse(request);
}
Remember to add the four extra properties to our HttpsClient class and you can read the properties after the OpenWrite operation is finished and the Stream has been closed
Sample VS 2012 project attached to article /have fun
BtsHttpReceiveTest.zip (35,83 kb)