Showing posts with label Biztalk 2006. Show all posts
Showing posts with label Biztalk 2006. Show all posts

Wednesday, August 06, 2008

BizTalk Business Rules Engine Handy functions in .NET

Working with the BizTalk 2006 R2 BRE api, I find myself going back to this code to start of as a base. These 2 functions get ALL of the versions of the policies or vocabularies.  If you want to work with only the latest, or the published ones, change the RulesStore.Filter enum to whatever your needs.

List of Policies

   1: public void GetPoliciesList()
   2: {
   3:     Microsoft.BizTalk.RuleEngineExtensions.RuleSetDeploymentDriver breDriver =
   4:         new Microsoft.BizTalk.RuleEngineExtensions.RuleSetDeploymentDriver();
   5:     Microsoft.RuleEngine.RuleStore breStore = breDriver.GetRuleStore();
   6:  
   7:     Microsoft.RuleEngine.RuleSetInfoCollection colPolInfo = null;
   8:     colPolInfo = breStore.GetRuleSets(RuleStore.Filter.All);
   9:     foreach (RuleSetInfo pInfo in colPolInfo)
  10:     {
  11:         Trace.WriteLine(string.Format("bts- Info = [{0}].v.{1}.{2}",
  12:             pInfo.Name, pInfo.MajorRevision, pInfo.MinorRevision));
  13:  
  14:         //get the policies to extract rules
  15:         Microsoft.RuleEngine.RuleSet pol = breStore.GetRuleSet(pInfo);
  16:         Trace.WriteLine(string.Format("bts- Count = [{0}]", pol.Rules.Count));
  17:     }
  18: }

This is how to get a list of all policies published on the BRE database.  Once you get all of the RuleSets, you can loop through each of them to retrieve the actual rules behind them.  Before getting to the rules, you need to get a RuleSet out of the RuleSetInfo.


List of Vocabularies



   1: public void GetVocabulariesList()
   2: {
   3:     Microsoft.BizTalk.RuleEngineExtensions.RuleSetDeploymentDriver breDriver = 
   4:         new Microsoft.BizTalk.RuleEngineExtensions.RuleSetDeploymentDriver();
   5:     Microsoft.RuleEngine.SqlRuleStore sqlRuleStore = (SqlRuleStore)breDriver.GetRuleStore();
   6:  
   7:     Microsoft.RuleEngine.VocabularyInfoCollection colVocInfo = null;
   8:     colVocInfo = sqlRuleStore.GetVocabularies(RuleStore.Filter.All);
   9:     foreach (VocabularyInfo vInfo in colVocInfo)
  10:     {
  11:         Trace.WriteLine(string.Format("bts- vInfo = [{0}].v.{1}.{2}",
  12:             vInfo.Name, vInfo.MajorRevision, vInfo.MinorRevision));
  13:  
  14:         //get the vocabulary to extract collection of definitions
  15:         Microsoft.RuleEngine.Vocabulary voc = sqlRuleStore.GetVocabulary(vInfo);
  16:         Trace.WriteLine(string.Format("bts- Count = [{0}]", voc.Definitions.Count));
  17:     }
  18: }

This is how to get a list of all vocabularies published on the BRE database.  If you need to see how to get to all of the definitions on a particular vocabulary, see my previous post: How to access BRE Vocabularies from .NET.


Noticed that there are some subtle differences in how you retrieve each piece of information.  For Policies you get a RuleStore while to get the Vocabularies you need to get a SQLRuleStore.


As usual, feedback is always welcome if you use this code.

Tuesday, July 29, 2008

Deploying Business Rules using C# in BizTalk 2006 R2

In one of my last project, I have been working extensively with the Business Rules Engine in BizTalk. This project contains some complex Federal/State/Company/ rules. Being a Health Management Care related project I have to deal with many issues like requirements, changing policies, rules scope to a certain type, etc.

Delivering this project took some time and effort.  Not only the requirements were *agile*, but trying to keep compliance with SOX laws was a challenge.  I can summarized all of the requirements to these 3:

Requirements:

  1. Policies have to be atomic (independent from changes to other policies)
  2. Versionning of policies and being able to execute ANY version, any time.
  3. Need to know which facts were used to determine an outcome.

