.NET Forum / .NET Framework / Security / September 2007
Why got error "Only one type of operation can be performed in a se
|
|
Thread rating:  |
Pucca - 13 Sep 2007 17:26 GMT 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.
 Signature Thanks.
Joe Kaplan - 13 Sep 2007 17:34 GMT 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.
 Signature Joe Kaplan-MS MVP Directory Services Programming Co-author of "The .NET Developer's Guide to Directory Services Programming" http://www.directoryprogramming.net --
> 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 [quoted text clipped - 5 lines] > > Does anyone what could possiblly be causing this error? Thank you. Pucca - 13 Sep 2007 18:40 GMT 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, globalPath, sid, ugid, true, unifiedID); if (!success) continue; newRows[index]["Imported"] = true; newRows[index]["Mapped"] = System.DBNull.Value; //to indicate no changes since commit if (!importUsers) { if (numOfGroupMapped > 0) numOfGroupMapped--; newRows[index]["MemberShip"] = true; } else { if(numOfUserMapped > 0) numOfUserMapped--; } } } }//end try catch (Exception ex) { MessageBox.Show(ex.Message, "PowerADvantage"); } finally { //clean up if (dsGlobal != null) dsGlobal.Dispose(); if (deSearchRoot != null) deSearchRoot.Dispose(); if (deUGID != null) deUGID.Dispose(); if (success) this.btnCommit.Enabled = false; } dgvTarget.Refresh(); return true; }
private bool Commit(DataRow dr, bool flag, string globalPath, string sid, int ugid, bool createGlob, int unifiedID) { DirectoryEntry deParent = new DirectoryEntry(), deAdUserFolder=null, dePrimaryGroup=new DirectoryEntry(); DirectoryEntry deNewContextObject = new DirectoryEntry(), deAdObjectImportTo = new DirectoryEntry(), deNewGloblObject = new DirectoryEntry(); string parentPath, strGid, pGroupSid = "", userName = "", globalFolderPath = CUnityDS.globalGroupsPath +dtGlobal.Rows[0]["curDomain"], adUserGroupFolderPath = "LDAP://CN=USERS, " + dtGlobal.Rows[0]["curDomain"], path; bool result = true, alreadyMember = false;
// create an instance of the Blob structure CUnityDS.Blob blob = new CUnityDS.Blob();
try { deAdUserFolder = new DirectoryEntry(dtGlobal.Rows[0]["ADPath"].ToString()); deAdObjectImportTo = CUnityDS.GetAdDE(sid, deAdUserFolder);
//Check to see if there is already a context object with this sid path = "LDAP://CN=Contexts,CN=PowerADvantage,CN=Symark,CN=Program Data," + curDomain; DirectoryEntry deSrchRoot = new DirectoryEntry(path); deNewContextObject = CUnityDS.GetContextEntry(deAdObjectImportTo, deSrchRoot); if (deNewContextObject != null) deNewContextObject.DeleteTree(); //Check to see if there is already a global object with this sid deSrchRoot.Path = globalFolderPath; deNewContextObject = CUnityDS.GetContextEntry(deAdObjectImportTo, deSrchRoot); if (deNewContextObject != null) deNewContextObject.DeleteTree();
//Start by creating the new user or group in the Context directory string cn = "cn=" + sid; deParent.Path = contextPath; deNewContextObject = deParent.Children.Add(cn, "meeting"); deParent.CommitChanges();
string UnixName = dr["Account"].ToString(); string strID = ugid.ToString(); deNewContextObject.Properties["meetingName"].Add((object)(UnixName));//unix account deNewContextObject.Properties["meetingID"].Add((object)(strID));//u/g id deNewContextObject.Properties["meetingMaxParticipants"].Add((object)("1")); //enabled deNewContextObject.CommitChanges();
#region Get PrimaryGroup //Get the user's primary Group sid if (importUsers) { pGroupSid = dr["pGroupSid"].ToString(); if(pGroupSid == "" || pGroupSid == null) { MessageBox.Show("Primary group is not found in Active Directory. " + deAdObjectImportTo.Properties["displayName"].Value.ToString() + " cannot be imported."); return false; } //We need to get the AD de of the primary group. We have to add the AD user of //the row that we're adding to context a member of this group in AD dePrimaryGroup = CUnityDS.GetAdDE(pGroupSid, deAdUserFolder); if (dePrimaryGroup == null) { MessageBox.Show("Primary group is not found in Active Directory. " + deAdObjectImportTo.Properties["displayName"].Value.ToString() + " cannot be imported."); result = false;
} else //Got the primary group de { string primaryGroupName = "CN=" + dePrimaryGroup.Properties["cn"].Value.ToString() + ","; //If the user to import is not a member of the primary group then make it so //Get rid of the ladp:// before append then verify membership
alreadyMember = CUnityDS.IsMemberAlready(primaryGroupName, deAdObjectImportTo);
path = deAdObjectImportTo.Path.Substring(7, deAdObjectImportTo.Path.Length - 7); if (!alreadyMember) { dePrimaryGroup.Properties["member"].Add(path); dePrimaryGroup.CommitChanges(); } if (pGroupSid == null) { MessageBox.Show("Error importing " + userName + ": Primary group GID can not be null or blank. Please correct and try again.", "PowerADvantage"); return false; } #endregion Get PrimaryGroup
CUnityDS.CUserContextData userContextData = new CUnityDS.CUserContextData(); //if Windows Logon Name = Unix Account name then set flag to use windlogon if (deAdObjectImportTo.Properties["sAMAccountName"].Value.ToString() == UnixName) userContextData.bWinLogOn = 1; else userContextData.bWinLogOn = 0; if (flag)//Use Unified ID? userContextData.bUnifiedID = 1; else userContextData.bUnifiedID = 0;
userContextData.IID = ugid; userContextData.Revision = 0;
userContextData.homeDir = dr["Directory"].ToString(); userContextData.shell = dr["Shell"].ToString(); userContextData.primaryGroupSID = pGroupSid;
// // allocate memry for the blob IntPtr pBlob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CUnityDS.Blob))); // call the function passing the pointer to the blob byref CUnityDS.LibWrap.EncodeAsnUser(ref pBlob, userContextData); // copy the unmanaged blob to managed struct Blob blob = (CUnityDS.Blob)Marshal.PtrToStructure(pBlob, typeof(CUnityDS.Blob)); // allocate byte array with size of blob.nLength byte[] meetingBlob = new byte[blob.nLength]; // marshal the data pointed to by pData into the byte array System.Runtime.InteropServices.Marshal.Copy(blob.pData, meetingBlob, 0, blob.nLength); //add the blob deNewContextObject.Properties["meetingBlob"].Add((object)meetingBlob);
deNewContextObject.CommitChanges(); result = true; numOfUserMapped++; } }//end importing a user else //importing a group { CUnityDS.CGroupContextData groupContextData = new CUnityDS.CGroupContextData(); //if Windows Logon Name = Unix Account name then set flag to use windlogon if (deAdObjectImportTo.Properties["sAMAccountName"].Value.ToString() == UnixName) groupContextData.bWinGroupName = 1; else groupContextData.bWinGroupName = 0; if (flag)//Use Unified ID? groupContextData.bUnifiedID = 1; else groupContextData.bUnifiedID = 0;
groupContextData.IID = ugid; groupContextData.Revision = 0;
// // allocate memry for the blob IntPtr pBlob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CUnityDS.Blob))); // call the function passing the pointer to the blob byref CUnityDS.LibWrap.EncodeAsnGroup(ref pBlob, groupContextData); // copy the unmanaged blob to managed struct Blob blob = (CUnityDS.Blob)Marshal.PtrToStructure(pBlob, typeof(CUnityDS.Blob)); // allocate byte array with size of blob.nLength byte[] meetingBlob = new byte[blob.nLength]; // marshal the data pointed to by pData into the byte array System.Runtime.InteropServices.Marshal.Copy(blob.pData, meetingBlob, 0, blob.nLength);
//add the blob deNewContextObject.Properties["meetingBlob"].Add((object)meetingBlob); deNewContextObject.CommitChanges(); result = true; numOfGroupMapped++;
} //if the context object was created successfully then create the Global object otherwise exit if (result == true) { //Now create the Global user or group object deParent.Path = globalFolderPath; deNewGloblObject = deParent.Children.Add(cn, "meeting"); deParent.CommitChanges(); if (deNewGloblObject != null) { deNewGloblObject.Properties["meetingName"].Add(dr["Login Name"].ToString()); deNewGloblObject.Properties["meetingID"].Add(unifiedID); deNewGloblObject.CommitChanges(); result = true; } else//Global object fail to create, return null then remove the matching context object { if (deNewContextObject == null) { deParent.Path = contextPath; deParent.Children.Remove(deNewContextObject); deParent.CommitChanges(); } result = false; } } } catch (Exception ex) { if (ex.Message.Contains("already exist")) { result = true; } else//Global object fail to create so delete the matching context object { MessageBox.Show(ex.Message, "PowerADvantage"); deParent.Path = contextPath; deParent.Children.Remove(deNewContextObject); deParent.CommitChanges(); result = false; } } finally { //clean up if (deParent != null) deParent.Dispose(); if (deNewContextObject != null) deNewContextObject.Dispose(); if (deAdUserFolder != null) deAdUserFolder.Dispose(); if (dePrimaryGroup != null) dePrimaryGroup.Dispose(); if (deAdObjectImportTo != null) deAdObjectImportTo.Dispose(); }
return result; }
 Signature Thanks.
