निम्नलिखित कोड मुझे त्रुटि देता है system.argumentexception an element with the same key already exists। जब मैं मित्र उप परीक्षण में निम्न पंक्ति का उपयोग करता हूं: '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"

अनुमतियां: सुरक्षा समूह-ए का पूर्ण नियंत्रण है, सुरक्षा समूह-बी में संशोधित अनुमति है

फ़ोल्डर: "C:\Temp\Folder_A"

अनुमतियां: SecurityGroup-C का पूर्ण नियंत्रण है

लेकिन यह केवल दो फोल्डर का एक उदाहरण है। वास्तव में, यह उप-फ़ोल्डरों के साथ कई सौ फ़ोल्डरों पर चलेगा। तदनुसार 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"
            }
        ]
    }
]
1
Baku Bakar 25 पद 2020, 01:26
आपके JSON में डुप्लीकेट प्रॉपर्टी नाम हैं -- "RandomValue01" एक ही permissions ऑब्जेक्ट में दो बार दिखाई देता है। क्या यह आपके प्रश्न में एक टाइपो है या आपको वास्तव में इसकी आवश्यकता है?
 – 
dbc
25 पद 2020, 23:59
नवीनतम JSON RFC बताता है कि नाम कब किसी ऑब्जेक्ट के भीतर अद्वितीय नहीं हैं, ऐसे ऑब्जेक्ट को प्राप्त करने वाले सॉफ़्टवेयर का व्यवहार अप्रत्याशित है। इसलिए मैं एक JSON ऑब्जेक्ट के भीतर डुप्लिकेट नामों की अनुमति देने की अनुशंसा नहीं करता हूं।
 – 
dbc
26 पद 2020, 00:09
जानकारी के लिए धन्यवाद, लेकिन मेरे कोड को बेहतर ढंग से समझने के लिए, रैंडमवेल्यू के साथ जोंस आउटपुट सिर्फ एक उदाहरण है। वास्तव में मूल्य अद्वितीय होंगे। मेरा प्रश्न मेरे VB.NET कोड पर आधारित है, जो प्रत्येक नए RandomValue के साथ बड़ा होगा - मैं इसे रोकना चाहता हूं, लेकिन कैसे?
 – 
Baku Bakar
26 पद 2020, 00:13
ठीक है, उस स्थिति में आप permissions संपत्ति को List(Of Dictionary(Of String, String)) के रूप में परिभाषित कर सकते हैं। Json.NET (और अन्य JSON धारावाहिक जैसे System.Text.Json) एक शब्दकोश को गतिशील कुंजियों के साथ JSON ऑब्जेक्ट के रूप में क्रमबद्ध करेंगे। यहां डेमो करें: dotnetfiddle.net/OeonWQ। क्या वह आपके सवाल का जवाब है?
 – 
dbc
26 पद 2020, 00:14
1
हाँ धन्यवाद! जादू की तरह काम करता है।
 – 
Baku Bakar
27 पद 2020, 17:33

1 उत्तर

सबसे बढ़िया उत्तर

आपका वर्तमान JSON [*].permissions[*] ऑब्जेक्ट्स के लिए स्थिर प्रॉपर्टी नामों का उपयोग करता है, इसलिए ToDictionary() के माध्यम से उनकी सूची को वैरिएबल कुंजी नामों के साथ डिक्शनरी में बदलने की कोशिश करने की कोई आवश्यकता नहीं है:

' This is not needed
.permissions = {
    GetFileSystemAccessRule(d).ToDictionary(Function(a) a.IdentityReference.ToString(), Function(a) a.FileSystemRights.ToString())
}

इसके बजाय, क्रमांकन के लिए प्रत्येक FileSystemAccessRule को कुछ उपयुक्त DTO में बदलें। एक अनाम प्रकार की वस्तु इस उद्देश्य के लिए अच्छी तरह से काम करती है:

Public Module DirectoryExtensions
    Function GetFileSystemAccessRules(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))
        Return arrRules.Cast(Of FileSystemAccessRule)()
    End Function
    
    Public Function SerializeFileAccessRules(ByVal curDirectory As String, Optional ByVal formatting As Formatting = Formatting.Indented)
        Dim di As DirectoryInfo = New DirectoryInfo(curDirectory)

        Dim directoryQuery = RecursiveEnumerableExtensions.Traverse(di, Function(d) d.GetDirectories())

        Dim list = directoryQuery.Select(
            Function(d) New With {
                .directory = d.FullName,
                .permissions = GetFileSystemAccessRules(d).Select(
                    Function(a) New With { 
                        .IdentityReference = a.IdentityReference.ToString(),
                        .AccessControlType = a.AccessControlType.ToString(),
                        .FileSystemRights = a.FileSystemRights.ToString(),
                        .IsInherited = a.IsInherited.ToString()
                    }
                )
            }
        )
        Return JsonConvert.SerializeObject(list, formatting)    
    End Function
End Module

Public Module RecursiveEnumerableExtensions
    ' Translated to vb.net from this answer https://stackoverflow.com/a/60997251/3744182
    ' To https://stackoverflow.com/questions/60994574/how-to-extract-all-values-for-all-jsonproperty-objects-with-a-specified-name-fro
    ' which was rewritten from the answer by Eric Lippert https://stackoverflow.com/users/88656/eric-lippert
    ' to "Efficient graph traversal with LINQ - eliminating recursion" https://stackoverflow.com/questions/10253161/efficient-graph-traversal-with-linq-eliminating-recursion
    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

डेमो फिडल यहां (जो दुर्भाग्य से https://dotnetfiddle.net क्लाइंट कोड पर सुरक्षा प्रतिबंधों के कारण लेकिन पूर्ण विश्वास में चलने योग्य होना चाहिए)।

1
dbc 27 पद 2020, 18:16