Monday, March 18, 2013

Execute Permission denied on object 'bts_ProcessHeartbeat_....'

It's always worth reposting a useful tip. This one was written by Paul Edwards in 2010 and I came across the problem recently. It occurs when you are using a Host Instance for an Isolated Host.  The full text of the error is

The following stored procedure call failed: " { call [dbo].[bts_ProcessHeartbeat_BizTalkServerIsolatedHost]( ?, ?, ?)}". SQL Server returned error string: "EXECUTE permission denied on object 'bts_ProcessHeartbeat_BizTalkServerIsolatedHost', database 'BizTalkMsgBoxDb', schema 'dbo'.".


The background is when you create a new Host then not only is the Host added to the BizTalk Management database but it also creates a stored procedure called 'bts_ProcessHeartbeat_'.
A new Database Role is also created called _USERS which includes the AD Group Name you specified when creating the Host.  When you create a Host Instance the Login account you use needs to be a member of this group in order to be granted Execute permissions.

But here's the issue: when using an Isolated Host (for recieve handlers of SOAP and HTTP), the stored procedure is called by the Application Pool account that your web site or virtual directory is running under. So you either need to make this account the same as the Host Instance login account or add it to the group you used when creating the Host. 

Saturday, February 9, 2013

BizTalk Hosts, Host Intances and Groups

People new to BizTalk struggle with the concept of Hosts and Host Instances. I've tried to find a simple article that I can direct people to but the articles I've read IMHO don't seem to provide a simple explanation.  So let me have a go.

When you create a new Host in BizTalk all you are doing is creating an entry in a table in the BizTalk Management database and nothing more.  You can attach an Orchestration to this Host, but it won't run until you create a Host Instance.  When you create a Host Instance you actually create a Windows Service and this is what does the work.  So you can start and stop Host Instances but Hosts have no such concept.

So what is the point of a Host? The answer is that its the way BizTalk offers us scalability. Let me provide the analogy of load balancing web servers. As you know you create 2 web servers that have different IP addresses.  And then someone sets up a load balancer for you and gives you the load balanced IP address (or the equivalent DNS entry).  When I point to the web server I use the load balanced IP address.  Same thing with BizTalk Hosts.  The Host entry is my load balanced "address".  Now it should make sense as to why I bind my Orchestrations to the Host name and NOT the Host Instance.  Its so I can get load balancing.  Now obviously with just 1 BizTalk Server this doesn't make a lot of sense so the next thing to understand is BizTalk Groups.

You can have several BizTalk Servers that belong to the same BizTalk Group.  So is it analogous to a load balanced cluster? No, not exactly, its more of a mechanism for distributing the processing across multiple servers.  They key point to understand is that there is only 1 copy of the BizTalk databases sitting on the SQL Server.  They are created when I configure my first BizTalk Server. 

When I add the second BizTalk Server and configure it I select the option to "Join an existing Group".  When configuration is complete and I open the BizTalk Admin console on my second server I see the Hosts that are created on Server 1.  Remember a Host is just a database entry and members of a BizTalk Group share the same database. 

Now here comes the magic bit. I can create a Host Instance on each of these two BizTalk Servers that will run my orchestrations.  So each now has a Windows Service running and BizTalk does the load balancing for me. 

Actually that is NOT how you should start out along the scalability route. There are some good articles on best practices for scaling BizTalk Server. The first configuration is 3 BizTalk Servers in a Group, one configured as a Process Host, one as Receive Host and one as the Send Host.  That's the first step in scalability.  You can then go on to add more servers to the group and use BizTalk's load balancing capability.  But this is where I'm going to stop because I'm not going to repeat what is in those excellent articles. 

Hope that helps.

Sunday, October 21, 2012

Replacing tempuri.org in a WCF Web Service


I keep forgetting how to do get rid of tempuri.org from a WCF web service.  And I also forget how to remove "Field" from the end of the properties on my class. This post deals with both.

Firstly, removal of tempuri.org I got form this blog.
The steps again are

1.) In your ServiceContract attribute constructor define the Namespace property.

[ServiceContract(Namespace = "http://myservice.com")]

public interface IMyService

2.) For your ServiceClass create the ServiceBehavior attribute with Namespace property

