gpt4 book ai didi

c# - 使用 AccountManagement 扩展类时如何设置二进制属性?

转载 作者:行者123 更新时间:2023-11-30 16:20:11 28 4
gpt4 key购买 nike

我正在使用 custom class to expose some custom schema in Active Directory .我正在存储一个二进制 blob,根据项目要求,此数据必须存储在 AD 中,我不能使用外部存储(如果可以的话我会这样做)。

当我创建用户时,它会很好地存储 blob。我也可以很好地检索 blob 并获取我的所有数据。问题是如果我需要更新值并且出现错误

小示例程序:

using System;
using System.DirectoryServices.AccountManagement;

namespace SandboxConsole40
{
class Program
{
static void Main(string[] args)
{
using(var context = new PrincipalContext(ContextType.Domain))
{
using (var clear = ExamplePrincipal.FindByIdentity(context, "example"))
{
if (clear != null)
clear.Delete();
}

using (var create = new ExamplePrincipal(context, "example", "Password1", false))
{
create.Save();
}

using (var set = ExamplePrincipal.FindByIdentity(context, "example"))
{
set.BlobData = new byte[] { 0xDE, 0xAD, 0xBE, 0xEF }; //This fails with method 2.
set.Save();
}

using (var lookup = ExamplePrincipal.FindByIdentity(context, "example"))
{
Console.WriteLine(BitConverter.ToString(lookup.BlobData));
}

using (var update = ExamplePrincipal.FindByIdentity(context, "example"))
{
update.BlobData = new byte[] { 0x12, 0x34, 0x56, 0x67 };
update.Save(); //This save fails with method 1.
}
}

Console.WriteLine("Done");
Console.ReadLine();
}

[DirectoryObjectClass("user")]
[DirectoryRdnPrefix("CN")]
class ExamplePrincipal : UserPrincipal
{
public ExamplePrincipal(PrincipalContext context) : base(context) { }

public ExamplePrincipal(PrincipalContext context, string samAccountName, string password, bool enabled)
: base(context, samAccountName, password, enabled) { }

public static new ExamplePrincipal FindByIdentity(PrincipalContext context, string identityValue)
{
return (ExamplePrincipal)FindByIdentityWithType(context, typeof(ExamplePrincipal), identityValue);
}

[DirectoryProperty("vwBlobData")]
public byte[] BlobData
{
get
{
if (ExtensionGet("vwBlobData").Length != 1)
return null;

return (byte[])ExtensionGet("vwBlobData")[0];
}
set
{
//method 1
this.ExtensionSet("vwBlobData", value );

//method 2
//this.ExtensionSet("vwBlobData", new object[] { value});
}
}
}
}
}

如果我使用方法 1,我会在 update.Save() 操作中得到以下异常

System.DirectoryServices.AccountManagement.PrincipalOperationException was unhandled  HResult=-2146233087  Message=The specified directory service attribute or value already exists.  Source=System.DirectoryServices.AccountManagement  ErrorCode=-2147016691  StackTrace:       //Snip  InnerException: System.DirectoryServices.DirectoryServicesCOMException       HResult=-2147016691       Message=The specified directory service attribute or value already exists.       Source=System.DirectoryServices       ErrorCode=-2147016691       ExtendedError=8321       ExtendedErrorMessage=00002081: AtrErr: DSID-030F154F, #1:    0: 00002081: DSID-030F154F, problem 1006 (ATT_OR_VALUE_EXISTS), data 0, Att 82818fec (vwBlobData)       StackTrace:            //Snip       InnerException: 

如果我使用方法 2,我会从 set.BlobData 调用的 this.ExtensionSet 调用中得到异常。

System.ArgumentException was unhandled  HResult=-2147024809  Message=Collections whose elements are another collection cannot be set by ExtensionClasses.  Source=System.DirectoryServices.AccountManagement  StackTrace:      //Snip  InnerException: 

总结:如果当前未设置该值,我可以设置该值,但如果我想覆盖现有值,则会出现错误。

最佳答案

我找到了解决方法,首先将值设置为 null 它不再抛出异常。

using (var update = ExamplePrincipal.FindByIdentity(context, "example"))
{
update.BlobData = null;
update.Save();
update.BlobData = new byte[] { 0x12, 0x34, 0x56, 0x67 };
update.Save(); //No longer fails with method 1.
}

如果有“正确”的方法,我将问题暂时悬而未决,看看是否还有其他人可以回答。


找到不需要强制保存的第二个解决方法。

[DirectoryProperty("vwBlobData")]
public byte[] BlobData
{
get
{
if (ExtensionGet("vwBlobData").Length != 1)
return null;

return (byte[])ExtensionGet("vwBlobData")[0];
}
set
{
((DirectoryEntry)this.GetUnderlyingObject())
.Properties["vwBlobData"].Value = value;
}
}

通过直接转换为底层对象,您可以直接设置值。我使用 ILSpy 检查并处理 AccountManagement 包装器处理底层对象,因此 GetUnderlyingObject() 调用不需要 Dispose()


最佳解决方案

我发现第二种变通方法需要持久化对象才能工作,所以我采用了两全其美的方法。这适用于您尚未持久化对象、对象为 null 以及对象已具有值的情况。

[DirectoryProperty("vwBlobData")]
public byte[] BlobData
{
get
{
if (ExtensionGet("vwBlobData").Length != 1)
return null;

return (byte[])ExtensionGet("vwBlobData")[0];
}
set
{
if(ExtensionGet("vwBlobData").Length == 0)
this.ExtensionSet("vwBlobData", data);
else
((DirectoryEntry)this.GetUnderlyingObject())
.Properties["vwBlobData"].Value = data;
}
}

关于c# - 使用 AccountManagement 扩展类时如何设置二进制属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14566887/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com