Wednesday, September 26, 2007

BizTalkDTADb (Suspect)

While trying to undeploy a Biztalk BRE Policy, I had this error:
Error inserting tracking information for ruleset "Final_WI_EmpMedical_HospitalCare" version 1.0 into the tracking database: Error encountered while connecting to database: "Initial Catalog=BizTalkDTADb;Data Source=xxxxx;Integrated Security=SSPI;"
Looking at the Management Studio, I soon discover that the tracking database was marked as suspect.



a quick google for it, turn out some instructions to get the DB out of the suspect state. I have tried most of them (reset status, emergency mode, detach data files, DBCC with data loss, etc.)



However, nothing seems to be able to get this database out of that status. The Sql configuration manager was taking a long time to execute a refresh. I have tried to shut down the SQL Agent service, and it was not allowing me to stop it.

Then I decided to check on the System event log and I found this entry in there:
The driver detected a controller error on \Device\Harddisk0.
hummmm... Nothing else seems to be wrong. Then the BiztalkMsgboxDb went into suspect mode as well.

I went ahead and reboot this server. However, it did not come back and it was giving me the gray screen on the Virtual Server Manager. Running out of time, and being pressure to get this machine up and running, I hit the PANIC button and undo all changes (Turn Off Virtual Machine and Discard Undo Disks)



Now the machine is back and running fine. I have started deploying all of my artifacts and BRE's to it. Then I noticed than on the other VPC's I have the same message on the system event log.

Jim Holmes pointed out that I should be looking at the Host Event Log instead, and yes, there it was:
The volume "E" only has 0 MB of space left. The virtual hard disk "E:\Virtual Machines\bztXXXXX\VirtualPCUndo_biztalkXXXXX_0_0_0_14495508212007.vud" associated with the virtual machine "biztalkXXXXX" has been expanded, and very little space remains. The virtual machine will be paused.
It would have been nice to see this error somewhere else, but I guess I have learned to not hit the PANIC button to soon and start thinking outside the box.

Like BLindman says "...the error in front of you might just be the symptom of a bigger issue..."

I am wiser now.

Sunday, September 16, 2007

Microsoft.RuleEngine.XmlHelper

Recently I have a requirement for a project involving the use of the BRE. The customer wanted to know which rules were being evaluated. They wanted to know the outcome of each of the business rules as they were applied to the facts submitted. More importantly, they wanted to know why *each* of the rules failed.

Here are the requirements
NumberDays >= 300
StateEmployment = OH
HoursWorked >= 1000
Gender = M
Condition = Final
The solution to these requirements was to implement a MAIN Policy that will test and evaluate for all conditions. Then writing a single business rule for each fact and negating that, would take care of the reasons for the policy to fail.

To maintain a list of those failed business rules, we can make use of the XMLHelper class that comes with the Business Rule Engine Assembly.

The first step is to add a reference to Microsoft.RuleEngine assembly. On the .NET Classes tab, right click and select Browse.


Now select the Microsoft.RuleEngine assembly.


After you click OK, you can see all of the interfaces exposed by this assembly. Select the Microsoft.RuleEngine.XMLHelper one, and you will see the methods


As you can see, there are several overloaded methods for the AddNode function. We will use this function to keep track of executed business rules.
Here is the schema that I will be using to illustrate the use of this handy feature:

I will be evaluating the information in the INPUT node, and I will be updating the information on the OUTPUT node. Inside the RulesApplied, there will be a node of RULE that will contain each business rule that was evaluated.

