How to avoid DTC when using PersistenceIOParticipant in WF4.0? - workflow-foundation-4

I am using PersistenceIOParticipant in WF4.0 to save something into database together with the persistence of the workflow instance. I have no idea that how to use the same connection object with the workflow persistence and I am forced to use the distributed transaction. Are there any ways to avoid using DTC?

I found the WF4 Sample project "WorkflowApplication ReadLine Host" useful
to see an example of persistenceIOParticipant in action.
I toggled the booleans in the constructor to verify that a transaction was being used and that
MSDTC was required.
See http://msdn.microsoft.com/en-us/library/dd764467.aspx

If using SQL Server 2008+, then it shouldn't matter if multiple connections are required. After using reflector on the SqlWorkflowInstanceStore, I discovered it was setting some additional properties on the connection string. Here is the code it uses to create a connection string:
SqlConnectionStringBuilder builder2 = new SqlConnectionStringBuilder(connectionString);
builder2.AsynchronousProcessing = true;
builder2.ConnectTimeout = (int)TimeSpan.FromSeconds(15.0).TotalSeconds;
builder2.ApplicationName = "DefaultPool";
SqlConnectionStringBuilder builder = builder2;
return builder.ToString();
I verified with profiler that MSDTC is not involved when using a custom IO participant and this connection string code. Don't forget to pass true to the base PersistenceIOParticipant constructor and flow Transaction.Current appropriately. Obviously, Microsoft could change that at anytime so use at your own discretion.

Related

Specifying default schema WebSpehere 8.5 Server

I am working on a migration project where we are migrating one application from Weblogic to Websphere 8.5 server.
In Weblogic server, we can specify default schema while creating datasource but I don't see same option in WebSpehere 8.5 server.
Is there any custom property through which we can set it , I tried currentSchema=MySchema but it did not work.
This answer requires significantly more work, but I'm including it because it's the designed solution to customize pretty much anything about a connection, including the schema. WebSphere Application Sever allows you to provide/extend a DataStoreHelper.
Knowledge Center document on providing a custom DataStoreHelper
In this case, you can extend com.ibm.websphere.rsadapter.Oracle11gDataStoreHelper.
JavaDoc for Oracle11gDataStoreHelper
The following methods will be of interest:
doConnectionSetup, which performs one-time initialization on a connection when it is first created
doConnectionCleanup, which resets connection state before returning it to the connection pool.
When you override doConnectionSetup, you are supplied with the newly created connection, upon which you can do,
super.doConnectionSetup(connection);
Statement stmt = connection.createStatement();
try {
stmt.execute(sqlToUpdateSchema);
} finally {
stmt.close();
}
doConnectionCleanup lets you account for the possibility that application code that is using the connection might switch the schema to something else. doConnectionCleanup gives you the opportunity to reset it. Again, you are supplied with a connection, upon which you can do,
super.doConnectionCleanup(connection);
Statement stmt = connection.createStatement();
try {
stmt.execute(sqlToUpdateSchema);
} finally {
stmt.close();
}
Note that in both cases, invoking the corresponding super class method is important to ensure you don't wipe out the database-specific initialization/cleanup code that WebSphere Application Server has built in based on the database.
As far as I know Weblogic only allows setting a default schema by setting the 'Init SQLto a SQL string which sets the current schema in the database, such asSQL ALTER SESSION SET CURRENT_SCHEMA=MySchema`. So, this answer is assuming the only way to set the current schema of a data source is via SQL.
In WebSphere, the closest thing to WebLogic's Init SQL is the preTestSQLString property on WebSphere.
The idea of the preTestSQLString property is that WebSphere will execute a very simple SQL statement to verify that you can connect to your database properly when the server is starting. Typically values for this property are really basic things like select 1 from dual', but since you can put in whatever SQL you want, you could setpreTestSQLStringtoSQL ALTER SESSION SET CURRENT_SCHEMA=MySchema`.
Steps from the WebSphere documentation (link):
In the administrative console, click Resources > JDBC providers.
Select a provider and click Data Sources under Additional properties.
Select a data source and click WebSphere Application Server data source properties under Additional properties.
Select the PreTest Connections check box.
Type a value for the PreTest Connection Retry Interval, which is measured in seconds. This property determines the frequency with which a new connection request is made after a pretest operation fails.
Type a valid SQL statement for the PreTest SQL String. Use a reliable SQL command, with minimal performance impact; this statement is processed each time a connection is obtained from the free pool.
For example, "select 1 from dual" in oracle or "SQL select 1" in SQL Server.
Universal Connection Pool (UCP) is a Java connection pool and the whitepaper "UCP with Webshere" shows how to set up UCP as a datasource.
for JDBC datasource, the steps are similar but, you can choose the default JDBC driver option.
Check out the paper for reference.

