Compare commits

..

No commits in common. "35a287017932331da575dbe61b42a7127c662a00" and "b4dcc35a8baaf9d3c6fbf003c97e84a08e4d2bcc" have entirely different histories.

4 changed files with 86 additions and 264 deletions

View File

@ -218,7 +218,6 @@
<Reference Include="System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> <Reference Include="System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>packages\System.Memory.4.5.1\lib\netstandard2.0\System.Memory.dll</HintPath> <HintPath>packages\System.Memory.4.5.1\lib\netstandard2.0\System.Memory.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Net.Http" />
<Reference Include="System.Numerics" /> <Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath> <HintPath>packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
@ -248,7 +247,6 @@
<Compile Include="Client.cs" /> <Compile Include="Client.cs" />
<Compile Include="ClientApp.cs" /> <Compile Include="ClientApp.cs" />
<Compile Include="ConfigFileParser.cs" /> <Compile Include="ConfigFileParser.cs" />
<Compile Include="ErrorLogger.cs" />
<Compile Include="ExtraParameter.cs" /> <Compile Include="ExtraParameter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>

View File

@ -5,7 +5,6 @@ using System.Linq;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json.Serialization;
namespace Creditcall.ChipDna.Client namespace Creditcall.ChipDna.Client
{ {
@ -250,6 +249,7 @@ namespace Creditcall.ChipDna.Client
{ {
{ ParameterKeys.Errors, errors }, { ParameterKeys.Errors, errors },
{ ParameterKeys.Reference, reference }, { ParameterKeys.Reference, reference },
{ ParameterKeys.TransactionResult, "ERROR" }
}; };
if (TransactionCompletionSource != null && !TransactionCompletionSource.Task.IsCompleted) if (TransactionCompletionSource != null && !TransactionCompletionSource.Task.IsCompleted)
@ -318,13 +318,13 @@ namespace Creditcall.ChipDna.Client
PerformStartTransaction("250", ""); PerformStartTransaction("250", "");
break; break;
case "C": case "C":
PerformConfirmTransaction("", ""); PerformConfirmTransaction("", out TransactionConfirmation confirmation);
break; break;
case "V": case "V":
PerformVoidTransaction(""); PerformVoidTransaction();
break; break;
case "I": case "I":
PerformGetTransactionInformation(""); PerformGetTransactionInformation();
break; break;
case "K": case "K":
PerformReleaseCard(); PerformReleaseCard();
@ -471,14 +471,14 @@ namespace Creditcall.ChipDna.Client
} }
} }
public Dictionary<string, string> GetStatus() private void GetStatus()
{ {
var transactionResult = new Dictionary<string, string>(); Console.WriteLine(ParameterKeys.VersionInformation + "\n" + ParameterKeys.ChipDnaStatus + "\n" + ParameterKeys.PaymentDeviceStatus + "\n" + ParameterKeys.RequestQueueStatus + "\n" + ParameterKeys.TmsStatus + "\n" + ParameterKeys.PaymentPlatformStatus);
var parameterSet = new ParameterSet(); var parameterSet = new ParameterSet();
var responseParameter = new List<Parameter>();
parameterSet.Add(GetExtraParams("GetStatus")); parameterSet.Add(GetExtraParams("GetStatus"));
Response response = chipDnaClientLib.GetStatus(parameterSet); Response response = chipDnaClientLib.GetStatus(GetRequestedParameterSet(parameterSet));
string errors; string errors;
var serverStatus = (ChipDnaStatus) null; var serverStatus = (ChipDnaStatus) null;
@ -495,13 +495,6 @@ namespace Creditcall.ChipDna.Client
{ {
Console.WriteLine(serverStatus); Console.WriteLine(serverStatus);
} }
responseParameter = response.ToList();
responseParameter.ForEach(parameter =>
{
transactionResult.Add(parameter.Key, parameter.Value);
});
return transactionResult;
} }
private void GetMerchantData() private void GetMerchantData()
@ -642,23 +635,19 @@ namespace Creditcall.ChipDna.Client
} }
} }
public Dictionary<string, string> PerformConfirmTransaction(string reference, string amount) public void PerformConfirmTransaction(string reference, out TransactionConfirmation confirmation)
{ {
var confirmationResult = new Dictionary<string, string>(); confirmation = new TransactionConfirmation();
var parameters = new ParameterSet(); var parameters = new ParameterSet();
parameters.Add(ParameterKeys.Reference, reference); parameters.Add(ParameterKeys.Reference, reference);
parameters.Add(ParameterKeys.Amount, amount);
parameters.Add(GetExtraParams("ConfirmTransaction")); parameters.Add(GetExtraParams("ConfirmTransaction"));
var response = chipDnaClientLib.ConfirmTransaction(parameters); var response = chipDnaClientLib.ConfirmTransaction(parameters);
var responseParameter = response.ToList();
responseParameter.ForEach(parameter =>
{
confirmationResult.Add(parameter.Key, parameter.Value);
});
string receipt, result; string receipt, result;
if (response.GetValue(ParameterKeys.TransactionResult, out result)) if (response.GetValue(ParameterKeys.TransactionResult, out result))
{ {
Console.WriteLine("Confirmed Transaction Result: {0}", result); Console.WriteLine("Confirmed Transaction Result: {0}", result);
confirmation.Result = result;
} }
if (response.GetValue(ParameterKeys.ReceiptDataMerchant, out receipt)) if (response.GetValue(ParameterKeys.ReceiptDataMerchant, out receipt))
{ {
@ -667,19 +656,21 @@ namespace Creditcall.ChipDna.Client
if (response.GetValue(ParameterKeys.ReceiptDataCardholder, out receipt)) if (response.GetValue(ParameterKeys.ReceiptDataCardholder, out receipt))
{ {
PrintReceiptData(ReceiptData.GetReceiptDataFromXml(receipt)); PrintReceiptData(ReceiptData.GetReceiptDataFromXml(receipt));
confirmation.ReceiptDataCardholder = receipt;
} }
string errors; string errors;
if (response.GetValue(ParameterKeys.Errors, out errors)) if (response.GetValue(ParameterKeys.Errors, out errors))
{ {
Console.WriteLine(ErrorsString("ConfirmTransaction Errors", errors)); Console.WriteLine(ErrorsString("ConfirmTransaction Errors", errors));
confirmation.Errors = errors;
} }
string errorDescription; string errorDescription;
if (response.GetValue(ParameterKeys.ErrorDescription, out errorDescription)) if (response.GetValue(ParameterKeys.ErrorDescription, out errorDescription))
{ {
Console.WriteLine("ErrorDescription: {0}", errorDescription); Console.WriteLine("ErrorDescription: {0}", errorDescription);
confirmation.ErrorDescription = errorDescription;
} }
return confirmationResult;
} }
private void DoUpdateTransaction() private void DoUpdateTransaction()
@ -748,13 +739,18 @@ namespace Creditcall.ChipDna.Client
} }
} }
public Dictionary<string, string> PerformVoidTransaction(string referenceValue) private void PerformVoidTransaction()
{ {
var transactionResult = new Dictionary<string, string>(); var reference = GetReference(true, "");
var voidReason = GetUserInput("\r\nPlease Enter Void Reason (Optional)");
var parameters = new ParameterSet(); var parameters = new ParameterSet();
if (!string.IsNullOrEmpty(referenceValue)) if (!string.IsNullOrEmpty(reference))
{ {
parameters.Add(ParameterKeys.Reference, referenceValue); parameters.Add(ParameterKeys.Reference, reference);
}
if (!String.IsNullOrEmpty(voidReason))
{
parameters.Add(ParameterKeys.VoidReason, voidReason);
} }
parameters.Add(GetExtraParams("VoidTransaction")); parameters.Add(GetExtraParams("VoidTransaction"));
@ -782,18 +778,12 @@ namespace Creditcall.ChipDna.Client
{ {
Console.WriteLine("ErrorDescription: {0}", errorDescription); Console.WriteLine("ErrorDescription: {0}", errorDescription);
} }
var responseParameter = response.ToList();
responseParameter.ForEach(parameter =>
{
transactionResult.Add(parameter.Key, parameter.Value);
});
return transactionResult;
} }
public Dictionary<string, string> PerformGetTransactionInformation(string referenceValue) private void PerformGetTransactionInformation()
{ {
var result = new Dictionary<string, string>(); var referenceValue = GetReference(true, "");
var parameters = new ParameterSet(); var parameters = new ParameterSet();
if (!string.IsNullOrEmpty(referenceValue)) if (!string.IsNullOrEmpty(referenceValue))
{ {
@ -804,11 +794,18 @@ namespace Creditcall.ChipDna.Client
var response = chipDnaClientLib.GetTransactionInformation(parameters); var response = chipDnaClientLib.GetTransactionInformation(parameters);
var responseParameter = response.ToList(); var responseParameter = response.ToList();
responseParameter.ForEach(parameter => responseParameter.ForEach(parameter =>
{ {
result.Add(parameter.Key, parameter.Value); if (parameter.Key == ParameterKeys.Errors)
{
Console.WriteLine(ErrorsString("GetTransactionInformation Errors", parameter.Value));
}
else
{
Console.WriteLine("{0} {1}", parameter.Key, parameter.Value);
}
}); });
return result;
} }
private static string GetUserInput(string prompt) private static string GetUserInput(string prompt)
@ -1461,7 +1458,6 @@ namespace Creditcall.ChipDna.Client
private void ChipDnaClientLibOnPaymentDeviceAvailabilityChangeEvent(object sender, EventParameters connectionEventArgs) private void ChipDnaClientLibOnPaymentDeviceAvailabilityChangeEvent(object sender, EventParameters connectionEventArgs)
{ {
var transactionResult = new Dictionary<string, string>();
var stringBuilder = new StringBuilder(); var stringBuilder = new StringBuilder();
connectionEventArgs.ToList().ForEach(param => connectionEventArgs.ToList().ForEach(param =>
{ {
@ -1479,9 +1475,7 @@ namespace Creditcall.ChipDna.Client
{ {
stringBuilder.Append(string.Format("[{0}]", param.ToString())); stringBuilder.Append(string.Format("[{0}]", param.ToString()));
} }
transactionResult.Add(param.Key, param.Value);
}); });
_ = ErrorLogger.SendLogErrorAsync(transactionResult);
Console.WriteLine("{0}: {1}", "Payment Device Availability Change Event", stringBuilder); Console.WriteLine("{0}: {1}", "Payment Device Availability Change Event", stringBuilder);
} }
@ -1507,11 +1501,6 @@ namespace Creditcall.ChipDna.Client
private void ChipDnaClientLibOnErrorEvent(object sender, ClientHelperErrorEventArgs errorEventArgs) private void ChipDnaClientLibOnErrorEvent(object sender, ClientHelperErrorEventArgs errorEventArgs)
{ {
var result = new Dictionary<string, string>
{
{ ParameterKeys.Errors, errorEventArgs.RaisedException.Message}
};
_ = ErrorLogger.SendLogErrorAsync(result);
PrintErrorEvent(errorEventArgs.RaisedException); PrintErrorEvent(errorEventArgs.RaisedException);
} }

View File

@ -19,7 +19,6 @@ namespace Creditcall.ChipDna.Client
private const int DefaultPort = 1869; private const int DefaultPort = 1869;
private const string DefaultIpAddress = "127.0.0.1"; private const string DefaultIpAddress = "127.0.0.1";
private const bool DefaultSaveReceipt = false; private const bool DefaultSaveReceipt = false;
private const int transactionTimeoutSeconds = 300;
private static Client client; private static Client client;
@ -73,18 +72,10 @@ namespace Creditcall.ChipDna.Client
{ {
HttpListener listener = new HttpListener(); HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://127.0.0.1:18181/start-transaction/"); listener.Prefixes.Add("http://127.0.0.1:18181/start-transaction/");
listener.Prefixes.Add("http://127.0.0.1:18181/confirm-transaction/");
listener.Prefixes.Add("http://127.0.0.1:18181/transaction-information/");
listener.Prefixes.Add("http://127.0.0.1:18181/void-transaction/");
listener.Prefixes.Add("http://127.0.0.1:18181/chipdna-status/");
listener.Start(); listener.Start();
Console.WriteLine("Listening on:"); Console.WriteLine("Listening on:");
Console.WriteLine(" http://127.0.0.1:18181/start-transaction/"); Console.WriteLine(" http://127.0.0.1:18181/start-transaction/");
Console.WriteLine(" http://127.0.0.1:18181/confirm-transaction/");
Console.WriteLine(" http://127.0.0.1:18181/transaction-information/");
Console.WriteLine(" http://127.0.0.1:18181/void-transaction/");
Console.WriteLine(" http://127.0.0.1:18181/chipdna-status/");
while (true) while (true)
{ {
@ -104,22 +95,6 @@ namespace Creditcall.ChipDna.Client
if (rawUrl.StartsWith("/start-transaction", StringComparison.OrdinalIgnoreCase)) if (rawUrl.StartsWith("/start-transaction", StringComparison.OrdinalIgnoreCase))
{ {
HandleStartTransaction(context); HandleStartTransaction(context);
} else if (rawUrl.StartsWith("/confirm-transaction", StringComparison.OrdinalIgnoreCase))
{
HandleConfirmTransaction(context);
}
else if (rawUrl.StartsWith("/transaction-information", StringComparison.OrdinalIgnoreCase))
{
HandleTransactionInformation(context);
}
else if (rawUrl.StartsWith("/void-transaction", StringComparison.OrdinalIgnoreCase))
{
HandleVoidTransaction(context);
}
else if (rawUrl.StartsWith("/chipdna-status", StringComparison.OrdinalIgnoreCase))
{
HandleGetStatus(context);
} }
else else
{ {
@ -140,127 +115,21 @@ namespace Creditcall.ChipDna.Client
} }
} }
private static void HandleGetStatus(HttpListenerContext context)
{
try
{
var statusResult = client.GetStatus();
var responseSerializer = new XmlSerializer(typeof(SerializableKeyValueList));
context.Response.ContentType = "application/xml";
var wrappedResult = new SerializableKeyValueList(statusResult);
responseSerializer.Serialize(context.Response.OutputStream, wrappedResult);
}
catch (Exception ex)
{
Console.WriteLine("Error in -status: " + ex.Message);
context.Response.StatusCode = 500;
}
finally
{
context.Response.OutputStream.Close();
}
}
private static void HandleTransactionInformation(HttpListenerContext context)
{
try
{
var serializer = new XmlSerializer(typeof(TransactionReferenceRequest));
TransactionReferenceRequest req = (TransactionReferenceRequest)serializer.Deserialize(context.Request.InputStream);
var transactionResult = client.PerformGetTransactionInformation(req.TransactionReference);
// Return the final key/value list
var responseSerializer = new XmlSerializer(typeof(SerializableKeyValueList));
context.Response.ContentType = "application/xml";
var wrappedResult = new SerializableKeyValueList(transactionResult);
responseSerializer.Serialize(context.Response.OutputStream, wrappedResult);
}
catch (Exception ex)
{
Console.WriteLine("Error in transaction-information: " + ex.Message);
context.Response.StatusCode = 500;
}
finally
{
context.Response.OutputStream.Close();
}
}
private static void HandleVoidTransaction(HttpListenerContext context)
{
try
{
var serializer = new XmlSerializer(typeof(TransactionReferenceRequest));
TransactionReferenceRequest req = (TransactionReferenceRequest)serializer.Deserialize(context.Request.InputStream);
var transactionResult = client.PerformVoidTransaction(req.TransactionReference);
// Return the final key/value list
var responseSerializer = new XmlSerializer(typeof(SerializableKeyValueList));
context.Response.ContentType = "application/xml";
var wrappedResult = new SerializableKeyValueList(transactionResult);
responseSerializer.Serialize(context.Response.OutputStream, wrappedResult);
}
catch (Exception ex)
{
Console.WriteLine("Error in transaction-information: " + ex.Message);
context.Response.StatusCode = 500;
}
finally
{
context.Response.OutputStream.Close();
}
}
private static void HandleConfirmTransaction(HttpListenerContext context)
{
try
{
var serializer = new XmlSerializer(typeof(ConfirmTransactionRequest));
ConfirmTransactionRequest payload = (ConfirmTransactionRequest)serializer.Deserialize(context.Request.InputStream);
Console.WriteLine($"Received confirm transaction: Amount={payload.Amount}, TransactionReference={payload.TransactionReference}");
var confirmationResult = client.PerformConfirmTransaction(payload.TransactionReference, payload.Amount);
var responseSerializer = new XmlSerializer(typeof(SerializableKeyValueList));
context.Response.ContentType = "application/xml";
var wrappedResult = new SerializableKeyValueList(confirmationResult);
responseSerializer.Serialize(context.Response.OutputStream, wrappedResult);
}
catch (Exception ex)
{
var errorMap = new Dictionary<string, string>
{
{ ParameterKeys.TransactionResult, "ERROR" },
{ ParameterKeys.Errors, $"ConfirmTransaction failed: {ex.Message}" }
};
var responseSerializer = new XmlSerializer(typeof(SerializableKeyValueList));
context.Response.ContentType = "application/xml";
var wrappedResult = new SerializableKeyValueList(errorMap);
responseSerializer.Serialize(context.Response.OutputStream, wrappedResult);
}
finally
{
context.Response.OutputStream.Close();
}
}
private static void HandleStartTransaction(HttpListenerContext context) private static void HandleStartTransaction(HttpListenerContext context)
{ {
const int transactionTimeoutSeconds = 300;
try try
{ {
var serializer = new XmlSerializer(typeof(TransactionPayload)); var serializer = new XmlSerializer(typeof(TransactionPayload));
TransactionPayload payload = (TransactionPayload)serializer.Deserialize(context.Request.InputStream); TransactionPayload payload = (TransactionPayload)serializer.Deserialize(context.Request.InputStream);
Console.WriteLine($"Received transaction request: Amount={payload.Amount}, Type={payload.TransactionType}"); Console.WriteLine($"Received start transaction: Amount={payload.amount}, Type={payload.transactionType}");
client.TransactionCompletionSource = new TaskCompletionSource<Dictionary<string, string>>(); client.TransactionCompletionSource = new TaskCompletionSource<Dictionary<string, string>>();
// start transaction (non-blocking) // start transaction (non-blocking)
client.PerformStartTransaction(payload.Amount, payload.TransactionType); client.PerformStartTransaction(payload.amount, payload.transactionType);
// Wait for completion with timeout // Wait for completion with timeout
var task = client.TransactionCompletionSource.Task; var task = client.TransactionCompletionSource.Task;
@ -299,6 +168,45 @@ namespace Creditcall.ChipDna.Client
return; return;
} }
// If it's a SALE and approved, call ConfirmTransaction and attach its XML
transactionResult.TryGetValue(ParameterKeys.TransactionType, out string txType);
transactionResult.TryGetValue(ParameterKeys.TransactionResult, out string txResult);
transactionResult.TryGetValue(ParameterKeys.Reference, out string txReference);
if (!string.IsNullOrEmpty(txType) && txType.Equals("SALE", StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrEmpty(txResult) && txResult.Equals("APPROVED", StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrEmpty(txReference))
{
try
{
TransactionConfirmation confirmation;
client.PerformConfirmTransaction(txReference, out confirmation);
// Keep original fields, but also add confirmation-prefixed fields
transactionResult["CONFIRM_RESULT"] = confirmation?.Result ?? "";
transactionResult["CONFIRM_ERRORS"] = confirmation?.Errors ?? "";
if (!string.IsNullOrEmpty(confirmation.ErrorDescription))
{
transactionResult["CONFIRM_ERRORS"] = $"{confirmation.Errors} {confirmation.ErrorDescription}";
}
if (!string.IsNullOrEmpty(confirmation?.ReceiptDataCardholder))
{
transactionResult[ParameterKeys.ReceiptDataCardholder] = confirmation.ReceiptDataCardholder;
}
// XML (omit declaration so it can be embedded)
var xml = SerializeToXml(confirmation, omitXmlDeclaration: true);
transactionResult["TRANSACTION_CONFIRMATION"] = xml;
}
catch (Exception ex)
{
// preserve original transaction result but add an error key
transactionResult["CONFIRM_RESULT"] = "ERROR";
transactionResult["CONFIRM_ERRORS"] = $"ConfirmTransaction failed: {ex.Message}";
}
}
// Return the final key/value list as before
var responseSerializer = new XmlSerializer(typeof(SerializableKeyValueList)); var responseSerializer = new XmlSerializer(typeof(SerializableKeyValueList));
context.Response.ContentType = "application/xml"; context.Response.ContentType = "application/xml";
var wrappedResult = new SerializableKeyValueList(transactionResult); var wrappedResult = new SerializableKeyValueList(transactionResult);
@ -313,7 +221,6 @@ namespace Creditcall.ChipDna.Client
{ {
context.Response.OutputStream.Close(); context.Response.OutputStream.Close();
} }
} }
private static string GetAbsolutePath(string fileName) private static string GetAbsolutePath(string fileName)
@ -401,8 +308,11 @@ namespace Creditcall.ChipDna.Client
[XmlRoot("TransactionPayload")] [XmlRoot("TransactionPayload")]
public class TransactionPayload public class TransactionPayload
{ {
public string Amount { get; set; } public string amount { get; set; }
public string TransactionType { get; set; } public string transactionType { get; set; }
// For confirm transaction
public string transactionReference { get; set; }
} }
[XmlRoot("TransactionConfirmation")] [XmlRoot("TransactionConfirmation")]
@ -412,20 +322,6 @@ namespace Creditcall.ChipDna.Client
public string Errors { get; set; } public string Errors { get; set; }
public string ErrorDescription { get; set; } public string ErrorDescription { get; set; }
public string ReceiptDataCardholder { get; set; } public string ReceiptDataCardholder { get; set; }
}
[XmlRoot("TransactionReferenceRequest")]
public class TransactionReferenceRequest
{
[XmlElement("TransactionReference")]
public string TransactionReference { get; set; }
}
[XmlRoot("ConfirmTransactionRequest")]
public class ConfirmTransactionRequest
{
public string Amount { get; set; }
public string TransactionReference { get; set; }
}
} }
}

View File

@ -1,61 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
namespace Creditcall.ChipDna.Client
{
public static class ErrorLogger
{
private static readonly HttpClient httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(10)
};
public static async Task SendLogErrorAsync(Dictionary<string, string> statusResult)
{
try
{
if (statusResult == null || statusResult.Count == 0)
return;
var url = "http://127.0.0.1:9091/logerror";
var wrappedResult = new SerializableKeyValueList(statusResult);
var serializer = new XmlSerializer(typeof(SerializableKeyValueList));
var ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
var settings = new XmlWriterSettings
{
OmitXmlDeclaration = false,
Indent = false,
Encoding = new UTF8Encoding(false)
};
using (var ms = new MemoryStream())
{
using (var xw = XmlWriter.Create(ms, settings))
{
serializer.Serialize(xw, wrappedResult, ns);
}
var content = new ByteArrayContent(ms.ToArray());
content.Headers.ContentType =
new MediaTypeHeaderValue("application/xml");
await httpClient.PostAsync(url, content);
}
}
catch (Exception ex)
{
Console.WriteLine("SendLogErrorAsync failed: " + ex.Message);
}
}
}
}