For the main requirement, I have created a Master Rule that determine the outcome, then I've created several *supporting* rules that will help me determine which of the rules were evaluated. The versionning requirement was already implemented by the BRE in BizTalk.

a sample of this would be something like this:

image

It quickly became very obvious that I have to deal with lots of policies and vocabularies.  If you ever tried using the Rules Deployment Wizard, you will see that it only allows you to export a SINGLE policy at a time.  Having over 500+ policies and over 30+ vocabularies  was not going to work out.

I have found the DeployRules.exe application written by Sreedhar Pelluru from Microsoft.  Here is the original article.  I took his program and modified to meet my needs.  Since I was only testing a set of policies at a time (i.e. Federal policies only), this tool provide me the ability to only load those policies that were relevant to the type I was working on. 

I know I have learned a lot about the BRE api from reading his well documented code.  With his permission, I have posted his original work and the modifications done to it back to the community at http://www.codeplex.com/DeployRules.  Yes it is still a work in progress.

Hope this help someone out there.

Tuesday, July 08, 2008

Importing BRE Vocabulary with Multiple versions

If you ever tried merging all of the versions of a single vocabulary into one XML file, so that you can import it on a single task, you will find that even though the Rules Engine Deployment Wizard understand the file format, it has a huge limitation [Bug..?  ;) ].  It only imports the last version of a vocabulary into the Rules Engine.

image

A sample vocabulary with 2 versions.

image

When Exporting this vocabulary I can't export all versions at once.  I have to export a single version at a time.!!

However, on the import, you can import a file that can contain multiple versions on it:

image

Once you export all individual files, you can merged them into a single xml file.

The format of the merged exported vocabulary will be something like this:

<brl xmlns="http://schemas.microsoft.com/businessruleslanguage/2002">   

  • <vocabulary id="9ab458cc-427a-4cea-bb1d-224dd5f96d98" name="CustomerLevels" uri="" description="">
            <version major="1" minor="1" description="" modifiedby="awing" date="2008-07-07T23:22:33.401-04:00"/>
            <vocabularydefinition id="b36b276e-451d-4783-8a06-623823211f85" name="Silver" description="Silver Description">
                ....................
        </vocabulary>

   

  • <vocabulary id="2422362a-77c0-4d0f-b2aa-fe6c1fe1f1d7" name="CustomerLevels" uri="" description="">
           <version major="1" minor="0" description="" modifiedby="awing" date="2008-07-07T22:39:37.19-04:00"/>
            <vocabularydefinition id="ba912d07-f96d-49ac-a2c4-e619fcec027e" name="Silver" description="Silver Description">
                ........................
        </vocabulary>

</brl>

As you can see there you can add as many versions to this file as you want.  However, the ReDeployWiz.exe only publish and import the latest one.

Trying to figure out why this is the behavior, I used my good old friend Reflector. Bringing Reflector on the Rules Engine Deployment Wizard, I see that there is a call to the RuleSetDeploymentDriver namespace. This doImport method calls the driver.ImportAndPublishFileRuleStore to import and publish at the same time.

RuleSetDeploymentDriver

image

It seems that there is no way around this call.  It seems to be a limitation on the use of the tool.  This ImportAndPublishFileRuleStore seems to only work on a single version at a time.  If you split the versions into their own file, it can handle it. The down side of this, is that you need to make multiple calls for an import.  And let's face it, the whole nature of versioning the policies and vocabularies becomes very cumbersome when you have over 500+ rules with multiple versions in them [yes, my current project has over 500+ policies and over 30+ vocabularies]

To get around this limitation on the tool, you will have to write your own application to deploy/export all versions of a vocabulary.  To accomplish this you will need to to call the SqlRuleStore namespace instead of the RuleSetDeploymentDriver.  This namespace have the ADD method which contain several overloaded parameters. One of which it allows you to publish or not publish your vocabulary.

image

