424 lines
19 KiB
C#
424 lines
19 KiB
C#
using Sarand.BusinessMgr.Net.Standard.Base.Data;
|
|
using Sarand.Net.Standard.Base.App;
|
|
using Sarand.Net.Standard.Base.Core;
|
|
using Sarand.Net.Standard.Base.Data;
|
|
using Sarand.Net.Standard.Base.Net;
|
|
using Sarand.Net.Standard.Base.Tasks;
|
|
using Sarand.Net.Standard.Base.Utils;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Xml.Linq;
|
|
|
|
namespace Sarand.BusinessMgr.Net.Standard.Base.WebService
|
|
{
|
|
//=======================================================================
|
|
// Business Web Service Client
|
|
// Make requests to BusinessMgr Web Service hosted by Windows Service application.
|
|
//-----------------------------------------------------------------------
|
|
// Threading:
|
|
// Ref. https://blog.xamarin.com/getting-started-with-async-await/
|
|
//=======================================================================
|
|
public class SbmWebServiceClient
|
|
{
|
|
//-------------------------------------------------------------------
|
|
// Definitions.
|
|
public class RequestData : SacsTaskData
|
|
{
|
|
/// <summary>
|
|
/// Web Service Request data.
|
|
/// <para>Cancellation token can optionally be supplied if available higher up the chain.</para>
|
|
/// </summary>
|
|
public RequestData(SbmWebServiceInstanceDefinition instanceDefinition, CancellationToken? cancellationToken = null) :
|
|
base(cancellationToken)
|
|
{
|
|
InstanceDefinition = instanceDefinition;
|
|
}
|
|
public SbmWebServiceInstanceDefinition InstanceDefinition { get; }
|
|
public String Data { get; set; } = "";
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Data members.
|
|
|
|
//-------------------------------------------------------------------
|
|
// Construction.
|
|
public SbmWebServiceClient()
|
|
{
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Properties.
|
|
|
|
//-------------------------------------------------------------------
|
|
// I s A l i v e
|
|
//-------------------------------------------------------------------
|
|
public async Task<bool> RequestIsAlive(SbmWebServiceInstanceDefinition instanceDefinition)
|
|
{
|
|
try
|
|
{
|
|
RequestData requestData = new RequestData(instanceDefinition);
|
|
SbmWebServiceResponse serviceResponse = await DoWebServiceRequest(requestData);
|
|
if (serviceResponse.ResponseData.EqualsCI(SbmWebServiceDfn.IsAliveResponse))
|
|
return true;
|
|
}
|
|
catch (Exception exc) { SaLogger.Warn($"{SysUtil.Fn} " + exc.GetLogMessage()); }
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// I t e m C o u n t R e q u e s t
|
|
//-------------------------------------------------------------------
|
|
public class ItemCountResponseData : SbmWebServiceResponse
|
|
{
|
|
public ItemCountResponseData(SbmWebServiceResponse serviceResponse) : base(serviceResponse) { }
|
|
public long ItemCount { get; set; }
|
|
}
|
|
public async Task<ItemCountResponseData> RequestItemCount(SbmWebServiceRequest.Config configRequest, Dictionary<String, String> filters, SacsTaskData taskData)
|
|
{
|
|
if (SacsSystem.DebugMode && configRequest.RequestType != SbmWebServiceRequest.RequestType.Count) Debugger.Break();
|
|
|
|
// Service Request.
|
|
SbmWebServiceRequest serviceRequestData = new SbmWebServiceRequest(configRequest);
|
|
serviceRequestData.Filters.AddRange(filters);
|
|
|
|
// Configure Web Service and make Request.
|
|
RequestData requestData = new RequestData(configRequest.Context.InstanceDefinition, taskData.CancellationToken) { Debug = taskData.Debug };
|
|
requestData.Data = serviceRequestData.GenerateRequestData();
|
|
SbmWebServiceResponse serviceResponse = await DoWebServiceRequest(requestData);
|
|
ItemCountResponseData responseData = new ItemCountResponseData(serviceResponse);
|
|
bool itemCountFound = false;
|
|
|
|
// Interpret response.
|
|
if (serviceResponse.ResponseElement != null && !taskData.IsCancellationRequested)
|
|
{
|
|
foreach (XElement responseChildElement in serviceResponse.ResponseElement.Elements())
|
|
{
|
|
if (responseChildElement.Name.LocalName.EqualsCI(SbmWebServiceDfn.ElementName.Data))
|
|
{
|
|
foreach (XElement dataElement in responseChildElement.Elements())
|
|
{
|
|
if (dataElement.Name.LocalName.EqualsCI(SbmWebServiceDfn.ElementName.Count))
|
|
{
|
|
itemCountFound = true;
|
|
responseData.ItemCount = StringUtil.ToLong(dataElement.Value);
|
|
break;
|
|
}
|
|
if (taskData.IsCancellationRequested) break;
|
|
}
|
|
}
|
|
if (itemCountFound || taskData.IsCancellationRequested) break;
|
|
}
|
|
}
|
|
if (!itemCountFound) responseData.ErrorStateMessage = "Incomplete item count";
|
|
if (taskData.IsCancellationRequested) responseData.TaskCancelled = true;
|
|
return responseData;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Q u e r y L i s t R e q u e s t
|
|
//-------------------------------------------------------------------
|
|
public class QueryListResponseData : SbmWebServiceResponse
|
|
{
|
|
public QueryListResponseData(SbmWebServiceResponse serviceResponse) : base(serviceResponse) { }
|
|
public List<SbmWebServiceItemData> Items { get; } = new List<SbmWebServiceItemData>();
|
|
public int Count { get; set; }
|
|
public int Total { get; set; }
|
|
public uint PageNo { get; set; }
|
|
public ushort PageLength { get; set; }
|
|
}
|
|
public async Task<QueryListResponseData> RequestQueryList(SbmWebServiceRequest.Config configRequest, Dictionary<String, String> filters, List<string> columns, List<String> sortColumns, SacsTaskData taskData)
|
|
{
|
|
if (SacsSystem.DebugMode && configRequest.RequestType != SbmWebServiceRequest.RequestType.QueryList) Debugger.Break();
|
|
|
|
// Service Request.
|
|
SbmWebServiceRequest serviceRequestData = new SbmWebServiceRequest(configRequest);
|
|
serviceRequestData.Filters.AddRange(filters);
|
|
serviceRequestData.Columns.AddRange(columns);
|
|
if (sortColumns != null) serviceRequestData.SortColumns.AddRange(sortColumns);
|
|
|
|
// Configure Web Service and make Request.
|
|
RequestData requestData = new RequestData(configRequest.Context.InstanceDefinition, taskData.CancellationToken) { Debug = taskData.Debug };
|
|
requestData.Data = serviceRequestData.GenerateRequestData();
|
|
SbmWebServiceResponse serviceResponse = await DoWebServiceRequest(requestData);
|
|
QueryListResponseData responseData = new QueryListResponseData(serviceResponse);
|
|
//if (SacsSystem.DebugMode && responseData.ResponseElement != null) SaLogger.Debug($"{SysUtil.Fn} Response:\n\n" + responseData.ResponseElement.FormatXml() + "\n");
|
|
|
|
// Interpret response.
|
|
if (serviceResponse.ResponseElement != null && !taskData.IsCancellationRequested)
|
|
{
|
|
foreach (XElement responseChildElement in serviceResponse.ResponseElement.Elements())
|
|
{
|
|
if (responseChildElement.Name.LocalName.EqualsCI(SbmWebServiceDfn.ElementName.Data))
|
|
{
|
|
foreach (XElement dataElement in responseChildElement.Elements())
|
|
{
|
|
if (dataElement.Name.LocalName.EqualsCI(SbmWebServiceDfn.ElementName.List))
|
|
{
|
|
// Paging info.
|
|
// <List Count="8" Total="196527" PageNo="1" PageLength="8">
|
|
responseData.Count = StringUtil.ToInt(dataElement.GetAttributeValue(SbmWebServiceDfn.AttributeName.Count));
|
|
responseData.Total = StringUtil.ToInt(dataElement.GetAttributeValue(SbmWebServiceDfn.AttributeName.Total));
|
|
responseData.PageNo = (uint)StringUtil.ToInt(dataElement.GetAttributeValue(SbmWebServiceDfn.AttributeName.PageNo));
|
|
responseData.PageLength = (ushort)StringUtil.ToInt(dataElement.GetAttributeValue(SbmWebServiceDfn.AttributeName.PageLength));
|
|
// Extract items.
|
|
foreach (XElement listElement in dataElement.Elements())
|
|
{
|
|
taskData.ThrowIfCancellationRequested();
|
|
if (listElement.Name.LocalName.EqualsCI(SbmWebServiceDfn.ElementName.Item))
|
|
{
|
|
SbmWebServiceItemData itemData = new SbmWebServiceItemData("");
|
|
List<String> fields = SacsCsvHandler.ParseCsvRecord(listElement.Value);
|
|
for (int fieldIdx = 0; fieldIdx < fields.Count && fieldIdx < columns.Count; fieldIdx++)
|
|
{
|
|
String column = columns[fieldIdx];
|
|
String field = fields[fieldIdx];
|
|
itemData.AddValue(column, field);
|
|
}
|
|
responseData.Items.Add(itemData);
|
|
}
|
|
if (taskData.IsCancellationRequested) break;
|
|
}
|
|
}
|
|
if (taskData.IsCancellationRequested) break;
|
|
}
|
|
}
|
|
if (taskData.IsCancellationRequested) break;
|
|
}
|
|
}
|
|
if (taskData.IsCancellationRequested) responseData.TaskCancelled = true;
|
|
return responseData;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// I t e m L i s t R e q u e s t
|
|
//-------------------------------------------------------------------
|
|
public class ItemListResponseData : SbmWebServiceResponse
|
|
{
|
|
public ItemListResponseData(SbmWebServiceResponse serviceResponse) : base(serviceResponse) { }
|
|
public List<SbmWebServiceItemData> Items { get; } = new List<SbmWebServiceItemData>();
|
|
public int Count { get; set; }
|
|
public int Total { get; set; }
|
|
public uint PageNo { get; set; }
|
|
public ushort PageLength { get; set; }
|
|
}
|
|
public async Task<ItemListResponseData> RequestItemList(SbmWebServiceRequest.Config configRequest, Dictionary<String, String> filters, List<String> sortColumns, SacsTaskData taskData)
|
|
{
|
|
if (SacsSystem.DebugMode && configRequest.RequestType != SbmWebServiceRequest.RequestType.ItemList) Debugger.Break();
|
|
|
|
// Service Request.
|
|
SbmWebServiceRequest serviceRequestData = new SbmWebServiceRequest(configRequest);
|
|
serviceRequestData.Filters.AddRange(filters);
|
|
if (sortColumns != null) serviceRequestData.SortColumns.AddRange(sortColumns);
|
|
|
|
// Configure Web Service and make Request.
|
|
RequestData requestData = new RequestData(configRequest.Context.InstanceDefinition, taskData.CancellationToken) { Debug = taskData.Debug };
|
|
requestData.Data = serviceRequestData.GenerateRequestData();
|
|
SbmWebServiceResponse serviceResponse = await DoWebServiceRequest(requestData);
|
|
ItemListResponseData responseData = new ItemListResponseData(serviceResponse);
|
|
//if (SacsSystem.DebugMode && responseData.ResponseElement != null) SaLogger.Debug($"{SysUtil.Fn} Response:\n\n" + responseData.ResponseElement.FormatXml() + "\n");
|
|
|
|
// Interpret response.
|
|
if (serviceResponse.ResponseElement != null && !taskData.IsCancellationRequested)
|
|
{
|
|
foreach (XElement responseChildElement in serviceResponse.ResponseElement.Elements())
|
|
{
|
|
if (responseChildElement.Name.LocalName.EqualsCI(SbmWebServiceDfn.ElementName.Data))
|
|
{
|
|
foreach (XElement dataElement in responseChildElement.Elements())
|
|
{
|
|
if (dataElement.Name.LocalName.EqualsCI(SbmWebServiceDfn.ElementName.List))
|
|
{
|
|
// Paging info.
|
|
// <List Count="8" Total="196527" PageNo="1" PageLength="8">
|
|
responseData.Count = StringUtil.ToInt(dataElement.GetAttributeValue(SbmWebServiceDfn.AttributeName.Count));
|
|
responseData.Total = StringUtil.ToInt(dataElement.GetAttributeValue(SbmWebServiceDfn.AttributeName.Total));
|
|
responseData.PageNo = (uint)StringUtil.ToInt(dataElement.GetAttributeValue(SbmWebServiceDfn.AttributeName.PageNo));
|
|
responseData.PageLength = (ushort)StringUtil.ToInt(dataElement.GetAttributeValue(SbmWebServiceDfn.AttributeName.PageLength));
|
|
// Extract items.
|
|
foreach (XElement listElement in dataElement.Elements())
|
|
{
|
|
taskData.ThrowIfCancellationRequested();
|
|
if (listElement.Name.LocalName.EqualsCI(SbmWebServiceDfn.ElementName.Item))
|
|
responseData.Items.Add(ExtractItemData(listElement, taskData));
|
|
if (taskData.IsCancellationRequested) break;
|
|
}
|
|
}
|
|
if (taskData.IsCancellationRequested) break;
|
|
}
|
|
}
|
|
if (taskData.IsCancellationRequested) break;
|
|
}
|
|
}
|
|
if (taskData.IsCancellationRequested) responseData.TaskCancelled = true;
|
|
return responseData;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// I t e m D a t a R e q u e s t
|
|
//-------------------------------------------------------------------
|
|
public class ItemDataResponseData : SbmWebServiceResponse
|
|
{
|
|
public ItemDataResponseData(SbmWebServiceResponse serviceResponse) : base(serviceResponse) { }
|
|
public XElement DataElement => (ResponseElement?.GetFirstChildElement(SbmWebServiceDfn.ElementName.Data) ?? null);
|
|
public XElement ItemElement => (DataElement?.GetFirstChildElement(SbmWebServiceDfn.ElementName.Item) ?? null);
|
|
public SbmWebServiceItemData Item { get; set; }
|
|
}
|
|
public async Task<ItemDataResponseData> RequestItemData(SbmWebServiceRequest.Config configRequest, Dictionary<String, String> filters, SacsTaskData taskData)
|
|
{
|
|
if (SacsSystem.DebugMode && configRequest.RequestType != SbmWebServiceRequest.RequestType.Item) Debugger.Break();
|
|
|
|
// Service Request.
|
|
SbmWebServiceRequest serviceRequestData = new SbmWebServiceRequest(configRequest);
|
|
serviceRequestData.Filters.AddRange(filters);
|
|
|
|
// Configure Web Service and make Request.
|
|
RequestData requestData = new RequestData(configRequest.Context.InstanceDefinition, taskData.CancellationToken) { Debug = taskData.Debug };
|
|
requestData.Data = serviceRequestData.GenerateRequestData();
|
|
SbmWebServiceResponse serviceResponse = await DoWebServiceRequest(requestData);
|
|
ItemDataResponseData responseData = new ItemDataResponseData(serviceResponse);
|
|
//if (SacsSystem.DebugMode && responseData.ResponseElement != null) SaLogger.Debug("Response:\n\n" + responseData.ResponseElement.FormatXml()+"\n");
|
|
|
|
// Extract item properties.
|
|
if (serviceResponse.ResponseElement != null && !taskData.IsCancellationRequested)
|
|
{
|
|
foreach (XElement responseChildElement in serviceResponse.ResponseElement.Elements())
|
|
{
|
|
requestData.ThrowIfCancellationRequested();
|
|
if (responseChildElement.Name.LocalName.EqualsCI(SbmWebServiceDfn.ElementName.Data))
|
|
{
|
|
foreach (XElement dataElement in responseChildElement.Elements())
|
|
{
|
|
requestData.ThrowIfCancellationRequested();
|
|
if (dataElement.Name.LocalName.EqualsCI(SbmWebServiceDfn.ElementName.Item))
|
|
responseData.Item = ExtractItemData(dataElement, taskData);
|
|
if (taskData.IsCancellationRequested) break;
|
|
}
|
|
}
|
|
if (taskData.IsCancellationRequested) break;
|
|
}
|
|
}
|
|
if (taskData.IsCancellationRequested) responseData.TaskCancelled = true;
|
|
return responseData;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// E x t r a c t I t e m
|
|
//-------------------------------------------------------------------
|
|
private SbmWebServiceItemData ExtractItemData(XElement itemElement, SacsTaskData taskData)
|
|
{
|
|
SbmWebServiceItemData itemData = new SbmWebServiceItemData(itemElement.GetAttributeValue(SbmWebServiceDfn.AttributeName.ItemType));
|
|
foreach (XElement itemDataElement in itemElement.Elements())
|
|
{
|
|
if (!itemDataElement.HasElements)
|
|
{
|
|
// No child elements - treat as item property.
|
|
itemData.AddValue(itemDataElement.Name.LocalName, itemDataElement.Value);
|
|
}
|
|
else if (itemDataElement.Name.LocalName.Length > 4 && itemDataElement.Name.LocalName.EndsWithCI("List"))
|
|
{
|
|
// Data elements has children and is a list of child items.
|
|
String childItemType = itemDataElement.Name.LocalName;
|
|
if (!itemData.ChildItems.ContainsKey(childItemType))
|
|
itemData.ChildItems[childItemType] = new List<SbmWebServiceItemData>();
|
|
foreach (XElement childItemElement in itemDataElement.Elements())
|
|
{
|
|
itemData.ChildItems[childItemType].Add(ExtractItemData(childItemElement, taskData));
|
|
if (taskData.IsCancellationRequested) break;
|
|
}
|
|
}
|
|
if (taskData.IsCancellationRequested) break;
|
|
}
|
|
return itemData;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// S t o r e I t e m R e q u e s t
|
|
//-------------------------------------------------------------------
|
|
public class StoreItemResponseData : SbmWebServiceResponse
|
|
{
|
|
public StoreItemResponseData(SbmWebServiceResponse serviceResponse) : base(serviceResponse) { }
|
|
public XElement DataElement => (ResponseElement?.GetFirstChildElement("Item") ?? null);
|
|
}
|
|
public async Task<StoreItemResponseData> StoreItem(SbmWebServiceRequest.Config configRequest, XElement itemElement, SacsTaskData taskData)
|
|
{
|
|
if (SacsSystem.DebugMode && configRequest.RequestType != SbmWebServiceRequest.RequestType.Store) Debugger.Break();
|
|
|
|
// Service Request.
|
|
SbmWebServiceRequest serviceRequestData = new SbmWebServiceRequest(configRequest);
|
|
serviceRequestData.ItemElement = itemElement;
|
|
|
|
// Configure Web Service and make Request.
|
|
RequestData requestData = new RequestData(configRequest.Context.InstanceDefinition, taskData.CancellationToken) { Debug = taskData.Debug };
|
|
requestData.Data = serviceRequestData.GenerateRequestData();
|
|
SbmWebServiceResponse serviceResponse = await DoWebServiceRequest(requestData);
|
|
|
|
// Return result.
|
|
return new StoreItemResponseData(serviceResponse);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// W e b S e r v i c e R e q u e s t
|
|
//-------------------------------------------------------------------
|
|
/// <summary>
|
|
/// Execute the web service request.
|
|
/// <para>Request data is encrypted and response data is decrypted automatically.</para>
|
|
/// </summary>
|
|
public async Task<SbmWebServiceResponse> DoWebServiceRequest(RequestData requestData)
|
|
{
|
|
SbmWebServiceResponse serviceResponse = null;
|
|
// Throw canceled exception if task has been cancelled - invoke at regular intervals.
|
|
requestData.ThrowIfCancellationRequested();
|
|
|
|
// Log request.
|
|
//if (SacsSystem.DebugMode) SaLogger.Debug($"{SysUtil.Fn} Request URL:" + requestData.InstanceDefinition.URL);
|
|
if (requestData.Debug)
|
|
{
|
|
if (requestData.Data.Length < 512)
|
|
SaLogger.Debug($"{SysUtil.Fn} Request:\n\t" + requestData.Data);
|
|
else SaLogger.Debug($"{SysUtil.Fn} Request length:" + requestData.Data.Length);
|
|
}
|
|
|
|
// Configure the request.
|
|
SacsHttpRequestData httpRequestData = new SacsHttpRequestData(requestData.CancellationToken)
|
|
{
|
|
Url = requestData.InstanceDefinition.URL,
|
|
TimeoutSecs = 1,
|
|
PostData = SbmWindowsServiceCrypter.EncryptRequestData(requestData.Data)
|
|
};
|
|
|
|
// Make the request.
|
|
DateTime started = DateTime.Now;
|
|
requestData.InstanceDefinition.LastRequestAt = started;
|
|
SacsHttpResponseData httpResponseData = await SacsHttpClient.DoRequest(httpRequestData);
|
|
|
|
// Construct the response.
|
|
SbmWebServiceResponse.Config serviceResponseConfig = new SbmWebServiceResponse.Config()
|
|
{
|
|
RequestStarted = started,
|
|
RequestCompleted = DateTime.Now,
|
|
HttpResponseData = httpResponseData
|
|
};
|
|
serviceResponse = new SbmWebServiceResponse(serviceResponseConfig);
|
|
|
|
// Note if request was successful.
|
|
if (httpResponseData.Success)
|
|
requestData.InstanceDefinition.LastSuccessfulRequestAt = serviceResponseConfig.RequestCompleted;
|
|
|
|
// Log response.
|
|
if (requestData.Debug)
|
|
{
|
|
if (serviceResponse.ResponseData.Length < 1024)
|
|
SaLogger.Debug($"{SysUtil.Fn} Response: " + serviceResponse.ResponseData);
|
|
else SaLogger.Debug($"{SysUtil.Fn} Response size: " + serviceResponse.ResponseData.Length);
|
|
}
|
|
return serviceResponse;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
}
|
|
//=======================================================================
|
|
}
|