Here is the sample output xml that I should get after the BRE executes:

    1 <ns0:Root xmlns:ns0="http://AW.SampleSchema.v1">
    2     <Input>
    3         <NumberDays>300</NumberDays>
    4         <StateEmployment>OH</StateEmployment>
    5         <HoursWorked>1000</HoursWorked>
    6         <Gender>X</Gender>
    7         <Condition>yxyxyx</Condition>
    8     </Input>
    9     <Output>
   10         <OutputStatus>false</OutputStatus>
   11         <RulesApplied>
   12             <Rule>
   13                 <RuleName>negGender</RuleName>
   14                 <RuleMessage>not a valid gender</RuleMessage>
   15             </Rule>
   16             <Rule>
   17                 <RuleName>negCondition</RuleName>
   18                 <RuleMessage>not a valid condition</RuleMessage>
   19             </Rule>
   22         </RulesApplied>
   23     </Output>
   24 </ns0:Root>

For this implementation, I will have one main business rule and 5 negative rules that will give me the reasons for failure.



The MainTest would look like this:


and each of the negative test will be a single test with the NOT predicate:


For the actions, I will be adding a RULE node to each negative rule. The important thing to remember in this xmlHelper is the xpath function:
./Rule[position()=last()]

This xpath function will place the insert location at the last position.

The Actions panel for the Main test will be:


The Actions panel for the negative rules will look something like this:


Notice that the first action is a call to the XmlHelper.AddNode. This will add the parent node named Rule.

Then there are 2 calls to the XmlHelper.AddNodeWithValue. These calls will add the child nodes and their corresponding value.

The default value for the outputStatus field is set to False by default. Then I only update that value if the MainTest passes.

Ahh. more importantly, read this article from Richard Seroter regarding static objects. You will need to add a value on the registry to get this function to work. On a windows 2003, the location will be:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\BusinessRules\3.0\StaticSupport

but on a Vista x64, the location is HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\BusinessRules\3.0\StaticSupport

Wednesday, September 12, 2007

Internal SOAP Processing Failure at Microsoft.BizTalk.WebServices.ServerProxy.Invoke

Searching for that Beautiful code, I have decided to do some refactoring of an existing ODX that gets published as a web service and gets consumed by another .NET application. This ODX was like the diamond on the rock. Except I did not name the schemas correctly to begin with. So I went ahead and change the schema and their types, etc...

Long story short, it executed almost all of the ODX, but it will always fail at the end with the Internal Soap Error. :@

SOAP exception error:
    1 The Web service returned an exception.
    2 System.Reflection.TargetInvocationException: 
    3 Exception has been thrown by the target of an invocation. 
    4 System.Web.Services.Protocols.SoapException: 
    5  Internal SOAP Processing Failure 
    6 at Microsoft.BizTalk.WebServices.ServerProxy.ServerProxy.Invoke(String functionName, Object[] parameters, ParamInfo[] inParamInfos, ParamInfo[] outParamInfos, Int32 bodyPartIndex, String bodyType, ArrayList inHeaders, ArrayList inoutHeaders, ArrayList& inoutHeaderResponses, ArrayList& outHeaderResponses, Type[] outHeaderTypes, String[] outHeaderNamespaces, SoapUnknownHeader[] unknownHeaders, SoapUnknownHeader[]& unknownHeaderResponses, Boolean oneway, Boolean spsSsoEnabled, Object cookie)
    7 at Microsoft.BizTalk.WebServices.ServerProxy.ServerProxy.Invoke(String functionName, Object[] parameters, ParamInfo[] inParamInfos, ParamInfo[] outParamInfos, Int32 bodyPartIndex, String bodyType, ArrayList inHeaders, ArrayList inoutHeaders, ArrayList& inoutHeaderResponses, ArrayList& outHeaderResponses, Type[] outHeaderTypes, String[] outHeaderNamespaces, SoapUnknownHeader[] unknownHeaders, SoapUnknownHeader[]& unknownHeaderResponses, Boolean oneway, Boolean spsSsoEnabled)
    8 at BRE.Application.BRE_Application_EligibilityResolver_SoapEligibilityPort.GetEligibility(CustomerCaseRoot part)
    9 at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
   10 at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
   11 at BRE_Application_EligibilityResolver_SoapEligibilityPort.GetEligibility(CustomerCaseRoot CustomerCaseRoot)
   12 
   13 
   14 --- End of inner exception stack trace ---
   15 at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   16 at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   17 at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   18 at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   19 at WebServiceStudio.MainForm.InvokeWebMethod()

