From 8738a98d000700ac63b622d16e3f9c29dacd8574 Mon Sep 17 00:00:00 2001 From: LiuXin Date: Mon, 18 Aug 2025 18:11:56 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=A4=9Aicc=E6=98=A0?= =?UTF-8?q?=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DaHua/RequestDto/DahuaVideoQueryDto.cs | 25 +++++++ .../VideoService/Video.API/Program.cs | 1 + .../VideoService/Video.API/appsettings.json | 24 ++++-- .../Dahvision/DahuaGeneralCtlService.cs | 73 +++++++++++++++---- .../Dahvision/UrlHostReplacer.cs | 26 +++++++ 5 files changed, 128 insertions(+), 21 deletions(-) create mode 100644 WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/UrlHostReplacer.cs diff --git a/WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/DaHua/RequestDto/DahuaVideoQueryDto.cs b/WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/DaHua/RequestDto/DahuaVideoQueryDto.cs index d042e23..cbf4a22 100644 --- a/WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/DaHua/RequestDto/DahuaVideoQueryDto.cs +++ b/WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/DaHua/RequestDto/DahuaVideoQueryDto.cs @@ -59,6 +59,11 @@ namespace Common.Shared.Application.DaHua public class PlaybackReqDto { public PlaybackItem Data { get; set; } + + /// + /// 如果多个icc平台的话,决定是哪个平台的回放 + /// + public string? IpAddress { get; set; } } /// @@ -109,6 +114,11 @@ namespace Common.Shared.Application.DaHua public class RtspPlayBackReqDto { public RtspPlaybackItem Data { get; set; } + + /// + /// 如果多个icc平台的话,决定是哪个平台的回放 + /// + public string? IpAddress { get; set; } } /// @@ -258,6 +268,11 @@ namespace Common.Shared.Application.DaHua /// [JsonPropertyName("data")] public StreamRequestData Data { get; set; } + + /// + /// 如果多个icc平台的话,决定是哪个平台的回放 + /// + public string? IpAddress { get; set; } } /// @@ -270,6 +285,11 @@ namespace Common.Shared.Application.DaHua /// [JsonPropertyName("data")] public StreamRtspRequestData Data { get; set; } + + /// + /// 如果多个icc平台的话,决定是哪个平台的回放 + /// + public string? IpAddress { get; set; } } /// @@ -398,5 +418,10 @@ namespace Common.Shared.Application.DaHua /// [JsonPropertyName("recordType")] public required string RecordType { get; set; } + + /// + /// 如果多个icc平台的话,决定是哪个平台的回放 + /// + public string? IpAddress { get; set; } } } \ No newline at end of file diff --git a/WeiCloud.Fusion/VideoService/Video.API/Program.cs b/WeiCloud.Fusion/VideoService/Video.API/Program.cs index e58b492..f91072e 100644 --- a/WeiCloud.Fusion/VideoService/Video.API/Program.cs +++ b/WeiCloud.Fusion/VideoService/Video.API/Program.cs @@ -1,5 +1,6 @@ using Autofac; using Autofac.Extensions.DependencyInjection; +using Common.Shared.Application.DaHua; using Common.Shared.DomainService; using Microsoft.OpenApi.Models; using NLog; diff --git a/WeiCloud.Fusion/VideoService/Video.API/appsettings.json b/WeiCloud.Fusion/VideoService/Video.API/appsettings.json index 2485a3e..5c7aa11 100644 --- a/WeiCloud.Fusion/VideoService/Video.API/appsettings.json +++ b/WeiCloud.Fusion/VideoService/Video.API/appsettings.json @@ -22,19 +22,29 @@ "RedisConnection": "v4.weienergy.cn:6380,allowadmin=true,password=Zrhredis#2019,defaultDatabase=10", "DBConnection": "server=v4.weienergy.cn;uid=root;pwd=Zrhdb#2019;port=3307;database=WeiCloudDB.Cap;default command timeout=100;CharSet=utf8;SslMode=None;allowPublicKeyRetrieval=true" }, + "VideoOpen": "1", //0表示部署视频对接,1表示不对接 //大华摄像头的配置 "DahuaAuth": { "Host": "demo.weienergy.cn:15214", "ClientId": "taiyanggong", - "RealRootHost": "192.168.21.18:9100", //RTSP实时播放的icc地址 - "RealReplaceHost": "demo.weienergy.cn:15210", //rtps试试播放的替换地址 - "TimeRootHost": "192.168.21.18:9320", //RTSP历史回放的icc地址 - "TimeReplaceHost": "demo.weienergy.cn:15211", //rtps历史回放的替换地址 - "ClientSecret": "6d6c78f8-3d4c-4e76-ab6b-827942a7b725", - "Username": "system", - "Password": "Admin123" + "Password": "Admin123", + "Real": { + "DefaultRoot": "192.168.21.18:9100", + "DefaultReplace": "demo.weienergy.cn:15210", + "Overrides": { + "192.168.21.20:9100": "demo.weienergy.cn:15210", + "10.20.30.40:9100": "demo.weienergy.cn:15210" + } + }, + "Time": { + "DefaultRoot": "192.168.21.18:9320", + "DefaultReplace": "demo.weienergy.cn:15211", + "Overrides": { + "192.168.21.20:9320": "demo.weienergy.cn:15211" + } + } } } \ No newline at end of file diff --git a/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/DahuaGeneralCtlService.cs b/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/DahuaGeneralCtlService.cs index 482f21a..e234798 100644 --- a/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/DahuaGeneralCtlService.cs +++ b/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/DahuaGeneralCtlService.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using System.Net.Http.Json; using System.Text.Json; +using Video.DomainService.Dahvision; namespace Video.DomainService { @@ -48,15 +49,18 @@ namespace Video.DomainService try { - // 2) Token:优先入参,其次缓存/获取(建议返回完整的 "Bearer xxx") var clientId = _configuration["DahuaAuth:ClientId"]; var token = await _tokenProviderService.GetTokenAsync(clientId!); - if (_tokenProviderService.IsTokenValid(token)) + if (!_tokenProviderService.IsTokenValid(token)) { _logger.LogWarning("hls等录像回放:token无效"); return new DaHApiResult { Success = false, Code = "1009", Msg = "token无效" }; } var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/video/stream/record"; + if (dto.IpAddress != null) + { + url = $"https://{dto.IpAddress}/evo-apigw/admin/API/video/stream/record"; + } // 3) 构造请求(把 dto 放进 Body),并用 SendAsync 发送,才能带上头 using var req = new HttpRequestMessage(HttpMethod.Post, url) @@ -80,7 +84,12 @@ namespace Video.DomainService _logger.LogWarning("录像请求业务失败: {Body}", body); return new DaHApiResult { Success = false, Code = "1008", Msg = "录像请求失败" }; } - result.Data!.Url = result.Data.Url + "?token=" + token; + result.Data!.Url = UrlHostReplacer.ReplaceHost( + result.Data.Url, + dto.IpAddress, + _configuration, + "Time" + ) + "?token=" + result.Data.Token; return result; } catch (Exception ex) @@ -107,13 +116,16 @@ namespace Video.DomainService var clientId = _configuration["DahuaAuth:ClientId"]; var token = await _tokenProviderService.GetTokenAsync(clientId!); - if (_tokenProviderService.IsTokenValid(token)) + if (!_tokenProviderService.IsTokenValid(token)) { _logger.LogWarning("查询普通录像信息列表:token无效"); return new DaHApiResult { Success = false, Code = "1009", Msg = "token无效" }; } var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/SS/Record/QueryRecords"; - + if (dto.IpAddress != null) + { + url = $"https://{dto.IpAddress}/evo-apigw/admin/API/SS/Record/QueryRecords"; + } using var req = new HttpRequestMessage(HttpMethod.Post, url) { Content = JsonContent.Create(dto) // 关键:把 dto 放进请求体 @@ -164,7 +176,7 @@ namespace Video.DomainService var clientId = _configuration["DahuaAuth:ClientId"]; var token = await _tokenProviderService.GetTokenAsync(clientId!); - if (_tokenProviderService.IsTokenValid(token)) + if (!_tokenProviderService.IsTokenValid(token)) { _logger.LogWarning("通道分页查询失败:token无效"); return new DaHApiResult { Success = false, Code = "1009", Msg = "token无效" }; @@ -225,7 +237,7 @@ namespace Video.DomainService // 2) Token:优先用入参;否则走缓存/获取(建议返回已带前缀的 "Bearer xxx") var clientId = _configuration["DahuaAuth:ClientId"]; var token = await _tokenProviderService.GetTokenAsync(clientId!); - if (_tokenProviderService.IsTokenValid(token)) + if (!_tokenProviderService.IsTokenValid(token)) { _logger.LogWarning(" HLS实时流请求失败:token无效"); return new DaHApiResult { Success = false, Code = "1009", Msg = "token无效" }; @@ -233,6 +245,11 @@ namespace Video.DomainService var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/video/stream/realtime"; + if (dto.IpAddress != null) + { + url = $"https://{dto.IpAddress}/evo-apigw/admin/API/video/stream/realtime"; + } + // 3) 用 HttpRequestMessage 发送,才能带上自定义头 using var req = new HttpRequestMessage(HttpMethod.Post, url) { @@ -255,7 +272,12 @@ namespace Video.DomainService _logger.LogWarning("实时流请求业务失败: {Body}", body); return new DaHApiResult { Success = false, Code = "1010", Msg = "实时流请求失败" }; } - result.Data!.Url = result.Data.Url + "?token=" + token; + result.Data!.Url = UrlHostReplacer.ReplaceHost( + result.Data.Url, + dto.IpAddress, + _configuration, + "Real" + ) + "?token=" + result.Data.Token; return result; } catch (Exception ex) @@ -335,13 +357,17 @@ namespace Video.DomainService // 先用缓存里的 token,不足5分钟过期再刷新(按你之前的口径来) var clientId = _configuration["DahuaAuth:ClientId"]; var token = await _tokenProviderService.GetTokenAsync(clientId!); - if (_tokenProviderService.IsTokenValid(token)) + if (!_tokenProviderService.IsTokenValid(token)) { _logger.LogWarning("rtsp录像回放:token无效"); return new DaHApiResult { Success = false, Code = "1009", Msg = "token无效" }; } var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/SS/Playback/StartPlaybackByTime"; + if (dto.IpAddress != null) + { + url = $"https://{dto.IpAddress}/evo-apigw/admin/API/SS/Playback/StartPlaybackByTime"; + } using var req = new HttpRequestMessage(HttpMethod.Post, url) { @@ -366,7 +392,12 @@ namespace Video.DomainService _logger.LogWarning("录像请求业务失败: {Body}", body); return new DaHApiResult { Success = false, Code = "1008", Msg = "录像请求失败" }; } - result.Data!.Url = result.Data.Url.Replace(_configuration["DahuaAuth:TimeRootHost"], _configuration["DahuaAuth:TimeReplaceHost"]) + "?token=" + result.Data.Token; + result.Data!.Url = UrlHostReplacer.ReplaceHost( + result.Data.Url, + dto.IpAddress, + _configuration, + "Time" + ) + "?token=" + result.Data.Token; return result; } catch (Exception ex) @@ -393,13 +424,17 @@ namespace Video.DomainService var clientId = _configuration["DahuaAuth:ClientId"]; var token = await _tokenProviderService.GetTokenAsync(clientId!); - if (_tokenProviderService.IsTokenValid(token)) + if (!_tokenProviderService.IsTokenValid(token)) { _logger.LogWarning("rtsp实时预览接口方式:token无效"); return new DaHApiResult { Success = false, Code = "1009", Msg = "token无效" }; } var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/MTS/Video/StartVideo"; + if (dto.IpAddress != null) + { + url = $"https://{dto.IpAddress}/evo-apigw/admin/API/MTS/Video/StartVideo"; + } using var req = new HttpRequestMessage(HttpMethod.Post, url) { @@ -424,7 +459,12 @@ namespace Video.DomainService _logger.LogWarning("实时流请求业务失败: {Body}", body); return new DaHApiResult { Success = false, Code = "1010", Msg = "实时流请求失败" }; } - result.Data!.Url = result.Data.Url.Replace(_configuration["DahuaAuth:RealRootHost"], _configuration["DahuaAuth:RealReplaceHost"]) + "?token=" + result.Data!.Token; + result.Data!.Url = UrlHostReplacer.ReplaceHost( + result.Data.Url, + dto.IpAddress, + _configuration, + "Real" + ) + "?token=" + result.Data.Token; return result; } catch (Exception ex) @@ -444,13 +484,18 @@ namespace Video.DomainService { var clientId = _configuration["DahuaAuth:ClientId"]; var token = await _tokenProviderService.GetTokenAsync(clientId!); - if (_tokenProviderService.IsTokenValid(token)) + if (!_tokenProviderService.IsTokenValid(token)) { _logger.LogWarning("下载:token无效"); return "下载地址无效"; } - return _configuration["DahuaAuth:Host"] + $"/evo-apigw/evo-httpnode/vod/cam/download.mp4?vcuid={dto.Vcuid}&subtype={dto.Subtype}&starttime={dto.StartTime}endtime={dto.EndTime}&videoType={dto.VideoType}&token={token}&recordType={dto.RecordType}"; + var url = _configuration["DahuaAuth:Host"]; + if (dto.IpAddress != null) + { + url = dto.IpAddress; + } + return url + $"/evo-apigw/evo-httpnode/vod/cam/download.mp4?vcuid={dto.Vcuid}&subtype={dto.Subtype}&starttime={dto.StartTime}endtime={dto.EndTime}&videoType={dto.VideoType}&token={token}&recordType={dto.RecordType}"; } } } \ No newline at end of file diff --git a/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/UrlHostReplacer.cs b/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/UrlHostReplacer.cs new file mode 100644 index 0000000..1d4e020 --- /dev/null +++ b/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/UrlHostReplacer.cs @@ -0,0 +1,26 @@ +using Microsoft.Extensions.Configuration; + +namespace Video.DomainService.Dahvision +{ + public static class UrlHostReplacer + { + public static string ReplaceHost(string url, string? ipAddress, IConfiguration config, string sectionName) + { + var section = config.GetSection($"DahuaAuth:{sectionName}"); + var defaultRoot = section["DefaultRoot"]!; + var defaultReplace = section["DefaultReplace"]!; + + // 1) 确定 fromHost + var fromHost = string.IsNullOrWhiteSpace(ipAddress) ? defaultRoot : ipAddress; + + // 2) 尝试在 Overrides 找对应的 value + var overrides = section.GetSection("Overrides").Get>() ?? new(); + var toHost = overrides.TryGetValue(fromHost, out var mapped) + ? mapped + : defaultReplace; + + // 3) 字符串替换 + return url.Replace(fromHost, toHost, StringComparison.OrdinalIgnoreCase); + } + } +} \ No newline at end of file From 02a957c992c7626711fc778bfe9d65d0b46f8382 Mon Sep 17 00:00:00 2001 From: LiuXin Date: Mon, 18 Aug 2025 19:21:01 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=80=E4=B8=8B?= =?UTF-8?q?=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DaHua/RequestDto/DahuaVideoQueryDto.cs | 23 ++-------- .../DaHTokenService/TokenProviderService.cs | 6 +-- .../DaHua/VideoManageController.cs | 16 +++---- .../Dahvision/DahuaGeneralCtlService.cs | 45 +++++++++---------- .../Dahvision/IDahuaGeneralCtlService.cs | 8 ++-- .../Dahvision/IRootVideoPlaybackService.cs | 8 ++-- .../Dahvision/RootVideoPlaybackService.cs | 16 +++---- 7 files changed, 52 insertions(+), 70 deletions(-) diff --git a/WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/DaHua/RequestDto/DahuaVideoQueryDto.cs b/WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/DaHua/RequestDto/DahuaVideoQueryDto.cs index cbf4a22..482d466 100644 --- a/WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/DaHua/RequestDto/DahuaVideoQueryDto.cs +++ b/WeiCloud.Fusion/Common.SharedService/Common.Shared.Application/DaHua/RequestDto/DahuaVideoQueryDto.cs @@ -59,11 +59,6 @@ namespace Common.Shared.Application.DaHua public class PlaybackReqDto { public PlaybackItem Data { get; set; } - - /// - /// 如果多个icc平台的话,决定是哪个平台的回放 - /// - public string? IpAddress { get; set; } } /// @@ -114,11 +109,6 @@ namespace Common.Shared.Application.DaHua public class RtspPlayBackReqDto { public RtspPlaybackItem Data { get; set; } - - /// - /// 如果多个icc平台的话,决定是哪个平台的回放 - /// - public string? IpAddress { get; set; } } /// @@ -268,11 +258,6 @@ namespace Common.Shared.Application.DaHua /// [JsonPropertyName("data")] public StreamRequestData Data { get; set; } - - /// - /// 如果多个icc平台的话,决定是哪个平台的回放 - /// - public string? IpAddress { get; set; } } /// @@ -286,10 +271,10 @@ namespace Common.Shared.Application.DaHua [JsonPropertyName("data")] public StreamRtspRequestData Data { get; set; } - /// - /// 如果多个icc平台的话,决定是哪个平台的回放 - /// - public string? IpAddress { get; set; } + ///// + ///// 如果多个icc平台的话,决定是哪个平台的回放 + ///// + //public string? IpAddress { get; set; } } /// diff --git a/WeiCloud.Fusion/Common.SharedService/Common.Shared.DomainService/DaHTokenService/TokenProviderService.cs b/WeiCloud.Fusion/Common.SharedService/Common.Shared.DomainService/DaHTokenService/TokenProviderService.cs index f2ee72a..602ce25 100644 --- a/WeiCloud.Fusion/Common.SharedService/Common.Shared.DomainService/DaHTokenService/TokenProviderService.cs +++ b/WeiCloud.Fusion/Common.SharedService/Common.Shared.DomainService/DaHTokenService/TokenProviderService.cs @@ -309,11 +309,11 @@ namespace Common.Shared.DomainService public bool IsTokenValid(string token) { // 避免 NullReferenceException - if (string.IsNullOrWhiteSpace(token)) - return true; + if (string.IsNullOrWhiteSpace(token) && token.Length < 10) + return false; // 统一写法,后续改条件只改这里 - return token.Length < 10; + return true; } #region RES加密 diff --git a/WeiCloud.Fusion/VideoService/Video.API/Controllers/DaHua/VideoManageController.cs b/WeiCloud.Fusion/VideoService/Video.API/Controllers/DaHua/VideoManageController.cs index 9d3d55a..e1f0add 100644 --- a/WeiCloud.Fusion/VideoService/Video.API/Controllers/DaHua/VideoManageController.cs +++ b/WeiCloud.Fusion/VideoService/Video.API/Controllers/DaHua/VideoManageController.cs @@ -37,9 +37,9 @@ namespace Video.API.Controllers.DaHua /// /// [HttpPost("playback/dh")] - public async Task> StartAndPlaybackDH(PlaybackReqDto dto) + public async Task> StartAndPlaybackDH([FromBody] PlaybackReqDto dto, [FromQuery] string? ipaddress) { - return await _rootVideoPlaybackService.GetDaHRecordVideoUrl(dto); + return await _rootVideoPlaybackService.GetDaHRecordVideoUrl(dto, ipaddress); } /// @@ -48,9 +48,9 @@ namespace Video.API.Controllers.DaHua /// /// [HttpPost("rtspplayback/dh")] - public async Task> RtspPlaybackByTime(RtspPlayBackReqDto dto) + public async Task> RtspPlaybackByTime([FromBody] RtspPlayBackReqDto dto, [FromQuery] string? ipaddress) { - return await _rootVideoPlaybackService.RtspPlaybackByTime(dto); + return await _rootVideoPlaybackService.RtspPlaybackByTime(dto, ipaddress); } /// @@ -59,9 +59,9 @@ namespace Video.API.Controllers.DaHua /// /// [HttpPost("realtime/dh")] - public async Task> GetRealtimeUrl(StreamReqDto dto) + public async Task> GetRealtimeUrl([FromBody] StreamReqDto dto, [FromQuery] string? ipaddress) { - return await _rootVideoPlaybackService.GetRealtimeUrl(dto); + return await _rootVideoPlaybackService.GetRealtimeUrl(dto, ipaddress); } /// @@ -70,9 +70,9 @@ namespace Video.API.Controllers.DaHua /// /// [HttpPost("rtspstart/dh")] - public async Task> RtspStartVideoUrl(StreamRtspReqDto dto) + public async Task> RtspStartVideoUrl([FromBody] StreamRtspReqDto dto, [FromQuery] string? ipaddress) { - return await _rootVideoPlaybackService.RtspStartVideoUrl(dto); + return await _rootVideoPlaybackService.RtspStartVideoUrl(dto, ipaddress); } /// diff --git a/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/DahuaGeneralCtlService.cs b/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/DahuaGeneralCtlService.cs index e234798..07aa32e 100644 --- a/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/DahuaGeneralCtlService.cs +++ b/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/DahuaGeneralCtlService.cs @@ -38,7 +38,7 @@ namespace Video.DomainService /// /// /// - public async Task> RecordVideoUrl(PlaybackReqDto dto) + public async Task> RecordVideoUrl(PlaybackReqDto dto, string? ipaddress) { // 1) 参数校验 + 早退 if (dto == null || string.IsNullOrWhiteSpace(dto.Data.ChannelId)) @@ -57,15 +57,15 @@ namespace Video.DomainService return new DaHApiResult { Success = false, Code = "1009", Msg = "token无效" }; } var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/video/stream/record"; - if (dto.IpAddress != null) + if (ipaddress != null) { - url = $"https://{dto.IpAddress}/evo-apigw/admin/API/video/stream/record"; + url = $"https://{ipaddress}/evo-apigw/admin/API/video/stream/record"; } // 3) 构造请求(把 dto 放进 Body),并用 SendAsync 发送,才能带上头 using var req = new HttpRequestMessage(HttpMethod.Post, url) { - Content = JsonContent.Create(dto) // 关键:别再丢 body 了 + Content = JsonContent.Create(dto.Data) // 关键:别再丢 body 了 }; req.Headers.TryAddWithoutValidation("Authorization", token); @@ -86,7 +86,7 @@ namespace Video.DomainService } result.Data!.Url = UrlHostReplacer.ReplaceHost( result.Data.Url, - dto.IpAddress, + ipaddress, _configuration, "Time" ) + "?token=" + result.Data.Token; @@ -122,13 +122,10 @@ namespace Video.DomainService return new DaHApiResult { Success = false, Code = "1009", Msg = "token无效" }; } var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/SS/Record/QueryRecords"; - if (dto.IpAddress != null) - { - url = $"https://{dto.IpAddress}/evo-apigw/admin/API/SS/Record/QueryRecords"; - } + using var req = new HttpRequestMessage(HttpMethod.Post, url) { - Content = JsonContent.Create(dto) // 关键:把 dto 放进请求体 + Content = JsonContent.Create(dto.Data) // 关键:把 dto 放进请求体 }; req.Headers.TryAddWithoutValidation("Authorization", token); @@ -223,7 +220,7 @@ namespace Video.DomainService /// /// /// - public async Task> RealtimeStreamUrl(StreamReqDto dto) + public async Task> RealtimeStreamUrl(StreamReqDto dto, string? ipaddress) { // 1) 参数校验 + 早退 if (dto == null || dto.Data == null) @@ -245,15 +242,15 @@ namespace Video.DomainService var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/video/stream/realtime"; - if (dto.IpAddress != null) + if (ipaddress != null) { - url = $"https://{dto.IpAddress}/evo-apigw/admin/API/video/stream/realtime"; + url = $"https://{ipaddress}/evo-apigw/admin/API/video/stream/realtime"; } // 3) 用 HttpRequestMessage 发送,才能带上自定义头 using var req = new HttpRequestMessage(HttpMethod.Post, url) { - Content = JsonContent.Create(dto) // 等价 PostAsJsonAsync,但不会丢头 + Content = JsonContent.Create(dto.Data) // 等价 PostAsJsonAsync,但不会丢头 }; req.Headers.TryAddWithoutValidation("Authorization", token); @@ -274,7 +271,7 @@ namespace Video.DomainService } result.Data!.Url = UrlHostReplacer.ReplaceHost( result.Data.Url, - dto.IpAddress, + ipaddress, _configuration, "Real" ) + "?token=" + result.Data.Token; @@ -345,7 +342,7 @@ namespace Video.DomainService /// /// /// - public async Task> RtspPlaybackByTime(RtspPlayBackReqDto dto) + public async Task> RtspPlaybackByTime(RtspPlayBackReqDto dto, string? ipaddress) { // 参数校验 + 早退 if (dto == null || string.IsNullOrWhiteSpace(dto.Data.ChannelId)) @@ -364,14 +361,14 @@ namespace Video.DomainService } var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/SS/Playback/StartPlaybackByTime"; - if (dto.IpAddress != null) + if (ipaddress != null) { - url = $"https://{dto.IpAddress}/evo-apigw/admin/API/SS/Playback/StartPlaybackByTime"; + url = $"https://{ipaddress}/evo-apigw/admin/API/SS/Playback/StartPlaybackByTime"; } using var req = new HttpRequestMessage(HttpMethod.Post, url) { - Content = JsonContent.Create(dto) // 关键:把 dto 放进请求体 + Content = JsonContent.Create(dto.Data) // 关键:把 dto 放进请求体 }; req.Headers.TryAddWithoutValidation("Authorization", token); @@ -394,7 +391,7 @@ namespace Video.DomainService } result.Data!.Url = UrlHostReplacer.ReplaceHost( result.Data.Url, - dto.IpAddress, + ipaddress, _configuration, "Time" ) + "?token=" + result.Data.Token; @@ -414,7 +411,7 @@ namespace Video.DomainService /// /// /// - public async Task> RtspStartVideoUrl(StreamRtspReqDto dto) + public async Task> RtspStartVideoUrl(StreamRtspReqDto dto, string? ipaddress) { if (dto == null || dto.Data == null) { @@ -431,9 +428,9 @@ namespace Video.DomainService } var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/admin/API/MTS/Video/StartVideo"; - if (dto.IpAddress != null) + if (ipaddress != null) { - url = $"https://{dto.IpAddress}/evo-apigw/admin/API/MTS/Video/StartVideo"; + url = $"https://{ipaddress}/evo-apigw/admin/API/MTS/Video/StartVideo"; } using var req = new HttpRequestMessage(HttpMethod.Post, url) @@ -461,7 +458,7 @@ namespace Video.DomainService } result.Data!.Url = UrlHostReplacer.ReplaceHost( result.Data.Url, - dto.IpAddress, + ipaddress, _configuration, "Real" ) + "?token=" + result.Data.Token; diff --git a/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/IDahuaGeneralCtlService.cs b/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/IDahuaGeneralCtlService.cs index 1a7f02e..215e0b3 100644 --- a/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/IDahuaGeneralCtlService.cs +++ b/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/IDahuaGeneralCtlService.cs @@ -19,14 +19,14 @@ namespace Video.DomainService /// /// /// - Task> RecordVideoUrl(PlaybackReqDto dto); + Task> RecordVideoUrl(PlaybackReqDto dto, string? ipaddress); /// /// Rtsp录像回放 /// /// /// - Task> RtspPlaybackByTime(RtspPlayBackReqDto dto); + Task> RtspPlaybackByTime(RtspPlayBackReqDto dto, string? ipaddress); /// /// 设备通道分页查询,需要用于HlsRecordVideo @@ -41,14 +41,14 @@ namespace Video.DomainService /// /// /// - Task> RealtimeStreamUrl(StreamReqDto dto); + Task> RealtimeStreamUrl(StreamReqDto dto, string? ipaddress); /// /// rtsp实时预览接口方式 /// /// /// - Task> RtspStartVideoUrl(StreamRtspReqDto dto); + Task> RtspStartVideoUrl(StreamRtspReqDto dto, string? ipaddress); /// /// 注销认证信息 diff --git a/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/IRootVideoPlaybackService.cs b/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/IRootVideoPlaybackService.cs index 6c6948a..a4b55f8 100644 --- a/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/IRootVideoPlaybackService.cs +++ b/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/IRootVideoPlaybackService.cs @@ -10,28 +10,28 @@ namespace Video.DomainService /// /// /// - Task> GetDaHRecordVideoUrl(PlaybackReqDto dto); + Task> GetDaHRecordVideoUrl(PlaybackReqDto dto, string? ipaddress); /// /// 大华的实时视频 /// /// /// - Task> GetRealtimeUrl(StreamReqDto dto); + Task> GetRealtimeUrl(StreamReqDto dto, string? ipaddress); /// /// rtsp实时预览接口方式 /// /// /// - Task> RtspStartVideoUrl(StreamRtspReqDto dto); + Task> RtspStartVideoUrl(StreamRtspReqDto dto, string? ipaddress); /// /// rtsp录像回放 /// /// /// - Task> RtspPlaybackByTime(RtspPlayBackReqDto dto); + Task> RtspPlaybackByTime(RtspPlayBackReqDto dto, string? ipaddress); /// /// 大华设备通道分页查询 diff --git a/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/RootVideoPlaybackService.cs b/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/RootVideoPlaybackService.cs index b9fd7a8..b48d433 100644 --- a/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/RootVideoPlaybackService.cs +++ b/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/RootVideoPlaybackService.cs @@ -35,11 +35,11 @@ namespace Video.DomainService /// /// /// - public async Task> GetDaHRecordVideoUrl(PlaybackReqDto dto) + public async Task> GetDaHRecordVideoUrl(PlaybackReqDto dto, string? ipaddress) { ApiResult result = new ApiResult() { Code = 200, Msg = "接口调用成功" }; - var urlReult = await _dahuaGeneralCtlService.RecordVideoUrl(dto); + var urlReult = await _dahuaGeneralCtlService.RecordVideoUrl(dto, ipaddress); if (!urlReult.Success) { result.Code = 500; @@ -58,10 +58,10 @@ namespace Video.DomainService /// /// /// - public async Task> GetRealtimeUrl(StreamReqDto dto) + public async Task> GetRealtimeUrl(StreamReqDto dto, string? ipaddress) { ApiResult result = new ApiResult() { Code = 200, Msg = "接口调用成功" }; - var urlReult = await _dahuaGeneralCtlService.RealtimeStreamUrl(dto); + var urlReult = await _dahuaGeneralCtlService.RealtimeStreamUrl(dto, ipaddress); if (!urlReult.Success) { result.Code = 500; @@ -123,10 +123,10 @@ namespace Video.DomainService /// /// /// - public async Task> RtspStartVideoUrl(StreamRtspReqDto dto) + public async Task> RtspStartVideoUrl(StreamRtspReqDto dto, string? ipaddress) { ApiResult result = new ApiResult() { Code = 200, Msg = "接口调用成功" }; - var urlReult = await _dahuaGeneralCtlService.RtspStartVideoUrl(dto); + var urlReult = await _dahuaGeneralCtlService.RtspStartVideoUrl(dto, ipaddress); if (!urlReult.Success) { result.Code = 500; @@ -142,11 +142,11 @@ namespace Video.DomainService /// /// /// - public async Task> RtspPlaybackByTime(RtspPlayBackReqDto dto) + public async Task> RtspPlaybackByTime(RtspPlayBackReqDto dto, string? ipaddress) { ApiResult result = new ApiResult() { Code = 200, Msg = "接口调用成功" }; - var urlReult = await _dahuaGeneralCtlService.RtspPlaybackByTime(dto); + var urlReult = await _dahuaGeneralCtlService.RtspPlaybackByTime(dto, ipaddress); if (!urlReult.Success) { result.Code = 500; From da31159aa768242a157f08e342695921e7a0459e Mon Sep 17 00:00:00 2001 From: LiuXin Date: Wed, 20 Aug 2025 10:33:50 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9token=E5=88=A4=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DahAlarm/DahuaGeneralCtlService.cs | 9 +++++---- WeiCloud.Fusion/VideoService/Video.API/appsettings.json | 4 ++-- .../Dahvision/DahuaGeneralCtlService.cs | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/WeiCloud.Fusion/AlarmService/Alarm.DomainService/DahAlarm/DahuaGeneralCtlService.cs b/WeiCloud.Fusion/AlarmService/Alarm.DomainService/DahAlarm/DahuaGeneralCtlService.cs index 767bdd7..8075153 100644 --- a/WeiCloud.Fusion/AlarmService/Alarm.DomainService/DahAlarm/DahuaGeneralCtlService.cs +++ b/WeiCloud.Fusion/AlarmService/Alarm.DomainService/DahAlarm/DahuaGeneralCtlService.cs @@ -122,7 +122,7 @@ namespace Alarm.DomainService.DahAlarm var clientId = _configuration["DahuaAuth:ClientId"]; var token = await _tokenProviderService.GetTokenAsync(clientId!); - if (_tokenProviderService.IsTokenValid(token)) + if (!_tokenProviderService.IsTokenValid(token)) { _logger.LogWarning("新增报警事件订阅:token无效"); return new DaHApiResult { Success = false, Code = "1009", Msg = "token无效" }; @@ -206,7 +206,7 @@ namespace Alarm.DomainService.DahAlarm { //拼接物联平台标准的mqtt消息格式 var payload = "[{\"taglabel\":\"" + dto.Info.DeviceCode + ".alart." + dto.Info.DeviceName + "\",\"value\":\"" + dto.Info.AlarmStat + "\",\"time\":\"" + DateTimeOffset.UtcNow.ToUnixTimeSeconds() + "\"}]"; - + //var payload = "[{\"taglabel\":\"残卫测试报警按钮.alarmStat\",\"value\":\"" + dto.Info.AlarmStat + "\",\"time\":\"" + DateTimeOffset.UtcNow.ToUnixTimeSeconds() + "\"}]"; await _mqttClient.EnsureConnectedAsync(mqttHostIp, mqttHostPort, mqttUsername, mqttPassword, topicName, mqttClientId); await _mqttClientService.PublishAsync(topicName, payload); @@ -232,7 +232,7 @@ namespace Alarm.DomainService.DahAlarm { var clientId = _configuration["DahuaAuth:ClientId"]; var token = await _tokenProviderService.GetTokenAsync(clientId!); - if (_tokenProviderService.IsTokenValid(token)) + if (!_tokenProviderService.IsTokenValid(token)) { _logger.LogWarning("取消订阅某个报警事件:token无效"); return false; @@ -279,11 +279,12 @@ namespace Alarm.DomainService.DahAlarm { var clientId = _configuration["DahuaAuth:ClientId"]; var token = await _tokenProviderService.GetTokenAsync(clientId!); - if (_tokenProviderService.IsTokenValid(token)) + if (!_tokenProviderService.IsTokenValid(token)) { _logger.LogWarning("获取事件列表:token无效"); return new DaHApiResult { Success = false, Code = "1009", Msg = "token无效" }; } + // var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/evo-brm/1.0.0/device/1000014"; var url = $"https://{_configuration["DahuaAuth:Host"]}/evo-apigw/evo-event/1.0.0/subscribe/subscribe-list?monitorType=url&category={name}"; try diff --git a/WeiCloud.Fusion/VideoService/Video.API/appsettings.json b/WeiCloud.Fusion/VideoService/Video.API/appsettings.json index 5c7aa11..84dcd9a 100644 --- a/WeiCloud.Fusion/VideoService/Video.API/appsettings.json +++ b/WeiCloud.Fusion/VideoService/Video.API/appsettings.json @@ -35,7 +35,7 @@ "DefaultRoot": "192.168.21.18:9100", "DefaultReplace": "demo.weienergy.cn:15210", "Overrides": { - "192.168.21.20:9100": "demo.weienergy.cn:15210", + "192.168.21.18:9100": "demo.weienergy.cn:15210", "10.20.30.40:9100": "demo.weienergy.cn:15210" } }, @@ -43,7 +43,7 @@ "DefaultRoot": "192.168.21.18:9320", "DefaultReplace": "demo.weienergy.cn:15211", "Overrides": { - "192.168.21.20:9320": "demo.weienergy.cn:15211" + "192.168.21.18:9320": "demo.weienergy.cn:15211" } } } diff --git a/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/DahuaGeneralCtlService.cs b/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/DahuaGeneralCtlService.cs index 07aa32e..bebad90 100644 --- a/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/DahuaGeneralCtlService.cs +++ b/WeiCloud.Fusion/VideoService/Video.DomainService/Dahvision/DahuaGeneralCtlService.cs @@ -337,7 +337,7 @@ namespace Video.DomainService /// /// rtsp录像回放 - /// (播放命令:ffplay -rtsp_transport tcp -i "rtsp://demo.weienergy.cn:15211/playback/pu/3?token=3")强制走tcp + /// (播放命令:ffplay -rtsp_transport tcp -i "rtsp://demo.weienergy.cn:15210/dss/monitor/param/cameraid=1000021%24104%26substream=1?token=430")强制走tcp /// /// /// From dc9bb2f1f9b7caf172fe25231102b5cf126cc55f Mon Sep 17 00:00:00 2001 From: LiuXin Date: Wed, 20 Aug 2025 10:45:54 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E6=95=B4=E7=90=86=E5=90=88=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WeiCloud.Fusion/WeiCloud.Fusion.sln | 32 +++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/WeiCloud.Fusion/WeiCloud.Fusion.sln b/WeiCloud.Fusion/WeiCloud.Fusion.sln index b75a7b2..572d1ba 100644 --- a/WeiCloud.Fusion/WeiCloud.Fusion.sln +++ b/WeiCloud.Fusion/WeiCloud.Fusion.sln @@ -43,10 +43,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParkingLotEntity", "Parking EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParkLotInfoService", "ParkLotInfoService\ParkLotInfoService.csproj", "{19E28D5D-C144-4FF5-B71D-D81DA3494AD9}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WeiCloud.Core", "WeiCloud.Core\WeiCloud.Core.csproj", "{B5C2EFBB-8991-48CB-95B6-77C0770D245D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WeiCloud.Core", "WeiCloud.Core\WeiCloud.Core.csproj", "{40B0D902-553C-C52F-71A2-56FB176FCCBD}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Video.Application", "VideoService\Video.Application\Video.Application.csproj", "{9F2BD2C5-6496-419D-B87A-4F481E963C4D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AlarmService", "AlarmService", "{18791734-CA81-482D-964A-CA6D0F308B8E}" @@ -65,6 +61,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Alarm.Application", "AlarmS EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.Shared.API", "Common.SharedService\Common.Shared.API\Common.Shared.API.csproj", "{1ACFAAE8-C86D-4582-B0B4-542B74970737}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WeiCloud.Core", "WeiCloud.Core\WeiCloud.Core.csproj", "{40B0D902-553C-C52F-71A2-56FB176FCCBD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -119,10 +117,14 @@ Global {D97C471C-3190-4F8E-A916-7A056A65EDCE}.Debug|Any CPU.Build.0 = Debug|Any CPU {D97C471C-3190-4F8E-A916-7A056A65EDCE}.Release|Any CPU.ActiveCfg = Release|Any CPU {D97C471C-3190-4F8E-A916-7A056A65EDCE}.Release|Any CPU.Build.0 = Release|Any CPU - {40B0D902-553C-C52F-71A2-56FB176FCCBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {40B0D902-553C-C52F-71A2-56FB176FCCBD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {40B0D902-553C-C52F-71A2-56FB176FCCBD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {40B0D902-553C-C52F-71A2-56FB176FCCBD}.Release|Any CPU.Build.0 = Release|Any CPU + {F5AA3CCF-ED0C-40E5-AE10-CDFDC89443F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F5AA3CCF-ED0C-40E5-AE10-CDFDC89443F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F5AA3CCF-ED0C-40E5-AE10-CDFDC89443F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F5AA3CCF-ED0C-40E5-AE10-CDFDC89443F0}.Release|Any CPU.Build.0 = Release|Any CPU + {19E28D5D-C144-4FF5-B71D-D81DA3494AD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {19E28D5D-C144-4FF5-B71D-D81DA3494AD9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {19E28D5D-C144-4FF5-B71D-D81DA3494AD9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {19E28D5D-C144-4FF5-B71D-D81DA3494AD9}.Release|Any CPU.Build.0 = Release|Any CPU {9F2BD2C5-6496-419D-B87A-4F481E963C4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9F2BD2C5-6496-419D-B87A-4F481E963C4D}.Debug|Any CPU.Build.0 = Debug|Any CPU {9F2BD2C5-6496-419D-B87A-4F481E963C4D}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -151,6 +153,10 @@ Global {1ACFAAE8-C86D-4582-B0B4-542B74970737}.Debug|Any CPU.Build.0 = Debug|Any CPU {1ACFAAE8-C86D-4582-B0B4-542B74970737}.Release|Any CPU.ActiveCfg = Release|Any CPU {1ACFAAE8-C86D-4582-B0B4-542B74970737}.Release|Any CPU.Build.0 = Release|Any CPU + {40B0D902-553C-C52F-71A2-56FB176FCCBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {40B0D902-553C-C52F-71A2-56FB176FCCBD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {40B0D902-553C-C52F-71A2-56FB176FCCBD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {40B0D902-553C-C52F-71A2-56FB176FCCBD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -168,6 +174,16 @@ Global {6CBD9E97-4FEF-4DA2-ADFB-21B4D9DB366F} = {19A25984-FFA8-49BE-A710-6F269A406C61} {058C0CAB-5956-4811-8340-86919DDB2845} = {19A25984-FFA8-49BE-A710-6F269A406C61} {D97C471C-3190-4F8E-A916-7A056A65EDCE} = {0A3134C8-219C-4674-B152-1FA6561E4217} + {F5AA3CCF-ED0C-40E5-AE10-CDFDC89443F0} = {0A3134C8-219C-4674-B152-1FA6561E4217} + {19E28D5D-C144-4FF5-B71D-D81DA3494AD9} = {0A3134C8-219C-4674-B152-1FA6561E4217} + {9F2BD2C5-6496-419D-B87A-4F481E963C4D} = {19A25984-FFA8-49BE-A710-6F269A406C61} + {2677EAF0-9F7F-4969-B8B1-3006F35EB93E} = {18791734-CA81-482D-964A-CA6D0F308B8E} + {9A5FBAFF-EBE8-3156-5547-FB3ED1DEB545} = {80F3B34B-C334-44D2-A861-31FD403AD57D} + {C2757FC0-54A9-BBD3-2E23-55F2F3912BA4} = {80F3B34B-C334-44D2-A861-31FD403AD57D} + {B6DDF83D-591E-38B6-2902-1624BE8AE9B9} = {18791734-CA81-482D-964A-CA6D0F308B8E} + {4B2C6EBE-E719-9F40-ADE6-C82DA632E554} = {18791734-CA81-482D-964A-CA6D0F308B8E} + {1ACFAAE8-C86D-4582-B0B4-542B74970737} = {80F3B34B-C334-44D2-A861-31FD403AD57D} + {40B0D902-553C-C52F-71A2-56FB176FCCBD} = {44DAA396-C724-480A-A2BC-9A33D29E8FEA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {379A56DA-D3F0-4E7E-8FF7-DA8E20015BF3}