Here is my sample code to import ALL versions of a vocabulary in .NET code:

    1 private static int ImportVocabulary(string filename)
    2 {
    3     int result = 0;
    4     // FileRuleStore - gives access to the BRL (XML) file containing policies and vocabularies
    5     FileRuleStore fileRuleStore = null;
    6 
    7     // RuleSetDeploymentDriver has the following important methods            
    8     Microsoft.BizTalk.RuleEngineExtensions.RuleSetDeploymentDriver dd = new Microsoft.BizTalk.RuleEngineExtensions.RuleSetDeploymentDriver();
    9 
   10     // SqlRuleStore - gives access t0 the rule engine database
   11     SqlRuleStore sqlRuleStore = (SqlRuleStore)dd.GetRuleStore();
   12 
   13     //Get VocabularyInfoCollection object based on the file
   14     fileRuleStore = new FileRuleStore(filename);
   15     VocabularyInfoCollection vocabularyInfoList = fileRuleStore.GetVocabularies(RuleStore.Filter.All);
   16     foreach (VocabularyInfo vocabularyInfo in vocabularyInfoList)
   17     {
   18         string vocabularyNameWithVer = string.Format("{0}.{1}.{2}", vocabularyInfo.Name, vocabularyInfo.MajorRevision, vocabularyInfo.MinorRevision);
   19         ExtractVocabularyNameMajorMinor(vocabularyNameWithVer);
   20         VocabularyInfo vi = new VocabularyInfo(App.vocabularyName, App.vocabularyMajorVer, App.vocabularyMinorVer);
   21         Vocabulary oVoc = fileRuleStore.GetVocabulary(vi);
   22         sqlRuleStore.Add(oVoc, App.publishVocabulary);
   23     }
   24     return result;
   25 }

There, now you don't have to be bound to import a single vocabulary version every time you need to move your rules from DEV to UAT to PROD.


Hope this saves someone lots of time and grief.  Happy BRE'ing... ;)

Wednesday, May 14, 2008

Distinguished fields of type xs:dateTime not Working on Orchestrations

Writing a spyke for a simple program, I came out with this odd behavior when I try to compile my BizTalk project.

image

I have created a simple schema, and in one of the fields I have field of type xs:dateTime. Well, when I have tried to use this field on an expression shape, I get this build compiler error:

'System.Xml.XmlDocument' does not contain a definition for 'XXXX'

where XXXX is the field name of the element that I have declared as a xs:dateTime type. I then went and set it up as a distinguished field. Here is a sample generated xml from my test schema:

  1. <ns0:Customer xmlns:ns0="http://DistingProperty.Test.Customer.v1">
    <FName>FName_0</FName>
    <DOB_datetime>1999-05-31T13:20:00.000-05:00</DOB_datetime>
    <DOB_date>1999-05-31</DOB_date>
    </ns0:Customer>

and this is the schema that I have used


image

When I am trying to use the distinguished field inside an expression shape, noticed that I get the Visual Studio IntelliSense:

image

When you try to read this value, it will always complain about the XmlDocument not being able to find the definition for the field that is defined as DateTime.

To get around this, you should use the System.Convert.ToString() instead of the .ToString() function;


1 Trace.WriteLine(" bad:[" + msgIN.DOB_datetime.ToString() + "]");

2 Trace.WriteLine("good:[" + System.Convert.ToString(msgIN.DOB_datetime) + "]");



Another lengthy way to get around this issue is to assign the distinguish field to an xmlNode and then use the xml Namespace Manager to get to the node value instead.

The code on my expression shape looks like this:


1 System.Diagnostics.Trace.WriteLine("bts- In here");

2

3 //assign values to person

4 xDoc = msgIN;

5

6 xmlnsMgr = new System.Xml.XmlNamespaceManager(xDoc.NameTable);

7 xmlnsMgr.AddNamespace("ns0", "http://DistingProperty.Test.Customer.v1");

8

9 xNode = xDoc.SelectSingleNode("/ns0:Customer/DOB_datetime", xmlnsMgr);

10 System.Diagnostics.Trace.WriteLine("bts-[" + xNode.OuterXml + "]");

11

12 xNode = xDoc.SelectSingleNode("/ns0:Customer/DOB_date", xmlnsMgr);

13 System.Diagnostics.Trace.WriteLine("bts-[" + xNode.OuterXml + "]");

14

15 //this works as expected

