"dataportal.fetch failed (The requested operation could not be performed because OLEDB provider 'ADSDSOObject' for linked server 'ADSI' does not support the required transaction interface)"

"dataportal.fetch failed (The requested operation could not be performed because OLEDB provider 'ADSDSOObject' for linked server 'ADSI' does not support the required transaction interface)"

Old forum URL: forums.lhotka.net/forums/t/7927.aspx


suman posted on Monday, November 02, 2009

"dataportal.fetch failed (The requested operation could not be performed because OLEDB provider 'ADSDSOObject' for linked server 'ADSI' does not support the required transaction interface)"


THis Nasty error appears when I do a fetch from the Active Directory using LDAP query immediately after I do an insertupdate to any table in my Database using CSLA.

I think the TransactionScope is still trying to put my linked server under transactions??

I see a serious issue here... Any solutions to this ? Other than moving the fetch from the Active Directory to an SSIS job?

RockfordLhotka replied on Monday, November 02, 2009

The way transaction monitors like TransactionScope or Enterprise Services work is to monitor your use of transactional resources like database connections, MSMQ, etc. They automatically enlist each transactional resource into your transaction to protect your work.

If you don't want a resource to be part of your transaction (or if your resource manager isn't compatible with the monitor - and many things aren't compatible with TransactionScope), then you need to either use a different monitor (such as Enterprise Services) or move the use of that resource out of your transactional scope.

To move the use of the resource out of the transactional scope, you need to use Manual transactions (in CSLA) and create your own transactional scope for the parts of your logic that should be transactional and do the non-transactional parts outside of that scope.

suman replied on Tuesday, November 03, 2009

As you suggested, I tried doing it manually but the problem still exists.


That means its not the problem with CSLA Framework. Its some thing to do with the TransactionScope in System.Transactions.



The strange part is that I am doing insert/update in a page using a set of objects and in a different page I am using different set of objects and trying to fetch from the AD. And the connection object is disposed in every call, but how come the transaction object is still spanning the linked server??? Defenitely this is not the way it should work...I think we should ask Microsoft..don't we..:-)

Regent replied on Tuesday, November 03, 2009

I would recommend you to use System.DirectoryServices namespace (it was there since the very first version on framework) for work with ActiveDirectory rather than linking AD via OLE DB provider - that will work faster and in a more object-oriented way...

suman replied on Wednesday, November 04, 2009

Thats exactly what I did. I got rid of that linked server and wrote a function in the business layer to use System.Directory Services...

Thanks...

ajj3085 replied on Monday, November 02, 2009

I would wrap this code around the part where you talk to AD:

using( var adTs = new TransactionScope( TransactionScopeOption.Suppress ) {

// do AD stuff here

    adTs.Complete();

}

Anything within that block will NOT occur within the context of the transaction, and should an exception occur, it will cause the outer TS to rollback as well (assuming you let the exception get past both using blocks).

Does that help?  Or do I misunderstand?

Andy

suman replied on Tuesday, November 03, 2009

Thanks Andy, I tried this but didnt help

In the insert/update:

[Transactional(TransactionalTypes.Manual)]
protected override void DataPortal_Insert()
{
using (TransactionScope txnTask = new TransactionScope(TransactionScopeOption.Required))
{
DoInsertUpdate();
txnTask.Complete();
}
}
[Transactional(TransactionalTypes.Manual)]
protected override void DataPortal_Update()
{
using (TransactionScope txnTask = new TransactionScope(TransactionScopeOption.Required))
{
DoInsertUpdate();
txnTask.Complete();
}
}



and in the fetch from AD:

private void DataPortal_Fetch()
{
using (TransactionScope txnUser = new TransactionScope(TransactionScopeOption.Suppress))
{
DoFetch();
txnUser.Complete();
}

}


But that nasty, dirty error still exist during the fetch...

ajj3085 replied on Wednesday, November 04, 2009

Oh, I thought you were trying to update AD while you were updating your database, didn't realize it was part of a fetch.  So what does your DoFetch look like?

suman replied on Wednesday, November 04, 2009

System.DirectoryServices is screamingly fast...
This function finds the users based on first few characters of Windows Login or FirstName

private void DoFetch(SingleCriteria criteria)
{
try
{
Log.Info("MYAPP", "UserFind", "Child_Fetch", "Begin");

this.RaiseListChangedEvents = false;
string userName = string.Empty;
string passWord = string.Empty;
string sPath = string.Empty;
ArrayList users = new ArrayList();
object[] objarray = new object[5];
userName = ConfigurationManager.AppSettings["ADUser"].ToString();

passWord = ConfigurationManager.AppSettings["ADPassword"].ToString();

sPath = ConfigurationManager.AppSettings["LDAP"].ToString();

DirectoryEntry dir = new DirectoryEntry(sPath, userName, passWord);
DirectorySearcher searcher = new DirectorySearcher(dir);
SearchResultCollection resultCollection = null;
ResultPropertyCollection propCollection = null;
ResultPropertyValueCollection propSam = null;
ResultPropertyValueCollection propFirstName = null;
ResultPropertyValueCollection propLastName = null;
ResultPropertyValueCollection propuserAccount = null;
ResultPropertyValueCollection propMail = null;

searcher.Filter = "(&(objectClass=user)(|(sAMAccountName=" + criteria.Value + "*)(givenName=" + criteria.Value + "*)))";
resultCollection = searcher.FindAll();

foreach (SearchResult result in resultCollection)
{
users.Clear();
propCollection = result.Properties;
propSam = propCollection["sAMAccountName"];
objarray[0] = propSam[0].ToString();

propFirstName = propCollection["givenName"];
if (propFirstName.Count > 0)
{
objarray[1] = propFirstName[0].ToString();
}
else
{
objarray[1] = "";
}
propLastName = propCollection["sn"];
if (propLastName.Count > 0)
{
objarray[2] = propLastName[0].ToString();
}
else
{
objarray[2] = "";
}
propuserAccount = propCollection["userAccountControl"];
if (propuserAccount.Count > 0)
{
objarray[3] = ConvertUserAccountControl(propuserAccount[0]);
}
else
{
objarray[3] = "true";
}
propMail = propCollection["mail"];
if (propMail.Count > 0)
{
objarray[4] = propMail[0].ToString();
}
else
{
objarray[4] = "";
}
users.Add(objarray);
IsReadOnly = false;
Add(User.GetUser(users));
IsReadOnly = true;
}

this.RaiseListChangedEvents = true;
}
catch (Exception ex)
{
Log.Error("MYAPP", "UserFind", "DoFetch", ex.Message, ex.StackTrace);
throw ex;
}
finally
{
Log.Info("MYAPP", "UserFind", "DoFetch", "End");
}
}

ajj3085 replied on Thursday, November 05, 2009

I don't see anything that would trigger transactions at all there, unless your Log class is opening database connections.  But even then, your fetch doens't have a Transactional I don't know whats going on.

suman replied on Friday, November 06, 2009

No. This is the new function which I wrote which is using System.DirectoryServices. I dont have any issues in this function.

I have replaced the other function which was running under transactionscope and was calling a stored procedure and that was using an LDAP connection string for a Linked Server to ADSI.

Copyright (c) Marimer LLC