| | | 1 | | using System.Globalization; |
| | | 2 | | using System.Xml.Linq; |
| | | 3 | | using Services.ApiServices.ApiSupplierRequestLog; |
| | | 4 | | |
| | | 5 | | namespace Services.ApiServices.AvdApi; |
| | | 6 | | |
| | | 7 | | public sealed class AvdSoapClient |
| | | 8 | | { |
| | 1 | 9 | | private static readonly XNamespace SoapNs = "http://schemas.xmlsoap.org/soap/envelope/"; |
| | 1 | 10 | | private static readonly XNamespace ServiceNs = "http://tempuri.org/"; |
| | 1 | 11 | | private static readonly XNamespace SerializationArraysNs = "http://schemas.microsoft.com/2003/10/Serialization/Array |
| | | 12 | | private readonly IHttpClientFactory _factory; |
| | | 13 | | private readonly AvdConfig _config; |
| | | 14 | | private readonly ApiSupplierRequestLogStore _logs; |
| | | 15 | | |
| | 46 | 16 | | public AvdSoapClient(IHttpClientFactory factory, AvdConfig config, ApiSupplierRequestLogStore logs) |
| | | 17 | | { |
| | 46 | 18 | | _factory = factory; |
| | 46 | 19 | | _config = config; |
| | 46 | 20 | | _logs = logs; |
| | 46 | 21 | | } |
| | | 22 | | |
| | | 23 | | public async Task<XElement> SendAsync( |
| | | 24 | | string operation, |
| | | 25 | | IReadOnlyDictionary<string, string?>? parameters = null, |
| | | 26 | | CancellationToken ct = default, |
| | | 27 | | IReadOnlyDictionary<string, IReadOnlyCollection<long>>? intArrayParameters = null) |
| | | 28 | | { |
| | 43 | 29 | | if (string.IsNullOrWhiteSpace(_config.Login) || string.IsNullOrWhiteSpace(_config.Password)) |
| | 0 | 30 | | throw new AvdApiException("Не настроены Avd:Login и/или Avd:Password."); |
| | | 31 | | |
| | 43 | 32 | | var operationElement = new XElement(ServiceNs + operation, |
| | 43 | 33 | | new XElement(ServiceNs + "login", _config.Login), |
| | 43 | 34 | | new XElement(ServiceNs + "password", _config.Password)); |
| | 404 | 35 | | foreach (var parameter in parameters ?? new Dictionary<string, string?>()) |
| | 159 | 36 | | operationElement.Add(new XElement(ServiceNs + parameter.Key, parameter.Value ?? string.Empty)); |
| | 90 | 37 | | foreach (var parameter in intArrayParameters ?? new Dictionary<string, IReadOnlyCollection<long>>()) |
| | 2 | 38 | | operationElement.Add(new XElement(ServiceNs + parameter.Key, |
| | 5 | 39 | | parameter.Value.Select(value => new XElement(SerializationArraysNs + "int", value)))); |
| | 43 | 40 | | var document = new XDocument(new XDeclaration("1.0", "utf-8", null), |
| | 43 | 41 | | new XElement(SoapNs + "Envelope", new XElement(SoapNs + "Body", operationElement))); |
| | 43 | 42 | | var body = document.ToString(SaveOptions.DisableFormatting); |
| | 43 | 43 | | var timer = System.Diagnostics.Stopwatch.StartNew(); |
| | | 44 | | try |
| | | 45 | | { |
| | 43 | 46 | | using var request = new HttpRequestMessage(HttpMethod.Post, _config.BaseUrl) |
| | 43 | 47 | | { |
| | 43 | 48 | | Content = new StringContent(body, System.Text.Encoding.UTF8, "text/xml") |
| | 43 | 49 | | }; |
| | 43 | 50 | | request.Headers.TryAddWithoutValidation("SOAPAction", $"http://tempuri.org/IAvdUserService/{operation}"); |
| | 43 | 51 | | using var response = await _factory.CreateClient("AvdApi").SendAsync(request, ct); |
| | 41 | 52 | | var responseText = await response.Content.ReadAsStringAsync(ct); |
| | 41 | 53 | | _logs.Add("Avd", "POST", operation, (int)response.StatusCode, timer, body, responseText); |
| | 41 | 54 | | if (!response.IsSuccessStatusCode) |
| | 4 | 55 | | throw new AvdApiException($"АВД вернул HTTP {(int)response.StatusCode}.", (int)response.StatusCode); |
| | 37 | 56 | | var xml = XDocument.Parse(responseText); |
| | 37 | 57 | | var fault = xml.Descendants(SoapNs + "Fault").FirstOrDefault(); |
| | 37 | 58 | | if (fault != null) |
| | 3 | 59 | | throw new AvdApiException($"АВД вернул SOAP Fault: {fault.Element("faultstring")?.Value ?? "без описания |
| | 34 | 60 | | return xml.Root ?? throw new AvdApiException("АВД вернул пустой SOAP-ответ."); |
| | | 61 | | } |
| | 14 | 62 | | catch (AvdApiException) { throw; } |
| | 2 | 63 | | catch (Exception ex) |
| | | 64 | | { |
| | 2 | 65 | | _logs.Add("Avd", "POST", operation, null, timer, body, ex.Message); |
| | 2 | 66 | | throw new AvdApiException("Не удалось выполнить SOAP-запрос к АВД.", innerException: ex); |
| | | 67 | | } |
| | 34 | 68 | | } |
| | | 69 | | |
| | 4518 | 70 | | public static string? Value(XElement element, string name) => element.Elements().FirstOrDefault(x => x.Name.LocalNam |
| | 154 | 71 | | public static decimal? DecimalValue(XElement element, string name) => decimal.TryParse(Value(element, name), NumberS |
| | 49 | 72 | | public static int? IntValue(XElement element, string name) => int.TryParse(Value(element, name), NumberStyles.Intege |
| | | 73 | | } |