Add project
Basic formatting applied. Unnecessary comments have been removed. Suspicious code is covered by TODO.
This commit is contained in:
@ -0,0 +1,27 @@
|
||||
using Hcs.ClientApi.DataTypes;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Hcs.ClientApi.DeviceMeteringApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Методы ГИС ЖКХ сервиса hcs-device-metering (показания приборов учета)
|
||||
/// </summary>
|
||||
public class HcsDeviceMeteringApi
|
||||
{
|
||||
public HcsClientConfig Config { get; private set; }
|
||||
|
||||
public HcsDeviceMeteringApi(HcsClientConfig config)
|
||||
{
|
||||
this.Config = config;
|
||||
}
|
||||
|
||||
public async Task<DateTime> РазместитьПоказания(
|
||||
ГисПриборУчета прибор, ГисПоказания показания, CancellationToken token = default)
|
||||
{
|
||||
var method = new HcsMethodImportMeteringDevicesValues(Config);
|
||||
return await method.ImportMeteringDevicesValues(прибор, показания, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,118 @@
|
||||
using Hcs.ClientApi.RemoteCaller;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using DeviceMetering = Hcs.Service.Async.DeviceMetering.v14_5_0_1;
|
||||
|
||||
namespace Hcs.Service.Async.DeviceMetering.v14_5_0_1
|
||||
{
|
||||
public partial class AckRequestAck : IHcsAck { }
|
||||
public partial class getStateResult : IHcsGetStateResult { }
|
||||
public partial class Fault : IHcsFault { }
|
||||
public partial class HeaderType : IHcsHeaderType { }
|
||||
}
|
||||
|
||||
namespace Hcs.ClientApi.DeviceMeteringApi
|
||||
{
|
||||
public class HcsDeviceMeteringMethod : HcsRemoteCallMethod
|
||||
{
|
||||
public HcsEndPoints EndPoint => HcsEndPoints.DeviceMeteringAsync;
|
||||
|
||||
public DeviceMetering.RequestHeader CreateRequestHeader() =>
|
||||
HcsRequestHelper.CreateHeader<DeviceMetering.RequestHeader>(ClientConfig);
|
||||
|
||||
public HcsDeviceMeteringMethod(HcsClientConfig config) : base(config) { }
|
||||
|
||||
public System.ServiceModel.EndpointAddress RemoteAddress
|
||||
=> GetEndpointAddress(HcsConstants.EndPointLocator.GetPath(EndPoint));
|
||||
|
||||
private DeviceMetering.DeviceMeteringPortTypesAsyncClient NewPortClient()
|
||||
{
|
||||
var client = new DeviceMetering.DeviceMeteringPortTypesAsyncClient(_binding, RemoteAddress);
|
||||
ConfigureEndpointCredentials(client.Endpoint, client.ClientCredentials);
|
||||
return client;
|
||||
}
|
||||
|
||||
public async Task<IHcsGetStateResult> SendAndWaitResultAsync(
|
||||
object request,
|
||||
Func<DeviceMetering.DeviceMeteringPortTypesAsyncClient, Task<IHcsAck>> sender,
|
||||
CancellationToken token)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (CanBeRestarted)
|
||||
{
|
||||
return await RunRepeatableTaskInsistentlyAsync(
|
||||
async () => await SendAndWaitResultAsyncImpl(request, sender, token), token);
|
||||
}
|
||||
else
|
||||
{
|
||||
return await SendAndWaitResultAsyncImpl(request, sender, token);
|
||||
}
|
||||
}
|
||||
catch (HcsRestartTimeoutException e)
|
||||
{
|
||||
if (!CanBeRestarted) throw new HcsException("Превышен лимит ожидания выполнения запроса", e);
|
||||
Log($"Перезапускаем запрос типа {request.GetType().Name}...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IHcsGetStateResult> SendAndWaitResultAsyncImpl(
|
||||
object request,
|
||||
Func<DeviceMetering.DeviceMeteringPortTypesAsyncClient, Task<IHcsAck>> sender,
|
||||
CancellationToken token)
|
||||
{
|
||||
if (request == null) throw new ArgumentNullException(nameof(request));
|
||||
string version = HcsRequestHelper.GetRequestVersionString(request);
|
||||
_config.Log($"Отправляем запрос: {RemoteAddress.Uri}/{request.GetType().Name} в версии {version}...");
|
||||
|
||||
var stopWatch = System.Diagnostics.Stopwatch.StartNew();
|
||||
|
||||
IHcsAck ack;
|
||||
using (var client = NewPortClient())
|
||||
{
|
||||
ack = await sender(client);
|
||||
}
|
||||
|
||||
stopWatch.Stop();
|
||||
_config.Log($"Запрос принят в обработку за {stopWatch.ElapsedMilliseconds}мс., подтверждение {ack.MessageGUID}");
|
||||
|
||||
var stateResult = await WaitForResultAsync(ack, true, token);
|
||||
|
||||
stateResult.Items.OfType<DeviceMetering.ErrorMessageType>().ToList().ForEach(x =>
|
||||
{
|
||||
throw HcsRemoteException.CreateNew(x.ErrorCode, x.Description);
|
||||
});
|
||||
|
||||
return stateResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выполняет однократную проверку наличия результата.
|
||||
/// Возвращает null если результата еще нет.
|
||||
/// </summary>
|
||||
protected override async Task<IHcsGetStateResult> TryGetResultAsync(IHcsAck sourceAck, CancellationToken token)
|
||||
{
|
||||
using (var client = NewPortClient())
|
||||
{
|
||||
var requestHeader = HcsRequestHelper.CreateHeader<DeviceMetering.RequestHeader>(_config);
|
||||
var requestBody = new DeviceMetering.getStateRequest { MessageGUID = sourceAck.MessageGUID };
|
||||
|
||||
var response = await client.getStateAsync(requestHeader, requestBody);
|
||||
var resultBody = response.getStateResult;
|
||||
|
||||
if (resultBody.RequestState == HcsAsyncRequestStateTypes.Ready)
|
||||
{
|
||||
return resultBody;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Hcs.ClientApi.DeviceMeteringApi
|
||||
{
|
||||
public class HcsDeviceMeteringUtil
|
||||
{
|
||||
public static string ConvertMeterReading(string reading, bool isRequired)
|
||||
{
|
||||
if (string.IsNullOrEmpty(reading)) return (isRequired ? "0" : null);
|
||||
|
||||
// TODO: Проверить комментарий
|
||||
// Исправляем типичный отказ ГИС в приеме показаний: заменяем запятую на точку
|
||||
string betterReading = reading.Contains(",") ? reading.Replace(",", ".") : reading;
|
||||
|
||||
// Шаблон из: http://open-gkh.ru/MeteringDeviceBase/MeteringValueType.html
|
||||
var match = Regex.Match(betterReading, "^\\d{1,15}(\\.\\d{1,7})?$");
|
||||
if (match.Success) return betterReading;
|
||||
|
||||
throw new HcsException($"Значение показания \"{reading}\" не соответствует требованиям ГИС: N.N");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
using Hcs.ClientApi.DataTypes;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using DeviceMetering = Hcs.Service.Async.DeviceMetering.v14_5_0_1;
|
||||
|
||||
namespace Hcs.ClientApi.DeviceMeteringApi
|
||||
{
|
||||
/// <summary>
|
||||
/// Размещение в ГИС показаний прибора учета
|
||||
/// http://open-gkh.ru/DeviceMetering/importMeteringDeviceValuesRequest.html
|
||||
/// </summary>
|
||||
public class HcsMethodImportMeteringDevicesValues : HcsDeviceMeteringMethod
|
||||
{
|
||||
public HcsMethodImportMeteringDevicesValues(HcsClientConfig config) : base(config)
|
||||
{
|
||||
CanBeRestarted = false;
|
||||
}
|
||||
|
||||
public async Task<DateTime> ImportMeteringDevicesValues(
|
||||
ГисПриборУчета прибор, ГисПоказания показания, CancellationToken token)
|
||||
{
|
||||
if (прибор == null) throw new ArgumentNullException(nameof(прибор));
|
||||
if (показания == null) throw new ArgumentNullException(nameof(показания));
|
||||
|
||||
var current = new DeviceMetering.importMeteringDeviceValuesRequestMeteringDevicesValuesElectricDeviceValueCurrentValue()
|
||||
{
|
||||
TransportGUID = FormatGuid(Guid.NewGuid()),
|
||||
DateValue = показания.ДатаСнятия,
|
||||
MeteringValueT1 = HcsDeviceMeteringUtil.ConvertMeterReading(показания.ПоказанияТ1, false),
|
||||
MeteringValueT2 = HcsDeviceMeteringUtil.ConvertMeterReading(показания.ПоказанияТ2, false),
|
||||
MeteringValueT3 = HcsDeviceMeteringUtil.ConvertMeterReading(показания.ПоказанияТ3, false)
|
||||
};
|
||||
|
||||
var electric = new DeviceMetering.importMeteringDeviceValuesRequestMeteringDevicesValuesElectricDeviceValue()
|
||||
{
|
||||
CurrentValue = current
|
||||
};
|
||||
|
||||
var value = new DeviceMetering.importMeteringDeviceValuesRequestMeteringDevicesValues()
|
||||
{
|
||||
ItemElementName = DeviceMetering.ItemChoiceType.MeteringDeviceRootGUID,
|
||||
Item = FormatGuid(прибор.ГуидПрибораУчета),
|
||||
Item1 = electric
|
||||
};
|
||||
|
||||
var request = new DeviceMetering.importMeteringDeviceValuesRequest()
|
||||
{
|
||||
Id = HcsConstants.SignedXmlElementId,
|
||||
MeteringDevicesValues = [value]
|
||||
};
|
||||
|
||||
var stateResult = await SendAndWaitResultAsync(request, async (portClient) =>
|
||||
{
|
||||
var ackResponse = await portClient.importMeteringDeviceValuesAsync(
|
||||
CreateRequestHeader(), request);
|
||||
return ackResponse.AckRequest.Ack;
|
||||
}, token);
|
||||
|
||||
|
||||
if (IsArrayEmpty(stateResult.Items)) throw new HcsException("Пустой stateResult.Items");
|
||||
|
||||
stateResult.Items.OfType<DeviceMetering.CommonResultTypeError>().ToList()
|
||||
.ForEach(error => { throw HcsRemoteException.CreateNew(error.ErrorCode, error.Description); });
|
||||
|
||||
var commonResult = RequireSingleItem<DeviceMetering.CommonResultType>(stateResult.Items);
|
||||
if (IsArrayEmpty(commonResult.Items)) throw new HcsException("Пустой commonResult.Items");
|
||||
|
||||
DateTime датаПриема = commonResult.Items.OfType<DateTime>().FirstOrDefault();
|
||||
if (датаПриема == default) throw new HcsException("Сервер не вернул дату приема им показаний");
|
||||
return датаПриема;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user