> 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 [quoted text clipped - 18 lines] > > > > Does anyone what could possiblly be causing this error? Thank you. Pucca - 13 Sep 2007 22:42 GMT 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();
 Signature Thanks.
> 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 [quoted text clipped - 18 lines] > > > > Does anyone what could possiblly be causing this error? Thank you. Joe Kaplan - 13 Sep 2007 22:49 GMT 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.
 Signature Joe Kaplan-MS MVP Directory Services Programming Co-author of "The .NET Developer's Guide to Directory Services Programming" http://www.directoryprogramming.net --
> 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 [quoted text clipped - 40 lines] >> > >> > Does anyone what could possiblly be causing this error? Thank you. Pucca - 14 Sep 2007 22:34 GMT 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.
 Signature Thanks.
> 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. [quoted text clipped - 55 lines] > >> > > >> > Does anyone what could possiblly be causing this error? Thank you. Pucca - 14 Sep 2007 22:40 GMT 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.
 Signature Thanks.
> 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. [quoted text clipped - 55 lines] > >> > > >> > Does anyone what could possiblly be causing this error? Thank you. Joe Kaplan - 15 Sep 2007 01:30 GMT 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.
 Signature Joe Kaplan-MS MVP Directory Services Programming Co-author of "The .NET Developer's Guide to Directory Services Programming" http://www.directoryprogramming.net --
> Also, I was getting the error becuase I was committing with both "Clear" > and [quoted text clipped - 71 lines] >> >> > >> >> > Does anyone what could possiblly be causing this error? Thank you. Pucca - 15 Sep 2007 01:40 GMT 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.
 Signature Thanks.
> 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 [quoted text clipped - 86 lines] > >> >> > > >> >> > Does anyone what could possiblly be causing this error? Thank you. Joe Kaplan - 15 Sep 2007 03:11 GMT 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.
 Signature Joe Kaplan-MS MVP Directory Services Programming Co-author of "The .NET Developer's Guide to Directory Services Programming" http://www.directoryprogramming.net --
> 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 [quoted text clipped - 4 lines] > Thank > you very much.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|