Passing a stream or a String to Flyway API instead of locations

I was wondering if there is a way for Flyway to accept an actual SQL migration as a string or a stream instead of searching for it on a classpath?
I'm constructing the SQL migration in Java on the fly and would like to call Flyway API and pass the migration as a paramter.
Please, let me know if this is possible.
Thank you
Not entirely what you are asking for, but looks like Java-based migrations might be a solution.
Basically instead of V1_0__script.sql you write V1_0__script.java class implementing JdbcMigration. Inside that class you have access to JDBC Connection:
class V1_0__script implements JdbcMigration {
public void migrate(Connection connection) throws Exception {
//...
}
}
In migrate() you are free to run your custom SQL queries.
There is no API available for this.
However, if you construct your SQL on the fly, it surely must be possible to construct it one statement at a time. Each statement can then be executed using the Connection parameter you get in a JdbcMigration

Constructing the Connection String for the DataContext Class

I see a couple of DataContext connection string questions. I'm going to try to differentiate this one a bit:
How does one construct a generic connection string to a database, localhost | User-PC\User | Some database... (it is hosted/managed by Microsoft SQL 2008)
I notice that it is IDisposable. So if I have multiple users hitting my site, my code can only access the database one instance at a time, and has to wait until each instance is disposed, in order for the data to be consistent for each user?
Is it possible, by any chance, to somehow enable LINQ in F#-Interactive, and connect to the database from there? I cannot figure out how to enable/load the System.Data dll into fsi. Maybe that is unique to my installation, or it is a common thread? (ie, my installation also does not recognize windows.base.dll--I have to manually get it from programs\reference assemblies).
Anyhow, I've pretty much conclusively discovered that
let x = new System.Data.Linq.DataContext("localhost")
...does not work.
1) How does one construct a generic connection string to a database?
There is no generic way to construct a connection string. The best thing to do is to keep the connection string in some configuration file where you can change it depending on your configuration (the name of SQL Server machine, authentication options, whether it is a file-based database or normal). There is a web site with examples for most of the options.
2) I notice that it is IDisposable. So if I have multiple users hitting my site, my code can only access the database one instance at a time [...]?
No, this is not how DataContext works. The DataContext does not keep a live connection to the server that would block anybody else from using the SQL server. It keeps some state (i.e. cached entities that were already obtained) and it uses optimistic concurrency to make sure that the state is consistent (you can use transactions to prevent other connections, if that's what you want).
3) Is it possible, by any chance, to somehow enable LINQ in F#-Interactive [...]?
That shouldn't be a problem. You can reference assemblies using #r "foo.dll" in F# interactive. The typical approach for F# 2.0 is to generate the data context using C# tools and then just reference it (for F# 3.0, things are easier because you can just use type provider).
If you generate LINQ to SQL data context for Northwind in C#, the F# Interactive use would look like this:
#r #"<whatever_path>\Northwind.dll"
#r "System.Data.Linq.dll"
open Northwind
open Microsoft.FSharp.Linq
let connStr = #"Data Source=.\SQLEXPRESS;AttachDbFilename=<path>\NORTHWND.MDF;" +
#"Integrated Security=True;User Instance=True"
let operation () =
// Using 'use' to make sure it gets disposed at the end
use db = new NorthwindDataContext(connStr)
// do something with the database
There actually is a somewhat generic way to construct a connection string:
open System.Data.Common
open System.Data.SqlClient
let providerName = "System.Data.SqlClient"
let factory = DbProviderFactories.GetFactory(providerName)
let cnBuilder = factory.CreateConnectionStringBuilder() :?> SqlConnectionStringBuilder
cnBuilder.DataSource <- "localhost"
cnBuilder.InitialCatalog <- "MyDatabase"
cnBuilder.IntegratedSecurity <- true
let connStr = cnBuilder.ConnectionString
My approach was to have 1 connection string and then use that for all of my DataContext connections. So this code builds the EntityConnectionString based on MyConnString:
protected override MyEntities CreateObjectContext()
{
string ConnString =ConfigurationManager.ConnectionStrings["MyConnString"];
string seConn = ConfigurationManager.ConnectionStrings["MyEntities"].ToString();
EntityConnectionStringBuilder ecsb = new EntityConnectionStringBuilder(seConn);
ecsb.ProviderConnectionString = ConnString;
EntityConnection ec = new EntityConnection(ecsb.ToString());
ScheduleEntities ctx = new ScheduleEntities(ec);
return ctx;
}