[System.ServiceModel.ServiceBehavior(Namespace = "http://myservice.com")]

class MyService : IMyService

3.) In all your bindings set the bindingNamespace property

<endpoint binding="basicHttpBinding" bindingNamespace="http://myservice.com"....
 

4.) To remove the word "Field" from the end of the properties

In your ServiceContract attribute constructor define the XmlSerializerFormatAttribute  property.

[Systme.ServiceModel.XmlSerializerFormatAttribute()]

public interface IMyService

5.) If you have an array of objects defined in your class and you return that array in your ServiceContract the previous step will give you an "Array" prefix.  To remove this in your ServiceClass comment out the line

//[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = http://myservice.com)]
 
 
 

Monday, October 1, 2012

WCF Web Services called from BizTalk

I have a BizTalk orchestration which is calling a WCF Web Service.  Now I'm processing lots of messages at once (about 8,000 at a time) but the web service was a bottle neck.
 
During testing we noticed that only 10 connections were opened to the web service at any one time.  As a result we were getting timeout issues and orchestrations were getting dehydrated.  We tinkered around in IIS but try as we might we could not figure out a way of increasing the number of connections. 

Then my colleaguse found this article which reports much better performance if you use net.tcp rather than http and the former has binding properties that can control the number of connections. You need to be cautious because there are quite a lot of factors to consider before changing protocols.  The advice is always to perform tests to determine which is the right protocol to use. 

I've not used net.tcp before so there are a couple of things you need to do first.
1. This will only work on Windows Server 2008 and R2

2. You need to install the feature of .Net 3.5 Framework WCF Activation to support non-HTTP protocols.  By default this is not selected, so you will need to go and install it from Server Manager.

3. One you have done that, you can add the net.tcp biding to the web site where your WCF web service is installed.  Note: keep both protocols: net.tcp and http for the web site.  Do this by editing the bindings and adding net.tcp with Binding Information like 80:*. But also go to Advanced Settings and change Enabled Protocols to htp,net.tcp.

4. Next you need to add the binding to the web.config of the WCF web service.  I did this using NotePad.  Keep the original basicHTTP binding in place because that way you can still check the the web service will load in the browser and you can see the WSDL. I've provided an extract from my web.config below.

<bindings> <netTcpBinding> <binding closeTimeout="00:01:00" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="100" maxReceivedMessageSize="65536" name="NetTcpBinding_IADService" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transferMode="Buffered"> <readerQuotas maxArrayLength="16384" maxBytesPerRead="4096" maxDepth="32" maxNameTableCharCount="16384" maxStringContentLength="8192"/> <security mode="None"> <transport clientcredentialtype="None" protectionLevel="None"/> <message clientCredentialType="UserName"/> </security> </binding> </netTcpBinding> </bindings>

<service name="WCFADService.ADService" > <host> <baseAddresses> <add baseAddress="net.tcp://localhost/WCFADService/ADService.svc"/> <add baseAddress="http://localhost/WCFADService/ADService.svc/mex"/> <add baseAddress="http://localhost/WCFADService/ADService.svc"/> </baseAddresses> </host> <endpoint address="" binding="netTcpBinding" contract="WCFADService.IADService" bindingConfiguration="NetTcpBinding_IADService" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service>

As far as the endpoint url for a net.tcp web service is concerned you can just replace the http:// with net.tcp://

You can test this in the usual way with a console application by using the net.tcp endpoint in the service reference. 

As far as consuming the net.tcp web service in BizTalk is concerned you can use the same consume web service wizard.  That will give you a Custom Binding xml file which you can import into BizTalk.  The magic is then when you click on Configure of the Send Port you get the ability to change the number of connections.
There are two properties here maxConnections and listenBacklog and we set them both to 50.  Sure enough when we tested this out I got 50 simultaneous connections. 

One last point is that running the web service like this hammered the CPU.  You would be well advised to put your web service on another server separate from the BizTalk Server. 



Saturday, March 17, 2012

Logging SOAP messages for a WCF Web Service

I had a need to log inbound SOAP messages to a WCF Web Service. It turns out this is really easy to do by adding some entries in the web.config.  Please note this only works with WCF services, not the old style ASMX web services. 

