Files
BusinessMgr-2019/SaBusMgrStandardBase/Base/WebService/SbmWebServiceClient.cs
T
2021-05-05 21:00:33 +01:00

432 lines
20 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 Sarand.Net.Standard.Base.Xml;
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)
{
String fn = GetType().Name + ".IsAlive";
try
{
RequestData requestData = new RequestData(instanceDefinition);
SbmWebServiceResponse serviceResponse = await DoWebServiceRequest(requestData);
if (serviceResponse.ResponseData.EqualsCI(SbmWebServiceDfn.IsAliveResponse))
return true;
}
catch (Exception exc) { SaLogger.Warn(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)
{
String fn = GetType().Name + ".GetItemCount";
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)
{
String fn = GetType().Name + ".GetItemList";
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(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)
{
String fn = GetType().Name + ".GetItemList";
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(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)
{
String fn = GetType().Name + ".GetItemData";
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)
{
String fn = GetType().Name + ".StoreItem";
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)
{
String fn = GetType().Name + ".DoWebServiceRequest";
SbmWebServiceResponse serviceResponse = null;
// Throw canceled exception if task has been cancelled - invoke at regular intervals.
requestData.ThrowIfCancellationRequested();
// Log request.
//if (SacsSystem.DebugMode) SaLogger.Debug(fn + " Request URL:" + requestData.InstanceDefinition.URL);
if (requestData.Debug)
{
if (requestData.Data.Length < 512)
SaLogger.Debug(fn + " Request:\n\t" + requestData.Data);
else SaLogger.Debug(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(fn + " Response: " + serviceResponse.ResponseData);
else SaLogger.Debug(fn + " Response size: " + serviceResponse.ResponseData.Length);
}
return serviceResponse;
}
//-------------------------------------------------------------------
}
//=======================================================================
}