The transaction manager has disabled its support for remote/network transactions

I'm using SQL Server and ASP.NET. I have the following function:
Using js = daoFactory.CreateJoinScope()
Using tran = New Transactions.TransactionScope()
'...
tran.Complete()
End Using
End Using
However, the following exception is thrown:
The transaction manager has disabled its support for remote/network transactions.
Description of JoinScope:
Public Class JoinScope
Implements IJoinScope
Implements IDisposable
'...
End Class
I have worked this way in another application with the same environment without a problem, but here I have this problem. What could I do to fix the issue?
Make sure that the "Distributed Transaction Coordinator" Service is
running on both database and client.
Also make sure you check "Network DTC Access", "Allow Remote Client",
"Allow Inbound/Outbound" and "Enable TIP".
To enable Network DTC Access for MS DTC transactions
Open the Component Services snap-in.
To open Component Services, click Start. In the search box, type dcomcnfg, and then press ENTER.
Expand the console tree to locate the DTC (for example, Local DTC) for which you want to enable Network MS DTC Access.
On the Action menu, click Properties.
Click the Security tab and make the following changes:
In Security Settings, select the Network DTC Access check box.
In Transaction Manager Communication, select the Allow Inbound and Allow Outbound check boxes.
I had a store procedure that call another store Procedure in "linked server".when I execute it in ssms it was ok,but when I call it in application(By Entity Framework),I got this error.
This article helped me and I used this script:
EXEC sp_serveroption #server = 'LinkedServer IP or Name',#optname = 'remote proc transaction promotion', #optvalue = 'false' ;
for more detail look at this:
Linked server : The partner transaction manager has disabled its support for remote/network transactions
In my scenario, the exception was being thrown because I was trying to create a new connection instance within a TransactionScope on an already existing connection:
Example:
void someFunction()
{
using (var db = new DBContext(GetConnectionString()))
{
using (var transaction = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
someOtherFunction(); // This function opens a new connection within this transaction, causing the exception.
}
}
}
void someOtherFunction()
{
using (var db = new DBContext(GetConnectionString()))
{
db.Whatever // <- Exception.
}
}
I was getting this issue intermittently, I had followed the instructions here and very similar ones elsewhere. All was configured correctly.
This page: http://sysadminwebsite.wordpress.com/2012/05/29/9/ helped me find the problem.
Basically I had duplicate CID's for the MSDTC across both servers. HKEY_CLASSES_ROOT\CID
See: http://msdn.microsoft.com/en-us/library/aa561924.aspx section Ensure that MSDTC is assigned a unique CID value
I am working with virtual servers and our server team likes to use the same image for every server. It's a simple fix and we didn't need a restart. But the DTC service did need setting to Automatic startup and did need to be started after the re-install.
Comment from answer: "make sure you use the same open connection for all the database calls inside the transaction. – Magnus"
Our users are stored in a separate db from the data I was working with in the transactions. Opening the db connection to get the user was causing this error for me. Moving the other db connection and user lookup outside of the transaction scope fixed the error.
I post the below solution here because after some searching this is where I landed, so other may too. I was trying to use EF 6 to call a stored procedure, but had a similar error because the stored procedure had a linked server being utilized.
The operation could not be performed because OLE DB provider _ for linked server _ was unable to begin a distributed transaction
The partner transaction manager has disabled its support for remote/network transactions*
Jumping over to SQL Client did fix my issue, which also confirmed for me that it was an EF thing.
EF model generated method based attempt:
db.SomeStoredProcedure();
ExecuteSqlCommand based attempt:
db.Database.ExecuteSqlCommand("exec [SomeDB].[dbo].[SomeStoredProcedure]");
With:
var connectionString = db.Database.Connection.ConnectionString;
var connection = new System.Data.SqlClient.SqlConnection(connectionString);
var cmd = connection.CreateCommand();
cmd.CommandText = "exec [SomeDB].[dbo].[SomeStoredProcedure]";
connection.Open();
var result = cmd.ExecuteNonQuery();
That code can be shortened, but I think that version is slightly more convenient for debugging and stepping through.
I don't believe that Sql Client is necessarily a preferred choice, but I felt this was at least worth sharing if anyone else having similar problems gets landed here by google.
The above Code is C#, but the concept of trying to switch over to Sql Client still applies. At the very least it will be diagnostic to attempt to do so.
I was having this issue with a linked server in SSMS while trying to create a stored procedure.
On the linked server, I changed the server option "Enable Promotion on Distributed Transaction" to False.
Screenshot of Server Options
If you could not find Local DTC in the component services try to run this PowerShell script first:
$DTCSettings = #(
"NetworkDtcAccess", # Network DTC Access
"NetworkDtcAccessClients", # Allow Remote Clients ( Client and Administration)
"NetworkDtcAccessAdmin", # Allow Remote Administration ( Client and Administration)
"NetworkDtcAccessTransactions", # (Transaction Manager Communication )
"NetworkDtcAccessInbound", # Allow Inbound (Transaction Manager Communication )
"NetworkDtcAccessOutbound" , # Allow Outbound (Transaction Manager Communication )
"XaTransactions", # Enable XA Transactions
"LuTransactions" # Enable SNA LU 6.2 Transactions
)
foreach($setting in $DTCSettings)
{
Set-ItemProperty -Path HKLM:\Software\Microsoft\MSDTC\Security -Name $setting -Value 1
}
Restart-Service msdtc
And it appears!
Source: The partner transaction manager has disabled its support for remote/network transactions
In case others have the same issue:
I had a similar error happening. turned out I was wrapping several SQL statements in a transactions, where one of them executed on a linked server (Merge statement in an EXEC(...) AT Server statement). I resolved the issue by opening a separate connection to the linked server, encapsulating that statement in a try...catch then abort the transaction on the original connection in case the catch is tripped.
I had the same error message. For me changing pooling=False to ;pooling=true;Max Pool Size=200 in the connection string fixed the problem.