16 System.Diagnostics.Trace.WriteLine("bts- " + msgIN.FName);

17


Which ever way you choose, this looks like a limitation on the way the XLANG/s in the Expression shape interprets the command code.

Friday, February 29, 2008

Grok talk on Business Rule Engine Essentials

I have presented a grok on BRE essentials tonight at our monthly Solutions Group meeting.  The main focus on my presentation was to give a quick glance at what is available to developers when they enter the realm of BizTalk.  Some smart guy once said that knowing what's available out there is half the battle.

Anyways, the main points of my talk was to show how you can interface with the BRE (from BRE to .NET, and from .NET to BRE).  I have found the BizTalk rules engine to be very efficient and fast.  In the last project we have, we had over 450+ policies, and each policy had an average of about 5-7 rules on each of them.  On top of that I had an orchestration that call the vocabularies, determine the policy that needed to be executed, and then execute that policy.  The time for all of this to happen, is between 1-2 seconds from the time the message enter BizTalk to the time it gets send back to the calling routine.

How do you show this much functionality in 20 minutes or less?  Well, I came out with this fictitious company that had the following requirements:

image

The first thing that you do in BizTalk is that you need to define the schemas that will contain the inputs and output of the message that you are dealing with.  So a simple schema:

image

Next, I have implemented those rules in the BRE composer

image

So now that I have the rules implemented, we need to get a way to call them and executed them.  Here is the sample solution code that will call this policy.

I have also included some code that shows how to call the vocabulary.  And some code to show how to implement a .NET assembly that can be called from the BRE.

image 

 

Feedback [good|bad] is always welcome.  Hope this help someone get a small peek into the vast universe of BizTalk.

Friday, November 16, 2007

How to install assembly to GAC on build event

I keep forgetting this line, and end up having to dig it out from other projects. I am putting it in here so that I can access it faster.

Basically, every time you build/rebuild your .NET assembly, it needs to be in the GAC for BizTalk to be able to use it. So, I put this code on the Build Events to move the assembly to the GAC.


"C:\Program Files (x86)\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe" /i $(TargetFileName)
there. Now I won't forget.

Wednesday, October 24, 2007

Evaluation Period has expired

I have run into this issue today. I was trying to update some business rules on a client's computer. They have a SQL and a separate BizTalk environment. So I have tried opening the SQL Management Studio from the BizTalk box, and I got this dialog box:


it says:
Evaluation period has expired. For information on how to upgrade your evaluation software please go to http://www.microsoft.com/sql/howtobuy
which of course takes you to a Microsoft Page not found. ;)

Apparently, they had installed the evaluation trial version of SQL Server 2005 client tools. BTW, this was never an issue with SQL Server 2000. If you went and installed the client tools, they did not expire.!

I put the Enterprise SKU binaries for SQL Server 2005, and ran the Setup.exe from the tools directory, and then I got this information:



clicking on the messages details, it mentions this:
- Edition Change Check (Warning)
Messages
  • Edition Change Check
  • To change an existing instance of Microsoft SQL Server 2005 to a different edition of SQL Server 2005, you must run SQL Server 2005 Setup from the command prompt and include the SKUUPGRADE=1 parameter.


FYI, you will need to run the setup.exe that is located in the SERVERS folder and not on the tools folder. Bring up a command prompt window and execute the
cmd> SETUP.exe SKUUPGRADE=1
then after running through the wizard, it will upgrade your SQL Management version to not be the trial version.



ahhh, that's much better.!

Monday, October 08, 2007

C# Generated code from Biztalk Orchestrations

Sometimes you get some odd error messages on your Orchestrations. And it gives you the line number where the error is occurring. To get to the source code generated from the XLang when it is creating the C# code, you can use this is old trick from the 2004 days.

It is still valid in Vista x64 and Biztalk 2006. :D

Open your registry and look for the following hive:
HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\8.0
now create a key named BiztalkProject

under this key, add a DWORD named GenerateCSFiles. Set the value to 1.




Now, close all instances of Visual Studio. Open a new instance of Visual Studio and create a Biztalk project


Build it. After it built, click on Show All Files:


Bingo, you will see the C# code:

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...;)