Thursday, December 13, 2007

COM Interop with .NET 2.0

For the month of December I am working on this small project (3-weeks) involving making some information available to end users through a mobile device. Yeah, that's cool. However, the code that grabs the information from the backend was all written in good old VB6 and classic ASP.

I am running into this one issue that is driving me nuts. I am trying to assign a class object to a property in the COM object. While it works for some properties/methods, it does not seem to be working for some other.


VB6 code that works:
[
    1 Private mAuthor As clsSomething
    2 Private mAuthorID As Long
    3 
    4 Public Property Get Author_ClassParam() As clsSomething
    5     On Error GoTo handleError
    6 
    7     If mAuthor Is Nothing Then
    8         If mObjectID = 0 Then
    9             Err.Raise 111, , "xxx item not initialized"
   10         End If
   11 
   12         Set mAuthor = New clsSomething
   13         [--- deleted stuff---]
   14 
   15     End If
   16     Set Author = mAuthor
   17     Exit Property
   18 
   19 handleError:
   20     mError.Raise Err.number, "[xxxxHistoryItem]" & Err.Description, False
   21     Set Author = Nothing
   22 End Property
   23 
   24 Public Property Set Author_ClassParam(ByVal value As clsSomething)
   25     Set mAuthor = value
   26 End Property
]

VB6 code that does not works:
[
    1 Private mAuthor As clsSomething
    2 Private mAuthorID As Long
    3 
    4 Public Property Get Author_VariantParam() As clsSomething
    5     On Error GoTo handleError
    6 
    7     If mAuthor Is Nothing Then
    8         If mObjectID = 0 Then
    9             Err.Raise 111, , "xxx item not initialized"
   10         End If
   11 
   12         Set mAuthor = New clsSomething
   13         [--- deleted stuff---]
   14 
   15     End If
   16     Set Author = mAuthor
   17     Exit Property
   18 
   19 handleError:
   20     mError.Raise Err.number, "[xxxxHistoryItem]" & Err.Description, False
   21     Set Author = Nothing
   22 End Property
   23 
   24 Public Property Set Author_VariantParam(ByVal value As Variant)
   25     Set mAuthor = value
   26 End Property
]


this is the .NET code that calls that VB6 COM object:
[
    1 public void ClassAssignment_COM()
    2 {
    3     clsSomething oAuthor = new clsSomething();
    4     oAuthor.AuthorID = 15;
    5 
    6     clsTransaction oTrnx = new clsTransaction();
    7     oTrnx.Author_ClassParam = oAuthor;
    8     Trace.WriteLine(String.Format("bts- ClassParam.AuthorID: [{0}]", oTrnx.Author_ClassParam.AuthorID));
    9 }
   10 
   11 public void VariantAssignment_COM()
   12 {
   13     clsSomething oAuthor = new clsSomething();
   14     oAuthor.AuthorID = 15;
   15 
   16     clsTransaction oTrnx = new clsTransaction();
   17     oTrnx.Author_VariantParam = oAuthor;
   18     Trace.WriteLine(String.Format("bts- VariantParam.AuthorID: [{0}]", oTrnx.Author_VariantParam.AuthorID));
   19 }
]

I get this error message at compile time:
Error 3 Property, indexer, or event 'Author_VariantParam' is not supported by the language; try directly calling accessor methods 'xxxx._clsTransaction.get_Author_VariantParam' or 'xxxx._clsTransaction.set_Author_VariantParam(object)'
C:\vsProjects\Tests\mock.cs 168 27 xxxx.yyyApplication.Web.Test


I have not found a solution to this problem. I know that variants are not supported in .NET, but com'on, there's got to be someone out there that knows a workaround this issue...

Wednesday, November 21, 2007

How to edit rich text in SharePoint 2007 forms

Since I have been using Window Live Writer, I have not had the need to write all of that html code (what is HTML?). I edit using Live Writer, and then I switch to HTML view, copy and paste the formatted text into the SharePoint text box. I thought it was weird that Microsoft will only give a blank text box and you need to go and figure out all of the markup tags.



Then I saw on this other developer screen that his text boxes look a lot different from mine..!!



Clicking on the
Click for help about adding HTML formatting.
just take you to the normal help, nothing useful there.

