Saxonite 1.2.11.4. BusinessMgr.

This commit is contained in:
Andy Howard
2024-06-04 16:14:45 +01:00
parent 7748941680
commit ba5801b4dc
33 changed files with 595 additions and 219 deletions
+16 -12
View File
@@ -5,16 +5,20 @@
### Modules ### Modules
* NB All projects upgraded to .Net 6, 28Nov23. * NB All projects upgraded to .Net 6, 28Nov23.
* SACS Standard Base * **SACS Base**
* Base class library. .Net Standard 2.1. C#. * C# Base class library, .Net6 (was .Net Standard 2.1).
* SACS Standard Dbas * **SACS Dbas**
* Base database interface library. .Net Standard 2.1. C#. * C# Base database interface library, .Net6 (was .Net Standard 2.1).
* SACS Standard Accounts * **SACS Proc**
* Base Acounts system interface library. .Net Standard 2.1. C#. * C# Base processes library, .Net6.
* SACS Standard Mob * **SACS Maui**
* Base Mobile application library. .Net Standard 2.1. C#. * C# Maui Mobile library, .Net6 (added Apr24).
* SACS Core Web * **SACS Xamarin** (Apr24 SACS Standard Mob)
* Base Web application library. [C# .Net 6] * C# Xamarin Mobile library, .Net6 (was .Net Standard 2.1).
* SACS Core Unit Tests * **SACS Web**
* Unit Tests. [C# .Net 6] * C# Base Web library, .Net 6.
* **SACS Accounts**
* C# Base Accounts system interface library, .Net6 (was .Net Standard 2.1).
* **SACS Unit Tests**
* C# Unit Tests, .Net 6.
@@ -19,6 +19,7 @@
<ProjectReference Include="..\SacsStandardAccounts\SacsStandardAccounts.csproj" /> <ProjectReference Include="..\SacsStandardAccounts\SacsStandardAccounts.csproj" />
<ProjectReference Include="..\SacsStandardBase\SacsStandardBase.csproj" /> <ProjectReference Include="..\SacsStandardBase\SacsStandardBase.csproj" />
<ProjectReference Include="..\SacsStandardDbas\SacsStandardDbas.csproj" /> <ProjectReference Include="..\SacsStandardDbas\SacsStandardDbas.csproj" />
<ProjectReference Include="..\SacsStandardProc\SacsStandardProc.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -1,4 +1,5 @@
using System; using System;
using System.Text.RegularExpressions;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sarand.Net.Standard.Base.Utils; using Sarand.Net.Standard.Base.Utils;
@@ -43,6 +44,61 @@ namespace Sarand.UnitTests.Core.Base.Utils
Assert.AreEqual(false, "Abc".IsBlank()); Assert.AreEqual(false, "Abc".IsBlank());
} }
//-------------------------------------------------------------------
// Regular Expression Matching.
//-------------------------------------------------------------------
[TestMethod]
public void StringUtil_Match()
{
// Match.
Assert.AreEqual(true, "ABCDEF".Match("CDE"));
Assert.AreEqual(true, "ABCDEF".MatchCI("cDe"));
Assert.AreEqual(true, "ABCDEF".Match("CDE", System.Text.RegularExpressions.RegexOptions.None));
Assert.AreEqual(true, "ABCDEF".Match(new Regex("CDE", System.Text.RegularExpressions.RegexOptions.None)));
Assert.AreEqual(true, "ABCDEF".Match(new Regex("cDe", System.Text.RegularExpressions.RegexOptions.IgnoreCase)));
// Match with escaped content.
Assert.AreEqual(true, "ABC\\sDEF".Match("\\\\s"));
Assert.AreEqual(true, "AB(CD)EF".Match("(..)"));
Assert.AreEqual(true, "AB(CD)EF".Match("\\(CD\\)"));
// Not match.
Assert.AreEqual(false, "ABCDEF".Match("cDe"));
Assert.AreEqual(false, "ABCDEF".MatchCI("eFg"));
Assert.AreEqual(false, "ABCDEF".Match("cDe", System.Text.RegularExpressions.RegexOptions.None));
Assert.AreEqual(false, "ABCDEF".Match(new Regex("cDe", System.Text.RegularExpressions.RegexOptions.None)));
}
[TestMethod]
public void StringUtil_IsMatch()
{
// IsMatch.
Assert.AreEqual(true, "ABCDEF".IsMatch("CDE"));
Assert.AreEqual(true, "ABCDEF".IsMatchCI("cDe"));
Assert.AreEqual(true, "ABCDEF".IsMatch("CDE", System.Text.RegularExpressions.RegexOptions.None));
Assert.AreEqual(true, "ABCDEF".IsMatch(new Regex("CDE", System.Text.RegularExpressions.RegexOptions.None)));
Assert.AreEqual(true, "ABCDEF".IsMatch(new Regex("cDe", System.Text.RegularExpressions.RegexOptions.IgnoreCase)));
// IsMatch with escaped content.
Assert.AreEqual(true, "ABC\\sDEF".IsMatch("\\\\s"));
Assert.AreEqual(true, "AB(CD)EF".IsMatch("(..)"));
Assert.AreEqual(true, "AB(CD)EF".IsMatch("\\(CD\\)"));
// Not match.
Assert.AreEqual(false, "ABCDEF".IsMatch("cDe"));
Assert.AreEqual(false, "ABCDEF".IsMatchCI("eFg"));
Assert.AreEqual(false, "ABCDEF".IsMatch("cDe", System.Text.RegularExpressions.RegexOptions.None));
Assert.AreEqual(false, "ABCDEF".IsMatch(new Regex("cDe", System.Text.RegularExpressions.RegexOptions.None)));
}
[TestMethod]
public void StringUtil_MatchCount()
{
// Match.
Assert.AreEqual(1, "ABCDEF".MatchCount(new Regex("CDE")));
Assert.AreEqual(2, "ABCDEFGHICDEJKL".MatchCount(new Regex("CDE")));
}
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Padding. // Padding.
//------------------------------------------------------------------- //-------------------------------------------------------------------
@@ -0,0 +1,42 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sarand.Net.Standard.Proc.Excel;
using System;
namespace Sacs.UnitTests.Net.Standard.Proc.Excel
{
[TestClass]
public class SaMsSpreadsheet_Tester
{
//-------------------------------------------------------------------
// Data members.
private Random random = new Random();
//-------------------------------------------------------------------
// GetPosForColId.
//-------------------------------------------------------------------
[TestMethod]
public void GetPosForColId_IsEmpty()
{
Assert.AreEqual(1, SaMsSpreadsheet.GetPosForColId("A"));
Assert.AreEqual(1, SaMsSpreadsheet.GetPosForColId("a"));
Assert.AreEqual(2, SaMsSpreadsheet.GetPosForColId("B"));
Assert.AreEqual(3, SaMsSpreadsheet.GetPosForColId("C"));
Assert.AreEqual(24, SaMsSpreadsheet.GetPosForColId("X"));
Assert.AreEqual(25, SaMsSpreadsheet.GetPosForColId("Y"));
Assert.AreEqual(26, SaMsSpreadsheet.GetPosForColId("Z"));
Assert.AreEqual(27, SaMsSpreadsheet.GetPosForColId("AA"));
Assert.AreEqual(28, SaMsSpreadsheet.GetPosForColId("AB"));
Assert.AreEqual(29, SaMsSpreadsheet.GetPosForColId("AC"));
Assert.AreEqual(128, SaMsSpreadsheet.GetPosForColId("DX"));
Assert.AreEqual(155, SaMsSpreadsheet.GetPosForColId("EY"));
Assert.AreEqual(182, SaMsSpreadsheet.GetPosForColId("FZ"));
// Invalid.
Assert.AreEqual(0, SaMsSpreadsheet.GetPosForColId(""));
Assert.AreEqual(0, SaMsSpreadsheet.GetPosForColId("1"));
Assert.AreEqual(0, SaMsSpreadsheet.GetPosForColId("A1"));
}
//-------------------------------------------------------------------
}
}
+6 -5
View File
@@ -141,7 +141,7 @@ namespace Sacs.Web.Components
//if (SacsSystem.DebugMode) SaLogger.Debug(SysUtil.Fn + "\n\tData: " + queryString + " \n\tEncrypted: " + encrypted); //if (SacsSystem.DebugMode) SaLogger.Debug(SysUtil.Fn + "\n\tData: " + queryString + " \n\tEncrypted: " + encrypted);
return encrypted; return encrypted;
} }
catch (Exception exc) { SaLogger.Warn(SysUtil.Fn + " " + ExceptionUtil.GetErrorStateMessage(exc)); } catch (Exception exc) { SaLogger.Warn($"{SysUtil.Fn} {ExceptionUtil.GetErrorStateMessage(exc)}"); }
return ""; return "";
} }
public static NameValueCollection DecryptParameters(String encrypted, String base64IV, String base64Key) public static NameValueCollection DecryptParameters(String encrypted, String base64IV, String base64Key)
@@ -253,10 +253,11 @@ namespace Sacs.Web.Components
public class ItemData_Base public class ItemData_Base
{ {
// Common item properties. // Common item properties.
public String Id { get; set; } public String Id { get; set; } = null;
public String Notes { get; set; } private String notes;
public String StatusCode { get; set; } public String Notes { get { return StringUtil.OnBlank(notes, null); } set { notes = StringUtil.EmptyOnNull(value).Trim(); } }
public String StatusDesc { get; set; } public String StatusCode { get; set; } = null;
public String StatusDesc { get; set; } = null;
// Flags for common status values. // Flags for common status values.
// Return true or null so that property is not serialised when false. // Return true or null so that property is not serialised when false.
public bool? Awaiting { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Awaiting)) ? true : (bool?)null; } } public bool? Awaiting { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Awaiting)) ? true : (bool?)null; } }
+1 -1
View File
@@ -6,7 +6,7 @@ namespace Sarand.Net.Standard.Base.Core
public abstract class SacsDisposable : IDisposable public abstract class SacsDisposable : IDisposable
{ {
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Data memebrs. // Data members.
private bool disposed = false; private bool disposed = false;
//------------------------------------------------------------------- //-------------------------------------------------------------------
+2 -2
View File
@@ -626,7 +626,7 @@ namespace Sarand.Net.Standard.Base.Dbas
{ {
if (bit > 0 && bit <= 32) if (bit > 0 && bit <= 32)
{ {
// The operation depands on whether the value should be matched or not. // The operation depends on whether the value should be matched or not.
String condition = (match? "<>" : "="); String condition = (match? "<>" : "=");
// Test is achieved by shifting the value so as to drop the target bit, shift back one bit // Test is achieved by shifting the value so as to drop the target bit, shift back one bit
// and identify those value that then do not match the original value shifted by one place less. // and identify those value that then do not match the original value shifted by one place less.
@@ -727,7 +727,7 @@ namespace Sarand.Net.Standard.Base.Dbas
{ {
// Must have an 'Order By' clause to use 'Offset ... Fetch Next ...' // Must have an 'Order By' clause to use 'Offset ... Fetch Next ...'
if (orderByData.IsEmpty()) if (orderByData.IsEmpty())
throw new NotSupportedException("Query paging requires sort ofrder to be specified"); throw new NotSupportedException("Query paging requires sort order to be specified");
if (DbGlobalDbms.Type != DbmsType.MsSql) if (DbGlobalDbms.Type != DbmsType.MsSql)
throw new NotSupportedException("Query paging only supported for MS SQL"); throw new NotSupportedException("Query paging only supported for MS SQL");
query += " OFFSET " + ((paging.PageNo - 1) * paging.PageLength) + " ROWS FETCH NEXT " + paging.PageLength + " ROWS ONLY"; query += " OFFSET " + ((paging.PageNo - 1) * paging.PageLength) + " ROWS FETCH NEXT " + paging.PageLength + " ROWS ONLY";
@@ -1,5 +1,7 @@
using Sarand.Net.Standard.Base.App; using Microsoft.Net.Http.Headers;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Net;
using Sarand.Net.Standard.Base.Tasks; using Sarand.Net.Standard.Base.Tasks;
using Sarand.Net.Standard.Base.Utils; using Sarand.Net.Standard.Base.Utils;
using System; using System;
@@ -29,7 +31,7 @@ namespace Sarand.Net.Standard.Base.Helpers
/// Request timeout. Default: 5 secs. /// Request timeout. Default: 5 secs.
/// <para>NB Not currently supported as can only be changed when static HTTP Client not in use.</para> /// <para>NB Not currently supported as can only be changed when static HTTP Client not in use.</para>
/// </summary> /// </summary>
public int TimeoutSecs { get; set; } = RequestTimeoutSecs_Default; public int TimeoutSecs { get; set; } = SacsHttpClient.RequestTimeoutSecs_Default;
/// <summary> /// <summary>
/// Headers to send with request. /// Headers to send with request.
/// <para>Accept, Accept-Charset, Accept-Encoding, Accept-Language, User-Agent, Transfer-Encoding, Pragma, Expect etc.</para> /// <para>Accept, Accept-Charset, Accept-Encoding, Accept-Language, User-Agent, Transfer-Encoding, Pragma, Expect etc.</para>
@@ -57,55 +59,28 @@ namespace Sarand.Net.Standard.Base.Helpers
//------------------------------------------------------------------- //-------------------------------------------------------------------
/// <summary>Response data</summary> /// <summary>Response data</summary>
public class ResponseData public class ResponseData : SacsHttpResponseData
{ {
public DateTime RequestStarted { get; set; }
public DateTime RequestCompleted { get; set; }
/// <summary>Response headers.</summary>
public Dictionary<String, IEnumerable<String>> ResponseHeaders { get; } = new Dictionary<String, IEnumerable<String>>();
/// <summary>Response content headers.</summary>
public Dictionary<String, IEnumerable<String>> ContentHeaders { get; } = new Dictionary<String, IEnumerable<String>>();
/// <summary>Indicates whether Status Code represents success.</summary>
public bool Success { get; set; }
/// <summary>HTTP Status Code.</summary>
public HttpStatusCode StatusCode { get; set; }
/// <summary>HTTP message version. Default: 1.1</summary>
public Version Version { get; set; }
/// <summary>HTTP Reason Code.</summary>
public String ReasonPhrase { get; set; } = "";
/// <summary>Response data.</summary>
public String Data { get; set; } = "";
/// <summary>Elapsed time for request.</summary>
public TimeSpan Elapsed { get; set; }
/// <summary>Exception thrown during handling of request.</summary>
public Exception Exception { get; set; }
/// <summary>Error state message - generally exception type and message.</summary>
public String ErrorStateMessage { get; set; }
} }
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Data members. // Data members.
private static readonly HttpClient httpClient;
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Static initialisation. // Static initialisation.
static SacsHttpClientHelper () static SacsHttpClientHelper()
{ {
// Configure client.
httpClient = new HttpClient();
httpClient.Timeout = new TimeSpan(0, 0, RequestTimeoutSecs_Default);
} }
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Properties. // Properties.
public static HttpClient HttpClient { get { return httpClient; } } public static HttpClient HttpClient { get { return SacsHttpClient.HttpClient; } }
public static int RequestTimeoutSecs_Default { get; } = 5; public static int RequestTimeoutSecs_Default { get { return SacsHttpClient.RequestTimeoutSecs_Default; } }
public static String HeaderName_ContentType { get; } = "Content-Type"; public static String HeaderName_ContentType { get {; return SacsHttpClient.HeaderName_ContentType; } }
//------------------------------------------------------------------- //-------------------------------------------------------------------
public static async Task<ResponseData> DoRequest (RequestData requestData) public static async Task<ResponseData> DoRequest(RequestData requestData)
{ {
String fn = "SacsHttpClientHelper.DoRequest";
requestData.ThrowIfCancellationRequested(); requestData.ThrowIfCancellationRequested();
ResponseData responseData = new ResponseData(); ResponseData responseData = new ResponseData();
@@ -114,14 +89,14 @@ namespace Sarand.Net.Standard.Base.Helpers
if (requestData.FormData.Count > 0) if (requestData.FormData.Count > 0)
{ {
postContent = new FormUrlEncodedContent(requestData.FormData); postContent = new FormUrlEncodedContent(requestData.FormData);
if (!requestData.ContentHeaders.ContainsKey(HeaderName_ContentType)) if (!requestData.ContentHeaders.ContainsKey(SacsHttpClient.HeaderName_ContentType))
requestData.ContentHeaders.Add(HeaderName_ContentType, "application/x-www-form-urlencoded; charset=utf-8"); requestData.ContentHeaders.Add(SacsHttpClient.HeaderName_ContentType, "application/x-www-form-urlencoded; charset=utf-8");
} }
else if (!StringUtil.IsEmpty(requestData.PostData) || requestData.ForcePost) else if (!StringUtil.IsEmpty(requestData.PostData) || requestData.ForcePost)
{ {
postContent = new StringContent(StringUtil.EmptyOnNull(requestData.PostData), Encoding.UTF8); postContent = new StringContent(StringUtil.EmptyOnNull(requestData.PostData), Encoding.UTF8);
if (!requestData.ContentHeaders.ContainsKey(HeaderName_ContentType)) if (!requestData.ContentHeaders.ContainsKey(SacsHttpClient.HeaderName_ContentType))
requestData.ContentHeaders.Add(HeaderName_ContentType, "text/plain; charset=utf-8"); requestData.ContentHeaders.Add(SacsHttpClient.HeaderName_ContentType, "text/plain; charset=utf-8");
} }
requestData.ThrowIfCancellationRequested(); requestData.ThrowIfCancellationRequested();
@@ -143,7 +118,7 @@ namespace Sarand.Net.Standard.Base.Helpers
} }
// Default request headers. // Default request headers.
if (HttpClient.DefaultRequestHeaders.Accept.Count == 0 && request.Headers.Accept.Count == 0) if (SacsHttpClient.HttpClient.DefaultRequestHeaders.Accept.Count == 0 && request.Headers.Accept.Count == 0)
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/*")); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/*"));
// Configure request. // Configure request.
@@ -163,7 +138,7 @@ namespace Sarand.Net.Standard.Base.Helpers
} }
// Send request. // Send request.
responseData.RequestStarted = DateTime.Now; responseData.RequestStarted = DateTime.Now;
response = await HttpClient.SendAsync(request, requestData.CancellationToken); response = await SacsHttpClient.HttpClient.SendAsync(request, requestData.CancellationToken);
responseData.RequestCompleted = DateTime.Now; responseData.RequestCompleted = DateTime.Now;
} }
else else
@@ -171,7 +146,7 @@ namespace Sarand.Net.Standard.Base.Helpers
// GET. // GET.
request.Method = HttpMethod.Get; request.Method = HttpMethod.Get;
responseData.RequestStarted = DateTime.Now; responseData.RequestStarted = DateTime.Now;
response = await HttpClient.SendAsync(request, requestData.CancellationToken); response = await SacsHttpClient.HttpClient.SendAsync(request, requestData.CancellationToken);
responseData.RequestCompleted = DateTime.Now; responseData.RequestCompleted = DateTime.Now;
} }
@@ -205,7 +180,7 @@ namespace Sarand.Net.Standard.Base.Helpers
exc = exc.InnerException; exc = exc.InnerException;
} }
String msg = exc.GetType().Name + ": " + exc.Message; String msg = exc.GetType().Name + ": " + exc.Message;
SaLogger.Warn(fn + " " + msg + ExceptionUtil.GetStackEntries(exc, 6).Concat("", "\n\t")); SaLogger.Warn(SysUtil.Fn + " " + msg + ExceptionUtil.GetStackEntries(exc, 6).Concat("", "\n\t"));
responseData.ErrorStateMessage = msg; responseData.ErrorStateMessage = msg;
} }
requestData.ThrowIfCancellationRequested(); requestData.ThrowIfCancellationRequested();
@@ -218,33 +193,9 @@ namespace Sarand.Net.Standard.Base.Helpers
//------------------------------------------------------------------- //-------------------------------------------------------------------
// R e s p o n s e S t a t u s D e s c r i p t i o n // R e s p o n s e S t a t u s D e s c r i p t i o n
//------------------------------------------------------------------- //-------------------------------------------------------------------
public static String GetResponseStatusDescription (HttpStatusCode httpStatus) public static String GetResponseStatusDescription(HttpStatusCode httpStatus)
{ {
// Ref. https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml return SacsHttpClient.GetResponseStatusDescription(httpStatus);
switch (httpStatus)
{
// 1xx: Informational - Request received, continuing process.
case HttpStatusCode.Continue: return "Continue";
// 2xx: Success - The action was successfully received, understood, and accepted.
case HttpStatusCode.OK: return "OK";
case HttpStatusCode.Created: return "Created";
case HttpStatusCode.Accepted: return "Accepted";
// 3xx: Redirection - Further action must be taken in order to complete the request.
case HttpStatusCode.MultipleChoices: return "Multiple choices";
case HttpStatusCode.MovedPermanently: return "Moved permanently";
case HttpStatusCode.Found: return "Found";
// 4xx: Client Error -The request contains bad syntax or cannot be fulfilled.
case HttpStatusCode.BadRequest: return "Bad request";
case HttpStatusCode.Unauthorized: return "Unauthorized";
case HttpStatusCode.PaymentRequired: return "Payment required";
case HttpStatusCode.Forbidden: return "Forbidden";
case HttpStatusCode.NotFound: return "Not found";
case HttpStatusCode.MethodNotAllowed: return "Method not allowed";
case HttpStatusCode.NotAcceptable: return "Not acceptable";
// 5xx: Server Error -The server failed to fulfill an apparently valid request.
case HttpStatusCode.InternalServerError: return "Internal server error";
}
return httpStatus.ToString();
} }
//------------------------------------------------------------------- //-------------------------------------------------------------------
@@ -15,6 +15,7 @@ namespace Sarand.Net.Standard.Base.Helpers
private static Random random; private static Random random;
public static Random Random { get { if (random == null) random = new Random(GetInt32(Int32.MaxValue)); return random; } } public static Random Random { get { if (random == null) random = new Random(GetInt32(Int32.MaxValue)); return random; } }
//-------------------------------------------------------------------
public static void Fill(byte[] byteArray) public static void Fill(byte[] byteArray)
{ {
RandomNumberGenerator.Fill(byteArray); RandomNumberGenerator.Fill(byteArray);
+130 -18
View File
@@ -1,23 +1,31 @@
using Sarand.Net.Standard.Base.App; using Microsoft.AspNetCore.Http;
using Microsoft.Net.Http.Headers;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.Tasks; using Sarand.Net.Standard.Base.Tasks;
using Sarand.Net.Standard.Base.Utils; using Sarand.Net.Standard.Base.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Reflection.Metadata;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using ZstdNet;
namespace Sarand.Net.Standard.Base.Net namespace Sarand.Net.Standard.Base.Net
{ {
//======================================================================= //=======================================================================
public class SacsHttpRequestData : SacsTaskData public class SacsHttpRequestData : SacsTaskData
{ {
public SacsHttpRequestData (CancellationToken? cancellationToken) : base(cancellationToken) { } public SacsHttpRequestData(CancellationToken? cancellationToken) : base(cancellationToken) { }
/// <summary>URL to send request to.</summary> /// <summary>URL to send request to.</summary>
public String Url { get; set; } public String Url { get; set; }
/// <summary> /// <summary>
@@ -50,6 +58,21 @@ namespace Sarand.Net.Standard.Base.Net
public bool ForcePost { get; set; } public bool ForcePost { get; set; }
} }
//=======================================================================
public class SacsHttpCookieData
{
public String HeaderValue { get; set; }
public String Name { get; set; }
public String Value { get; set; }
public DateTime Expires { get; set; }
public long MaxAge { get; set; }
public String Path { get; set; }
public String Domain { get; set; }
public bool Secure { get; set; }
public bool HttpOnly { get; set; }
public Dictionary<string, string> Properties { get; } = new Dictionary<string, string>();
}
//======================================================================= //=======================================================================
public class SacsHttpResponseData public class SacsHttpResponseData
{ {
@@ -59,10 +82,14 @@ namespace Sarand.Net.Standard.Base.Net
public Dictionary<String, IEnumerable<String>> ResponseHeaders { get; } = new Dictionary<String, IEnumerable<String>>(); public Dictionary<String, IEnumerable<String>> ResponseHeaders { get; } = new Dictionary<String, IEnumerable<String>>();
/// <summary>Response content headers.</summary> /// <summary>Response content headers.</summary>
public Dictionary<String, IEnumerable<String>> ContentHeaders { get; } = new Dictionary<String, IEnumerable<String>>(); public Dictionary<String, IEnumerable<String>> ContentHeaders { get; } = new Dictionary<String, IEnumerable<String>>();
/// <summary>Response cookies from 'Set-Cookie' header.</summary>
public Dictionary<String, SacsHttpCookieData> Cookies { get; } = new Dictionary<string, SacsHttpCookieData>();
/// <summary>Indicates whether Status Code represents success.</summary> /// <summary>Indicates whether Status Code represents success.</summary>
public bool Success { get; set; } public bool Success { get; set; }
/// <summary>HTTP Status Code.</summary> /// <summary>HTTP Status Code.</summary>
public HttpStatusCode StatusCode { get; set; } public HttpStatusCode StatusCode { get; set; }
/// <summary>HTTP message version. Default: 1.1</summary>
public Version Version { get; set; }
/// <summary>HTTP Reason Code.</summary> /// <summary>HTTP Reason Code.</summary>
public String ReasonPhrase { get; set; } = ""; public String ReasonPhrase { get; set; } = "";
/// <summary>Response data.</summary> /// <summary>Response data.</summary>
@@ -80,26 +107,28 @@ namespace Sarand.Net.Standard.Base.Net
{ {
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Data members. // Data members.
private static readonly HttpClient client; private static readonly HttpClient httpClient;
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Static initialisation. // Static initialisation.
static SacsHttpClient () static SacsHttpClient()
{ {
// Configure client. // Configure client.
client = new HttpClient(); httpClient = new HttpClient();
client.Timeout = new TimeSpan(0, 0, RequestTimeoutSecs_Default); httpClient.Timeout = new TimeSpan(0, 0, RequestTimeoutSecs_Default);
ProductInfoHeaderValue productInfoHeaderValue = new ProductInfoHeaderValue("Saratoga", "1.2.3");
httpClient.DefaultRequestHeaders.UserAgent.Add(productInfoHeaderValue);
} }
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Properties. // Properties.
public static HttpClient HttpClient { get { return httpClient; } }
public static int RequestTimeoutSecs_Default { get; } = 5; public static int RequestTimeoutSecs_Default { get; } = 5;
public static String HeaderName_ContentType { get; } = "Content-Type"; public static String HeaderName_ContentType { get; } = HeaderNames.ContentType;
//------------------------------------------------------------------- //-------------------------------------------------------------------
public static async Task<SacsHttpResponseData> DoRequest (SacsHttpRequestData requestData) public static async Task<SacsHttpResponseData> DoRequest(SacsHttpRequestData requestData)
{ {
String fn = "SacsHttpClient.DoRequest";
SacsHttpResponseData responseData = new SacsHttpResponseData(); SacsHttpResponseData responseData = new SacsHttpResponseData();
requestData.ThrowIfCancellationRequested(); requestData.ThrowIfCancellationRequested();
@@ -109,13 +138,13 @@ namespace Sarand.Net.Standard.Base.Net
{ {
postContent = new FormUrlEncodedContent(requestData.FormData); postContent = new FormUrlEncodedContent(requestData.FormData);
if (!requestData.ContentHeaders.ContainsKey(HeaderName_ContentType)) if (!requestData.ContentHeaders.ContainsKey(HeaderName_ContentType))
requestData.ContentHeaders.Add(HeaderName_ContentType,"application/x-www-form-urlencoded; charset=utf-8"); requestData.ContentHeaders.Add(HeaderName_ContentType, "application/x-www-form-urlencoded; charset=utf-8");
} }
else if (!StringUtil.IsEmpty(requestData.PostData) || requestData.ForcePost) else if (!StringUtil.IsEmpty(requestData.PostData) || requestData.ForcePost)
{ {
postContent = new StringContent(StringUtil.EmptyOnNull(requestData.PostData), Encoding.UTF8); postContent = new StringContent(StringUtil.EmptyOnNull(requestData.PostData), Encoding.UTF8);
if (!requestData.ContentHeaders.ContainsKey(HeaderName_ContentType)) if (!requestData.ContentHeaders.ContainsKey(HeaderName_ContentType))
requestData.ContentHeaders.Add(HeaderName_ContentType,"text/plain; charset=utf-8"); requestData.ContentHeaders.Add(HeaderName_ContentType, "text/plain; charset=utf-8");
} }
requestData.ThrowIfCancellationRequested(); requestData.ThrowIfCancellationRequested();
@@ -137,7 +166,7 @@ namespace Sarand.Net.Standard.Base.Net
} }
// Default request headers. // Default request headers.
if (client.DefaultRequestHeaders.Accept.Count == 0 && request.Headers.Accept.Count == 0) if (httpClient.DefaultRequestHeaders.Accept.Count == 0 && request.Headers.Accept.Count == 0)
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/*")); request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/*"));
// Configure request. // Configure request.
@@ -157,7 +186,7 @@ namespace Sarand.Net.Standard.Base.Net
} }
// Send request. // Send request.
responseData.RequestStarted = DateTime.Now; responseData.RequestStarted = DateTime.Now;
response = await client.SendAsync(request, requestData.CancellationToken); response = await httpClient.SendAsync(request, requestData.CancellationToken);
responseData.RequestCompleted = DateTime.Now; responseData.RequestCompleted = DateTime.Now;
} }
else else
@@ -165,25 +194,61 @@ namespace Sarand.Net.Standard.Base.Net
// GET. // GET.
request.Method = HttpMethod.Get; request.Method = HttpMethod.Get;
responseData.RequestStarted = DateTime.Now; responseData.RequestStarted = DateTime.Now;
response = await client.SendAsync(request, requestData.CancellationToken); response = await httpClient.SendAsync(request, requestData.CancellationToken);
responseData.RequestCompleted = DateTime.Now; responseData.RequestCompleted = DateTime.Now;
} }
// Extract resopnse data. // Extract response data.
responseData.Version = response.Version;
responseData.Success = response.IsSuccessStatusCode; responseData.Success = response.IsSuccessStatusCode;
responseData.StatusCode = response.StatusCode; responseData.StatusCode = response.StatusCode;
responseData.ReasonPhrase = response.ReasonPhrase; responseData.ReasonPhrase = response.ReasonPhrase;
// Extract response headers.
if (response.Headers != null) if (response.Headers != null)
{ {
foreach (var header in response.Headers) foreach (var header in response.Headers)
responseData.ResponseHeaders[header.Key] = new List<String>(header.Value); responseData.ResponseHeaders[header.Key] = new List<String>(header.Value);
} }
// Extract response content headers.
if (response.Content != null && response.Content.Headers != null) if (response.Content != null && response.Content.Headers != null)
{ {
foreach (var header in response.Content.Headers) foreach (var header in response.Content.Headers)
responseData.ContentHeaders[header.Key] = new List<String>(header.Value); responseData.ContentHeaders[header.Key] = new List<String>(header.Value);
} }
responseData.Data = await response.Content.ReadAsStringAsync(); // Extract response cookies.
if (response.Headers.Contains(HeaderNames.SetCookie))
{
foreach (var cookieHeader in response.Headers.GetValues(HeaderNames.SetCookie))
{
SacsHttpCookieData cookie = ExtractCookieFromHeader(cookieHeader);
if (cookie != null && !StringUtil.IsBlank(cookie.Name))
responseData.Cookies.Add(cookie.Name, cookie);
}
}
// Extract response payload.
var contentEncodings = responseData.ContentHeaders.GetValueOrDefault(HeaderNames.ContentEncoding, new List<String>());
using (var responseStream = await response.Content.ReadAsStreamAsync())
{
// Check if response needs to be decompressed, as directed by 'content-encoding' header.
Stream decompressedStream = null;
if (contentEncodings.ContainsCI("gzip"))
decompressedStream = new GZipStream(responseStream, CompressionMode.Decompress);
else if (contentEncodings.ContainsCI("deflate"))
decompressedStream = new DeflateStream(responseStream, CompressionMode.Decompress);
else if (contentEncodings.ContainsCI("br"))
decompressedStream = new BrotliStream(responseStream, CompressionMode.Decompress);
else if (contentEncodings.ContainsCI("zstd"))
decompressedStream = new DecompressionStream(responseStream);
// Read the response payload, decompressed if necessary.
using (var streamReader = new StreamReader(decompressedStream != null ? decompressedStream : responseStream))
responseData.Data = await streamReader.ReadToEndAsync();
// Clean-up.
if (decompressedStream != null)
decompressedStream.Dispose();
}
// Clean-up.
if (response != null) response.Dispose(); if (response != null) response.Dispose();
} }
} }
@@ -198,7 +263,7 @@ namespace Sarand.Net.Standard.Base.Net
exc = exc.InnerException; exc = exc.InnerException;
} }
String msg = exc.GetType().Name + ": " + exc.Message; String msg = exc.GetType().Name + ": " + exc.Message;
SaLogger.Warn(fn + " " + msg + ExceptionUtil.GetStackEntries(exc, 6).Concat("", "\n\t")); SaLogger.Warn(SysUtil.Fn + " " + msg + ExceptionUtil.GetStackEntries(exc, 6).Concat("", "\n\t"));
responseData.ErrorStateMessage = msg; responseData.ErrorStateMessage = msg;
} }
requestData.ThrowIfCancellationRequested(); requestData.ThrowIfCancellationRequested();
@@ -208,10 +273,57 @@ namespace Sarand.Net.Standard.Base.Net
return responseData; return responseData;
} }
//-------------------------------------------------------------------
// Cookies.
//-------------------------------------------------------------------
public static SacsHttpCookieData ExtractCookieFromHeader(String cookieHeader)
{
SacsHttpCookieData cookie = null;
String[] cookieParts = cookieHeader.Split(';');
if (cookieParts.Count() > 1)
{
cookie = new SacsHttpCookieData();
cookie.HeaderValue = cookieHeader;
// Name and value.
String[] cookieNameValue = cookieParts[0].Trim().Split(new char[] { '=' }, 2);
cookie.Name = cookieNameValue[0].Trim();
cookie.Value = cookieNameValue.Count() > 1 ? cookieNameValue[1].Trim() : "";
// Other properties.
for (int i = 1; i < cookieParts.Length; i++)
{
string[] properties = cookieParts[i].Trim().Split(new char[] { '=' }, 2);
String propertyName = properties[0].Trim();
String propertyValue = properties.Count() > 1 ? properties[1].Trim() : "True";
cookie.Properties.Add(propertyName, propertyValue);
if (propertyName.EqualsCI("Domain"))
cookie.Domain = propertyValue;
else if (propertyName.EqualsCI("Path"))
cookie.Path = propertyValue;
else if (propertyName.EqualsCI("Expires"))
{
cookie.Expires = DateUtil.ParseExact(propertyValue, "ddd, d MMM yyyy HH:mm:ss GMT");
if (!DateUtil.IsValid(cookie.Expires))
{
DateTime expires;
DateTime.TryParse(propertyValue, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out expires);
cookie.Expires = expires;
}
}
else if (propertyName.EqualsCI("Max-Age"))
cookie.MaxAge = StringUtil.ToLong(propertyValue);
else if (propertyName.EqualsCI("Secure"))
cookie.Secure = StringUtil.ToBool(propertyValue);
else if (propertyName.EqualsCI("HttpOnly"))
cookie.HttpOnly = StringUtil.ToBool(propertyValue);
}
}
return cookie;
}
//------------------------------------------------------------------- //-------------------------------------------------------------------
// R e s p o n s e S t a t u s D e s c r i p t i o n // R e s p o n s e S t a t u s D e s c r i p t i o n
//------------------------------------------------------------------- //-------------------------------------------------------------------
public static String GetResponseStatusDescription (HttpStatusCode httpStatus) public static String GetResponseStatusDescription(HttpStatusCode httpStatus)
{ {
// Ref. https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml // Ref. https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
switch (httpStatus) switch (httpStatus)
+52 -5
View File
@@ -1,4 +1,5 @@
using Sarand.Net.Standard.Base.Core; using Org.BouncyCastle.Asn1.Ocsp;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils; using Sarand.Net.Standard.Base.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -13,13 +14,13 @@ namespace Sarand.Net.Standard.Base.Net
// H T M L E n c o d i n g // H T M L E n c o d i n g
//------------------------------------------------------------------- //-------------------------------------------------------------------
/// <summary>Converts a string to an HTML-encoded string.</summary> /// <summary>Converts a string to an HTML-encoded string.</summary>
public static String HtmlEncode (this String value) public static String HtmlEncode(this String value)
{ {
if (StringUtil.IsEmpty(value)) return value; if (StringUtil.IsEmpty(value)) return value;
return WebUtility.HtmlEncode(value); return WebUtility.HtmlEncode(value);
} }
/// <summary>Converts a string that has been HTML-encoded for HTTP transmission into a decoded string.</summary> /// <summary>Converts a string that has been HTML-encoded for HTTP transmission into a decoded string.</summary>
public static String HtmlDecode (this String value) public static String HtmlDecode(this String value)
{ {
if (StringUtil.IsEmpty(value)) return value; if (StringUtil.IsEmpty(value)) return value;
return WebUtility.HtmlDecode(value); return WebUtility.HtmlDecode(value);
@@ -29,18 +30,64 @@ namespace Sarand.Net.Standard.Base.Net
// U R L E n c o d i n g // U R L E n c o d i n g
//------------------------------------------------------------------- //-------------------------------------------------------------------
/// <summary>Converts a string to an HTML-encoded string.</summary> /// <summary>Converts a string to an HTML-encoded string.</summary>
public static String UrlEncode (this String value) public static String UrlEncode(this String value)
{ {
if (StringUtil.IsEmpty(value)) return value; if (StringUtil.IsEmpty(value)) return value;
return WebUtility.UrlEncode(value); return WebUtility.UrlEncode(value);
} }
/// <summary>Converts a string that has been HTML-encoded for HTTP transmission into a decoded string.</summary> /// <summary>Converts a string that has been HTML-encoded for HTTP transmission into a decoded string.</summary>
public static String UrlDecode (this String value) public static String UrlDecode(this String value)
{ {
if (StringUtil.IsEmpty(value)) return value; if (StringUtil.IsEmpty(value)) return value;
return WebUtility.UrlDecode(value); return WebUtility.UrlDecode(value);
} }
//-------------------------------------------------------------------
// URI Builder.
/// <summary>
/// Configure HTTP URI builder.
/// </summary>
public static UriBuilder ConfigureUriBuilder(this UriBuilder uriBuilder, String host, String path, String query = null)
{
uriBuilder.Scheme = "http";
uriBuilder.Host = StringUtil.OnBlank(host);
uriBuilder.Path = StringUtil.OnBlank(path);
uriBuilder.Query = StringUtil.OnBlank(query);
return uriBuilder;
}
/// <summary>
/// Create HTTP URI builder.
/// </summary>
public static UriBuilder CreateUriBuilder(String host, String path, String query = null)
{
UriBuilder uriBuilder = new UriBuilder();
return uriBuilder.ConfigureUriBuilder(host, path, query);
}
/// <summary>
/// Configure HTTPS URI builder.
/// </summary>
public static UriBuilder ConfigureSslUriBuilder(this UriBuilder uriBuilder, String host, String path, String query = null)
{
uriBuilder.Scheme = "https";
uriBuilder.Port = 443;
uriBuilder.Host = StringUtil.OnBlank(host);
uriBuilder.Path = StringUtil.OnBlank(path);
uriBuilder.Query = StringUtil.OnBlank(query);
return uriBuilder;
}
/// <summary>
/// Create HTTPS URI builder.
/// </summary>
public static UriBuilder CreateSslUriBuilder(String host, String path, String query = null)
{
UriBuilder uriBuilder = new UriBuilder();
return uriBuilder.ConfigureSslUriBuilder(host, path, query);
}
//------------------------------------------------------------------- //-------------------------------------------------------------------
} }
} }
+1 -1
View File
@@ -12,7 +12,7 @@ namespace Sarand.Net.Standard.Base.Tasks
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Data members. // Data members.
// Cancellation token source - allows task cancellation to be triggered // Cancellation token source - allows task cancellation to be triggered
// if the cancellation tokden wasn't supplied on construction. // if the cancellation token wasn't supplied on construction.
private CancellationTokenSource cancellationTokenSource = null; private CancellationTokenSource cancellationTokenSource = null;
//------------------------------------------------------------------- //-------------------------------------------------------------------
+6 -3
View File
@@ -59,9 +59,12 @@ namespace Sarand.Net.Standard.Base.Utils
public static List<String> GetStackEntries(this Exception exc, int entries = 0) public static List<String> GetStackEntries(this Exception exc, int entries = 0)
{ {
List<String> stackEntries = new List<string>(); List<String> stackEntries = new List<string>();
stackEntries.AddRange(exc.StackTrace.Split(new String[] { "\r\n" }, (entries > 0 ? entries : 999), StringSplitOptions.None)); if (exc.StackTrace != null)
for (int idx = 0; idx < stackEntries.Count; idx++) {
stackEntries[idx] = stackEntries[idx].Replace(" at ", ""); stackEntries.AddRange(exc.StackTrace.Split(new String[] { "\r\n" }, (entries > 0 ? entries : 999), StringSplitOptions.None));
for (int idx = 0; idx < stackEntries.Count; idx++)
stackEntries[idx] = stackEntries[idx].Replace(" at ", "");
}
return stackEntries; return stackEntries;
} }
+23 -2
View File
@@ -9,7 +9,7 @@ namespace Sarand.Net.Standard.Base.Utils
public static class ListUtil public static class ListUtil
{ {
//------------------------------------------------------------------- //-------------------------------------------------------------------
public static void ClearAndDispose<T> (this IList<T> values) where T : IDisposable public static void ClearAndDispose<T>(this IList<T> values) where T : IDisposable
{ {
while (values.Count > 0) while (values.Count > 0)
{ {
@@ -50,7 +50,12 @@ namespace Sarand.Net.Standard.Base.Utils
/// <summary>Unique values only - ignores number of instances of each value.</summary> /// <summary>Unique values only - ignores number of instances of each value.</summary>
UniqueValuesOnly = 0x02, UniqueValuesOnly = 0x02,
} }
public static bool Equals<T> (this IList<T> sourceList, IList<T> targetList, Equality equality) /// <summary>
/// Compare content of two lists.
/// <para>- Exact ensures precise number and sequence of elements.</para>
/// <para>- Unique allows any number and sequence as long as each item is present in both lists.</para>
/// </summary>
public static bool Equals<T>(this IList<T> sourceList, IList<T> targetList, Equality equality)
{ {
bool sameLength = (sourceList.Count == targetList.Count); bool sameLength = (sourceList.Count == targetList.Count);
if (equality == Equality.Exact) if (equality == Equality.Exact)
@@ -69,6 +74,22 @@ namespace Sarand.Net.Standard.Base.Utils
return true; return true;
} }
//-------------------------------------------------------------------
/// <summary>
/// Remove the specified range of items from the list to a new list.
/// </summary>
public static List<T> ExtractRange<T>(this List<T> values, int index, int count)
{
List<T> extractedValues = new List<T>();
if (values.Any())
{
count = Math.Min(values.Count(), count);
extractedValues.AddRange(values.GetRange(index, count));
values.RemoveRange(index, count);
}
return extractedValues;
}
//------------------------------------------------------------------- //-------------------------------------------------------------------
} }
//======================================================================= //=======================================================================
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
namespace Sarand.Net.Standard.Base.Utils
{
//=======================================================================
public static class NewtonsoftJsonUtil
{
//-------------------------------------------------------------------
// Extracting.
//-------------------------------------------------------------------
//-------------------------------------------------------------------
// Parsing.
//-------------------------------------------------------------------
/// <summary>Parse data as JSON Token.</summary>
public static JToken ParseJsonToken(string jsonData)
{
return JToken.Parse(jsonData);
}
/// <summary>Parse data as JSON Token.</summary>
public static JToken ParseJsonToken(string jsonData, out Exception excOut)
{
excOut = null;
try
{
return JToken.Parse(jsonData);
}
catch (Exception exc)
{
excOut = exc;
}
return null;
}
//-------------------------------------------------------------------
/// <summary>Parse data as JSON Object.</summary>
public static JObject ParseJsonObject(string jsonData)
{
return JObject.Parse(jsonData);
}
/// <summary>Parse data as JSON Object.</summary>
public static JObject ParseJsonObject(string jsonData, out Exception excOut)
{
excOut = null;
try
{
return JObject.Parse(jsonData);
}
catch (Exception exc)
{
excOut = exc;
}
return null;
}
//-------------------------------------------------------------------
/// <summary>Parse data as JSON Object.</summary>
public static JArray ParseJsonArray(string jsonData)
{
return JArray.Parse(jsonData);
}
/// <summary>Parse data as JSON Object.</summary>
public static JArray ParseJsonArray(string jsonData, out Exception excOut)
{
excOut = null;
try
{
return JArray.Parse(jsonData);
}
catch (Exception exc)
{
excOut = exc;
}
return null;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+62 -8
View File
@@ -66,7 +66,7 @@ namespace Sarand.Net.Standard.Base.Utils
// Regular expressions. // Regular expressions.
//------------------------------------------------------------------- //-------------------------------------------------------------------
/// <summary> /// <summary>
/// Create Regex from (quoted) expression and apply Regex.Match to String value and return Match.Success. /// Apply Regex.Match to String value and return Match.Success.
/// <para>- Case sensitive.</para> /// <para>- Case sensitive.</para>
/// </summary> /// </summary>
public static bool Match(this String value, String expression) public static bool Match(this String value, String expression)
@@ -74,7 +74,7 @@ namespace Sarand.Net.Standard.Base.Utils
return value.Match(expression, RegexOptions.None); return value.Match(expression, RegexOptions.None);
} }
/// <summary> /// <summary>
/// Create Regex from (quoted) expression and apply Regex.Match to String value and return Match.Success. /// Apply Regex.Match to String value and return Match.Success, ignoring case.
/// <para>- Case insensitive.</para> /// <para>- Case insensitive.</para>
/// </summary> /// </summary>
public static bool MatchCI(this String value, String expression) public static bool MatchCI(this String value, String expression)
@@ -82,12 +82,11 @@ namespace Sarand.Net.Standard.Base.Utils
return value.Match(expression, RegexOptions.IgnoreCase); return value.Match(expression, RegexOptions.IgnoreCase);
} }
/// <summary> /// <summary>
/// Create Regex from (quoted) expression and apply Regex.Match to String value and return Match.Success. /// Apply Regex.Match to String value and return Match.Success.
/// <para>- Supply options as required.</para>
/// </summary> /// </summary>
public static bool Match(this String value, String expression, RegexOptions options) public static bool Match(this String value, String expression, RegexOptions options)
{ {
return new Regex(Regex.Escape(expression), options).Match(value).Success; return Regex.Match(value, expression, options).Success;
} }
/// <summary> /// <summary>
/// Apply Regex.Match to String value and return Match.Success. /// Apply Regex.Match to String value and return Match.Success.
@@ -96,12 +95,67 @@ namespace Sarand.Net.Standard.Base.Utils
{ {
return re.Match(value).Success; return re.Match(value).Success;
} }
/// <summary> /// <summary>
/// Apply Regex.Matches to String value and return true if any matches found. /// Apply Regex.IsMatch to String value.
/// <para>- Case sensitive.</para>
/// </summary> /// </summary>
public static bool Matches(this String value, Regex re) public static bool IsMatch(this String value, String expression)
{ {
return re.Matches(value).Count < 1; return value.IsMatch(expression, RegexOptions.None);
}
/// <summary>
/// Apply Regex.IsMatch to String value, ignoring case.
/// <para>- Case insensitive.</para>
/// </summary>
public static bool IsMatchCI(this String value, String expression)
{
return value.IsMatch(new Regex(Regex.Escape(expression), RegexOptions.IgnoreCase));
}
/// <summary>
/// Apply Regex.IsMatch to String value.
/// </summary>
public static bool IsMatch(this String value, String expression, RegexOptions options)
{
return Regex.IsMatch(value, expression, options);
}
/// <summary>
/// Apply Regex.IsMatch to String value.
/// </summary>
public static bool IsMatch(this String value, Regex re)
{
return re.IsMatch(value);
}
/// <summary>
/// Apply Regex.Matches to String value and return number of matches found.
/// <para>- Case sensitive.</para>
/// </summary>
public static int MatchCount(this String value, String expression)
{
return value.MatchCount(expression, RegexOptions.None);
}
/// <summary>
/// Apply Regex.Matches to String value and return number of matches found.
/// <para>- Case insensitive.</para>
/// </summary>
public static int MatchCountCI(this String value, String expression)
{
return value.MatchCount(expression, RegexOptions.IgnoreCase);
}
/// <summary>
/// Apply Regex.Matches to String value and return number of matches found.
/// </summary>
public static int MatchCount(this String value, String expression, RegexOptions options)
{
return Regex.Matches(value, expression, options).Count;
}
/// <summary>
/// Apply Regex.Matches to String value and return number of matches found.
/// </summary>
public static int MatchCount(this String value, Regex re)
{
return re.Matches(value).Count;
} }
//------------------------------------------------------------------- //-------------------------------------------------------------------
-45
View File
@@ -1,45 +0,0 @@
using Sarand.Net.Standard.Base.Core;
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
namespace Sarand.Net.Standard.Base.Utils
{
public static class WebUtil
{
//-------------------------------------------------------------------
// H T M L E n c o d i n g
//-------------------------------------------------------------------
/// <summary>Converts a string to an HTML-encoded string.</summary>
public static String HtmlEncode (this String value)
{
if (StringUtil.IsEmpty(value)) return value;
return WebUtility.HtmlEncode(value);
}
/// <summary>Converts a string that has been HTML-encoded for HTTP transmission into a decoded string.</summary>
public static String HtmlDecode (this String value)
{
if (StringUtil.IsEmpty(value)) return value;
return WebUtility.HtmlDecode(value);
}
//-------------------------------------------------------------------
// U R L E n c o d i n g
//-------------------------------------------------------------------
/// <summary>Converts a string to an HTML-encoded string.</summary>
public static String UrlEncode (this String value)
{
if (StringUtil.IsEmpty(value)) return value;
return WebUtility.UrlEncode(value);
}
/// <summary>Converts a string that has been HTML-encoded for HTTP transmission into a decoded string.</summary>
public static String UrlDecode (this String value)
{
if (StringUtil.IsEmpty(value)) return value;
return WebUtility.UrlDecode(value);
}
//-------------------------------------------------------------------
}
}
+2 -1
View File
@@ -7,11 +7,12 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="CsvHelper" Version="19.0.0" /> <PackageReference Include="CsvHelper" Version="19.0.0" />
<PackageReference Include="MailKit" Version="4.5.0" /> <PackageReference Include="MailKit" Version="4.6.0" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" /> <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" /> <PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
<PackageReference Include="ZstdNet" Version="1.4.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -20,7 +20,7 @@ namespace Sarand.Net.Standard.Dbas.Base
{ {
VS2017, VS2017,
/// <summary> /// <summary>
/// Visual Studio 2019 version. StringListUtil rather than StringListUtil. /// Visual Studio 2019 version. StringListUtil rather than StringList.
/// </summary> /// </summary>
VS2019 VS2019
} }
@@ -36,7 +36,7 @@ namespace Sarand.Net.Standard.Dbas.Base
} }
public class Config public class Config
{ {
public SarandCommonVersion SarandCommonVersion { get; set; } = SarandCommonVersion.VS2017; public SarandCommonVersion SarandCommonVersion { get; set; } = SarandCommonVersion.VS2019;
public DotNetVersion DotNetVersion { get; set; } = DotNetVersion.Framework; public DotNetVersion DotNetVersion { get; set; } = DotNetVersion.Framework;
public SacsDatabase Database { get; set; } public SacsDatabase Database { get; set; }
public Dbms DbmsOutput { get; set; } = Dbms.ODBC; public Dbms DbmsOutput { get; set; } = Dbms.ODBC;
@@ -46,10 +46,12 @@ namespace Sarand.Net.Standard.Dbas.Base
public class SchemaData public class SchemaData
{ {
// Tables to be included (all others excluded) or those to be excluded. // Tables to be included (all others excluded) or those to be excluded.
public List<String> Tables_Included { get; } = new List<String>(); public HashSet<String> Tables_Included { get; } = new HashSet<String>(StringComparer.InvariantCultureIgnoreCase);
public List<String> Tables_Excluded { get; } = new List<String>(); public HashSet<String> Tables_Excluded { get; } = new HashSet<String>(StringComparer.InvariantCultureIgnoreCase);
// Schema capitalisation - for class name prefix etc - where capitalising first letter is insufficient.
public Dictionary<String, String> SchemaNameCapitalisation { get; } = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
// Alternative table names. // Alternative table names.
public Dictionary<String, List<String>> AlternativeTableNames { get; } = new Dictionary<string, List<string>>(); public Dictionary<String, List<String>> AlternativeTableNames { get; } = new Dictionary<string, List<string>>(StringComparer.InvariantCultureIgnoreCase);
public void AddAlternativeTableName(String tableName, String tableNameAlternative) public void AddAlternativeTableName(String tableName, String tableNameAlternative)
{ {
if (!AlternativeTableNames.ContainsKey(tableName)) AlternativeTableNames[tableName] = new List<string>(); if (!AlternativeTableNames.ContainsKey(tableName)) AlternativeTableNames[tableName] = new List<string>();
@@ -66,7 +68,7 @@ namespace Sarand.Net.Standard.Dbas.Base
public class DefinitionClassConfig public class DefinitionClassConfig
{ {
/// <summary>Using namespaces for database definition and table class usings.</summary> /// <summary>Using namespaces for database definition and table class usings.</summary>
public List<String> Usings { get; } = new List<String>() { "Sarand.Net.Standard.Base.Core", "Sarand.Net.Standard.Base.Dbas" }; public HashSet<String> Usings { get; } = new HashSet<String>() { "Sarand.Net.Standard.Base.Core", "Sarand.Net.Standard.Base.Dbas" };
public String Namespace { get; set; } = "Sarand.Application.Core.Base"; public String Namespace { get; set; } = "Sarand.Application.Core.Base";
public String Classname { get; set; } = "SaDbDfn"; public String Classname { get; set; } = "SaDbDfn";
} }
@@ -75,7 +77,7 @@ namespace Sarand.Net.Standard.Dbas.Base
public class TableClassConfig public class TableClassConfig
{ {
/// <summary>Using namespaces for table classes.</summary> /// <summary>Using namespaces for table classes.</summary>
public List<String> Usings { get; } = new List<String>() { "Sarand.Net.Standard.Base.Core", "Sarand.Net.Standard.Base.Dbas" }; public HashSet<String> Usings { get; } = new HashSet<String>() { "Sarand.Net.Standard.Base.Core", "Sarand.Net.Standard.Base.Dbas" };
public String Namespace_BaseClass { get; set; } = "Sarand.Net.Standard.Dbas.Data"; public String Namespace_BaseClass { get; set; } = "Sarand.Net.Standard.Dbas.Data";
public String Namespace { get; set; } = "Sarand.Application.Dbas"; public String Namespace { get; set; } = "Sarand.Application.Dbas";
public String BaseClass { get; set; } = "DbDataItem"; public String BaseClass { get; set; } = "DbDataItem";
@@ -89,6 +91,7 @@ namespace Sarand.Net.Standard.Dbas.Base
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Data members. // Data members.
private Config config = null; private Config config = null;
private const String DefaultSchema_MSSQL = "dbo";
private static String /*lf = "\n",*/ crlf = "\r\n", tab1 = "\t", tab2 = "\t\t", tab3 = "\t\t\t", tab4 = "\t\t\t\t", tab5 = "\t\t\t\t\t"; private static String /*lf = "\n",*/ crlf = "\r\n", tab1 = "\t", tab2 = "\t\t", tab3 = "\t\t\t", tab4 = "\t\t\t\t", tab5 = "\t\t\t\t\t";
// Reserved words. // Reserved words.
private static readonly String[] reservedWords = private static readonly String[] reservedWords =
@@ -313,10 +316,19 @@ namespace Sarand.Net.Standard.Dbas.Base
file.WriteLine(tab2 + "{"); file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "int tableIdx = (int)table - 1;"); file.WriteLine(tab3 + "int tableIdx = (int)table - 1;");
file.WriteLine(tab3 + "if (tableIdx < 0 || tableIdx >= tableCount) return String.Empty;"); file.WriteLine(tab3 + "if (tableIdx < 0 || tableIdx >= tableCount) return String.Empty;");
file.WriteLine(tab3 + "String tableName = tables[(int)tableIdx];"); file.WriteLine(tab3 + "String tableName = tables[(int)tableIdx].Name;");
file.WriteLine(tab3 + "if (delimitReservedWords) tableName = DelimitReservedWord(tableName);"); file.WriteLine(tab3 + "if (delimitReservedWords) tableName = DelimitReservedWord(tableName);");
file.WriteLine(tab3 + "return tableName;"); file.WriteLine(tab3 + "return tableName;");
file.WriteLine(tab2 + "}"); file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static String GetTableNameQual (TableIdx table, bool delimitReservedWords = true)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "int tableIdx = (int)table - 1;");
file.WriteLine(tab3 + "if (tableIdx < 0 || tableIdx >= tableCount) return String.Empty;");
file.WriteLine(tab3 + "String schemaName = tables[(int)tableIdx].Schema;");
file.WriteLine(tab3 + "String tableName = tables[(int)tableIdx].Name;");
file.WriteLine(tab3 + "if (delimitReservedWords) { schemaName = DelimitReservedWord(schemaName); tableName = DelimitReservedWord(tableName); }");
file.WriteLine(tab3 + "return (StringUtil.IsBlank(schemaName) ? \"\" : schemaName + \".\") + tableName;");
file.WriteLine(tab2 + "}");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------"); file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
// Table for Column method. // Table for Column method.
@@ -369,8 +381,15 @@ namespace Sarand.Net.Standard.Dbas.Base
file.WriteLine(tab2 + "}"); file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static String DelimitReservedWord (String word)"); file.WriteLine(tab2 + "public static String DelimitReservedWord (String word)");
file.WriteLine(tab2 + "{"); file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "if (!IsReservedWord(word)) return word;"); file.WriteLine(tab3 + "return IsReservedWord(word) ? DelimitWord(word) : word;");
file.WriteLine(tab3 + "switch (reservedWordDelim)"); file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static String DelimitWord (String word)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "return DelimitWord(word, reservedWordDelim);");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "public static String DelimitWord (String word, DbReservedWordDelim wordDelim)");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "switch (wordDelim)");
file.WriteLine(tab3 + "{"); file.WriteLine(tab3 + "{");
file.WriteLine(tab4 + "case DbReservedWordDelim.None:"); file.WriteLine(tab4 + "case DbReservedWordDelim.None:");
file.WriteLine(tab5 + "break;"); file.WriteLine(tab5 + "break;");
@@ -447,12 +466,22 @@ namespace Sarand.Net.Standard.Dbas.Base
file.WriteLine(tab2 + "}"); file.WriteLine(tab2 + "}");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------"); file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
// Table definitions. // Table names.
file.WriteLine(tab2 + "// Table definitions."); file.WriteLine(tab2 + "// Table definitions.");
file.WriteLine(tab2 + "private static readonly String[] tables ="); file.WriteLine(tab2 + "private class TableDfn");
file.WriteLine(tab2 + "{");
file.WriteLine(tab3 + "internal String Schema { get; set; }");
file.WriteLine(tab3 + "internal String Name { get; set; }");
file.WriteLine(tab3 + "internal TableDfn (String schema, String name)");
file.WriteLine(tab3 + "{");
file.WriteLine(tab4 + "this.Schema= schema;");
file.WriteLine(tab4 + "this.Name = name;");
file.WriteLine(tab3 + "}");
file.WriteLine(tab2 + "}");
file.WriteLine(tab2 + "private static readonly TableDfn[] tables =");
file.WriteLine(tab2 + "{"); file.WriteLine(tab2 + "{");
foreach (DbDfnTable tableDfn in tableDfns) foreach (DbDfnTable tableDfn in tableDfns)
file.WriteLine(tab3 + "\"" + tableDfn.Name + "\", "); file.WriteLine(tab3 + "new TableDfn(\"" + tableDfn.Schema + "\",\"" + tableDfn.Name + "\"),");
file.WriteLine(tab2 + "};"); file.WriteLine(tab2 + "};");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------"); file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
@@ -476,7 +505,6 @@ namespace Sarand.Net.Standard.Dbas.Base
file.WriteLine(tab4 + "this.DataLen = dataLen;"); file.WriteLine(tab4 + "this.DataLen = dataLen;");
file.WriteLine(tab3 + "}"); file.WriteLine(tab3 + "}");
file.WriteLine(tab2 + "}"); file.WriteLine(tab2 + "}");
file.WriteLine(crlf + tab2 + "//-------------------------------------------------------------------");
file.WriteLine(tab2 + "private static readonly ColumnDfn[] columns ="); file.WriteLine(tab2 + "private static readonly ColumnDfn[] columns =");
file.WriteLine(tab2 + "{"); file.WriteLine(tab2 + "{");
uint tableIdx = 0; uint tableIdx = 0;
@@ -505,6 +533,10 @@ namespace Sarand.Net.Standard.Dbas.Base
private void GenerateTableInterfaceClass(DbDfnTable tableDfn) private void GenerateTableInterfaceClass(DbDfnTable tableDfn)
{ {
String className = tableDfn.Name + "_Db"; String className = tableDfn.Name + "_Db";
if (!StringUtil.IsEmpty(tableDfn.Schema) && !tableDfn.Schema.EqualsCI("dbo"))
{
className = config.Schema.SchemaNameCapitalisation.GetValueOrDefault(tableDfn.Schema, StringUtil.CapitaliseFirst(tableDfn.Schema)) + "_" + className;
}
List<String> primaryColumnNames = tableDfn.GetPrimaryColumnNames(); List<String> primaryColumnNames = tableDfn.GetPrimaryColumnNames();
String identityColumnName = tableDfn.Columns.GetIdentityColumnName(); String identityColumnName = tableDfn.Columns.GetIdentityColumnName();
String identityColumnVariableTypeName = tableDfn.Columns.GetIdentityColumnVariableTypeName(); String identityColumnVariableTypeName = tableDfn.Columns.GetIdentityColumnVariableTypeName();
@@ -141,7 +141,7 @@ namespace Sarand.Net.Standard.Dbas.Base
if (StringUtil.IsEmpty(config.DatabaseName)) if (StringUtil.IsEmpty(config.DatabaseName))
config.DatabaseName = sqlDatabase; config.DatabaseName = sqlDatabase;
SaLogger.Info("DatabaseConsole.GenerateConnectionString Driver: " + sqlDriver + ". Server: " + sqlServer + ". Database: " + sqlDatabase + ". Connection: " + connectionString); SaLogger.Info($"{SysUtil.Fn} Driver: " + sqlDriver + ". Server: " + sqlServer + ". Database: " + sqlDatabase + ". Connection: " + connectionString);
} }
return connectionString; return connectionString;
} }
@@ -219,7 +219,7 @@ namespace Sarand.Net.Standard.Dbas.Base
else else
{ {
#if DEBUG #if DEBUG
SaLogger.Debug("DropDbIndex Table: " + tableName + "; Index: " + indexName + "; Exception: " + database.ErrorStateMessage); SaLogger.Debug($"{SysUtil.Fn} Table: " + tableName + "; Index: " + indexName + "; Exception: " + database.ErrorStateMessage);
#endif #endif
SetErrorState("Failed to drop index " + indexName + " on " + tableName + " - " + database.ErrorStateMessage); SetErrorState("Failed to drop index " + indexName + " on " + tableName + " - " + database.ErrorStateMessage);
} }
@@ -240,7 +240,7 @@ namespace Sarand.Net.Standard.Dbas.Base
else else
{ {
#if DEBUG #if DEBUG
SaLogger.Debug("DropDbIndex Table: " + tableName + "; Index: " + indexName + "; Exception: " + database.ErrorStateMessage); SaLogger.Debug($"{SysUtil.Fn} Table: " + tableName + "; Index: " + indexName + "; Exception: " + database.ErrorStateMessage);
#endif #endif
SetErrorState("Failed to drop primary key " + indexName + " on " + tableName + " - " + database.ErrorStateMessage); SetErrorState("Failed to drop primary key " + indexName + " on " + tableName + " - " + database.ErrorStateMessage);
} }
@@ -288,7 +288,7 @@ namespace Sarand.Net.Standard.Dbas.Base
else else
{ {
#if DEBUG #if DEBUG
SaLogger.Debug("CreatePrimaryDbIndex Table: %" + tableName + "; Index: " + indexName + "; Exception: " + database.ErrorStateMessage); SaLogger.Debug($"{SysUtil.Fn} Table: %" + tableName + "; Index: " + indexName + "; Exception: " + database.ErrorStateMessage);
#endif #endif
SetErrorState("Failed to create primary index " + indexName + " on " + tableName + " - " + database.ErrorStateMessage); SetErrorState("Failed to create primary index " + indexName + " on " + tableName + " - " + database.ErrorStateMessage);
} }
@@ -322,7 +322,7 @@ namespace Sarand.Net.Standard.Dbas.Base
else else
{ {
#if DEBUG #if DEBUG
SaLogger.Debug("CreateDbIndex Table: " + tableName + "; Index: " + indexName + "; Exception: " + database.ErrorStateMessage); SaLogger.Debug($"{SysUtil.Fn} Table: " + tableName + "; Index: " + indexName + "; Exception: " + database.ErrorStateMessage);
#endif #endif
SetErrorState("Failed to create index " + indexName + " on " + tableName + " - " + database.ErrorStateMessage); SetErrorState("Failed to create index " + indexName + " on " + tableName + " - " + database.ErrorStateMessage);
} }
@@ -57,8 +57,8 @@ namespace Sarand.Net.Standard.Dbas.CodeType
OutputDirectory = directory, OutputDirectory = directory,
}; };
// Schema - Tables. // Schema - Tables.
config.Schema.Tables_Included.AddRange(new String[] { "SaCodeType", "SaCode" }); config.Schema.Tables_Included.UnionWith(new String[] { "SaCodeType", "SaCode" });
config.Schema.Tables_Excluded.AddRange(new String[] { }); config.Schema.Tables_Excluded.UnionWith(new String[] { });
// Schema - Columns. // Schema - Columns.
config.Schema.InsertOnlyColumns.Add(".*", "CreateOn,CreateBy,CreateHost"); config.Schema.InsertOnlyColumns.Add(".*", "CreateOn,CreateBy,CreateHost");
config.Schema.InsertOnlyColumns.Add("SaCodeType", "Code"); config.Schema.InsertOnlyColumns.Add("SaCodeType", "Code");
@@ -384,7 +384,7 @@ namespace Sarand.Net.Standard.Dbas.Data
// Only populate table names and/or table schemas where not previously done. // Only populate table names and/or table schemas where not previously done.
if (tables.Count < 1 || tables.Exists(item => !item.HasColumns())) if (tables.Count < 1 || tables.Exists(item => !item.HasColumns()))
{ {
// Use a single connection for table and schaema population. // Use a single connection for table and schema population.
using (DbConnection dbConnection = CreateConnection(true)) using (DbConnection dbConnection = CreateConnection(true))
{ {
dbConnection.Open(); dbConnection.Open();
@@ -58,8 +58,8 @@ namespace Sarand.Net.Standard.Dbas.Interface
OutputDirectory = directory, OutputDirectory = directory,
}; };
// Schema - Tables. // Schema - Tables.
config.Schema.Tables_Included.AddRange(new String[] { "SaInterface", "SaInterfaceProcess", "SaInterfaceProcessMessage", "SaInterfaceDataItem", "SaInterfaceProcessDataItem" }); config.Schema.Tables_Included.UnionWith(new String[] { "SaInterface", "SaInterfaceProcess", "SaInterfaceProcessMessage", "SaInterfaceDataItem", "SaInterfaceProcessDataItem" });
config.Schema.Tables_Excluded.AddRange(new String[] { }); config.Schema.Tables_Excluded.UnionWith(new String[] { });
config.Schema.AddAlternativeTableName("SaInterface", "Interface"); config.Schema.AddAlternativeTableName("SaInterface", "Interface");
config.Schema.AddAlternativeTableName("SaInterfaceProcess", "InterfaceProcess"); config.Schema.AddAlternativeTableName("SaInterfaceProcess", "InterfaceProcess");
config.Schema.AddAlternativeTableName("SaInterfaceProcessMessage", "InterfaceProcessMessage"); config.Schema.AddAlternativeTableName("SaInterfaceProcessMessage", "InterfaceProcessMessage");
@@ -58,8 +58,8 @@ namespace Sarand.Net.Standard.Dbas.ItemData
OutputDirectory = directory, OutputDirectory = directory,
}; };
// Schema - Tables. // Schema - Tables.
config.Schema.Tables_Included.AddRange(new String[] { "SaItemData" }); config.Schema.Tables_Included.UnionWith(new String[] { "SaItemData" });
config.Schema.Tables_Excluded.AddRange(new String[] { }); config.Schema.Tables_Excluded.UnionWith(new String[] { });
// Schema - Columns. // Schema - Columns.
config.Schema.InsertOnlyColumns.Add(".*", "CreateOn,CreateBy,CreateHost"); config.Schema.InsertOnlyColumns.Add(".*", "CreateOn,CreateBy,CreateHost");
config.Schema.InsertOnlyColumns.Add("SaItemData", "ItemType,ItemId,Name,Context"); config.Schema.InsertOnlyColumns.Add("SaItemData", "ItemType,ItemId,Name,Context");
@@ -62,8 +62,8 @@ namespace Sarand.Net.Standard.Dbas.ItemDocs
OutputDirectory = directory, OutputDirectory = directory,
}; };
// Schema - Tables. // Schema - Tables.
config.Schema.Tables_Included.AddRange(new String[] { "SaItemDoc" }); config.Schema.Tables_Included.UnionWith(new String[] { "SaItemDoc" });
config.Schema.Tables_Excluded.AddRange(new String[] { }); config.Schema.Tables_Excluded.UnionWith(new String[] { });
// Schema - Columns. // Schema - Columns.
config.Schema.InsertOnlyColumns.Add(".*", "CreateOn,CreateBy,CreateHost"); config.Schema.InsertOnlyColumns.Add(".*", "CreateOn,CreateBy,CreateHost");
config.Schema.InsertOnlyColumns.Add("SaItemDocs", "ItemType,ItemId,Name,Context"); config.Schema.InsertOnlyColumns.Add("SaItemDocs", "ItemType,ItemId,Name,Context");
@@ -58,8 +58,8 @@ namespace Sarand.Net.Standard.Dbas.ItemOptions
OutputDirectory = directory, OutputDirectory = directory,
}; };
// Schema - Tables. // Schema - Tables.
config.Schema.Tables_Included.AddRange(new String[] { "SaItemOption" }); config.Schema.Tables_Included.UnionWith(new String[] { "SaItemOption" });
config.Schema.Tables_Excluded.AddRange(new String[] { }); config.Schema.Tables_Excluded.UnionWith(new String[] { });
// Schema - Columns. // Schema - Columns.
config.Schema.InsertOnlyColumns.Add(".*", "CreateOn,CreateBy,CreateHost"); config.Schema.InsertOnlyColumns.Add(".*", "CreateOn,CreateBy,CreateHost");
config.Schema.InsertOnlyColumns.Add("SaItemOption", "ItemType,ItemId,Name,Context"); config.Schema.InsertOnlyColumns.Add("SaItemOption", "ItemType,ItemId,Name,Context");
@@ -58,8 +58,8 @@ namespace Sarand.Net.Standard.Dbas.ReferenceData
OutputDirectory = directory, OutputDirectory = directory,
}; };
// Schema - Tables. // Schema - Tables.
config.Schema.Tables_Included.AddRange(new String[] { "Language", "Region", "Currency", "TaxCode", "UnitMeasure" }); config.Schema.Tables_Included.UnionWith(new String[] { "Language", "Region", "Currency", "TaxCode", "UnitMeasure" });
config.Schema.Tables_Excluded.AddRange(new String[] { }); config.Schema.Tables_Excluded.UnionWith(new String[] { });
// Schema - Columns. // Schema - Columns.
config.Schema.InsertOnlyColumns.Add(".*", "CreateOn,CreateBy,CreateHost"); config.Schema.InsertOnlyColumns.Add(".*", "CreateOn,CreateBy,CreateHost");
config.Schema.InsertOnlyColumns.Add("Language", ""); config.Schema.InsertOnlyColumns.Add("Language", "");
@@ -57,8 +57,8 @@ namespace Sarand.Net.Standard.Dbas.Security
OutputDirectory = directory, OutputDirectory = directory,
}; };
// Schema - Tables. // Schema - Tables.
config.Schema.Tables_Included.AddRange(new String[] { "SaSecItem", "SaSecLink" }); config.Schema.Tables_Included.UnionWith(new String[] { "SaSecItem", "SaSecLink" });
config.Schema.Tables_Excluded.AddRange(new String[] { }); config.Schema.Tables_Excluded.UnionWith(new String[] { });
config.Schema.AddAlternativeTableName("SaSecItem", "SaSecurityItem"); config.Schema.AddAlternativeTableName("SaSecItem", "SaSecurityItem");
config.Schema.AddAlternativeTableName("SaSecLink", "SaSecurityLink"); config.Schema.AddAlternativeTableName("SaSecLink", "SaSecurityLink");
// Schema - Columns. // Schema - Columns.
@@ -58,8 +58,8 @@ namespace Sarand.Net.Standard.Dbas.UpdateLog
OutputDirectory = directory, OutputDirectory = directory,
}; };
// Schema - Tables. // Schema - Tables.
config.Schema.Tables_Included.AddRange(new String[] { "SaAttrUpdate" }); config.Schema.Tables_Included.UnionWith(new String[] { "SaAttrUpdate" });
config.Schema.Tables_Excluded.AddRange(new String[] { }); config.Schema.Tables_Excluded.UnionWith(new String[] { });
// SChema - Columns. // SChema - Columns.
config.Schema.InsertOnlyColumns.Add(".*", "CreateOn,CreateBy,CreateHost"); config.Schema.InsertOnlyColumns.Add(".*", "CreateOn,CreateBy,CreateHost");
config.Schema.InsertOnlyColumns.Add("SaAttrUpdate", "ItemType,ItemId,Logged,Attribute"); config.Schema.InsertOnlyColumns.Add("SaAttrUpdate", "ItemType,ItemId,Logged,Attribute");
@@ -587,14 +587,14 @@ namespace Sarand.Net.Standard.Proc.Excel
public static int GetPosForColId(String colId) public static int GetPosForColId(String colId)
{ {
colId = StringUtil.TrimWhitespace(StringUtil.OnBlank(colId)).ToUpper(); colId = StringUtil.TrimWhitespace(StringUtil.OnBlank(colId)).ToUpper();
if (!colId.Matches(new Regex("[A-Z]+"))) if (!colId.IsMatch("^[A-Z]{1,2}$"))
{ {
SaLogger.Warn(SysUtil.Fn + " Invalid column Id supplied: '" + colId + "'"); SaLogger.Warn(SysUtil.Fn + " Invalid column Id supplied: '" + colId + "'");
return -1; return 0;
} }
int col = (colId[0] - 'A'); int col = (colId[0] - 'A' + 1);
if (colId.Length > 1) if (colId.Length > 1)
col = ((colId[1] - 'A') * 26) + (colId[0] - 'A'); col = (col * 26) + (colId[1] - 'A' + 1);
return col; return col;
} }
@@ -845,7 +845,7 @@ namespace Sarand.Net.Standard.Proc.Excel
try try
{ {
if (IsCellDate(cell)) if (IsCellDate(cell))
return new DataValue(cell.DateCellValue); return new DataValue((DateTime)(cell.DateCellValue ?? DateTime.MinValue));
if (IsCellNumeric(cell)) if (IsCellNumeric(cell))
{ {
double value = cell.NumericCellValue; double value = cell.NumericCellValue;
@@ -971,7 +971,7 @@ namespace Sarand.Net.Standard.Proc.Excel
try try
{ {
IRow row = GetRowByPos(rowPos, true); IRow row = GetRowByPos(rowPos, true);
for (int valueIdx = 0; valueIdx < values.Count; valueIdx++) for (int valueIdx = 0; valueIdx < values.Count; valueIdx++)
{ {
uint colPos = (uint)Math.Max(1, colPosStart + valueIdx); uint colPos = (uint)Math.Max(1, colPosStart + valueIdx);
Object value = values[valueIdx]; Object value = values[valueIdx];
+8 -3
View File
@@ -1,4 +1,6 @@
using Sarand.Net.Standard.Base.Procs; using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Procs;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
@@ -13,8 +15,11 @@ namespace Sarand.Net.Standard.Proc.Procs
// Definitions. // Definitions.
public new class Config : SaProcess_Base.Config public new class Config : SaProcess_Base.Config
{ {
protected Config() : base() protected Config(DbUpdateInfo dbUpdateInfo) : base()
{ } {
this.DbUpdateInfo = dbUpdateInfo;
}
public DbUpdateInfo DbUpdateInfo { get; }
} }
//------------------------------------------------------------------- //-------------------------------------------------------------------
+2 -2
View File
@@ -10,8 +10,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="3.0.1" /> <PackageReference Include="DocumentFormat.OpenXml" Version="3.0.2" />
<PackageReference Include="NPOI" Version="2.6.2" /> <PackageReference Include="NPOI" Version="2.7.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>