JsonPath more examples.
In my blog I have a lot of example of Xpath (navigation to XML document), all programmers use Xpath since XML document was born, my firs notes about Xpath I write at 2001 year:
- 2001: XQUERY и XPATH
- 2005: XSLT-преобразования.
- 2009: Как парсить XML SOAP в MS SQL
- 2018: Parse HTML by HtmlAgilityPack (Xpath selector) and CsQuery (jQuery selector).
- 2021: Linux shell parser (Renci.SshNet.SshClient, MySqlConnector.NET, RSA encription, Console password, XDocument/XPath, Tuple, Regex, Buffer.BlockCopy, Stream, Base64String, UTF8.GetBytes, ToString("X2"))
I use JSON permanently in my project, for example I'm author of Prozorro auction web site Prozorro useful links, whole this site based on JSON manipulation. However I still have no even one topic about JsonPath navigation. A couple of simplest examples you can see in page https://www.newtonsoft.com/json/help/html/SelectToken.htm, but my current project uses JSON as base format and all my backend API return JSON data. Therefore I must parse JSON in frontend and in BLL layer, what use data from other elementary API.
This is controller wrapper around my BLL singleton service. More details about singleton function please see in page Notes about singleton service..
1: Imports BackendAPI.KVM
2: Imports BackendAPI.Model
3: Imports BackendAPI.Services
4: Imports BackendAPI.Helper
5: Imports Microsoft.AspNetCore.Http
6: Imports Microsoft.AspNetCore.Mvc
7: Imports Microsoft.AspNetCore.Routing
8: Imports Microsoft.Extensions.Configuration
9: Imports Microsoft.Extensions.Logging
10: Imports System.Xml.XPath
11: Imports System.Net.Mime
12: Imports Microsoft.EntityFrameworkCore
13: Imports Microsoft.AspNetCore.Hosting
14: Imports System.Reflection
15: Imports BackendAPI.Coin
16: Imports Newtonsoft.Json
17: Imports System.Net.Mime.MediaTypeNames
18: Imports Newtonsoft.Json.Linq
19: Imports Microsoft.Extensions.DependencyInjection
20:
21: Namespace WebApi.Controllers
22:
23:
24: <ApiController>
25: <Route("[controller]/[action]")>
26: Public Class KvmDeployVmController
27: Inherits ControllerBase
28:
29: Private ReadOnly _UserService As IUserService
30: Private _DbForTrace As ApplicationDbContext
31: Private _DB As ApplicationDbContext
32: Private ReadOnly _Log As ILogger(Of KvmDeployVmController)
33: Private ReadOnly _Trace As Boolean
34: Private ReadOnly _WithResult As Boolean
35: Private ReadOnly _Aes As AesCryptor
36: Private ReadOnly _httpContextAccessor As IHttpContextAccessor
37: Private ReadOnly _urlHelper As LinkGenerator
38: Private ReadOnly _WebHostEnvironment As IWebHostEnvironment
39: Private ReadOnly _VmImage As VmImageController
40: Private ReadOnly _KvmDiskOperation As KvmDiskOperationController
41: Private ReadOnly _DeployVmService As DeployVmService
42: Private ReadOnly _Configuration As IConfiguration
43: Private ReadOnly _KvmOperation As KvmOperationController
44: ReadOnly _RequestTraceID As String
45:
46: Public Sub New(ByVal UserService As IUserService,
47: DbContext As ApplicationDbContext,
48: Logger As ILogger(Of KvmDeployVmController),
49: Configuration As IConfiguration,
50: Cryptor As IAesCryptor,
51: httpContextAccessor As IHttpContextAccessor,
52: urlHelper As LinkGenerator,
53: webHostEnvironment As IWebHostEnvironment,
54: VmImageController As VmImageController,
55: KvmDiskOperationController As KvmDiskOperationController,
56: KvmOperationController As KvmOperationController)
57:
58: _UserService = UserService
59: _DB = DbContext
60: _Log = Logger
61: _Aes = Cryptor
62: _httpContextAccessor = httpContextAccessor
63: _urlHelper = urlHelper 'trash
64: _Trace = Configuration.GetValue(Of Boolean)("TraceAPI:Trace")
65: _WithResult = Configuration.GetValue(Of Boolean)("TraceAPI:Trace")
66: _Configuration = Configuration
67: _WebHostEnvironment = webHostEnvironment
68: _VmImage = VmImageController
69: _KvmDiskOperation = KvmDiskOperationController
70: _KvmOperation = KvmOperationController
71: _DeployVmService = Startup.DeployVmServiceInstance
72: End Sub
73:
74: <State("Ok. BLL function working with singlton service")>
75: <Security(SecurityLevel.User)>
76: <TraceResponse()>
77: <Jwt.Authorize>
78: <HttpPost>
79: Public Function DeployVM(Model As DeployVmRequest) As IActionResult
80: TraceRequest(Reflection.MethodBase.GetCurrentMethod.Name, "")
81: Dim CurUsers = _UserService.GetCurrentUser(_httpContextAccessor.HttpContext.Request.Headers("JwtUserName")(0))
82: If CurUsers.IsAdmin Or Check(Reflection.MethodBase.GetCurrentMethod.Name, Model, _DB) Then
83: Dim Ret1 As JArray = _DeployVmService.DeployVM(
84: _DB,
85: _UserService,
86: _KvmOperation,
87: _httpContextAccessor,
88: _WebHostEnvironment,
89: _KvmDiskOperation,
90: _VmImage,
91: _Configuration,
92: _Aes,
93: Me,
94: CurUsers,
95: Model.ToCoin,
96: Model.ServerI,
97: Model.ServerDecryptPass)
98: Return Ok(Ret1)
99: Else
100: Return Unauthorized()
101: End If
102: End Function
...:
And this is singleton service to allocation VM for project user. This function has more than 100 steps (and during project evolution new and new steps is appears), so in this example I will show first 7 step.
1: Public Enum DeployVmState
2: Ready = 0
3: Start = 1
4: NotEmpty = 2
5: AbortListPartitionImagesFromDB = 4
6: ListPartitionImages = 5
7: AbortListPartitionImages = 6
8: ListPartitionImagesCompare = 7
9: AbortListPartitionImagesCompare = 8
10: SelectPartitionToDeploy = 9
11: AbortSelectPartitionToDeploy = 10
12: AbortToKvmStorageDevice = 11
13: SelectPartitionToDeployCompare = 12
14: AbortSelectPartitionToDeployCompare = 13
15: AddPartitionToServer = 14
16: AbortAddPartitionToServer = 15
17: AbortAddPartitionToServerStrangeResult = 16
18: ListDevicePartition = 17
19: AbortListDevicePartition = 18
20: ListDiskDevice = 19
21: AbortListDiskDevice = 20
22: AddPartitionToDB = 21
23: AbortAddPartitionToDB = 22
..:
Result of allocation (DeployVmState)is stored in singleton service and need to reset for other allocation.
1: Imports System.Drawing
2: Imports BackendAPI.KVM
3: Imports BackendAPI.Model
4: Imports BackendAPI.Services
5: Imports BackendAPI.VM
6: Imports BackendAPI.WebApi.Controllers
7: Imports Microsoft.AspNetCore.Hosting
8: Imports Microsoft.AspNetCore.Http
9: Imports Microsoft.AspNetCore.Mvc
10: Imports Microsoft.AspNetCore.Mvc.Routing
11: Imports Microsoft.AspNetCore.Routing
12: Imports Microsoft.Extensions.Configuration
13: Imports Microsoft.Extensions.DependencyInjection
14: Imports Microsoft.Extensions.Logging
15: Imports Newtonsoft
16: Imports Newtonsoft.Json
17: Imports Newtonsoft.Json.Linq
18:
19: Public Class DeployVmService
20: Implements IDeployVmService
21:
22: Private Shared ReadOnly _DeployVmServiceInstance As DeployVmService = New DeployVmService()
23: Private Shared _CurrentState As DeployVmState
24: Private Shared _ServiceCount As Integer = 0
25: Private Shared _DeployLog As JArray
26: Private Shared _DB As ApplicationDbContext
27: Private Shared _Log As ILogger(Of IDeployVmService)
28: Private Shared _Trace As Boolean
29: Private Shared _WithResult As Boolean
30: Private Shared _Aes As AesCryptor
31: Private Shared _HttpContextAccessor As IHttpContextAccessor
32: Private Shared _KvmOperation As KvmOperationController
33: Private Shared _KvmDiskOperation As KvmDiskOperationController
34: Private Shared _VmImage As VmImageController
35: Private Shared _KvmDeployVm As KvmDeployVmController
36: Private Shared _UserService As IUserService
37:
38: #Region "Singlton"
39: Public Sub New()
40: _DeployLog = New JArray()
41: _CurrentState = DeployVmState.Ready
42: _ServiceCount += 1
43: End Sub
44:
45: 'GetInstance() method that returns the value of the static variable
46: Public Shared Function GetInstance() As DeployVmService
47: Return _DeployVmServiceInstance
48: End Function
49:
50: Public Function GetServiceCount() As Integer Implements IDeployVmService.GetServiceCount
51: Return _ServiceCount
52: End Function
53: #End Region
54: Public Function GetState() As DeployVmState Implements IDeployVmService.GetState
55: Return _CurrentState
56: End Function
57:
58: Public Function GetDeployLog() As JArray Implements IDeployVmService.GetDeployLog
59: Return _DeployLog
60: End Function
61:
62: Public Function DeployVM(
63: DbContext As ApplicationDbContext,
64: UserService As IUserService,
65: KvmOperation As KvmOperationController,
66: httpContextAccessor As IHttpContextAccessor,
67: webHostEnvironment As IWebHostEnvironment,
68: KvmDiskOperation As KvmDiskOperationController,
69: VmImage As VmImageController,
70: Configuration As IConfiguration,
71: Cryptor As IAesCryptor,
72: KvmDeployVm As KvmDeployVmController,
73: CurUsers As ApplicationUser,
74: ToCoin As Integer,
75: ServerI As Integer,
76: ServerDecryptPass As String) As JArray Implements IDeployVmService.DeployVM
77:
78: _Log = Startup.LoggerFactoryInstance.CreateLogger(Of DeployVmService)
79: _UserService = UserService
80: _DB = DbContext
81: _Aes = Cryptor
82: _HttpContextAccessor = httpContextAccessor
83: _Trace = Configuration.GetValue(Of Boolean)("TraceAPI:Trace")
84: _WithResult = Configuration.GetValue(Of Boolean)("TraceAPI:Trace")
85: _KvmOperation = KvmOperation
86: _KvmDiskOperation = KvmDiskOperation
87: _VmImage = VmImage
88: _KvmDeployVm = KvmDeployVm
89: _CurrentState = DeployVmState.Start
90: '
91: Dim IsNotEmpty As Boolean = _DeployLog.Any
92: If Not IsNotEmpty Then
93: '
94: Dim Res1 As IActionResult = _VmImage.ListPartitionImagesFromDB()
95: If Res1.GetType.Name = "OkObjectResult" Then
96: AddOkResultToDeploylog(Of List(Of KvmVmImage))(Res1, "ListPartitionImagesFromDB")
97: _CurrentState = DeployVmState.ListPartitionImages
98: 'check is Image really present
99: Dim Res2 As IActionResult = _VmImage.ListPartitionImages(New ListPartitionImagesRequest With {
100: .ServerI = ServerI,
101: .ServerDecryptPass = ServerDecryptPass
102: })
103: If Res2.GetType.Name = "OkObjectResult" Then
104: Dim Res2Value As List(Of Tmp1) = JsonConvert.DeserializeObject(Of List(Of Tmp1))(JsonConvert.SerializeObject(TryCast(Res2, OkObjectResult).Value))
105: Dim Res2Log As New JObject
106: Res2Log.Add("ListPartitionImages", JToken.FromObject(Res2Value))
107: _DeployLog.Add(Res2Log)
108: Dim ImageDbPresent As List(Of String) = _DeployLog.SelectToken("$..ListPartitionImagesFromDB").SelectTokens("$..FileName").Select(Of String)(Function(X) X).ToList
109: Dim FileRepository As List(Of String) = _DeployLog.SelectToken("$..ListPartitionImages").SelectTokens("$..Name").Select(Of String)(Function(X) X).ToList
110: Dim FilePresentInBothPlace = ImageDbPresent.Where(Function(X) FileRepository.Any(Function(Z) Z = X)).FirstOrDefault
111: If Not String.IsNullOrEmpty(FilePresentInBothPlace) Then
112: _CurrentState = DeployVmState.ListPartitionImagesCompare
113: Dim VmImageFileNameForDeploy As String = _DeployLog.SelectToken("$..ListPartitionImagesFromDB[?(@.ToCoin == " & ToCoin & ")].FileName").Value(Of String)
114: 'check with needed size to selected coin
115: Dim Res3 As IActionResult = _KvmDeployVm.SelectPartitionToDeploy1(New SelectPartitionToDeployRequest With {
116: .ServerI = ServerI,
117: .ServerDecryptPass = ServerDecryptPass,
118: .ToCoin = ToCoin
119: })
120: If Res3.GetType.Name = "OkObjectResult" Then
121: AddOkResultToDeploylog(Of AdmKvmDevicePartitionReport)(Res3, "SelectPartitionToDeploy")
122: _CurrentState = DeployVmState.ListPartitionImages
124: Dim FreePartSectors As Long = _DeployLog.SelectToken("$..SelectPartitionToDeploy").SelectTokens("$..Length").Select(Of Long)(Function(X) X).FirstOrDefault
125: Dim StartTrack As Long = _DeployLog.SelectToken("$..SelectPartitionToDeploy").SelectTokens("$..Start").FirstOrDefault.Value(Of Long)
126: Dim EndTrack As Long = _DeployLog.SelectToken("$..SelectPartitionToDeploy").SelectTokens("$..End").FirstOrDefault.Value(Of Long)
127: Dim StorageDevice As String = _DeployLog.SelectToken("$..SelectPartitionToDeploy").SelectTokens("$..StorageDevice").FirstOrDefault.Value(Of String)
128: Dim ToKvmStorageDeviceToken = _DeployLog.SelectToken("$..SelectPartitionToDeploy").SelectTokens("$..ToKvmStorageDevice").FirstOrDefault
129: If ToKvmStorageDeviceToken IsNot Nothing Then
130: Dim ToKvmStorageDevice As Integer = _DeployLog.SelectToken("$..SelectPartitionToDeploy").SelectTokens("$..ToKvmStorageDevice").FirstOrDefault.Value(Of Integer)
131: Dim VmImageSource As Long = _DeployLog.SelectToken("$..ListPartitionImagesFromDB[?(@.FileName=='" & VmImageFileNameForDeploy & "')].SourceSize").Value(Of Long)
132: If FreePartSectors * 512 >= VmImageSource Then
133: _CurrentState = DeployVmState.SelectPartitionToDeployCompare
134: 'add new partition to server
135: Dim Res4 As IActionResult = _KvmDiskOperation.AddPartitionToServer(New AddPartitionRequest With {
136: .ServerI = ServerI,
137: .ServerDecryptPass = ServerDecryptPass,
138: .ServerDevice = StorageDevice,
139: .StartTrack = StartTrack,
140: .EndTrack = EndTrack
141: })
142: If Res4.GetType.Name = "OkObjectResult" Then
143: Dim Res4Value As Tmp2 = JsonConvert.DeserializeObject(Of Tmp2)(JsonConvert.SerializeObject(TryCast(Res4, OkObjectResult).Value))
144: Dim Res4Log As New JObject
145: Res4Log.Add("AddPartitionToServer", JToken.FromObject(Res4Value))
146: _DeployLog.Add(Res4Log)
147: 'correct is
148: '{"value":{"error":["Information: You may need to update /etc/fstab.","",""],"result":["\r
149: '"{""Value"":{""Error"":[""Warning: The resulting partition is not properly aligned for best performance:"",""234881058s % 2048s != 0s"",""Information: You may need to update /etc/fstab."","""",""""],
150: If Res4Value.Value.[Error].Any(Function(X) X = "Information: You may need to update /etc/fstab.") Then
151: _CurrentState = DeployVmState.ListDevicePartition
152: 'prepare parameters for AddPartitionToDB
153: Dim Res5 As IActionResult = _KvmDiskOperation.ListDevicePartition(New ListPartitionRequest With {
154: .ServerI = ServerI,
155: .ServerDecryptPass = ServerDecryptPass,
156: .ServerDevice = StorageDevice
157: })
158: If Res5.GetType.Name = "OkObjectResult" Then
159: AddOkResultToDeploylog(Of ListDevicePartitionOkResponse)(Res5, "ListDevicePartition")
160: _CurrentState = DeployVmState.ListDevicePartition
161: Dim ToKvmHost As Integer = _DeployLog.SelectToken("$..ListDevicePartition.KvmStorageDevice.ToKvmHost").Value(Of Integer)
162: Dim NewPartitionName As String = _DeployLog.SelectToken("$..ListDevicePartition").SelectToken("$.KvmDevicePartition[?(@.Start == " & StartTrack & ")].Name").Value(Of String)
163: Dim NewPartitionType As String = _DeployLog.SelectToken("$..ListDevicePartition").SelectToken("$.KvmDevicePartition[?(@.Start == " & StartTrack & ")].Type").Value(Of String)
164: Dim NewPartitionSize As String = _DeployLog.SelectToken("$..ListDevicePartition").SelectToken("$.KvmDevicePartition[?(@.Start == " & StartTrack & ")].Size").Value(Of String)
165: Dim NewPartitionStart As Long = _DeployLog.SelectToken("$..ListDevicePartition").SelectToken("$.KvmDevicePartition[?(@.Start == " & StartTrack & ")].Start").Value(Of Long)
166: Dim NewPartitionEnd As Long = _DeployLog.SelectToken("$..ListDevicePartition").SelectToken("$.KvmDevicePartition[?(@.Start == " & StartTrack & ")].End").Value(Of Long)
167: Dim NewPartitionSectors As Long = _DeployLog.SelectToken("$..ListDevicePartition").SelectToken("$.KvmDevicePartition[?(@.Start == " & StartTrack & ")].Sectors").Value(Of Long)
168: 'also read 3 parameters from ListDiskDevice
169: Dim Res6 As IActionResult = _KvmDiskOperation.ListDiskDevice(New ListDiskDeviceRequest With {
170: .ServerI = ServerI,
171: .ServerDecryptPass = ServerDecryptPass
172: })
173: If Res6.GetType.Name = "OkObjectResult" Then
174: AddOkResultToDeploylog(Of List(Of KvmBlkidDevice))(Res6, "ListDiskDevice")
175: _CurrentState = DeployVmState.ListDiskDevice
176: Dim UUID As String = _DeployLog.SelectToken($"$..ListDiskDevice[?(@.Name=='{NewPartitionName}')].UUID").Value(Of String)
177: Dim PartUUID As String = _DeployLog.SelectToken($"$..ListDiskDevice[?(@.Name=='{NewPartitionName}')].PartUUID").Value(Of String)
178: Dim BlockSize As Nullable(Of Integer) = _DeployLog.SelectToken($"$..ListDiskDevice[?(@.Name=='{NewPartitionName}')].BlockSize ").Value(Of Nullable(Of Integer))
179: 'AddPartitionToDB
180: Dim Res7 As IActionResult = _KvmDiskOperation.AddPartitionToDB(New AddPartitionToDbRequest With {
181: .ToKvmStorageDevice = ToKvmStorageDevice,
182: .ToKvmLvmDevice = Nothing,
183: .Name = NewPartitionName,
184: .Type = "Linux filesystem",
185: .UUID = UUID,
186: .PartUUID = PartUUID,
187: .PtType = "dos",
188: .PartLabel = "primary",
189: .BlockSize = BlockSize,
190: .Size = NewPartitionSize,
191: .Start = NewPartitionStart,
192: .[End] = NewPartitionEnd,
193: .Sectors = NewPartitionSectors,
194: .IsKvmInternal = Nothing,
195: .ToVmSpecial = Nothing,
196: .ToVm = Nothing, '<-------
197: .IsBootable = 1,
198: .CurrentState = $"ALLocated for user {CurUsers.UserName} for coin {ToCoin}"
199: })
200: If Res7.GetType.Name = "OkObjectResult" Then
201: _CurrentState = DeployVmState.AddPartitionToDB
202: AddOkResultToDeploylog(Of Integer)(Res7, "AddPartitionToDB")
203:
...:
1107:
1108: Else
1109: _CurrentState = DeployVmState.AbortAddPartitionToDB
1110: Dim Res7Err As New JObject
1111: Res7Err.Add("AbortAddPartitionToDB", JToken.FromObject(Res7))
1112: _DeployLog.Add(Res7Err)
1113: End If
1114: Else
1115: _CurrentState = DeployVmState.AbortListDiskDevice
1116: Dim Res6Err As New JObject
1117: Res6Err.Add("AbortListDiskDevice", JToken.FromObject(Res6))
1118: _DeployLog.Add(Res6Err)
1119: End If
1120: Else
1121: _CurrentState = DeployVmState.AbortListDevicePartition
1122: Dim Res5Err As New JObject
1123: Res5Err.Add("AbortListDevicePartition", JToken.FromObject(Res5))
1124: _DeployLog.Add(Res5Err)
1125: End If
1126: Else
1127: _CurrentState = DeployVmState.AbortAddPartitionToServerStrangeResult
1128: End If
1129: Else
1130: _CurrentState = DeployVmState.AbortAddPartitionToServer
1131: Dim Res4Err As New JObject
1132: Res4Err.Add("AbortAddPartitionToServer", JToken.FromObject(Res3))
1133: _DeployLog.Add(Res4Err)
1134: End If
1135: Else
1136: _CurrentState = DeployVmState.AbortSelectPartitionToDeployCompare
1137: End If
1138: Else
1139: _CurrentState = DeployVmState.AbortToKvmStorageDevice
1140: Dim Res3Err As New JObject
1141: Res3Err.Add("AbortToKvmStorageDevice", JToken.FromObject(Res3))
1142: _DeployLog.Add(Res3Err)
1143: End If
1144: Else
1145: _CurrentState = DeployVmState.AbortSelectPartitionToDeploy
1146: Dim Res3Err As New JObject
1147: Res3Err.Add("AbortSelectPartitionToDeploy", JToken.FromObject(Res3))
1148: _DeployLog.Add(Res3Err)
1149: End If
1150: Else
1151: _CurrentState = DeployVmState.AbortListPartitionImagesCompare
1152: End If
1153: Else
1154: _CurrentState = DeployVmState.AbortListPartitionImages
1155: Dim Res2Err As New JObject
1156: Res2Err.Add("AbortListPartitionImages", JToken.FromObject(Res2))
1157: _DeployLog.Add(Res2Err)
1158: End If
1159: Else
1160: _CurrentState = DeployVmState.AbortListPartitionImagesFromDB
1161: Dim Res1Err As New JObject
1162: Res1Err.Add("AbortListPartitionImagesFromDB", JToken.FromObject(Res1))
1163: _DeployLog.Add(Res1Err)
1164: End If
1165: Else
1166: _CurrentState = DeployVmState.NotEmpty
1167: End If
1168: Return _DeployLog
1169: End Function
1170: Public Function Abort() As JArray Implements IDeployVmService.Abort
1171: Dim OldLog As JArray = _DeployLog
1172: _CurrentState = DeployVmState.Ready
1173: _DeployLog = New JArray
1174: Return OldLog
1175: End Function
1176:
1177: Sub AddOkResultToDeploylog(Of T)(ApiResult As IActionResult, ApiKey As String)
1178: Dim ResValue As T = TryCast(ApiResult, OkObjectResult).Value
1179: Dim ResLog As New JObject
1180: ResLog.Add(ApiKey, JToken.FromObject(ResValue))
1181: _DeployLog.Add(ResLog)
1182: End Sub
1183:
1184: Class Tmp1
1185: Property Name As String
1186: Property LastWriteTime As DateTime
1187: Property Size As Long
1188: End Class
1189:
1190: Class Tmp2
1191: Property Value As Tmp3
1192: End Class
1193:
1194: Class Tmp3
1195: Property [Error] As List(Of String)
1196: Property Result As List(Of String)
1197: End Class
1198:
1199: End Class
And this is 3 version of JSON produced by this service - one JSON with successful allocation (I restrict full result only with first 7 step) and 2 JSON result with unsuccessful allocation.
- successful allocation (first 7 step) Success.Json
- unsuccessful allocation AbortToKvmStorageDevice.Json
- unsuccessful allocation AbortAddPartitionToServerStrangeResult.json
|