As always take a backup of the web.config before making changes.

Find the </system.servicemodel>tag and then just above it add

<diagnostics>
<messagelogging logentiremessage="true" logmalformedmessages="false" logmessagesatservicelevel="true" logmessagesattransportlevel="false" maxmessagestolog="3000" maxsizeofmessagetolog="3000" />
</diagnostics>

Then at the bottom of the web.config just before </configuration>add this

<system.diagnostics>
<trace autoflush ="true" />
<sources>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add initializedata="c:\PDFOutput\messages.svclog" name="messages" type="System.Diagnostics.XmlWriterTraceListener"/>
</listeners>
</source>
</sources>
</system.diagnostics>


Be sure to use the svclog extension.  Recycle your WCF service and send some messages through. 
Now you are going to find the svclog hard to read unless you have the SVCTraceViewer.EXE 
Its part of the Windows SDK and well worth downloading.

Monday, March 5, 2012

Deploying Web Sites with an MSI

I have blogged before about using MSIs to deploy but this post deals specifially with deploying a web site and its files to a target server.  This post assumes you are deploying to a Windows Server 2008 (R2) server with IIS 7.5 already installed.  The beauty about using this MSI is it will create a functioning web site for you by the time you click Finish.  Uninstall will remove the web site.  It uses the APPCMD utility which is located in  system32\inetsrv\ on the target server. 
I started with a generic Setup project that I could re-use.  I call this the WebSiteInstaller. In the class that inherits from System.Configuration.Install.Installer, I added an OnAfterInstall override procedure. What it does is uses 2 parameters that are prompted for during installation and passes them to a CreateWebsSite batch file. These 2 paramaters are the Physical path for the web site directory (e.g. c:\inetpub\wwwroot) and the port number. I also added an Uninstall procedure that will call DeleteWebsSite.BAT.

protected override void OnAfterInstall(IDictionary savedState)
{
base.OnAfterInstall(savedState);

// Retrive the target path of the Installation directory
string targetPath = this.Context.Parameters["targetdir"];

// Retrive the Physical path of the web Site
string phyPath = this.Context.Parameters["phyPath"];

// Save the Physical Path in the save state.
savedState.Add("phyPath", phyPath);

// Retrieve the Port of the WebSite.
string websitePort = this.Context.Parameters["webSitePort"];
string arg = @"""" + phyPath + @"""" + " " + websitePort + " " + @"""" + targetPath;

// Execute the CreateWebsSite batch process to create all the components related to WebSIte
ExecuteProcess(targetPath + "CreateWebsSite.BAT", arg);
}

public override void Uninstall(IDictionary savedState)
{
base.Uninstall(savedState);

// Retrive the target path of the Installation directory
string targetPath = this.Context.Parameters["targetdir"];

// Retrive the Physical path of the web Site
string phyPath = Convert.ToString(savedState["phyPath"]);
string arg = @"""" + phyPath;

// Execute the DeleteWebSite batch process to delete all the components related to WebSIte
ExecuteProcess(targetPath + "DeleteWebsSite.BAT", arg);
}
For the source to the ExecuteProcess function, see my earlier post .Thats it for the generic WebSiteInstaller project.
So now I can go to my Web Site Solution and add the WebSiteInstaller project and another Setup project. In my Setup project I add the Primary Output of my web site project and the WebSiteInstaller. By the way, when creating your web site don;t use File -> New -> Web but instead use File -> New -> Project -> Web -> ASP.NET Web Application. The latter will create a DLL and so gives you a Primary Output.

In my earlier post I explained how to add a Custom Dialog screen. You will need 2 parameters called PHYPATH and WEBSITEPORT. For Custom Actions add, and this is important, the Primary Output from WebSiteInstaller. The CustomActionData needs to be
For the Install Action

/phyPath="[PHYPATH]" /webSitePort="[WEBPORT]" /targetdir="[TARGETDIR]\
For the Uninstall Action

/targetdir="[TARGETDIR]\"
Last thing to do in this setup project is to add the two batch files.
Here is the content of the CREATEWEBSSITE.BAT. Note here my website name is WCFSaveFile which you will have to change. And you have to specify which files you want to copy to the target directory. In my case its an SVC and the web.config and the contents of the bin directory.

