Initial commit: solution and project structure
This commit is contained in:
commit
02805630d0
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
.vs/
|
||||||
|
*.user
|
||||||
|
*.log
|
||||||
|
appsettings.Development.json
|
||||||
25
SlReport.sln
Normal file
25
SlReport.sln
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.14.36603.0 d17.14
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SlReport", "SlReport\SlReport.csproj", "{2FCE8950-D2A2-4730-96DD-4DB3EB1BD1FD}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{2FCE8950-D2A2-4730-96DD-4DB3EB1BD1FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2FCE8950-D2A2-4730-96DD-4DB3EB1BD1FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2FCE8950-D2A2-4730-96DD-4DB3EB1BD1FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2FCE8950-D2A2-4730-96DD-4DB3EB1BD1FD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {9351DED9-BDB8-4A4C-97B2-582D3BBF902B}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
6
SlReport/App.config
Normal file
6
SlReport/App.config
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
||||||
192
SlReport/Program.cs
Normal file
192
SlReport/Program.cs
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static SignLanguageReportApiClient api;
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Console.Title = "SL REPORT – API TEST HARNESS";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
api = new SignLanguageReportApiClient("https://localhost:44367/");
|
||||||
|
|
||||||
|
LogHeader("SL REPORT TEST STARTED");
|
||||||
|
|
||||||
|
var userId = RegisterUser();
|
||||||
|
if (userId == Guid.Empty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RegisterClient();
|
||||||
|
MapUser(userId);
|
||||||
|
CaptureSessions();
|
||||||
|
ReportAllHistory();
|
||||||
|
ReportFilteredHistory();
|
||||||
|
ListAllClients();
|
||||||
|
|
||||||
|
LogHeader("SL REPORT TEST COMPLETED");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogFatal("UNHANDLED FATAL ERROR", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("\nPress ENTER to exit...");
|
||||||
|
Console.ReadLine();
|
||||||
|
}
|
||||||
|
static Guid RegisterUser()
|
||||||
|
{
|
||||||
|
return SafeCall(
|
||||||
|
() => api.RegisterUser("test_user3", "123456"),
|
||||||
|
"RegisterUser"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
static void RegisterClient()
|
||||||
|
{
|
||||||
|
SafeCall(
|
||||||
|
() => api.RegisterClient("13351", "MORO"),
|
||||||
|
"RegisterClient"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
static void MapUser(Guid userId)
|
||||||
|
{
|
||||||
|
SafeCall(
|
||||||
|
() => api.MapUser(userId, "13351", "MORO"),
|
||||||
|
"MapUser"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
static void CaptureSessions()
|
||||||
|
{
|
||||||
|
SafeCall(() => api.Capture("13351", "MORO"), "Capture #1");
|
||||||
|
SafeCall(() => api.Capture("13351", "MORO"), "Capture #2");
|
||||||
|
}
|
||||||
|
static void ReportAllHistory()
|
||||||
|
{
|
||||||
|
var history = SafeCall(
|
||||||
|
() => api.ReportAllClientHistory("13351", "MORO"),
|
||||||
|
"ReportAllClientHistory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (history == null) return;
|
||||||
|
|
||||||
|
LogInfo($"History records: {history.Count}");
|
||||||
|
foreach (var h in history)
|
||||||
|
LogInfo($"{h.captDate:yyyy-MM-dd HH:mm:ss} , Sessions: {h.NoOfSessions}");
|
||||||
|
}
|
||||||
|
static void ReportFilteredHistory()
|
||||||
|
{
|
||||||
|
var from = DateTime.Today.AddDays(-7);
|
||||||
|
var to = DateTime.Today;
|
||||||
|
|
||||||
|
var history = SafeCall(
|
||||||
|
() => api.ReportClientHistory("13351", "MORO", from, to),
|
||||||
|
"ReportClientHistory"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (history != null)
|
||||||
|
LogInfo($"Filtered records: {history.Count}");
|
||||||
|
foreach (var h in history)
|
||||||
|
LogInfo($"{h.captDate:yyyy-MM-dd HH:mm:ss} , Sessions: {h.NoOfSessions}");
|
||||||
|
|
||||||
|
}
|
||||||
|
static void ListAllClients()
|
||||||
|
{
|
||||||
|
var clients = SafeCall(
|
||||||
|
() => api.ListAllClients(),
|
||||||
|
"ListAllClients"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (clients != null)
|
||||||
|
LogInfo($"Total clients: {clients.Count}");
|
||||||
|
foreach (var c in clients)
|
||||||
|
LogInfo($"cid: {c.cid}, srv: {c.srv}, addingDate: {c.addingDate}, lastCaptDate: {c.lastCaptDate}, NoOfCapt: {c.NoOfCapt}");
|
||||||
|
|
||||||
|
}
|
||||||
|
static T SafeCall<T>(Func<T> action, string stepName)
|
||||||
|
{
|
||||||
|
var sw = Stopwatch.StartNew();
|
||||||
|
LogStep(stepName);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = action();
|
||||||
|
sw.Stop();
|
||||||
|
LogSuccess($"{stepName} completed in {sw.ElapsedMilliseconds} ms");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (WebException wex)
|
||||||
|
{
|
||||||
|
sw.Stop();
|
||||||
|
LogError(stepName, "NETWORK / HTTP ERROR", wex);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
sw.Stop();
|
||||||
|
LogError(stepName, "APPLICATION ERROR", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LogHeader(string msg)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Cyan;
|
||||||
|
Console.WriteLine("\n======================================");
|
||||||
|
Console.WriteLine(msg);
|
||||||
|
Console.WriteLine("======================================\n");
|
||||||
|
Console.ResetColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LogStep(string msg)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||||
|
Console.WriteLine($"> {msg}");
|
||||||
|
Console.ResetColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LogSuccess(string msg)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
Console.WriteLine($"✔ {msg}\n");
|
||||||
|
Console.ResetColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LogInfo(string msg)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Gray;
|
||||||
|
Console.WriteLine($" {msg}");
|
||||||
|
Console.ResetColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LogError(string step, string type, Exception ex)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
Console.WriteLine($"✖ {step} FAILED [{type}]");
|
||||||
|
Console.WriteLine($" Message: {ex.Message}");
|
||||||
|
|
||||||
|
if (ex.InnerException != null)
|
||||||
|
Console.WriteLine($" Inner: {ex.InnerException.Message}");
|
||||||
|
|
||||||
|
Console.ResetColor();
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LogFatal(string msg, Exception ex)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.DarkRed;
|
||||||
|
Console.WriteLine("!!! FATAL ERROR !!!");
|
||||||
|
Console.WriteLine(msg);
|
||||||
|
|
||||||
|
if (ex != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
Console.WriteLine(ex.StackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.ResetColor();
|
||||||
|
}
|
||||||
|
}
|
||||||
33
SlReport/Properties/AssemblyInfo.cs
Normal file
33
SlReport/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("SlReport")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("SlReport")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2026")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("2fce8950-d2a2-4730-96dd-4db3eb1bd1fd")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
109
SlReport/SignLanguageReportApiClient.cs
Normal file
109
SlReport/SignLanguageReportApiClient.cs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
using MindRockets.WebTools.Client;
|
||||||
|
using MindRockets.WebTools.Contracts;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
|
||||||
|
public class SignLanguageReportApiClient : ModernAPIClient
|
||||||
|
{
|
||||||
|
public SignLanguageReportApiClient(string endPointHost)
|
||||||
|
: base(endPointHost)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid RegisterUser(string username, string pwd)
|
||||||
|
{
|
||||||
|
var data = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "username", username },
|
||||||
|
{ "pwd", pwd }
|
||||||
|
};
|
||||||
|
|
||||||
|
return PostAction<Guid>("slrep", "reguser", data.Secure(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RegisterClient(string cid, string srv)
|
||||||
|
{
|
||||||
|
var data = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "cid", cid },
|
||||||
|
{ "srv", srv }
|
||||||
|
};
|
||||||
|
|
||||||
|
return PostAction<bool>("slrep", "regclient", data.Secure(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MapUser(Guid userId, string cid, string srv)
|
||||||
|
{
|
||||||
|
var data = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "userid", userId.ToString() },
|
||||||
|
{ "cid", cid },
|
||||||
|
{ "srv", srv }
|
||||||
|
};
|
||||||
|
|
||||||
|
return PostAction<bool>("slrep", "mapuser", data.Secure(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Capture(string cid, string srv)
|
||||||
|
{
|
||||||
|
var data = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "cid", cid },
|
||||||
|
{ "srv", srv }
|
||||||
|
};
|
||||||
|
|
||||||
|
return PostAction<bool>("slrep", "capt", data.Secure(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ClientHistory> ReportAllClientHistory(string cid, string srv)
|
||||||
|
{
|
||||||
|
var data = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "cid", cid },
|
||||||
|
{ "srv", srv }
|
||||||
|
};
|
||||||
|
|
||||||
|
return PostAction<List<ClientHistory>>("slrep", "repallcid", data.Secure(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ClientHistory> ReportClientHistory(
|
||||||
|
string cid,
|
||||||
|
string srv,
|
||||||
|
DateTime from,
|
||||||
|
DateTime to)
|
||||||
|
{
|
||||||
|
var data = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "cid", cid },
|
||||||
|
{ "srv", srv },
|
||||||
|
{ "from", from },
|
||||||
|
{ "to", to }
|
||||||
|
};
|
||||||
|
|
||||||
|
return PostAction<List<ClientHistory>>("slrep", "repcid", data.Secure(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ClientInfo> ListAllClients()
|
||||||
|
{
|
||||||
|
return PostAction<List<ClientInfo>>("slrep", "listallclients", NoParams.Secure(), true);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class ClientInfo
|
||||||
|
{
|
||||||
|
public string cid { get; set; }
|
||||||
|
public string srv { get; set; }
|
||||||
|
public DateTime addingDate { get; set; }
|
||||||
|
public DateTime? lastCaptDate { get; set; }
|
||||||
|
public int NoOfCapt { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ClientHistory
|
||||||
|
{
|
||||||
|
public DateTime captDate { get; set; }
|
||||||
|
public int NoOfSessions { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
115
SlReport/SlReport.csproj
Normal file
115
SlReport/SlReport.csproj
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{2FCE8950-D2A2-4730-96DD-4DB3EB1BD1FD}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>SlReport</RootNamespace>
|
||||||
|
<AssemblyName>SlReport</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="MindRockets.WebTools, Version=1.5.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\MindRockets.WebTools.1.6.0\lib\net47\MindRockets.WebTools.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="MindRockets.WebTools.Client, Version=1.4.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\MindRockets.WebTools.Client.1.4.0\lib\net47\MindRockets.WebTools.Client.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="MindRockets.WebTools.Contracts, Version=1.3.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\MindRockets.WebTools.Contracts.1.3.0\lib\net47\MindRockets.WebTools.Contracts.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="MindRockets.WebTools.Json, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\MindRockets.WebTools.Json.1.0.0\lib\net47\MindRockets.WebTools.Json.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="MindRocketsInc.Helpers, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\MindRocketsInc.Helpers.1.5.2\lib\net45\MindRocketsInc.Helpers.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.ComponentModel.Composition" />
|
||||||
|
<Reference Include="System.Configuration" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.IO, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.IO.4.3.0\lib\net462\System.IO.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Net.Http, Version=4.1.1.3, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Security.Cryptography.Algorithms, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Web" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="SignLanguageReportApiClient.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="WebClient\modern-client.js" />
|
||||||
|
<Content Include="WebClient\modern-utils.js" />
|
||||||
|
<Content Include="WebClient\ModernAPIClient_Documentation.html" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
||||||
130
SlReport/WebClient/ModernAPIClient_Documentation.html
Normal file
130
SlReport/WebClient/ModernAPIClient_Documentation.html
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>ModernAPIClient Documentation</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body class="bg-light">
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h1 class="mb-4">ModernAPIClient Documentation</h1>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Overview</h2>
|
||||||
|
<p>The <code>ModernAPIClient</code> class is designed to simplify API interactions in a web environment. It supports making <code>GET</code> and <code>POST</code> requests, including handling file uploads and securely managing request parameters.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Initialization</h2>
|
||||||
|
<pre><code>const client = new ModernAPIClient('https://api.example.com');</code></pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Memory Optimization and Security</h2>
|
||||||
|
<p>When the <code>ModernAPIClient</code> is instantiated, it automatically decrypts and stores certain values (e.g., <code>MemOptimizeMethod</code> and <code>MemStackFrame</code>) that are used to secure API requests. These values are expected to be present as Base64-encoded hidden fields in the HTML page.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Methods</h2>
|
||||||
|
|
||||||
|
<h3>1. <code>postAction(controller, action, parameters, secure = false)</code></h3>
|
||||||
|
<p>Sends a <code>POST</code> request to a specific controller and action within the API.</p>
|
||||||
|
<p><strong>Parameters:</strong></p>
|
||||||
|
<ul>
|
||||||
|
<li><code>controller</code> (string): The controller name.</li>
|
||||||
|
<li><code>action</code> (string): The action name.</li>
|
||||||
|
<li><code>parameters</code> (object): An object containing key-value pairs to be sent as the POST body.</li>
|
||||||
|
<li><code>secure</code> (boolean): If <code>true</code>, the request will be secured with additional parameters.</li>
|
||||||
|
</ul>
|
||||||
|
<p><strong>Returns:</strong> A <code>Promise</code> that resolves with the response data.</p>
|
||||||
|
|
||||||
|
<h4>Example:</h4>
|
||||||
|
<pre><code>const parameters = { param1: 'value1' };
|
||||||
|
client.postAction('exampleController', 'exampleAction', parameters)
|
||||||
|
.then(response => console.log('POST Action Result:', response))
|
||||||
|
.catch(error => console.error('Error in POST Action:', error));</code></pre>
|
||||||
|
|
||||||
|
<h3>2. <code>postFileAction(controller, action, fileName, secure = false)</code></h3>
|
||||||
|
<p>Sends a <code>POST</code> request to upload a file to a specific controller and action within the API.</p>
|
||||||
|
<p><strong>Parameters:</strong></p>
|
||||||
|
<ul>
|
||||||
|
<li><code>controller</code> (string): The controller name.</li>
|
||||||
|
<li><code>action</code> (string): The action name.</li>
|
||||||
|
<li><code>fileName</code> (string): The file to be uploaded.</li>
|
||||||
|
<li><code>secure</code> (boolean): If <code>true</code>, the request will be secured with additional parameters.</li>
|
||||||
|
</ul>
|
||||||
|
<p><strong>Returns:</strong> A <code>Promise</code> that resolves with the response data.</p>
|
||||||
|
|
||||||
|
<h4>Example:</h4>
|
||||||
|
<pre><code>const fileInput = document.getElementById('fileInput');
|
||||||
|
const file = fileInput.files[0];
|
||||||
|
client.postFileAction('uploadController', 'uploadAction', file)
|
||||||
|
.then(response => console.log('File Upload Result:', response))
|
||||||
|
.catch(error => console.error('Error in File Upload:', error));</code></pre>
|
||||||
|
|
||||||
|
<h3>3. <code>getAction(controller, action, parameters, secure = false)</code></h3>
|
||||||
|
<p>Sends a <code>GET</code> request to a specific controller and action within the API.</p>
|
||||||
|
<p><strong>Parameters:</strong></p>
|
||||||
|
<ul>
|
||||||
|
<li><code>controller</code> (string): The controller name.</li>
|
||||||
|
<li><code>action</code> (string): The action name.</li>
|
||||||
|
<li><code>parameters</code> (object): An object containing key-value pairs to be sent as query string parameters.</li>
|
||||||
|
<li><code>secure</code> (boolean): If <code>true</code>, the request will be secured with additional parameters.</li>
|
||||||
|
</ul>
|
||||||
|
<p><strong>Returns:</strong> A <code>Promise</code> that resolves with the response data.</p>
|
||||||
|
|
||||||
|
<h4>Example:</h4>
|
||||||
|
<pre><code>const parameters = { param1: 'value1' };
|
||||||
|
client.getAction('exampleController', 'exampleAction', parameters)
|
||||||
|
.then(response => console.log('GET Action Result:', response))
|
||||||
|
.catch(error => console.error('Error in GET Action:', error));</code></pre>
|
||||||
|
|
||||||
|
<h3>4. <code>getStatic(staticRoute, parameters, secure = false)</code></h3>
|
||||||
|
<p>Sends a <code>GET</code> request to a specific static route within the API.</p>
|
||||||
|
<p><strong>Parameters:</strong></p>
|
||||||
|
<ul>
|
||||||
|
<li><code>staticRoute</code> (string): The static route.</li>
|
||||||
|
<li><code>parameters</code> (object): An object containing key-value pairs to be sent as query string parameters.</li>
|
||||||
|
<li><code>secure</code> (boolean): If <code>true</code>, the request will be secured with additional parameters.</li>
|
||||||
|
</ul>
|
||||||
|
<p><strong>Returns:</strong> A <code>Promise</code> that resolves with the response data.</p>
|
||||||
|
|
||||||
|
<h4>Example:</h4>
|
||||||
|
<pre><code>const parameters = { param1: 'value1' };
|
||||||
|
client.getStatic('/staticRoute', parameters)
|
||||||
|
.then(response => console.log('GET Static Result:', response))
|
||||||
|
.catch(error => console.error('Error in GET Static:', error));</code></pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Secure Requests</h2>
|
||||||
|
<p>For secure API interactions, set the <code>secure</code> parameter to <code>true</code> in any of the methods. This will add additional parameters, such as a timestamp and values from decrypted memory, to the request.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Example Workflow</h2>
|
||||||
|
<pre><code>// Initialize the client with the base API URL
|
||||||
|
const client = new ModernAPIClient('https://api.example.com');
|
||||||
|
|
||||||
|
// Perform a secure POST request
|
||||||
|
const postParams = { param1: 'value1', param2: 'value2' };
|
||||||
|
client.postAction('myController', 'myAction', postParams, true)
|
||||||
|
.then(response => console.log('POST Response:', response))
|
||||||
|
.catch(error => console.error('POST Error:', error));
|
||||||
|
|
||||||
|
// Perform a secure GET request
|
||||||
|
const getParams = { param1: 'value1' };
|
||||||
|
client.getAction('myController', 'myGetAction', getParams, true)
|
||||||
|
.then(response => console.log('GET Response:', response))
|
||||||
|
.catch(error => console.error('GET Error:', error));</code></pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Conclusion</h2>
|
||||||
|
<p>The <code>ModernAPIClient</code> class is a powerful tool for interacting with RESTful APIs in a web environment. It offers flexibility with its secure request options and supports a variety of request types, including file uploads. By following the examples provided, you can easily integrate this class into your web applications.</p>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
150
SlReport/WebClient/modern-client.js
Normal file
150
SlReport/WebClient/modern-client.js
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
class ModernAPIClient {
|
||||||
|
constructor(endpointHost) {
|
||||||
|
this._endpointHost = verifyUrlNotEndingWithSlash(endpointHost);
|
||||||
|
this.MemOptimizeMethod = '';
|
||||||
|
this.MemStackFrame = '';
|
||||||
|
|
||||||
|
this.initializeMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeMemory() {
|
||||||
|
optimizeMemory();
|
||||||
|
this.MemOptimizeMethod = MemOptimizeMethod;
|
||||||
|
this.MemStackFrame = MemStackFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
secureRequest(parameters) {
|
||||||
|
if (this.MemOptimizeMethod && this.MemStackFrame) {
|
||||||
|
parameters[this.MemOptimizeMethod] = this.MemStackFrame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async postFileActionResponse(controller, action, fileName, secure = false) {
|
||||||
|
return this.postFileStaticResponse(`/api/${controller}/${action}`, fileName, secure);
|
||||||
|
}
|
||||||
|
|
||||||
|
async postFileAction(controller, action, fileName, secure = false) {
|
||||||
|
const response = await this.postFileStaticResponse(`/api/${controller}/${action}`, fileName, secure);
|
||||||
|
if (response.Results === "OK") {
|
||||||
|
return response.Data;
|
||||||
|
} else {
|
||||||
|
throw new Error(response.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async postFileStaticResponse(staticRoute, fileName, secure = false) {
|
||||||
|
staticRoute = verifyStartingRouteWithSlash(staticRoute);
|
||||||
|
let requestURL = `${this._endpointHost}${staticRoute}`;
|
||||||
|
|
||||||
|
if (secure) {
|
||||||
|
const securityDictionary = {};
|
||||||
|
this.secureRequest(securityDictionary);
|
||||||
|
const params = new URLSearchParams(securityDictionary).toString();
|
||||||
|
requestURL += requestURL.includes('?') ? `&${params}` : `?${params}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', fileName);
|
||||||
|
|
||||||
|
const response = await fetch(requestURL, {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
|
||||||
|
return await parseActionResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
async postFileStatic(staticRoute, fileName, secure = false) {
|
||||||
|
const response = await this.postFileStaticResponse(staticRoute, fileName, secure);
|
||||||
|
if (response.Results === "OK") {
|
||||||
|
return response.Data;
|
||||||
|
} else {
|
||||||
|
throw new Error(response.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async postStaticResponse(staticRoute, parameters, secure = false) {
|
||||||
|
parameters = removeUndefinedValues(parameters);
|
||||||
|
staticRoute = verifyStartingRouteWithSlash(staticRoute);
|
||||||
|
let requestURL = `${this._endpointHost}${staticRoute}`;
|
||||||
|
|
||||||
|
if (secure) {
|
||||||
|
this.secureRequest(parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(requestURL, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
body: new URLSearchParams(parameters).toString()
|
||||||
|
});
|
||||||
|
|
||||||
|
return await parseActionResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
async postStatic(staticRoute, parameters, secure = false) {
|
||||||
|
const response = await this.postStaticResponse(staticRoute, parameters, secure);
|
||||||
|
if (response.Results === "OK") {
|
||||||
|
return response.Data;
|
||||||
|
} else {
|
||||||
|
throw new Error(response.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async postActionResponse(controller, action, parameters, secure = false) {
|
||||||
|
return this.postStaticResponse(`/api/${controller}/${action}`, parameters, secure);
|
||||||
|
}
|
||||||
|
|
||||||
|
async postAction(controller, action, parameters, secure = false) {
|
||||||
|
const response = await this.postActionResponse(controller, action, parameters, secure);
|
||||||
|
if (response.Results === "OK") {
|
||||||
|
return response.Data;
|
||||||
|
} else {
|
||||||
|
throw new Error(response.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStaticResponse(staticRoute, parameters, secure = false) {
|
||||||
|
staticRoute = verifyStartingRouteWithSlash(staticRoute);
|
||||||
|
let requestURL = `${this._endpointHost}${staticRoute}`;
|
||||||
|
|
||||||
|
parameters = removeUndefinedValues(parameters);
|
||||||
|
if (parameters && Object.keys(parameters).length > 0) {
|
||||||
|
if (secure) {
|
||||||
|
this.secureRequest(parameters);
|
||||||
|
}
|
||||||
|
const params = new URLSearchParams(parameters).toString();
|
||||||
|
requestURL += requestURL.includes('?') ? `&${params}` : `?${params}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(requestURL);
|
||||||
|
return await parseActionResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStatic(staticRoute, parameters, secure = false) {
|
||||||
|
const response = await this.getStaticResponse(staticRoute, parameters, secure);
|
||||||
|
if (response.Results === "OK") {
|
||||||
|
return response.Data;
|
||||||
|
} else {
|
||||||
|
throw new Error(response.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAction(controller, action, parameters, secure = false) {
|
||||||
|
const response = await this.getActionResponse(controller, action, parameters, secure);
|
||||||
|
if (response.Results === "OK") {
|
||||||
|
return response.Data;
|
||||||
|
} else {
|
||||||
|
throw new Error(response.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getActionResponse(controller, action, parameters, secure = false) {
|
||||||
|
return this.getStaticResponse(`/api/${controller}/${action}`, parameters, secure);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose() {
|
||||||
|
// Cleanup tasks if any
|
||||||
|
}
|
||||||
|
}
|
||||||
67
SlReport/WebClient/modern-utils.js
Normal file
67
SlReport/WebClient/modern-utils.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// modern-utils.js
|
||||||
|
// modern-utils.js
|
||||||
|
|
||||||
|
// Variables to store the decrypted values
|
||||||
|
let MemOptimizeMethod = '';
|
||||||
|
let MemStackFrame = '';
|
||||||
|
|
||||||
|
// Function to simulate decryption (you'll replace this with your actual decryption logic)
|
||||||
|
function decryptBase64(encodedString) {
|
||||||
|
try {
|
||||||
|
return atob(encodedString); // Base64 decode
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Decryption failed', e);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to extract and decrypt values from hidden fields
|
||||||
|
function optimizeMemory() {
|
||||||
|
const methodField = document.getElementById('MemOptimizeMethod');
|
||||||
|
const frameField = document.getElementById('MemStackFrame');
|
||||||
|
|
||||||
|
if (methodField && frameField) {
|
||||||
|
MemOptimizeMethod = decryptBase64(methodField.value);
|
||||||
|
MemStackFrame = decryptBase64(frameField.value);
|
||||||
|
} else {
|
||||||
|
console.error('Hidden fields for MemOptimizeMethod and MemStackFrame not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach variables and functions to the window object so they are globally available
|
||||||
|
window.MemOptimizeMethod = MemOptimizeMethod;
|
||||||
|
window.MemStackFrame = MemStackFrame;
|
||||||
|
window.optimizeMemory = optimizeMemory;
|
||||||
|
|
||||||
|
function verifyUrlNotEndingWithSlash(url) {
|
||||||
|
return url.endsWith('/') ? url.slice(0, -1) : url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function verifyStartingRouteWithSlash(route) {
|
||||||
|
return route.startsWith('/') ? route : `/${route}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async function parseActionResponse(response) {
|
||||||
|
const contentType = response.headers.get('Content-Type');
|
||||||
|
|
||||||
|
if (contentType && contentType.includes('application/json')) {
|
||||||
|
return await response.json();
|
||||||
|
} else {
|
||||||
|
return await response.text();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function removeUndefinedValues(obj) {
|
||||||
|
for (const key in obj) {
|
||||||
|
if (obj[key] === undefined) {
|
||||||
|
delete obj[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
window.removeUndefinedValues = removeUndefinedValues;
|
||||||
|
// Attach functions to the window object so they are globally available
|
||||||
|
window.verifyUrlNotEndingWithSlash = verifyUrlNotEndingWithSlash;
|
||||||
|
window.verifyStartingRouteWithSlash = verifyStartingRouteWithSlash;
|
||||||
|
window.parseActionResponse = parseActionResponse;
|
||||||
16
SlReport/packages.config
Normal file
16
SlReport/packages.config
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="MindRockets.WebTools" version="1.6.0" targetFramework="net48" />
|
||||||
|
<package id="MindRockets.WebTools.Client" version="1.4.0" targetFramework="net48" />
|
||||||
|
<package id="MindRockets.WebTools.Contracts" version="1.3.0" targetFramework="net48" />
|
||||||
|
<package id="MindRockets.WebTools.Json" version="1.0.0" targetFramework="net48" />
|
||||||
|
<package id="MindRocketsInc.Helpers" version="1.5.2" targetFramework="net48" />
|
||||||
|
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net48" />
|
||||||
|
<package id="System.IO" version="4.3.0" targetFramework="net48" />
|
||||||
|
<package id="System.Net.Http" version="4.3.4" targetFramework="net48" />
|
||||||
|
<package id="System.Runtime" version="4.3.0" targetFramework="net48" />
|
||||||
|
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net48" />
|
||||||
|
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net48" />
|
||||||
|
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net48" />
|
||||||
|
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net48" />
|
||||||
|
</packages>
|
||||||
Loading…
x
Reference in New Issue
Block a user