asp.net webservice OnUnload?

I'm creating a web service which has a number of methods, all of which make use of a SqlConnection. It seems logical that I would declare a class level connection and initialise it in the web service constructor.
Problem is I cannot find a definitive way to release the connection when the web service call completes, so I have a connection leak. I've tried overriding the Dipose() method but it doesn't get called in a reasonable timeframe (actually not at all in my testing). For good measure I also tried attaching a handler to the Disposed() event but as expected same problem.
Is there nothing similar to Page.OnUnload for web service classes? It seems hard to believe I would have to establish a separate connection in every individual method.
Any suggestions?
It seems logical that I would declare a class level connection and initialise it in the web service constructor.
No, this doesn't seem logical at all. ADO.NET uses a connection pooling so that you don't need to do this. This connection pool is per connection string per application domain.
So you could simply draw a new connection from the pool in each web method and return it to the pool at the end (the using statements will take care of this):
[WebMethod]
public void Foo()
{
// Here you are NOT creating a new connection to the database
// you are just drawing one from the connection pool
using (var conn = new SqlConnection(SomeConnectionString))
using (var cmd = conn.CreateCommand())
{
// Here you are NOT opening a new connection to the database
conn.Open();
cmd.CommandText = "SELECT id FROM foo";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// do something with the results
}
}
} // Here you are NOT closing the connection, you are just returning it to the pool
}
So here's an advice: don't try to manage connections manually by using some class fields, static fields, ... Leave this management to ADO.NET as it does it better.
Remark: The code I've shown usually resides in a data access layer which is called by the web method.

Resources