by community-syndication | Jan 29, 2008 | BizTalk Community Blogs via Syndication
This is really a note to self, as I have a habit of forgetting the numerous issues I have overcome and feel my blog can be a great repository for such information, as it may also assist someone else out there. I haven't been as rigorous with this as I should have recently. Well, for a long time actually!
Anyway, quite a simple one really, but one I have managed to forget. If you are setting up a new WCF web service hosted within IIS you may receive errors such as that below:
Event Type: Error
Event Source: ASP.NET 2.0.50727.0
Event Category: None
Event ID: 1088
Description:
Failed to execute request because the App-Domain could not be created. Error: 0x80070005 Access is denied.
Event Type: Warning
Event Source: ASP.NET 2.0.50727.0
Event Category: None
Event ID: 1073
Description:
Failed to initialize the AppDomain:/LM/W3SVC/1/Root/<your app domain>
Exception: System.IO.FileLoadException
Message: Could not load file or assembly 'System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. Access is denied.
StackTrace: at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
at System.Activator.CreateInstance(String assemblyName, String typeName, Boolean ignoreCase, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, Evidence securityInfo, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(String assemblyName, String typeName)
at System.AppDomain.CreateInstance(String assemblyName, String typeName)
at System.AppDomain.CreateInstance(String assemblyName, String typeName)
at System.Web.Hosting.ApplicationManager.CreateAppDomainWithHostingEnvironment(String appId, IApplicationHost appHost, HostingEnvironmentParameters hostingParameters)
at System.Web.Hosting.ApplicationManager.CreateAppDomainWithHostingEnvironmentAndReportErrors(String appId, IApplicationHost appHost, HostingEnvironmentParameters hostingParameters
I am sure there are other reasons for receiving these errors, but the times I have come across it have been due to the account defined withint the associated application pool not having read permission to the application's web.config file.
by community-syndication | Jan 28, 2008 | BizTalk Community Blogs via Syndication
Ever had the need to create an enumeration of values for a field or element within a BizTalk Schema? Did you know that you can store those values inside an Access database for synchronization with the enumeration values for the schema?
The BizTalk schema provides a CodeList feature that can be used to point to an Access 2003 database. When setting the appropriate properties, the values are pulled from the database and stored as enumerated values for the field/element.
In order to do this, create an Access database (MDB file extension) that has a table with a name that contains an underscore (e.g. Xml_OrderTypes). The table should contain at least 3 special columns: code, value, and desc (short for description). It can contain more columns than this; however, these column names are hard coded in the schema codelist feature to retrieve the enumerated values (see image below).
The code column allows you to specify a collection type that will then be used with an element/field's restricted, derivative CodeList property value. The value column will be the enumerated values added to the enumeration xs:restriction section of the schema. The desc column will contain the description of the each value, if populated, inside a dialog box that allows you to select which values are valid for a particular field/element within a schema. Populate the table with appropriate values for each column and save the database.
Next, create a standard schema and open its Schema node properties. There are a couple of properties that are used to enable the CodeList feature. First, set the CodeList Database path to a file path containing an Access 2003 database (see image below).
Next, set the Standard and StandardVersion properties to the name of the Access 2003 table containing the possible enumerated values. The algorithm is to set each respective property so that the concatenation of Standard and StandardVersion properties equals the Table Name within the Access 2003 database joined with an underscore. For example, if the Access 2003 database was named XmlSchemaTypes.mdb, and you have a table named SchemaTypes_v1, you should set the Standard property value to SchemaTypes and the StandardVersion property value to v1. You can use whatever naming scheme that you'd like, as long as it follows the algorithm (see image below).
Once you've set up the Access database and the schema standard properties, you can start creating fields/elements with their enumerated values from the Access database.
Next, create an element/field, set its Derived By property to Restriction, and type in the name of the collection type specified inside the Access 2003 database table for the CodeList property. For example, in the Access database image (first screenshot), the code column contains collection types for orderTypes, creditCardTypes, and cardTypes. If this element contains collections for OrderTypes, specify orderTypes as the value for the CodeList. When this property is set, you can successfully click the ellipsis (…) button next to it, invoking the display of a dialog box that shows all the possible enumerated values from the database. This gives you the opportunity to select all the values, or just a few for the element/field (see image below).
Select all the values you like for the allowable enumerations.
So how does it all work? After you've configured all the settings for the element/field, an annotation is added to the schema, allowing the BizTalk Schema editor to query the Access database table for the specified values. These values are added to the schema as an xs:enumeration-restriction, thus they are actually embedded into the schema with the values (see image below).
Whenever you need to update the values, reload the schema inside the designer, and reset the CodeList property. This will reload the dialog, invoking the BizTalk editor to re-query the Access database.
Happy coding!!!
by community-syndication | Jan 28, 2008 | BizTalk Community Blogs via Syndication
Consultants (like me) tend to exist in very different worlds than enterprise architects and developers. We get exposure across a broad range of companies, flitting from site to site, solving problems, spewing wisdom, and moving on. That’s a great position to be in as you get to see a lot of different business problems and solutions. That’s also sometimes a not-so-good position as you see people struggling, often with the same problems, and coming up with solutions that can vary wildly in both approach and effectiveness.
In BizTalk-land, nowhere is this as evident as around deployment. Why, I don’t know, but many people seem to struggle with it. Developers will focus on making the solution work, and then suddenly realize they need to deploy, and wonder how they will go about doing that. This made more complex as BizTalk solutions can, and often do, span a wide range of technologies.
The BizTalk product team has come up with a great deployment story. This has not always been the case, but it certainly is now. We have all the bits and pieces we need to be able to implement highly-repeatable deployment packages. However, many developers seem to either not realize that, or they’re not in a position (due to budgets and tight deadlines) to take the time to “do it right”.
I would argue that not taking the time to implement a 100% repeatable build process is something that you CAN’T AFFORD to skip. The ultimate cumulative costs, in ghost-chasing troubleshooting, production outages, and lost productivity can far outweigh the up-front costs of implementing a highly-repeatable, reliable and effective build process. In some shops it may be OK to hand an IT pro a deployment script that has 15 manual steps, however, I’d rather not rely on a human to ensure that every step happens in the prescribed sequence. What if you miss step 12?
I know a lot of others (such as Scott Colestock) have done great focused work in the area of deployments. I embarked on this path somewhat by accident. I was on a client project where we were migrating MSIs, BizTalk’s preferred unit of deployment, between environments. I was doing this by exporting an MSI from the admin tool. One day, I forgot to update a binding file (a resource included with the MSI), and proceeded to chase ghosts for a little while when my import was nattering about ports I knew no longer existed. Frustrated, I promised myself this would never happen to me again, and I wrote a little batch file that would automatically update the binding resources for me, I wouldn’t have to remember, I’d just run an “UpdateBizTalkResources.cmd” script, and magic would happen.
That’s how it began, and it just kind of grew organically from there. This blog post is not about how it ends, but I want to share where I am at now. Ever project adds to this, and it has been an iterative process spanning several projects over the past couple of years.
So where am I at? At a client site last year I was able to take a somewhat simple application, and generate an MSI that reduces the deployment time of that robotics-control BizTalk solution to just a few minutes. Everything is scripted, everything is repeatable. At another client site last year, I took a solution that spans perhaps 20 BizTalk projects, and reduced creation of the MSIs (including compilation, etc) to running a series of scripts. Elapsed time to re-gen the 8 MSIs is under 15 minutes, deployment to a green-field pristine BizTalk environment, also under 15 minutes, for all 8 MSIs (which generate 5 separate BizTalk applications). The IT guys on that particular project loved me, as I took their deployments from being a two day “hope this works” process to a 15 minute highly-repeatable process with only a handful of steps.
To those fortunate few among you that have the luxury of being able to spend the time to implement highly-repeatable, highly-scripted, as-touch-free-as-possible build processes, this may seem pretty routine. However, a lot of BizTalk shops don’t have this degree of process implemented.
For the rest of you, I am posting my current script (with some client info removed, removed items are marked by “[” and “]”). Most of it should be self-explanatory, but at a high level, it:
- Creates a log file. All steps that occur, and their results, are recorded in the log
- Compiles the SLN file by calling DEVENV
- Removes the existing BizTalk app and uninstalls it (if it exists) to ensure a clean “not tweaked by a developer” build
- Creates a BizTalk application
- Adds the resources (including binding files for each environment)
- Exports an MSI
In some cases, you’ll need to do more when the application installs, which you can handle with pore and post-processing scripts. For example, in one case, I needed to move DLLs created by the SAP adapter into a specific folder. Just to make it challenging, the target folder changed with environments. Fortunately, I could detect the environment by querying an environment variable, and move the file accordingly. All of that was transparent to the IT Pro who just ran the MSI. In another case, all solution DLLs needed to be put into specific folder locations. In yet another case, while working on the ESB Guidance, Marty, Tom and I wrote scripts that automatically did everything from creating user accounts and app pools through to creating virtual roots and assigning app pools. Post-processing scripts are a powerful tool, you can do a LOT there.
In practice, I develop this script in my development VM. When the time comes to deploy to the integration environment (pre-QA/UAT), I am actually doing my first pass at testing the build/deploy process. Usually, the REAL MSI is created when the script is run on a “build server”. That MSI moves into QA. If everything succeeds and is accepted in QA, then that same MSI (don’t re-generate!) moves into production.
I hope you’ll find the techniques used below help improve the quality and repeatability of your builds, and help to simplify your build and deployment process. As always, I’d welcome any comments/thoughts you all may have on how this can be further improved.
—————————
@echo off
mode con cols=100 lines=120
CLS
SETLOCAL
SET APP_NAME=[name]
SET BIZTALK_APP_NAME=[app name]
SET BinPath=source code\bin
SET BasePath=[path]\Source Code
SET LOG_LOCATION=%CD%\LogFile.txt
REM Uncomment the following line to echo everything out to the screen
REM set LOG_LOCATION=con
SET Database=”BizTalkMgmtDb”
SET Server=”.”
echo ##################################################################################### >> %LOG_LOCATION%
echo %DATE% %TIME% Running %APP_NAME% build script >> %LOG_LOCATION%
echo ##################################################################################### >> %LOG_LOCATION%
echo Setting up…
echo ############# >> %LOG_LOCATION%
echo Setting up… >> %LOG_LOCATION%
echo ############# >> %LOG_LOCATION%
CALL vsvars32.bat
echo Building….
echo ############# >> %LOG_LOCATION%
echo Building …. >> %LOG_LOCATION%
echo ############# >> %LOG_LOCATION%
cd %BasePath%
echo. >> %LOG_LOCATION%
echo ********************************************************************************************** >> %LOG_LOCATION%
echo *** Working in directory: %CD% *** >> %LOG_LOCATION%
echo ********************************************************************************************** >> %LOG_LOCATION%
echo. >> %LOG_LOCATION%
DEVENV ..\..\%APP_NAME%.BizTalk.sln /build Deployment >> %LOG_LOCATION%
IF %ERRORLEVEL% NEQ 0 (
SET msg=Could not build Visual Studio solution
GOTO ErrorRoutine)
rem To ensure we have a clean environment free of any legacy or manually added resources, try to remove and uninstall the app
echo Cleaning environment….
echo ######################## >> %LOG_LOCATION%
echo Cleaning environment…. >> %LOG_LOCATION%
echo ######################## >> %LOG_LOCATION%
BTSTask UninstallApp -ApplicationName:%BIZTALK_APP_NAME% >> %LOG_LOCATION%
BTSTask RemoveApp -ApplicationName:%BIZTALK_APP_NAME% >> %LOG_LOCATION%
BTSTask AddApp -ApplicationName:%BIZTALK_APP_NAME% >> %LOG_LOCATION%
IF %ERRORLEVEL% NEQ 0 (
echo ####################################################################### >> %LOG_LOCATION%
echo #### Warning: BizTalk application %BIZTALK_APP_NAME% already existed. >> %LOG_LOCATION%
echo #### Application is being 1-uninstalled and 2-removed >> %LOG_LOCATION%
echo ####################################################################### >> %LOG_LOCATION%
)
echo *** Adding assemblies generated by SAP adapter to %APP_NAME% resources. The post-processing script will move it to the right folder (destination varies by environment)
BTSTask AddResource /ApplicationName:%BIZTALK_APP_NAME% /Type:System.BizTalk:BizTalkAssembly /Source:”C:\Program Files\Microsoft BizTalk Adapter v2.0 for mySAP Business Suite\Bin\Z_MATERIAL_SPECS.dll” /Destination:”%%BTAD_InstallDir%%\Z_MATERIAL_SPECS.dll” /Server:%Server% /Database:%Database% /Overwrite >> %LOG_LOCATION%
IF %ERRORLEVEL% NEQ 0 (
SET msg=Could not add SAP DLL to BizTalk application
GOTO ErrorRoutine)
echo Adding binding files…
echo ####################### >> %LOG_LOCATION%
echo Adding binding files… >> %LOG_LOCATION%
echo ####################### >> %LOG_LOCATION%
BTSTask AddResource /ApplicationName:”%BIZTALK_APP_NAME%” /Type:System.BizTalk:BizTalkBinding /Server:%Server% /Database:%Database% /Overwrite /Source:”..\..\build\Bindings\%BIZTALK_APP_NAME%_Bindings_DEV.xml” /Property:TargetEnvironment=”Development” >> %LOG_LOCATION%
IF %ERRORLEVEL% NEQ 0 (
echo #################################################################### >> %LOG_LOCATION%
echo #### Warning: could not find DEV binding file >> %LOG_LOCATION%
echo #################################################################### >> %LOG_LOCATION%
)
BTSTask AddResource /ApplicationName:”%BIZTALK_APP_NAME%” /Type:System.BizTalk:BizTalkBinding /Server:%Server% /Database:%Database% /Overwrite /Source:”..\..\build\Bindings\%BIZTALK_APP_NAME%_Bindings_QA.xml” /Property:TargetEnvironment=”Q.A.” >> %LOG_LOCATION%
IF %ERRORLEVEL% NEQ 0 (
echo #################################################################### >> %LOG_LOCATION%
echo #### Warning: could not find QA binding file >> %LOG_LOCATION%
echo #################################################################### >> %LOG_LOCATION%
)
BTSTask AddResource /ApplicationName:”%BIZTALK_APP_NAME%” /Type:System.BizTalk:BizTalkBinding /Server:%Server% /Database:%Database% /Overwrite /Source:”..\..\build\Bindings\%BIZTALK_APP_NAME%_Bindings_PRD.xml” /Property:TargetEnvironment=”Production” >> %LOG_LOCATION%
IF %ERRORLEVEL% NEQ 0 (
echo #################################################################### >> %LOG_LOCATION%
echo #### Warning: could not find PRD binding file >> %LOG_LOCATION%
echo #################################################################### >> %LOG_LOCATION%
)
echo Creating MSI…
echo ############### >> %LOG_LOCATION%
echo Creating MSI… >> %LOG_LOCATION%
echo ############### >> %LOG_LOCATION%
BTSTask ExportApp -ApplicationName:%BIZTALK_APP_NAME% -Package:..\..\build\%BIZTALK_APP_NAME%.msi >> %LOG_LOCATION%
IF %ERRORLEVEL% NEQ 0 (
SET msg=Could not export MSI
GOTO ErrorRoutine)
GOTO :End
:ErrorRoutine
echo #################################################################### >> %LOG_LOCATION%
echo #################################################################### >> %LOG_LOCATION%
echo Error: %msg% >> %LOG_LOCATION%
echo #################################################################### >> %LOG_LOCATION%
echo #################################################################### >> %LOG_LOCATION%
GOTO :End
:End
echo. >> %LOG_LOCATION%
echo. >> %LOG_LOCATION%
echo ##################################################################################### >> %LOG_LOCATION%
echo –> Completed: %DATE% %TIME% Running %APP_NAME% build script >> %LOG_LOCATION%
echo ##################################################################################### >> %LOG_LOCATION%
Technorati Tags: BizTalk
by community-syndication | Jan 27, 2008 | BizTalk Community Blogs via Syndication
You must have read in the documentation that the SAP adapter does not support/honour the timeout values specified on the binding (sendTimeout, openTimeout, etc). However, at times you might yet receive timeout related exceptions from the adapter. Why?
The SAP Adapter uses the SAP RFC SDK Library to communicate with SAP. The API calls in this SDK don’t support timeouts, and hence, when making a call using this API, the adapter is helpless if an API invocation ends up taking a really long time. However, in most of the code paths within the adapter, the adapter performs a bunch of steps – some of them within the adapter, while the rest involving API invocations in the RFC SDK.
Now, as mentioned above, the timeout is not honored during a single API invocation. However, in between API calls, if the adapter determines that a timeout has occurred, then it does throw a TimeoutException.
But why does it throw an ArgumentOutOfRangeException at times? That is a side effect of the internal implementation; however, the error message might be something to the tune of “Timeout must be greater than or equal to TimeSpan.Zero”, indicating a timeout related exception.
If you find such exceptions common in your environment, you should increase the sendTimeout value on the SAPBinding (the default is 1 minute, which might be insufficient when sending IDocs or executing BAPIs with a large amount of data, for example).
by community-syndication | Jan 27, 2008 | BizTalk Community Blogs via Syndication
You must have read in the documentation that the SAP adapter does not support/honour the timeout values specified on the binding (sendTimeout, openTimeout, etc). However, at times you might yet receive timeout related exceptions from the adapter. Why?
The SAP Adapter uses the SAP RFC SDK Library to communicate with SAP. The API calls in this SDK don’t support timeouts, and hence, when making a call using this API, the adapter is helpless if an API invocation ends up taking a really long time. However, in most of the code paths within the adapter, the adapter performs a bunch of steps – some of them within the adapter, while the rest involving API invocations in the RFC SDK.
Now, as mentioned above, the timeout is not honored during a single API invocation. However, in between API calls, if the adapter determines that a timeout has occurred, then it does throw a TimeoutException.
But why does it throw an ArgumentOutOfRangeException at times? That is a side effect of the internal implementation; however, the error message might be something to the tune of “Timeout must be greater than or equal to TimeSpan.Zero”, indicating a timeout related exception.
If you find such exceptions common in your environment, you should increase the sendTimeout value on the SAPBinding (the default is 1 minute, which might be insufficient when sending IDocs or executing BAPIs with a large amount of data, for example).