Friday, March 22, 2013

BizTalk Deployment Framework

I've been using the BizTalk Deployment Framework in particular for highly available environments where there are 2 Receive hosts, 2 Send hosts and 2 Process hosts.  The 2 receive hosts are clustered which works well when you have orchestrations exposed as WCF web services because you can install the virtual directories on both servers and not have a single point of failure. 

The Deployment Framework allows you to deploy your BizTalk assemblies to the GAC and optionally to install them to the BizTalk management database.  So in this 6 server arrangement you select to deploy to the BizTalk management database on one of the servers and deploy just the assemblies to the GAC on the other 5.

Now the Deployment Framework provides the ability to install your virtual directories as part of the deployment but here is where you hit your first problem. It only does so when you select "deploy to management database" as true which means you only get them deployed onto one server.  And your deployment instructions need to be clear about which server you install the virtual directories on. 

I've deployed a lot of web services so I have experience in creating virtual directories and application pools.  The APPCMD is my best friend and can be called using

%systemroot%\system32\inetsrv\APPCMD

So I started to create a Windows CMD file called CreateVDir.cmd.  And it occurred to me I can use the %COMPUTERNAME% to specify which server I want to execute commands on.

IF NOT "%COMPUTERNAME"=="%RECEIVEHOST1%" GOTO END
IF NOT "%COMPUTERNAME"=="%RECEIVEHOST2%" GOTO END

In this case I am passing RECEIVEHOST1 and RECEIVEHOST2 as parameters to the CreateVDir.cmd along with the Virtual Directory name, the physical path and the user name and password for the Application Pool account.  And the great thing is I can have these as environment settings in the SSO and pass them into CreateVDir.cmd as $(VDIR_UserName) $(ReceiveHost1) etc.

So I just need to create a Target in BTDFPROJ as
<Target AfterTargets="" Name="CustomDeployTarget">
<Exec command="..\CreateVdir.cmd <vdirname> <physpath>  $(VDIR_UserName)  $(VDIR_UserPass) $(ReceiveHost1)  $(ReceiveHost2)"/>
</Target><

I also need to create a CustomUndeployTarget which calls my DeleteVdir.cmd file and then I have all the control I need. I like this approach. I keep my BTDFPROJ file simple and I have CMD files that I can create and test independently of the deployment process.

Good old DOS commands!

Monday, March 18, 2013

Create IIS Virtual Directory using APPCMD

The command line script below allows you to create a Virtual Directory from an existing physical directory and set up an application pool.  In this case the application pool will be running under a domain service account. 

To use an identity of Network Service then replace
/processModel.identityType:SpecificUser  ...
with
/processModel.identityType:NetworkUser


@echo OFF

IF "%1"=="" GOTO Syntax
IF "%2"=="" GOTO Syntax
IF "%3"=="" GOTO Syntax
IF "%4"=="" GOTO Syntax

set VDIRNAME=%1
set PHYPATH=%2
set USERNAME=%3
set PASSWORD=%4

REM Create Application Pool

%systemroot%\system32\inetsrv\APPCMD add apppool /name:%VDIRNAME%AppPool

%systemroot%\system32\inetsrv\APPCMD set apppool "%VDIRNAME%AppPool" /managedRuntimeVersion:v4.0

%systemroot%\system32\inetsrv\APPCMD set apppool "%VDIRNAME%AppPool" /managedpipelineMode:Classic

%systemroot%\system32\inetsrv\APPCMD set apppool "%VDIRNAME%AppPool" /processModel.identityType:SpecificUser /processModel.userName:%USERNAME% /processModel.password:%PASSWORD%

REM Add Virtual Directory

%systemroot%\system32\inetsrv\APPCMD add app /site.name:"Default Web Site" /path:/%VDIRNAME% /physicalpath:"%PHYPATH%"

%systemroot%\system32\inetsrv\APPCMD set app "Default Web Site/%VDIRNAME%" /applicationpool:%VDIRNAME%AppPool

:SYNTAX
ECHO.
ECHO VDir Name and Physical Path Required
ECHO.
ECHO CreateVDir.CMD VDirName C:\PhysPath Domain\UserName Password
ECHO example CreateVDir TEST c:\inetpub\wwwroot\test buildx\btsuser Password1





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.