this error is not the most useful error found. After re-starting all of my process from scratch (delete the application, the bindings, restart the host, restart VStudio), then I still could not find the offending bug.

Usually when I find myself trashing for more than an hour, I try to get some help in the form of "pair-debugging", so I asked my friend Monish to pair with me. After finding out that I had the wrong receive pipelines (PassThru Transmit instead of XML [default behavior when publishing through the wizard]). we got this other error:


    1 A response message sent to adapter "SOAP" 
    2 on receive port "WebPort_EligibilityService/AppEligibilityResolverSoapPort" 
    3 with URI "/EligibilityService/AppEligibilityResolverSoapPort.asmx" 
    4 is suspended. 
    5 Error details: There is an error in XML document (33, 25). 
    6 MessageId:  {3460C12E-A95A-4108-8112-63244EA9D10D}
    7 InstanceID: {C9B8E15C-FF4E-4B36-AFD3-1550B83AE01D}


which seems to point to an XML validation. :D

Now we are getting somewhere.!! On my refactoring of the schemas for BizTalk, I have changed all of the ID's from INT to string, *ALL* of them except one... ;)

Lesson learned: Either get a smart friend named Monish, or be prepare to spend lots of time if you refactor Biztalk schemas.

Friday, September 07, 2007

How to access BRE Vocabularies from .NET

Let's assume that you need to access a Biztalk Business rules vocabulary definitions from a .NET assembly. You need to understand how the BRE API is setup to handle this.

Let's create a vocabulary with a definition constant of type string:



Now create the definition with the type of string as follows:



Exporting this vocabulary using the Business Rules Engine Deployment Wizard, the xml will look like this: [notice all 6 fields in green...]

1
<?xml version="1.0" encoding="utf-8"?>
    2 <brl xmlns="http://schemas.microsoft.com/businessruleslanguage/2002">
    3   <vocabulary id="1d3ad67e-1ed3-46ed-88a7-23199eef8fcd" name="Sample_ValidNames" uri="" description="">
    4     <version major="1" minor="0" description="" modifiedby="LocalDC\awing" date="2007-09-07T21:55:45.545-04:00" />
    5     <vocabularydefinition id="cdff8b38-e565-4942-b76f-72161449a457" name="Definition1_DefinitionName" description="Definition1_DefinitionDescription">
    6       <literaldefinition type="string">
    7         <string>Definition1_DefinitionValue</string>
    8       </literaldefinition>
    9       <formatstring language="en-US" string="Definition1_DefinitionDisplayName" />
   10     </vocabularydefinition>
   11   </vocabulary>
   12 </brl>

To access the different part of this vocabulary, I use this C# code to access all of the parts for this vocabulary definition.

Add the namespaces:

    1 using System.Diagnostics;
    2 using Microsoft.RuleEngine;

