【发布时间】:2020-12-24 22:26:57
【问题描述】:
下面的代码给了我错误system.argumentexception an element with the same key already exists。当我在 Friend Sub Test 中使用以下行时:'Dim str_rootdirectory As String = Directory.GetCurrentDirectory() ' "C:\TEMP" 它可以工作。有什么区别?
我的 VB.NET 代码:
Public Class Form1
Public Sub recur_getdirectories(ByVal di As DirectoryInfo)
For Each directory As DirectoryInfo In di.GetDirectories()
'get each directory and call the module main to get the security info and write to json
Call Module1.Main(directory.FullName)
recur_getdirectories(directory)
Next
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim rootDirectory As String = TextBox1.Text.Trim()
Dim di As New DirectoryInfo(rootDirectory)
'get directories recursively and work with each of them
recur_getdirectories(di)
End Sub
End Class
Public Module RecursiveEnumerableExtensions
Iterator Function Traverse(Of T)(ByVal root As T, ByVal children As Func(Of T, IEnumerable(Of T)), ByVal Optional includeSelf As Boolean = True) As IEnumerable(Of T)
If includeSelf Then Yield root
Dim stack = New Stack(Of IEnumerator(Of T))()
Try
stack.Push(children(root).GetEnumerator())
While stack.Count <> 0
Dim enumerator = stack.Peek()
If Not enumerator.MoveNext() Then
stack.Pop()
enumerator.Dispose()
Else
Yield enumerator.Current
stack.Push(children(enumerator.Current).GetEnumerator())
End If
End While
Finally
For Each enumerator In stack
enumerator.Dispose()
Next
End Try
End Function
End Module
Public Module TestClass
Function GetFileSystemAccessRule(d As DirectoryInfo) As IEnumerable(Of FileSystemAccessRule)
Dim ds As DirectorySecurity = d.GetAccessControl()
Dim arrRules As AuthorizationRuleCollection = ds.GetAccessRules(True, True, GetType(Security.Principal.NTAccount))
For Each authorizationRule As FileSystemAccessRule In arrRules
Dim strAclIdentityReference As String = authorizationRule.IdentityReference.ToString()
Dim strInheritanceFlags As String = authorizationRule.InheritanceFlags.ToString()
Dim strAccessControlType As String = authorizationRule.AccessControlType.ToString()
Dim strFileSystemRights As String = authorizationRule.FileSystemRights.ToString()
Dim strIsInherited As String = authorizationRule.IsInherited.ToString()
Next
' This function should return the following values, because they should be mentoined in the JSON:
' IdentityReference = strAclIdentityReference
' InheritanceFlags = strInheritanceFlags
' AccessControlType = strAccessControlType
' FileSystemRights = strFileSystemRights
' IsInherited = strIsInherited
Return ds.GetAccessRules(True, True, GetType(System.Security.Principal.NTAccount)).Cast(Of FileSystemAccessRule)()
End Function
Friend Sub Test(ByVal curDirectory As String)
'Dim str_rootdirectory As String = Directory.GetCurrentDirectory() ' "C:\TEMP"
Dim str_rootdirectory As String = curDirectory
Dim di As DirectoryInfo = New DirectoryInfo(str_rootdirectory)
Dim directoryQuery = RecursiveEnumerableExtensions.Traverse(di, Function(d) d.GetDirectories())
Dim list = directoryQuery.Select(
Function(d) New With {
.directory = d.FullName,
.permissions = {
GetFileSystemAccessRule(d).ToDictionary(Function(a) a.IdentityReference.ToString(), Function(a) a.FileSystemRights.ToString())
}
}
)
Dim json = JsonConvert.SerializeObject(list, Formatting.Indented)
File.WriteAllText("ABCD.json", json)
End Sub
End Module
Public Module Module1
Public Sub Main(ByVal curDirectory As String)
Console.WriteLine("Environment version: " & Environment.Version.ToString())
Console.WriteLine("Json.NET version: " & GetType(JsonSerializer).Assembly.FullName)
Console.WriteLine("")
Try
TestClass.Test(curDirectory)
Catch ex As Exception
Console.WriteLine("Unhandled exception: ")
Console.WriteLine(ex)
Throw
End Try
End Sub
End Module
我的示例文件夹结构:
文件夹: "C:\Temp"
权限: SecurityGroup-A 拥有完全控制权, SecurityGroup-B 有修改权限
文件夹: "C:\Temp\Folder_A"
权限: SecurityGroup-C 拥有完全控制权
但这只是两个文件夹的示例。实际上,它将运行数百个带有子文件夹的文件夹。因此 JSON 将扩展。
我的json输出期望:
[{
"directory": "C:\\TEMP",
"permissions": [{
"IdentityReference": "CONTOSO\\SecurityGroup-A",
"AccessControlType": "Allow",
"FileSystemRights": "FullControl",
"IsInherited": "TRUE"
}, {
"IdentityReference": "CONTOSO\\SecurityGroup-B",
"AccessControlType": "Allow",
"FileSystemRights": "Modify",
"IsInherited": "False"
}
]
}, {
"directory": "C:\\TEMP\\Folder_A",
"permissions": [{
"IdentityReference": "CONTOSO\\SecurityGroup-C",
"AccessControlType": "Allow",
"FileSystemRights": "Full Control",
"IsInherited": "False"
}
]
}
]
【问题讨论】:
-
您的 JSON 包含重复的属性名称 --
"RandomValue01"在同一个permissions对象中出现两次。这是您的问题中的错字还是您真的需要这个? -
最新的JSON RFC 声明当对象中的名称不唯一时,接收此类对象的软件的行为是不可预测的。 所以我不推荐允许在单个 JSON 对象中重复名称。
-
感谢您提供的信息,但带有随机值的 json 输出只是一个示例,以便更好地理解我的代码。实际上,这些值将是唯一的。我的问题更多基于我的 VB.NET 代码,它会随着每个新的 RandomValue 一起增长——我想防止这种情况发生,但是如何防止呢?
-
好的,在这种情况下,您可以将
permissions属性定义为List(Of Dictionary(Of String, String))。 Json.NET(和其他 JSON 序列化器,如System.Text.Json)会将字典序列化为带有动态键的 JSON 对象。演示在这里:dotnetfiddle.net/OeonWQ。这能回答你的问题吗? -
谢谢,但我认为我无法正确提出我的请求。让我们根据您的代码继续我的问题。想象在你的代码中你有一个新的子。在 sub 里面有一个代码,它将递归地循环通过你的 windows 文件系统并得到
a) all directorys in your windows explorer和b) read the security permissions of each directory。您将收到的数据超过千倍。但是您希望以 JSON 格式输出。如果不使用line 31/38 for directory和line 33/34/40 for RandomValues中的hardcoded values,您将如何在代码中实现这一点?