Well, I found out that it was just another x64 vs x32 bit kind of deal. Since moving to the 64bit bandwagon, I almost exclusively use Internet Explorer (64 bit). It is a great way to get to the Microsoft sites without being bogged down by all of the flash advertisement (oh yeah, those flash do not work on 64bit... ;)

However, there is a whole new world out there if you use the 32bit version of Internet Explorer.!!

yikes.

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.

Thursday, November 15, 2007

Enum.Parse

I had this issue, in which in one of my C# class, I had a enum type. Then I wanted to send a string to a method, which will populate this object. The problem was that the enum type was an integer, and I was passing a string down to the object.

    1 public enum ProductTypeEnum : int 
    2 {
    3     blue = 10,
    4     red = 20,
    5     green = 30
    6 } 

Here is the class that I was using to populate with values:

    1 public void GetDiscountTest_BLUE_Preferred()
    2 {
    3     OrderDetail inOrder = new OrderDetail();
    4     inOrder.ProductType = (Int32) ProductTypeEnum.blue;
    5     inOrder.Quantity = 100;

Now, I wanted to replace the code with something like this:

    1 public void GetDiscountTest_BLUE_Preferred(string sColorName)
    2 {
    3     OrderDetail inOrder = new OrderDetail();
    4     inOrder.ProductType = ConvertToEnum(sColorName);
    5     inOrder.Quantity = 100;


Here is the code to accomplish that:
    1 public void WorkingDiscount(string sColorName)
    2 {
    3     OrderDetail inOrder = new OrderDetail();
    4     inOrder.ProductType = (Int32)Enum.Parse(typeof(ProductTypeEnum), sColorName);
    5     inOrder.Quantity = 100;

now I will remember this.

Tuesday, November 13, 2007

Biztalk 2006 R2 Upgrade gotchas?

I just finished upgrading to R2 on my Vista x64. So far everything seems to be running fine, except....

Business Rules Engine:

There is a new location for the assemblies now. On Biztalk 2006, the location for the BRE assemblies was this

c:\Program Files (x86)\Microsoft BizTalk Server 2006\Microsoft.RuleEngine.dll

However, after removing my 2006 version, and freshly installed the R2 version, I have to go and recompile all of my assemblies that had a reference to the Microsoft.RuleEngine. The new location is

C:\Program Files (x86)\Common Files\Microsoft BizTalk\Microsoft.RuleEngine.dll

Other than this, everything seems to be running smoothly (Orchestrations, pipelines, etc...) so far. I will update this post as I find any more gotchas (if any... ;)

Tuesday, November 06, 2007

My Biztalk Tools

For our group [Connected system] we started talking about what each of us was using to develop on BizTalk.

We come out with a list of tools. Here I am going to publish the tools that I have installed and that I used most of the time.

DebugView: of course this is the number one. ;) I like to use it with a filter, so that I only see the trace information that I send. For instance I pre-append the word: bts- to all of my trace.writelines.
System.Diagnostics.Trace.WriteLine(String.Format("bts- args: [{0}]", args));

DTC Tester Tool: this will test the configuration of your Distributed Transaction settings. It will come in handy when you have to setup BizTalk in multiple environments.


Biztalk Best Practice Analyzer tool: this will evaluate the installation of BizTalk. Helpful in those cases that you come into a client that has pre-installed BizTalk on their environment.

It not only analyzes your BizTalk installation, but it also give you the documentation as to why this is important. It also gives you the steps to go about fixing any problems that it find with your configuration.


SmartPaster: this is one of those ideas that one person implements, and now after using it a few times, I can't live without. Nice work.


CopySourceAsHtml: I use this add-in to html-encode my source code before I post it on my blog.



Biztalk Documenter: This tool out of codeplex is a good addition to that *finish* touch on your projects. One thing that I like about it is that it takes a snapshot of your orchestration and create the MSDN style documentation. It is also a great tool to document those BRE's. It creates a treeview like view of all your rules and their predicates. I run this during and at the end of the projects to document my artifacts and Business Rules Policies and Vocabularies.


Notepad 2: Another free tool that is in my list of AWESOME tools to use. No installation required and it provides all of the functionality needed from a simple editor. One of the features that I like the most of this editor is the fact that it can format XML and it has the Always On Top option.!! I love to be able to copy long xpath's from the Biztalk schemas and paste on this editor. Keeping it on top of the other windows, make it very useful.

FoxitReader: I am a big fan of NOT installing tools. Specially when I am at a customer site, and have to use their equipment. I love to put my thumb drive in and be able to use any of the the tools in there without having to install them. FoxIt has a small footprint, and it lighting fast to open any PDF document.

Process Explorer: Yet another jewel from SysInternals. This one is a better task manager. it is very useful to see some of the process that are running on the background, and some of those *hidden* programs on the network.

WebService Studio: I have talked about this tool in the past here. It is still my favorite tool to quickly test an asmx web service.

Database Publishing Wizard: good to get data to and from different sql servers. I used it primarily to get schemas from the customer environment to my vpc sandbox, so that I can reproduce whatever condition/data that they require.


XML Spy: Although it is a commercial tool, I love their grid representation for xml schemas and just plain xml data. I have been a fan of this product since XML Spy version 3.0...!!

vs

Another cool feature of this tool is that it can instantiate Soap request into a web service.



HyperSnap: my screen capture tool of preference. I like the fact that you can capture a region and then you can save that snapshot to any of the major picture formats out there.

Beyond Compare 2: Windiff is child's play when you compare it to Beyond Compare 2. Download the 30-day and try it yourself. It allows you to visually pinpoint differences in 2 files down to the character that is not equal. It also provides editing within the comparison main screen, and it allows you to synch any changes from either of the files into the other one.

ReSharper 3.0: Last but not least my FAVORITE add-in for visual studio 2005.!! I started using this product back on DotNet 1.1, and I have been hooked on it ever since.


Sunday, October 28, 2007

How to create your own industry...

Recently, I was in my native Panama on a personal trip. Being raining season, the best way to get around is to get a 4x4, so I rented a 2008 Land Cruiser. Driving on the rain forest of Chiriqui made me realized that this 4x4 was the right choice.

Everything was dandy and fine, 'till Tuesday. That day I came to find out that there is a whole new industry that has exploded in the past 10yrs: Trading of Car logos.!

Yes. Those precious logos we don't even pay attention in the US, are the striving goods in Panama. This is how the story unfolds. I parked in front of a well lit, populated commercial area. It is 2:30pm and I am talking to a veterinarian inside the clinic. Next thing I know, some guy walks in and tells me that he saw this other guy stealing my car logo. WTF?

As I walked outside, I see 2 guys running about a block away and turning into this open market. So I decided against chasing them into the public market. With a regular screwdriver, they have popped the front logo of my brand new rented car while walking by.




So what's one to do? call the policy of course.!! I waited for about 1.5hrs for the policy to arrive. They checked my US passport and they told me that this is quite common and that there is nothing they can do. If I had caught the guys that have stolen the logo, then they could arrest them and file charges. (hummm... am I missing the point?, I thought that was their job.!!

They wont even give me a police report for the insurance company. I have to go to the local county office and filed a complaint. So here I go to this building that everybody goes to. They *investigate* robberies, assaults, murders, stolen goods, etc. It was awesome to see some of the stuff that they have recovered: (check out the portion of fence against the wall...)




Yes, those are toilet seats that were stolen, and have been recovered.!! [...honey, let's save some money and buy a used toilet seat. ;)

Well, after my grievance was officially filed, I call the insurance company and they told me that this kind of things do happen regularly. However, they do NOT cover partial thefts... WTF? Yeap, if the car have been stolen completely, then I did not have to pay anything. However, now I am responsible to pay $85.00 that the manufacturer charges to replace the logo.!!

Talking to some guy walking by, he suggested that I checked the local Chinese Autopart that sell replicas for about $8-$10. However, the car being rented and all, I decided against it.

The very next day, talking to a customer of the Vet, she mentioned that she knows someone that knows someone that could get me an original logo for cheaper that I could pay the dealer. hummm. She goes and give me her cell phone and tell me to give her a call the next day at 9am.

This is getting very interesting. Of course I call the next day, I talk to her, and yes she said that she was able to get me an original Land Cruiser 2008 logo for $40.00.



After some haggling over the phone, we settle for $25.00. She was to drop off the logo at the vet clinic with the secretary there where I am supposed to leave the money (cash only of course.!) and that will complete the transaction. Funny, this sounds so fishy. I get my logo stolen in front of the vet clinic, and then 3 days later, I am paying $25.00 to a completely stranger for an original logo... ;) But, under the circumstances, I rather pay that $25.00 that trying to explain and haggle with the rental agency, which I know will make me pay for the replacement.

Then I start noticing on the other cars, that their logos have either been stolen or that they have paid someone to make sure no one steals their logo:




I have also heard that some transportation buses pay $3-$4 per logo, no questions asked. I was not able to get a picture of these buses, but they told me that they use the logos as decorations, just like trophies, and they display them all over inside the main cab.

No, I did not place the logo back on the car. One hour before I drop off the car at the airport, I pop the logo back onto the car and drove straight and returned the car.

Supply and demand at its best.!

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:

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

Wednesday, August 29, 2007

Service Unavailable when deploying an ASMX Service

I deployed an ASMX service to a newly configured machine.
When I open the ASMX, I get the dreaded Service Unavailable error.



looking at the system log, I see this entry:
Event Type: Error
Event Source: DCOM
Event Category: None
Event ID: 10016
Date: 8/29/2007
Time: 8:35:35 AM
User: NT AUTHORITY\NETWORK SERVICE
Computer: CONTOSOQABTS
Description:
The application-specific permission settings do not grant Local Activation permission for the COM Server application with CLSID
{A9E69610-B80D-11D0-B9B9-00A0C922E750}
to the user NT AUTHORITY\NETWORK SERVICE SID (S-1-5-20). This security permission can be modified using the Component Services administrative tool.

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
all of the IIS settings seems fine. When I set the DefaultAppPool to the administrator account, I get this other error:
Event Type: Warning
Event Source: W3SVC
Event Category: None
Event ID: 1057
Date: 8/29/2007
Time: 9:14:43 AM
User: N/A
Computer: TAMSQABIZTALK
Description:
The identity of application pool 'DefaultAppPool' is invalid, so the World Wide Web Publishing Service can not create a worker process to serve the application pool. Therefore, the application pool has been disabled.

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
Then Dan found this article on MSDN that seems to solve this issue. Basically, you need to add the account that the application pool is running under to the IIS_WPG [IIS Worker Process Group].

Saturday, August 18, 2007

Resetting a BRE policy that has been deployed

During the development and testing of Business Rules Engine policies, you will find yourself having to modify a policy that has already been published and deployed. You can go directly to the SQL server and run this command to reset those policies.


    1 USE BizTalkRuleEngineDb
    2 go
    3 
    4 DECLARE @RuleSetID int
    5 
    6 SELECT @RuleSetID = nRuleSetID
    7 FROM RE_Ruleset
    8 WHERE strName IN ( 'LoanApproval', 'LoanNotification')
    9 AND nMajor=1 AND nMinor=0
   10 
   11 UPDATE RE_Ruleset
   12 SET nStatus = 0
   13 WHERE nRuleSetID = @RuleSetID
   14 
   15 DELETE FROM re_deployment_config WHERE nRuleSetID = @RuleSetID
   16 DELETE FROM re_tracking_ID WHERE nRuleSetID = @RuleSetID



To reset a vocabulary that has been published, you will run this other command:



    1 USE BizTalkRuleEngineDb
    2 go
    3 
    4 DECLARE @nVocabularyID int
    5 SELECT @nVocabularyID = nVocabularyID
    6 FROM re_vocabulary
    7 WHERE strName = 'Contoso.ValidStates'
    8 AND nMajor=1 AND nMinor=0
    9 
   10 UPDATE re_vocabulary
   11 SET nStatus = 0
   12 WHERE nVocabularyID = @nVocabularyID



There will be times, that a particular policy, after you have reset its status on the BRE database, it does not go and clear up from cache. If this is the case, then you will need to stop/start the BRE service:


    1 NET STOP RuleEngineUpdateService
    2 NET START RuleEngineUpdateService

note: [The WROX Professional Biztalk Server 2006 book explained this concept]