then copy the following code:

    1         public void GetAllDefinitionsFromVocabulary(string vocabularyName)
    2         {
    3             RuleStore breStore;
    4             RuleSetDeploymentDriver breDriver = new RuleSetDeploymentDriver();
    5 
    6             breStore = breDriver.GetRuleStore();
    7             Trace.WriteLine(string.Format("bts- ## Vocabulary:[{0}] ##", vocabularyName));
    8             Trace.WriteLine("bts-");
    9 
   10             VocabularyInfoCollection breVocInfoCol;
   11             breVocInfoCol = breStore.GetVocabularies(vocabularyName, RuleStore.Filter.All);
   12             foreach (VocabularyInfo oVoc in breVocInfoCol)
   13             {
   14                 Vocabulary _vocab = breStore.GetVocabulary(oVoc);                
   15 
   16                 foreach (VocabularyDefinition vocDefn in _vocab.Definitions)
   17                 {
   18                     ///string x = o["en-US"].Format;
   19                     Trace.WriteLine(string.Format("bts- Definition.Id: [{0}]", vocDefn.Id));
   20                     Trace.WriteLine(string.Format("bts- Definition.Name: [{0}]", vocDefn.Name));
   21                     Trace.WriteLine(string.Format("bts- Definition.Description: [{0}]", vocDefn.Description));
   22 
   23                     LiteralDefinition literalDefinition = vocDefn as LiteralDefinition;
   24 
   25                     //literaldefinition
   26                     if (literalDefinition != null)
   27                     {
   28                         if (literalDefinition.Value != null)
   29                         {
   30                             Trace.WriteLine(string.Format("bts- literal: [{0}]", literalDefinition.Value.ToString()));
   31                         }
   32                     }
   33 
   34                     //formatstring definition
   35                     foreach (FormatString frm in vocDefn.FormatStrings)
   36                     {
   37                         Trace.WriteLine(string.Format("bts- frm.Language: [{0}]", frm.Language));
   38                         Trace.WriteLine(string.Format("bts- frm.Format: [{0}]", frm.Format));
   39                     }
   40 
   41                     Trace.WriteLine("bts- ----------------------------------");
   42                 }
   43             }

So if I call my method with the vocabulary name = Sample_ValidNames. Then in DebugView you can see that we get all 6 fields that we set on the wizard and on the XML exported file.

    1 [5844] bts- ## Vocabulary:[Sample_ValidNames] ## 
    2 [5844] bts- 
    3 [5844] bts- Definition.Id: [cdff8b38-e565-4942-b76f-72161449a457] 
    4 [5844] bts- Definition.Name: [Definition1_DefinitionName] 
    5 [5844] bts- Definition.Description: [Definition1_DefinitionDescription] 
    6 [5844] bts- literal: [Definition1_DefinitionValue] 
    7 [5844] bts- frm.Language: [en-US] 
    8 [5844] bts- frm.Format: [Definition1_DefinitionDisplayName] 
    9 [5844] bts- ---------------------------------- 
   10 [5844] bts- Done 

There, hope this helps someone. [dont forget to post your comment if this code helps you out.. ;)

Wednesday, September 05, 2007

Removing Strong named assembly from GAC

I have created a .NET helper to provide me access to the BRE. In Vista, I stumbled upon this weird error. Everything has been working fine for the past month or so, now I am trying to deploy a newer version of this .NET helper, and I found that I could not un-deploy this assembly from the GAC.

After closing all programs, I still see this reference:


Looking at the Process Explorer I find that there is an instance of the MMC running. BTW, if you use regular Task Manager, you wont even see this instance. This instance has this command:


"C:\Program Files (x86)\Microsoft BizTalk Server 2006\BTSmmc.msc" "C:\Program Files (x86)\Microsoft BizTalk Server 2006\BTSmmc.msc" -32
Funny thing is that I can't kill this process in my explorer. When I try killing it from the Process Emplorer, it gives me this error:
Error opening process: The parameter is incorrect.
If I try to un-install it from the GAC directly (right-click on assembly), I get this error:
Assembly Cache Viewer = Uninstall failed
Access is denied: 'BRE.EDSHelper'

Running out of ideas, I decided to run the gacutil with elevated privileges in Vista.

Yeap, that did the trick... :D
gacutil /u BRE.EDSHelper
    1 C:\Windows\system32>gacutil /u bre.edshelper
    2 Microsoft (R) .NET Global Assembly Cache Utility.  Version 2.0.50727.42
    3 Copyright (c) Microsoft Corporation.  All rights reserved.
    4 
    5 
    6 Assembly: bre.edshelper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=47ef5031caf5d372, processorArchitecture=MSIL
    7 Uninstalled: bre.edshelper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=47ef5031caf5d372, processorArchitecture=MSIL
    8 Number of assemblies uninstalled = 1
    9 Number of failures = 0

Ahhh UAC is a beautiful and dangerous feature. And yet, I still keep it turn on (it rocks...;)