Groups | Blog | Home
all groups > dotnet security > september 2007 >

dotnet security : Why got error "Only one type of operation can be performed in a se


Pucca
9/13/2007 9:26:01 AM
Hi, I'm using vs2005, .net 2 for a C# windows applicaiton running on Win2K
server. One method of this application, deletes, creates and modify several
Directory Entry. This is running fine on my development PC. I put this on
another server and I would get error: "Only one type of operation can be
performed in a sequence"

Does anyone what could possiblly be causing this error? Thank you.
--
Pucca
9/13/2007 10:40:00 AM
Hi Joe, Both my development PC and the Virtual Machine are running Win2K
Server. The error occur on the VM server when the code runs through this 2
methods. What's confusing for me is that it works for my PC but getting
error on our VM test machine. Thank you.

private bool StartCommit()
{
DataRow[] newRows;
string path, sid, strUnifiedID, ID, globalPath;
DirectoryEntry de = new DirectoryEntry();
SearchResult sr;
int unifiedID = 0, ugid;
bool useUnifiedID = false, success = false, available = false;
DirectoryEntry deUGID = new DirectoryEntry();

if (importUsers)
{
globalPath = CUnityDS.globalUsersPath +
dtGlobal.Rows[0]["curDomain"].ToString();
ID = "UID";
path =
"LDAP://CN=NextUnifiedID,CN=Users,CN=Global,CN=PowerADvantage,CN=Symark,CN=Program Data," + dtGlobal.Rows[0]["curDomain"].ToString();
}
else
{
globalPath = CUnityDS.globalGroupsPath +
dtGlobal.Rows[0]["curDomain"].ToString();
ID = "GID";
path =
"LDAP://CN=NextUnifiedID,CN=Groups,CN=Global,CN=PowerADvantage,CN=Symark,CN=Program Data," + dtGlobal.Rows[0]["curDomain"].ToString();
}

DirectoryEntry deSearchRoot = new DirectoryEntry(globalPath);
DirectorySearcher dsGlobal = new DirectorySearcher(deSearchRoot);
dsGlobal.PropertiesToLoad.Add("meetingID");
dsGlobal.SearchScope = SearchScope.OneLevel;

try
{
//Let's get all the rows that have been updated
if(importUsers)
newRows = tblTarget.Select("Mapped = true", "objectSid",
DataViewRowState.CurrentRows);
else
newRows = tblTargetGroup.Select("Mapped = true",
"objectSid", DataViewRowState.CurrentRows);

if (newRows.Length <= 0)
{
return false;
}

//Proecess each row found to import
for (int index = 0; index < newRows.Length; index++)
{
ugid = Convert.ToInt32(newRows[index][ID].ToString());
//Check if a Global object already exists for this row
and get the Unified ID
sid = newRows[index]["objectSid"].ToString();
dsGlobal.Filter = "cn = " + sid;
sr = dsGlobal.FindOne();
if (sr != null)//Global object already exists
{
de = sr.GetDirectoryEntry();
strUnifiedID =
de.Properties["meetingID"].Value.ToString();
available = CUnityDS.UnifiedIdAvailable(globalPath,
strUnifiedID);
if (!available)
{
strUnifiedID = CUnityDS.GetNextUnifiedID(path,
strUnifiedID);
}
if (strUnifiedID == null)
{
MessageBox.Show("Error obtaining a unified id.",
"PowerADvantage");
return false;
}
unifiedID = Convert.ToInt32(strUnifiedID);

if (unifiedID == ugid)
useUnifiedID = true;
else
useUnifiedID = false;
Commit(newRows[index], useUnifiedID, globalPath,
sid, ugid, true, unifiedID);
}
else//no Global object so use the ugid as the unified ID
but if it is
//already used as a unified id by another object then
use the next
//available unified id
{
de = null;
//No object found Global folder, use the ugid but
check it's not used already
available = CUnityDS.UnifiedIdAvailable(globalPath,
ugid.ToString());

if (available)//OK to use the ugid
{
unifiedID = ugid;
useUnifiedID = true;
}
else//ugid is already used as unified id by other
object. Use the next avaible unified id
{
try
{
deUGID.Path = path;
//string test =
deUGID.Properties["cn"].Value.ToString();
}
catch (COMException cep)
{
MessageBox.Show(cep.Message + " Error Code:
" + cep.ErrorCode.ToString(), "PowerADvantage");
return false;
}
if (deUGID == null ||
deUGID.Properties["meetingID"].Value == System.DBNull.Value)
{
MessageBox.Show("Not able to retrieve the
next available unified ID. Please " +
"exit and call for support.",
"PowerADvantage");
return false;
}
//Verify if the id obtain is not in used. If
already in used then increment and
//test until it is avaiable. Set the next avail
id back to the folder
strUnifiedID =
deUGID.Properties["meetingID"].Value.ToString();
strUnifiedID =
CUnityDS.GetNextUnifiedID(globalPath, strUnifiedID);
if (strUnifiedID == null)
{
MessageBox.Show("Error obtaining a unified
id.", "PowerADvantage");
return false;
}
unifiedID = Convert.ToInt32(strUnifiedID);//use
this avialbe ID
if (unifiedID == ugid)
useUnifiedID = true;

//inc to set next available Unified ID
deUGID.Properties["meetingID"].Clear();
int newUid = unifiedID + 1;
string strNewUID = newUid.ToString();
deUGID.Properties["meetingID"].Add(strNewUID);
deUGID.CommitChanges();
}

success = Commit(newRows[index], useUnifiedID,
Joe Kaplan
9/13/2007 11:34:04 AM
You need to provide more detail here. Can you show an example of the code
that produces the error, the exact error stack trace and more information
about the differences between your development machine OS and the deployment
server?

It could be that you have run into an ADSI limitation on Win2K server where
multiple different types of attribute modifications are not allowed, but it
isn't clear if that is the problem. If that is, you need to either write
your code differently or upgrade the server OS to a version of Windows that
supports that ADSI feature (2K3 server).

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
[quoted text, click to view]

Pucca
9/13/2007 2:42:07 PM
Since there is no VS for me to debug on the VM server I put in a bunch of
messages to see where I'm getting this error. It's apparently coming from my
StartCommit() method in the following code when deUGID is doing the "Add"
method. Can you see what could possible cuase this? Again, the same is
running just fine on my development PC.

int newUid = unifiedID + 1;
string strNewUID = newUid.ToString();
deUGID.Properties["meetingID"].Clear();
deUGID.Properties["meetingID"].Add(strNewUID);//This is the line of code
giving error
deUGID.CommitChanges();

--
Thanks.


[quoted text, click to view]
Joe Kaplan
9/13/2007 4:49:19 PM
Yeah, that looks like a multiple attribute modification type of problem. Do
you have the full stack trace of the error message? That would be helpful.

Is there any service pack difference between the two machines?

BTW, if you just want to overwrite an attribute value, it is much more
straightforward just to do:

entry.Properties["xxxx].Value = xxxx;

That will probably make the problem go away, even if you don't ever learn
the exact underlying cause.

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
[quoted text, click to view]

Pucca
9/14/2007 2:34:02 PM
Yes, that did fix the problem. Because this problem only ocurring at the
Virutal Machine that doesn't have the VS installed so I dont' have any stack
information. However, the VM Win2k server has the same SP as my development
PC. But why would the same code ran OK on my server but not on the VM
server? Thank you.
--
Thanks.


[quoted text, click to view]
Pucca
9/14/2007 2:40:02 PM
Also, I was getting the error becuase I was committing with both "Clear" and
"Add" method done? AD would only allow commit of one Operation at a time?
Thank you.
--
Thanks.


[quoted text, click to view]
Pucca
9/14/2007 5:40:01 PM
Thank you Joe. So, there is probablly some differences between my
development PC and the VM pc. Even though I can confirm that both are win2k
server with sp4 and .net 2.0. It's strange that it would work on my PC but
not the vm. However, the fix per your suggestion did fix the problem. Thank
you very much.
--
Thanks.


[quoted text, click to view]
Joe Kaplan
9/14/2007 7:30:52 PM
Yes, the issue is that you with older versions of ADSI, you can't mix
different property modification operations. For example, in ADSI there is
an add, remove, replace and clear operation. If you do an operation on the
DirectoryEntry property cache that cause more than one of those to be done
before you commit changes, it will fail.

Newer versions of ADSI allow the multiple modifications. You normally get
different versions of ADSI with different versions of Windows (including
service packs), so that's why this issue tends to vary by OS. There have
been a variety of changes to the underlying implementation between .NET 1.0,
1.1, 1.1 SP1 and .NET 2.0, so if you have different .NET versions, that
could also be at issue.

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
[quoted text, click to view]

Joe Kaplan
9/14/2007 9:11:37 PM
You might check the versions of your ADSI DLLs and see if there is any
difference. Otherwise, I really don't know why you'd see a behavior
difference at all. At least you have a workaround. :)

Joe K.

--
Joe Kaplan-MS MVP Directory Services Programming
Co-author of "The .NET Developer's Guide to Directory Services Programming"
http://www.directoryprogramming.net
--
[quoted text, click to view]

AddThis Social Bookmark Button