I have a C# trace routine, that writes data to a SQL Trace table. It’s kind of like my own Log4Net, and allows a unified trace between BizTalk, WebServices, and other types of progams.
I had the interesting task the last month of writing a WCF Custom Behavior to make JSON work in BizTalk 2010. Moving to 2013 or 2016 was simply not possible at this client in time for implementing the project.
So I had lots of Trace statements in the custom behavior. The bizarre thing was that when I call the trading partner’s webservice, and it succeeded, then I could see the rows inserted. In Debug/Attach mode I could see them as well. But if the trading partners’ webservice returned any error, all the rows inserted were being rolled-backed (rollback). And of course, the Trace results are much more needed in the event of an error; for example, I want to see the JSON that was created.
I earlier had decided to write the JSON to a disk directory. But I still prefer having it in the Trace as well. The Trace has an column of XML data type, where I can store text and blobs. (If the data is not XML, the C# trace program just puts a dummy xml <wrapper> tag around it. Normally in this column I store the request and response to and from any web service. It makes debugging very fast and easy.
I started researching about distributing transactions, and fortunately found a quick and easy fix. All I had to do was add the “Enlist=false” statement to the connection string:
I found the answer on this page about .NET distribution transactions. At first I thought I might have to change my C# code to use “EnlistDistributedTransaction” method, but that wasn’t necessary. Just changing the connection string as shown above worked.
Install will default to this directory, and here is the curl.exe: “c:\Program Files\cURL\bin\curl.exe”.
You need to find the MSI. Many downloads of CURL will include the source code and it requires you to build it with C++ compilers and such. That’s more trouble than you usually need to go through when you just want to install and use the tool. Fortunately, the anonymous author at “ConfusedByCode.com” has been nice enough to create the MSI (Microsoft System Installer) files for CURL so that you can download it, install it, and be using it within minutes.
What is CURL?
A command line tool for getting or sending files using URL syntax.
How is CURL applicable to BizTalk or B2B Teams
B2B and BizTalk developers can use CURL to test websites, often of their trading partners. CURL can be run as part of a batch (.bat) or command (.cmd) file if you need to automate a test or schedule a download using Windows Task Scheduler.
Example Curl commands
Download the HTML of a page to your disk:
curl -o example.html www.example.com
A client C# program was call an orchestration published as a web service. I was turning on Basic Authenticiation in BizTalk and IIS. C# client program kept getting: “The requested service [service name] could not be activated. See the server’s dianostic trace logs for more information.
NOTE: This may not be your solution. We had DNS pointing a subdomain.domain.com to one of two servers. I simply had the servers crossed. I think they were having a load balancing issue, and had DNS just pointing to one of the two. Other users were on Machine A, so I logged on to Machine B, thinking that’s where the DNS was pointing. Later I confirmed that DNS was in fact pointing to Machine A.
One day, I hope to be able to fully understand and explain the “Ambient Transaction” true/false option in BizTalk WCF-SQL and WCF-Custom send and receive ports. Until then, I’m going to collect the most relevant info and blogs here:
Specifies whether the SQL adapter performs the operations using the transactional context provided by the caller. Default is true, which means that the adapter always performs the operations in a transactional context. If there are other resources participating in the transaction, and SQL Server also joins the transaction, the transaction gets elevated to an MSDTC transaction.
However, there can be scenarios where you do not want the adapter to perform operations in a transactional context. For example:
While performing a simple Select operation on a SQL Server database
While specifying a polling statement that performs a Select operation, and does not involve any changes to the table either through a Delete statement or by invoking a stored procedure.
Both these operations do not make any updates to the database table and, hence, elevating these operations to use an MSDTC transaction can be a performance overhead. In such scenarios, you can set the binding property to false so that the SQL adapter does not perform the operations in a transactional context.
Not performing operations in a transactional context is advisable only for operations that do not make changes to the database. For operations that update data in the database, we recommend setting the binding property to true; otherwise you might either experience message loss or duplicate messages, depending on whether you are performing inbound or outbound operations.
http://msdn.microsoft.com/en-us/library/ms973865.aspx (Richard Seroter above refers to the “Ambient Transaction” feature as being part of the Systems.Transaction in .NET Framework 2.0 and afterwards. It seems like understanding Ambient Transactions from native C# first would be key to understanding how it works in BizTalk.
The above link provides the following information, but as for me now, it does not pass the “so what” and the “WIIFM” (What’s In It for Me) test.
System.Transactions defines a concept called an ambient transaction. The ambient transaction is the transaction that is present in the thread that the current application code is executing within. To obtain a reference to the ambient transaction call the static Current property of Transaction:
If there is no ambient transaction, Current will return null.
The ambient transaction object is stored in the thread local storage (TLS). As a result, when the thread winds its way across multiple objects and methods, all objects and methods can access their ambient transaction.
Later it says:
The value of TransactionScopeOption lets you control whether the scope takes part in a transaction, and if so, whether it will join the ambient transaction or become the root scope of a new transaction.
A TransactionScope object has three options:
Join the ambient transaction.
Be a new scope root, that is, start a new transaction and have that transaction be the new ambient transaction inside its own scope.
Do not take part in a transaction at all.
This forum post tries to answer the question: “What exactly is an ambient transaction?”
There are 2 main kinds of transactions; connection transactions and ambient transactions. A connection transaction (such as SqlTransaction) is tied directly to the db connection (such as SqlConnection), which means that you have to keep passing the connection around – OK in some cases, but doesn’t allow “create/use/release” usage, and doesn’t allow cross-db work.
The alternative is an ambient transaction; new in .NET 2.0, the TransactionScope object (System.Transactions.dll) allows use over a range of operations (suitable providers will automatically enlist in the ambient transaction). This makes it easy to retro-fit into existing (non-transactional) code, and to talk to multiple providers (although DTC will get involved if you talk to more than one).
Note here that the two methods can handle their own connections (open/use/close/dispose), yet they will silently become part of the ambient transaction without us having to pass anything in.
If your code errors, Dispose() will be called without Complete(), so it will be rolled back. The expected nesting etc is supported, although you can’t roll-back an inner transaction yet complete the outer transaction: if anybody is unhappy, the transaction is aborted.
The other advantage of TransactionScope is that it isn’t tied just to databases; any transaction-aware provider can use it. WCF, for example. Or there are even some TransactionScope-compatible object models around (i.e. .NET classes with rollback capability – perhaps easier than a memento, although I’ve never used this approach myself).
Blog on on the topic: Transaction.Current and Ambient Transactions by Florin Lazar:
A transaction which automatically identifies a code block that needs to support a transaction without explicitly mentioning any transaction related things. An ambient transaction is not tied just to a database, any transaction aware provider can be used. TransactionScope implements an ambient transaction. If you see the use of TransactionScope, you will not find transaction related anything sent to any method or setting any property. A code block is automatically attached with the transaction if that code is in any TransactionScope. A WCF transaction is another example of a transaction aware provider. Any one can write a transaction aware provider like the WCF implementation.
WCF-SQL and DTC Ambient Transactions in a cross domain scenario
The ambient transaction option ensures that the BizTalk adapter flows a transaction through to SQL Server and thus the SQL transaction will only commit when the message received by BizTalk is successfully written to the BizTalk message box database. This is of course crucial in a guaranteed delivery based solution where you can’t afford to lose any messages.
I found that all worked well when ambient transactions were turned off, however when turned on it looked like the receive location just hangs, holding a lock on SQL resources (I tried to do a select on the table in question using SQL Server Management Studio and it couldn’t return any values due to locks being in place) which won’t be removed until the host instance is reset.
The above blog talks about using DTCPing and DTCTester to identify DTC issues, and fixing them by laxing the security options in the DTC configuration.
Conclusions (or lack thereof):
So for now, I suggest studying that second web page to get an idea of what the topic is really about. If I had time, I would write some C# programs to test outside of BizTalk.
My client uses a non-standard SQL port number.
So for example, when connecting in SSMS (SQL Server Management Studio), we type in “MyServer,1234” for the server name. This also works in connection strings (i.e. specify servername, then comma, then port number.
I suppose if you were using a named instance, it would be “MyServer/MyInstance,1234”.
But if you are using WCF/SQL Adapter, it’s a little obtuse, you must specify the port number in the “InstanceName” property field, even though you are not using an instance:
Specifing port number for SQL Server (in WCF/SQL Adapter for BizTalk)
Type a comma, followed by the port number in the instance name.
Exception: System.ServiceModel.CommunicationException: There was an error while trying to serialize parameter http://tempuri.org/:ExportValuationPolicyNumberResult. The InnerException message was ‘Type ‘TFBIC.RCT.WCFWebServices.ExpressLync.MainStreetValuation’ with data contract name ‘MainStreetValuation:http://schemas.datacontract.org/2004/07/TFBIC.RCT.WCFWebServices.ExpressLync’ is not expected. Add any types not known statically to the list of known types – for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.’. Please see InnerException for more details. —> System.Runtime.Serialization.SerializationException: Type ‘TFBIC.RCT.WCFWebServices.ExpressLync.MainStreetValuation’ with data contract name ‘MainStreetValuation:http://schemas.datacontract.org/2004/07/TFBIC.RCT.WCFWebServices.ExpressLync’ is not expected. Add any types not known statically to the list of known types – for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
1. Manually create a proxy to the WCF Service from the command line like so:
svcutil /serializer:XmlSerializer http://localhost:46122/ValuationService.svc
2. Add the [XmlSerializerFormat] to your ServiceContract on the WCF Service
By doing this, we force our WCF Service to use the XmlSerializer rather than the default DataContractSerializer. Note: you?ll need to call the WCF service from you new proxy in your sample code.
The following was confirmed to work with Visual Studio 2008 in Dec 2009.
1. In Visual Studio, right click on your existing solution and select “add” then “New Project”. Select “Other Project Types” ? “Setup & Deployment” ? “Web Setup Project”.
2. Right-click on your new project and select “Add” then “Project Output”. Select the desired WCF project from the select box at the top, and make sure to select BOTH “Primary Output” and “Content Files”.
3. Build your project
4. Under the debug directory, you will find the generated .msi file.
5. Run the MSI. You can install into a different directory on your local machine to see if it works. I suggest after the install, you open IIS, verify, and in IIS 7 you use the content tab, click right-click “Browse” on one of your .svc files, and make sure it opens correctly in the browser.
1. The default IIS Virtual Directory name is the same as your Visual Studio Project name. I’m trying to figure out how to change that …
1. Add a dialog box with four buttons. I named the button “EnvironmentButton”.
Set values of each button to literals such as LOCAL, QA, STAGING, PROD.
2. I created a directory called CustomWebConfigs, with subdirectories called QA, STAGE, and PROD. Each one has a file called web.config. I used this disk structure so the file could always be called web.config and no need to rename it.
3. I did an “add file” for the CustomWebConfigs/Prod/Web.Config and set the “condition” property to: EnvironmentButton = “PROD”
NOTE2: Use only one equal sign, not two! Enclose the value in double quotes.
4. Set TargetName property to “Web.config”
5. Repeat steps 3-4 for each web.config file that you need.