@echo OFF

set PHYPATH=%1
set PORT=%2
set SOURCEPATH=%3

set "FULLPATH=%PHYPATH%\WCFSaveFile"

md %FULLPATH%
md %FULLPATH%\bin

copy %SOURCEPATH%SaveFileService.svc" %FULLPATH%
copy %SOURCEPATH%web.config" %FULLPATH%
copy %SOURCEPATH%bin\*.*" %FULLPATH%\bin

REM Create Application Pool

%systemroot%\system32\inetsrv\APPCMD add apppool /name:WCFSaveFile
%systemroot%\system32\inetsrv\APPCMD set apppool "WCFSaveFile" /managedRuntimeVersion:v4.0
%systemroot%\system32\inetsrv\APPCMD set apppool "WCFSaveFile" /managedpipelineMode:Classic
%systemroot%\system32\inetsrv\APPCMD set apppool "WCFSaveFile" -processModel.identityType:NetworkService

REM Create WebSite

%systemroot%\system32\inetsrv\APPCMD add site /name:WCFSaveFile /bindings:"http/*:%PORT%:" /physicalPath:%FULLPATH%
%systemroot%\system32\inetsrv\APPCMD set app "WCFSaveFile/" /applicationPool:WCFSaveFile


The content of DELETEWEBSSITE.BAT is as follows.

@echo OFF

set PHYPATH=%1
set "FULLPATH=%PHYPATH%\WCFSaveFile"

REM Delete WebSite

%systemroot%\system32\inetsrv\APPCMD delete site /site.name:WCFSaveFile

REM Delete Application Pool

%systemroot%\system32\inetsrv\APPCMD delete apppool /apppool.name:WCFSaveFile

REM Delete virtual path

echo %FULLPATH%\bin\

del %FULLPATH%\bin\*.*" /Q
del %FULLPATH%\*.*" /Q
rd %FULLPATH%\bin
rd %FULLPATH%
Thats it. Your MSI should install the web site, create the App Pool and set it to .Net FW 4.0. I have just reused this for another web site and it took me only a few minutes to have a working MSI.
Hope you find it useful.
One last word of warning. NEVER add a final \ to the physical path when prompted by the MSI because it gives an obscure error.

Tuesday, November 29, 2011

How to create a null destination node in a BizTalk Map

This is the second time recently I came across this requirement so I guess others need it too. This post describes how to set a destintation node to null based upon a condition.

My situation was the source node contained a DateTime which was either valid or set to a zero length string. As some of you will know setting a date to a zero length string will actually set the date to 0001-01-01.  That is the date when the world began, allegedly.  My destination node is a date field too so I want to ignore the invalid date.  But here's the thing - I need to set the target node to null because I need the node present in the output.

The solution is to use a logical operator (= or <>) and a value mapping functoid.  In my case I am using a Script functoid to convert the source node value from DateTime to Date.  So the Script output is a date string.  By the way if you are wondering why I just don't test for this in the Script and set the return parameter to null, its becasue this doesn't work!
The <> functoid checks if the output is 0001-01-01 and sends true or false to the Value Mapping Functoid. As you can see I added 0001-01-01 as a constant for the second parameter.  Remember this is a Not Equal operator so it will return true if its a valid date and false if it is 0001-01-01. 

The magic happens in the Value Mapping functoid.  The description explains what it does. If the value of the first input parameter is true then the value of the second input parameter is returned.  It should add if the first input parameter is false, then the destination node is set to null
So all you have to do is select the correct logical operator (either = or <>) so that its output is true if you want to pass the value to the destination and false when you want to set it to null.  But be sure you have the parameters the right way round.  The logical operator needs to be at the top, the value of the source node is below.

Update 24/04/2012: I also ran into a problem where the source node was a Record, that did not contain data but held other elements.  I found that for the child elements the trick I used above worked well but, the parent element always appeared in the output as  < ParentNode />

I struggled for a long while to get rid of the offending  < ParentNode /> but in the end found that simply using the Logical Existence (?) functoid on the ParentNode was enough.  The result was the ParentNode was completely absent from the output except when any of the child elements contained data.