Saxonite 1.2.11.2

This commit is contained in:
Andy Howard
2024-02-27 15:45:02 +00:00
parent f3350fdc23
commit 2239f37408
54 changed files with 3613 additions and 1175 deletions
+3 -2
View File
@@ -98,7 +98,9 @@ namespace Sarand.Net.Standard.Base.Core
public String DateTimeSeparator { get; set; } = " ";
public String TimeFormat { get; set; } = "HH:mm";
public DataValue.DataType DataType { get; set; } = DataValue.DataType.String;
public bool IsNumeric { get { return DataType == DataValue.DataType.Long || DataType == DataValue.DataType.Double || DataType == DataValue.DataType.Decimal; } }
public bool Resizable { get; set; } = true;
public bool WrapText { get; set; } = false;
public bool Hidden { get; set; } = false;
public bool Frozen { get; set; } = false;
// Drop-down configuration.
@@ -107,12 +109,11 @@ namespace Sarand.Net.Standard.Base.Core
public bool ExclusiveValues { get; set; } = true;
/// <summary>User entered values (Exclusive=false) are converted if corresponding value found in list.</summary>
public bool MatchCase { get; set; } = true;
// Edit configuration:
// Edit configuration.
public int MaxLength { get; set; } = 0;
public bool ReadOnly { get; set; } = false;
public bool Uppercase { get; set; } = false;
public bool Lowercase { get; set; } = false;
public bool Numeric { get; set; } = false;
public bool Password { get; set; } = false;
// Sort attributes.
/// <summary>Sort mode. Default: 'On'.</summary>
+53
View File
@@ -172,6 +172,7 @@ namespace Sarand.Net.Standard.Base.Core
}
return 0.0;
}
/// <summary>Return value interpretted as boolean.</summary>
public bool ToBool ()
{
if (value == null) return false;
@@ -190,6 +191,7 @@ namespace Sarand.Net.Standard.Base.Core
}
return false;
}
/// <summary>Return explicit boolean value or false for other types.</summary>
public bool AsBool ()
{
// Convert to specific type of data - fails if type is not correct:
@@ -369,10 +371,58 @@ namespace Sarand.Net.Standard.Base.Core
}
//=======================================================================
// Data Value list extension functions.
public static class DataValueList
{
//-------------------------------------------------------------------
// Population.
/// <summary>Add a String value to the list.</summary>
public static void Add(this List<DataValue> values, String value)
{
values.Add(new DataValue(value));
}
/// <summary>Add a boolean value to the list.</summary>
public static void Add(this List<DataValue> values, bool value)
{
values.Add(new DataValue(value));
}
/// <summary>Add an integer value to the list.</summary>
public static void Add(this List<DataValue> values, int value)
{
values.Add(new DataValue(value));
}
/// <summary>Add a long value to the list.</summary>
public static void Add(this List<DataValue> values, long value)
{
values.Add(new DataValue(value));
}
/// <summary>Add a double value to the list.</summary>
public static void Add(this List<DataValue> values, double value)
{
values.Add(new DataValue(value));
}
/// <summary>Add a decimal value to the list.</summary>
public static void Add(this List<DataValue> values, decimal value)
{
values.Add(new DataValue(value));
}
/// <summary>Add a date time value to the list.</summary>
public static void Add(this List<DataValue> values, DateTime value)
{
values.Add(new DataValue(value));
}
//-------------------------------------------------------------------
// Conversion.
/// <summary>Convert all data values to strings.</summary>
public static List<String> ToStringList (this List<DataValue> values)
{
@@ -381,6 +431,7 @@ namespace Sarand.Net.Standard.Base.Core
stringValues.Add(values.ToString());
return stringValues;
}
/// <summary>
/// Convert the data values to raw objects.
/// <para>eg. For population to Excel spreadsheet cells.</para>
@@ -409,6 +460,7 @@ namespace Sarand.Net.Standard.Base.Core
//-------------------------------------------------------------------
// Numeric - only with compatible numeric values.
/// <summary>Minimum numeric value in the list.</summary>
public static DataValue GetMinValue (this List<DataValue> values)
{
@@ -425,6 +477,7 @@ namespace Sarand.Net.Standard.Base.Core
}
return minValue;
}
/// <summary>Maximum numeric value in the list.</summary>
public static DataValue GetMaxValue (this List<DataValue> values)
{
+1 -1
View File
@@ -19,7 +19,7 @@ namespace Sarand.Net.Standard.Base.Core
// Disposal.
~SacsDisposable ()
{
Dispose(false);
Dispose(!disposed);
}
public void Dispose ()
{
@@ -38,8 +38,20 @@ namespace Sarand.Net.Standard.Base.Helpers
public new String PreferredContentType { set { base.PreferredContentType = value; } }
}
//-------------------------------------------------------------------
// Definitions.
/// <summary>Excel legacy - xls.</summary>
public static readonly String ContentType_Excel_Legacy = "application/vnd.ms-excel";
/// <summary>Excel open - xlsx.</summary>
public static readonly String ContentType_Excel_Open = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
/// <summary>Excel macro enabled - xlsm.</summary>
public static readonly String ContentType_Excel_MacroEnabled = "application/vnd.ms-excel.sheet.macroEnabled.12";
/// <summary>Excel binary macro enabled - xlsb.</summary>
public static readonly String ContentType_Excel_BinaryMacroEnabled = "application/vnd.ms-excel.sheet.binary.macroEnabled.12";
//-------------------------------------------------------------------
// Data members.
static String ContentType_Generic = "application/octet-stream";
private static readonly List<ContentTypeData> contentTypes;
private static FileExtensionContentTypeProvider provider = null;
private static readonly HashSet<Sacs.MimeType> allowedMimeTypes_CV = new HashSet<Sacs.MimeType>()
@@ -87,8 +99,8 @@ namespace Sarand.Net.Standard.Base.Helpers
new ContentTypeData_Internal("docx", "Microsoft Word (OpenXML)", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", Sacs.MimeType.MsDocx),
new ContentTypeData_Internal("odt", "OpenDocument text document", "application/vnd.oasis.opendocument.text", Sacs.MimeType.OpenDocText),
// Spreadsheets.
new ContentTypeData_Internal("xls", "Microsoft Excel", "application/vnd.ms-excel", Sacs.MimeType.MsXls),
new ContentTypeData_Internal("xlsx", "Microsoft Excel (OpenXML)", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", Sacs.MimeType.MsXlsx),
new ContentTypeData_Internal("xls", "Microsoft Excel", ContentType_Excel_Legacy, Sacs.MimeType.MsXls),
new ContentTypeData_Internal("xlsx", "Microsoft Excel (OpenXML)", ContentType_Excel_Open, Sacs.MimeType.MsXlsx),
new ContentTypeData_Internal("ods", "OpenDocument spreadsheet document", "application/vnd.oasis.opendocument.spreadsheet", Sacs.MimeType.OpenDocSpreadsheet),
// Miscellaneous.
new ContentTypeData_Internal("aac", "AAC audio", "audio/aac"),
@@ -156,7 +168,7 @@ namespace Sarand.Net.Standard.Base.Helpers
//-------------------------------------------------------------------
// Properties.
/// <summary>Generic content type used for 'unknown' document types.</summary>
public static String ContentTypeDefault { get; } = "application/octet-stream";
public static String ContentTypeDefault { get; } = ContentType_Generic;
/// <summary>Selection of comon content types.</summary>
public static List<ContentTypeData> ContentTypes { get { return new List<ContentTypeData>(contentTypes); } }
public static FileExtensionContentTypeProvider Provider
@@ -223,6 +235,20 @@ namespace Sarand.Net.Standard.Base.Helpers
}
//----------------------------------------------------------------------
/// <summary>Convert the enumerated Mime to content type.</summary>
public static String GetContentTypeFromMimeType(Sacs.MimeType mime)
{
if (mime == Sacs.MimeType.Unknown) return ContentTypeDefault;
ContentTypeData contentTypeData = contentTypes.Find(item => item.Mime.Equals(mime));
if (contentTypeData != null)
return contentTypeData.ContentType;
return ContentTypeDefault;
}
//----------------------------------------------------------------------
// Mime type.
//----------------------------------------------------------------------
/// <summary>Convert the content type to enumerated Mime.</summary>
public static Sacs.MimeType GetMimeTypeFromContentType(this String contentType)
{
+342 -58
View File
@@ -1,29 +1,37 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging.Abstractions;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Tasks;
using Sarand.Net.Standard.Base.Utils;
using static Sarand.Net.Standard.Base.Procs.SaProcess_Base;
namespace Sarand.Net.Standard.Base.Procs
{
//=======================================================================
public interface ISacsProcessNotifier
{
void OnStartProcess ();
void SetProgressInfo (List<String> progressInfo);
void OnEndProcess ();
}
//=======================================================================
public abstract class SaProcess_Base : SacsDisposable
{
//-------------------------------------------------------------------
// Exceptions.
[Serializable]
public class InProgressException : Exception
{
public InProgressException() { }
public InProgressException(string message) : base(message) { }
public InProgressException(string message, Exception inner) : base(message, inner) { }
}
//-------------------------------------------------------------------
// Process options and groups - for configuration of process to run.
// See Sarand.Win.Forms.Utility.SaForm_SelectOptions.
public class OptionData
{
public OptionData (TypeCodeDesc option)
public OptionData(TypeCodeDesc option)
{
Option = option;
}
@@ -33,7 +41,7 @@ namespace Sarand.Net.Standard.Base.Procs
}
public class GroupData
{
public GroupData (TypeCodeDesc optionGroup)
public GroupData(TypeCodeDesc optionGroup)
{
OptionGroup = optionGroup;
}
@@ -55,13 +63,13 @@ namespace Sarand.Net.Standard.Base.Procs
}
public class Config
{
protected Config ()
protected Config()
{
}
/// <summary>Identifies the type of process.</summary>
public ProcessType ProcessType { get; set; } = ProcessType.Unknown;
/// <summary>Is the process to be run in 'Test' mode.</summary>
public bool TestProcess{ get; set; } = SacsSystem.DebugMode;
public bool TestProcess { get; set; } = SacsSystem.DebugMode;
/// <summary>Process imports data.</summary>
public bool Import { get { return ProcessType == ProcessType.ImportData || ProcessType == ProcessType.ImportExportData; } }
/// <summary>Process exports data.</summary>
@@ -74,28 +82,131 @@ namespace Sarand.Net.Standard.Base.Procs
public bool Automated { get; set; } = false;
}
//-------------------------------------------------------------------
// Process control definitions.
public class ProcessMessage
{
public ProcessMessage(String message, SaMessageLevel level = SaMessageLevel.Info)
{
this.Message = message;
this.Level = level;
}
public String Message { get; }
public SaMessageLevel Level { get; }
public int Instances { get; internal set; }
}
private class ProcessControlData
{
// Interrupt.
private class InterruptData
{
public readonly Object lockable = new object();
private bool interrupted = false;
public bool Interrupted { get { lock (lockable) { return interrupted; } } set { lock (lockable) { interrupted = value; } } }
}
private InterruptData interrupt { get; } = new InterruptData();
public bool Interrupted { get { return interrupt.Interrupted; } set { interrupt.Interrupted = value; } }
// Process messages.
private class ProcessMessagesData
{
public readonly Object lockable = new object();
public List<ProcessMessage> messages { get; } = new List<ProcessMessage>();
}
private ProcessMessagesData processMessages { get; } = new ProcessMessagesData();
/// <summary>Convert the message levele to one of the 3 values used with Process Messages: Info, Warning, Error.</summary>
public static SaMessageLevel GetLevel(SaMessageLevel level)
{
if (level == SaMessageLevel.Error || level == SaMessageLevel.Fatal || level == SaMessageLevel.Exception)
level = SaMessageLevel.Error;
else if (level == SaMessageLevel.Warning)
level = SaMessageLevel.Warning;
else
level = SaMessageLevel.Info;
return level;
}
/// <summary>Add a message of the specified level (Info, Warning, Error).</summary>
public bool AddProcessMessage(String message, SaMessageLevel level)
{
message = StringUtil.TrimWhitespace(message);
if (StringUtil.IsBlank(message)) return false;
level = GetLevel(level);
lock (processMessages.lockable)
{
ProcessMessage procMsg = processMessages.messages.Find(item => item.Message.EqualsCI(message) && item.Level == level);
// Duplicate messages increment the 'Instances' value.
if (procMsg != null)
procMsg.Instances++;
// Otherwise add a new message to the list.
else processMessages.messages.Add(new ProcessMessage(message, level));
}
return true;
}
/// <summary>Are there any message of the specified level (Info, Warning, Error).</summary>
public bool HasProcessMessages(SaMessageLevel level)
{
lock (processMessages.lockable)
return processMessages.messages.Exists(item => item.Level == GetLevel(level));
}
/// <summary>Get the first message of the specified level (Info, Warning, Error).</summary>
public String GetProcessMessage(SaMessageLevel level)
{
lock (processMessages.lockable)
return processMessages.messages.Find(item => item.Level == GetLevel(level))?.Message ?? "";
}
/// <summary>Return all process messages.</summary>
public List<ProcessMessage> GetProcessMessages()
{
List<ProcessMessage> messages = new List<ProcessMessage>();
lock (processMessages.lockable)
messages.AddRange(processMessages.messages);
return messages;
}
/// <summary>Return all process messages of the specified Level (Info, Warning, Error).</summary>
public List<ProcessMessage> GetProcessMessages(SaMessageLevel level)
{
List<ProcessMessage> messages = new List<ProcessMessage>();
lock (processMessages.lockable)
messages.AddRange(processMessages.messages.FindAll(item => item.Level == GetLevel(level)));
return messages;
}
/// <summary>Clear process messages.</summary>
public void ClearProcessMessages()
{
lock (processMessages.lockable)
processMessages.messages.Clear();
}
// Task control data.
private SacsTaskData taskData = null;
public SacsTaskData TaskData { get { return taskData; } set { if (taskData != null) taskData.Dispose(); taskData = value; } }
}
//-------------------------------------------------------------------
// Data members.
private Config config;
private String processError = "";
private ProcessControlData Control { get; } = new ProcessControlData();
//-------------------------------------------------------------------
// Construction.
protected SaProcess_Base (Config config)
protected SaProcess_Base(Config config)
{
this.config = config;
}
protected override void Dispose (bool disposing)
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Clear process data to dispose.
Control.TaskData = null;
}
}
//-------------------------------------------------------------------
// Properties.
public bool DebugMode { get { return SacsSystem.DebugMode; } }
public ISacsProcessNotifier ProcessNotifier { get; set; } = null;
public bool Processing { get; protected set; } = false;
public bool ProcessEnded { get; protected set; } = false;
public DateTime StartedAt { get; private set; } = DateTime.MinValue;
@@ -120,56 +231,195 @@ namespace Sarand.Net.Standard.Base.Procs
public virtual List<StringPair> ProcessingStatistics { get { return new List<StringPair>(); } }
//-------------------------------------------------------------------
// Run process inline.
public bool RunProcess ()
// Run process asynchronously.
private class AsyncProcessData : SacsDisposable
{
String fn = GetType().Name+".RunProcess";
if (ProcessNotifier == null)
throw new NotSupportedException("Process Notifier must be specified");
public AsyncProcessData(Task task)
{
this.Task = task;
}
protected override void Dispose(bool disposing)
{
if (disposing) { }
}
public Task Task { get; }
}
private AsyncProcessData AsyncData { get; set; }
public bool IsAsync { get { return AsyncData != null; } }
private void ClearAsyncData()
{
if (AsyncData != null)
{
lock (AsyncData)
{
AsyncData.Dispose();
AsyncData = null;
}
}
}
/// <summary>
/// Run the process asynchronously.
/// </summary>
/// <returns></returns>
/// <exception cref="InProgressException">If process is already running.</exception>
public async void RunAsync()
{
if (AsyncData != null)
throw new InProgressException();
Control.TaskData = new SacsTaskData();
// Run on separate thread.
Task task = new Task(() =>
{
try
{
// Execute the process.
RunProcess();
}
catch (OperationCanceledException exc)
{
SaLogger.Warn(exc.GetType().Name + " during asynchronous processing on " + GetType().Name);
}
finally
{
// Clear processing data.
ClearAsyncData();
}
}, Control.TaskData.CancellationToken);
AsyncData = new AsyncProcessData(task);
task.Start();
await task;
}
//-------------------------------------------------------------------
// Run process inline.
public bool RunProcess()
{
String fn = GetType().Name + ".RunProcess";
// Prepare process.
bool runProcess = false;
Reset();
if (Control.TaskData == null)
Control.TaskData = new SacsTaskData();
Processing = true;
StartedAt = DateTime.Now;
// Process starting.
try
{
// Notify start of process and log/ignore exceptions.
ProcessNotifier.OnStartProcess();
InvokeProcessStarting();
}
catch (Exception exc)
{
SaLogger.Error(fn + " OnStartProcess: " + GetProcessError() + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
String msg = exc.GetType().Name + ": " + exc.Message;
AddErrorMessage(msg);
SaLogger.Error(fn + " ProcessStarting: " + msg + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
}
// Process running.
try
{
// Run process.
OnProcessStarting();
runProcess = Run();
OnProcessEnding();
}
catch (Exception exc)
{
SetProcessError(exc.GetType().Name + ": " + exc.Message);
SaLogger.Error(fn + " " + GetProcessError() + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
String msg = exc.GetType().Name + ": " + exc.Message;
AddErrorMessage(msg);
SaLogger.Error(fn + " " + msg + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
}
// Processing completed.
FinishedAt = DateTime.Now;
Processing = false;
ProcessEnded = true;
finally
{
// Processing completed.
FinishedAt = DateTime.Now;
Processing = false;
ProcessEnded = true;
Control.TaskData = null;
}
// Process completed.
try
{
// Notify end of process and log/ignore exceptions.
ProcessNotifier.OnEndProcess();
// Notify completion of process and log/ignore exceptions.
InvokeProcessCompleted();
}
catch (Exception exc)
{
SaLogger.Error(fn + " OnEndProcess: " + GetProcessError() + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
String msg = exc.GetType().Name + ": " + exc.Message;
AddErrorMessage(msg);
SaLogger.Error(fn + " ProcessCompleted: " + msg + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
}
return runProcess;
}
protected abstract bool Run ();
protected virtual void OnProcessStarting () { }
protected virtual void OnProcessEnding () { }
protected abstract bool Run();
//-------------------------------------------------------------------
public async Task StopProcessAsync(int timeout = 50)
{
if (!Processing) return;
if (AsyncData != null)
{
try
{
// Cancel the task.
Control.TaskData.TriggerCancellation();
// Wait for task termination or timeout.
if (await Task.WhenAny(AsyncData.Task, Task.Delay(Math.Max(20, Math.Min(1000, timeout)))) != AsyncData.Task)
{
// Timeout completed before task - force termination.
Control.TaskData.ThrowIfCancellationRequested();
}
}
finally
{
Control.TaskData = null;
ClearAsyncData();
}
}
}
//-------------------------------------------------------------------
// Processing events.
// Processing Starting.
public class ProcessStartingEventArgs : EventArgs { }
public event EventHandler<ProcessStartingEventArgs> OnProcessStarting;
protected virtual void InvokeProcessStarting()
{
if (OnProcessStarting != null)
{
ProcessStartingEventArgs args = new ProcessStartingEventArgs();
OnProcessStarting(this, args);
}
}
// Process Info Updated.
public class ProgressInfoUpdatedEventArgs : EventArgs
{
public List<String> ProgressInfo { get; } = new List<string>();
}
public event EventHandler<ProgressInfoUpdatedEventArgs> OnProgressInfoUpdated;
protected virtual void InvokeProgressInfoUpdated(List<String> progressInfo)
{
if (OnProgressInfoUpdated != null)
{
ProgressInfoUpdatedEventArgs args = new ProgressInfoUpdatedEventArgs();
args.ProgressInfo.AddRange(progressInfo);
OnProgressInfoUpdated(this, args);
}
}
// Processing Completed.
public class ProcessCompletedEventArgs : EventArgs { }
public event EventHandler<ProcessCompletedEventArgs> OnProcessCompleted;
protected virtual void InvokeProcessCompleted()
{
if (OnProcessCompleted != null)
{
ProcessCompletedEventArgs args = new ProcessCompletedEventArgs();
OnProcessCompleted(this, args);
}
}
//-------------------------------------------------------------------
// Process control.
@@ -177,15 +427,15 @@ namespace Sarand.Net.Standard.Base.Procs
{
get
{
if (HasProcessError()) return false;
if (isInterrupted) return false;
if (HasErrorMessage()) return false;
if (Control.Interrupted) return false;
return true;
}
}
private void Reset ()
private void Reset()
{
ClearProcessError();
isInterrupted = false;
Control.ClearProcessMessages();
Control.Interrupted = false;
ProcessEnded = false;
StartedAt = DateTime.MinValue;
FinishedAt = DateTime.MinValue;
@@ -193,36 +443,70 @@ namespace Sarand.Net.Standard.Base.Procs
//-------------------------------------------------------------------
// Progress information.
protected void SetProgressInfo (String progressInfo)
protected void SetProgressInfo(String progressInfo)
{
SetProgressInfo(StringListUtil.CreateList(progressInfo));
}
protected void SetProgressInfo (List<String> progressInfo)
protected void SetProgressInfo(List<String> progressInfo)
{
if (ProcessNotifier != null)
ProcessNotifier.SetProgressInfo(progressInfo);
InvokeProgressInfoUpdated(progressInfo);
}
//-------------------------------------------------------------------
// Error handling.
public bool HasProcessError () { return !StringUtil.IsEmpty(processError); }
public String GetProcessError () { return StringUtil.EmptyOnNull(processError); }
public void ClearProcessError () { processError = ""; }
/// <summary>Record the processing error - always returns false.</summary>
public bool SetProcessError (String error)
// Process messages.
/// <summary>Add a message of the specified level (Info, Warning, Error).</summary>
protected void AddMessage(String message, SaMessageLevel level)
{
processError = StringUtil.EmptyOnNull(error);
if (Control.AddProcessMessage(message, level))
SaLogger.Log(GetType().Name + " " + message, ProcessControlData.GetLevel(level));
}
protected void AddInfoMessage(String message)
{
AddMessage(message, SaMessageLevel.Info);
}
protected void AddWarningMessage(String message)
{
AddMessage(message, SaMessageLevel.Warning);
}
/// <summary>Add the error message and always return false.</summary>
protected bool AddErrorMessage(String message)
{
AddMessage(message, SaMessageLevel.Error);
return false;
}
/// <summary>Are there any error messages.</summary>
public bool HasErrorMessage()
{
return Control.HasProcessMessages(SaMessageLevel.Error);
}
/// <summary>Get the first error message.</summary>
public String GetErrorMessage()
{
return Control.GetProcessMessage(SaMessageLevel.Error);
}
/// <summary>Return all process messages.</summary>
public List<ProcessMessage> GetProcessMessages()
{
return Control.GetProcessMessages();
}
/// <summary>Return all process messages of the specified Level (Info, Warning, Error).</summary>
public List<ProcessMessage> GetProcessMessages(SaMessageLevel level)
{
return Control.GetProcessMessages(level);
}
/// <summary>Clear process messages.</summary>
public void ClearProcessMessages()
{
Control.ClearProcessMessages();
}
//-------------------------------------------------------------------
// Interruption.
private bool isInterrupted = false;
public bool IsInterrupted
{
get { return isInterrupted; }
get { return Control.Interrupted; }
}
public bool Interrupt ()
public bool Interrupt()
{
if (!config.AllowInterruption)
{
@@ -230,10 +514,10 @@ namespace Sarand.Net.Standard.Base.Procs
return false;
}
if (config.ConfirmInterruption && !IsInterruptionConfirmed()) return false;
isInterrupted = true;
Control.Interrupted = true;
return true;
}
protected virtual bool IsInterruptionConfirmed ()
protected virtual bool IsInterruptionConfirmed()
{
return true;
}
+7 -3
View File
@@ -17,7 +17,7 @@ namespace Sarand.Net.Standard.Base.Tasks
//-------------------------------------------------------------------
// Construction.
public SacsTaskData (CancellationToken? cancellationToken)
public SacsTaskData (CancellationToken? cancellationToken = null)
{
if (cancellationToken != null)
{
@@ -49,18 +49,22 @@ namespace Sarand.Net.Standard.Base.Tasks
// Properties.
public bool Debug { get; set; }
/// <summary>Token to allow the async request to be cancelled.</summary>
public CancellationToken CancellationToken { get; }
//-------------------------------------------------------------------
// C a n c e l l a t i o n
//-------------------------------------------------------------------
/// <summary>Token to allow the async request to be cancelled.</summary>
public CancellationToken CancellationToken { get; }
/// <summary>Gets whether cancellation has been requested.</summary>
public bool IsCancellationRequested { get { return CancellationToken.IsCancellationRequested; } }
/// <summary>Throws a System.OperationCanceledException if this token has had cancellation requested.</summary>
public void ThrowIfCancellationRequested()
{
CancellationToken.ThrowIfCancellationRequested();
}
/// <summary>Can cancellation be triggered here?</summary>
public bool CanBeCancelled { get { return cancellationTokenSource != null; } }
public bool TriggerCancellation ()
+3 -2
View File
@@ -79,7 +79,8 @@ namespace Sarand.Net.Standard.Base.Utils
/// </summary>
public static SixLabors.ImageSharp.Image LoadImage(byte[] imageData, out IImageFormat format)
{
var image = Image.Load<Rgba32>(imageData, out format);
var image = Image.Load<Rgba32>(imageData);
format = Image.DetectFormat(imageData);
return image;
}
@@ -90,7 +91,7 @@ namespace Sarand.Net.Standard.Base.Utils
{
using (MemoryStream ms = new MemoryStream())
{
var imageEncoder = image.GetConfiguration().ImageFormatsManager.FindEncoder(imageFormat);
var imageEncoder = image.Configuration.ImageFormatsManager.GetEncoder(imageFormat);
image.Save(ms, imageEncoder);
return ms.ToArray();
}
+13 -20
View File
@@ -1,4 +1,5 @@
using System;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
@@ -26,32 +27,24 @@ namespace Sarand.Net.Standard.Base.Utils
if (Object.ReferenceEquals(source, null))
return default(T);
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
using (stream)
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
// initialize inner objects individually
// for example in default constructor some list property initialized with some values,
// but in 'source' these items are cleaned -
// without ObjectCreationHandling.Replace default constructor values will be added to result
var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}
//-------------------------------------------------------------------
// Serialize.
public static String Serialize<T>(T source)
// Serialize using JSON.
public static String ToJson<T>(T source)
{
if (!typeof(T).IsSerializable) throw new ArgumentException("The type must be serializable.", "source");
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null)) return "";
// Serialise to String.
IFormatter formatter = new BinaryFormatter();
using (Stream stream = new MemoryStream())
using (StreamReader streamReader = new StreamReader(stream))
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return streamReader.ReadToEnd();
}
// Serialise to JSON String.
return JsonConvert.SerializeObject(source);
}
//-------------------------------------------------------------------
+14
View File
@@ -231,7 +231,20 @@ namespace Sarand.Net.Standard.Base.Utils
Regex regexMultipleInternal = new Regex("[" + Regex.Escape(new String(trimChars)) + "]{2,}", RegexOptions.None);
return regexMultipleInternal.Replace(value, replacement);
}
private static Regex regexWhitespace = new Regex("\\s+", RegexOptions.Compiled);
/// <summary>
/// Trim all leading and trailling whitespace and replace internal whitespace with a single space.
/// </summary>
public static String TrimWhitespace(this String value)
{
return regexWhitespace.Replace(value, " ").Trim();
}
private static Regex regexMultipleSpaces = new Regex("[ ]{2,}", RegexOptions.Compiled);
/// <summary>
/// Replace multiple spaces with a single space.
/// </summary>
public static String TrimInternalSpaces(this String value)
{
return regexMultipleSpaces.Replace(value, " ");
@@ -540,6 +553,7 @@ namespace Sarand.Net.Standard.Base.Utils
if (value.ToDouble() != 0.0) return true;
if (value.Left(1).EqualsCI("Y")) return true;
if (value.EqualsCI("True")) return true;
if (value.EqualsCI("On")) return true;
return false;
}
+74 -5
View File
@@ -1,13 +1,82 @@
namespace Sarand.Net.Standard.Base.Utils
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace Sarand.Net.Standard.Base.Utils
{
//=======================================================================
public class SysUtil
public static class SysUtil
{
//-------------------------------------------------------------------
// Data members.
/// <summary>Get calling code's class name.</summary>
/// <returns></returns>
[MethodImpl(MethodImplOptions.NoInlining)]
public static string GetCallerClassName()
{
try
{
var stackFrame = new StackTrace().GetFrame(1);
var methodInfo = stackFrame.GetMethod();
return methodInfo.ReflectedType.Name.TrimWhitespace();
}
catch (Exception) { }
return "";
}
/// <summary>Get calling code's fucntion name.</summary>
[MethodImpl(MethodImplOptions.NoInlining)]
public static string GetCallerMemberName([CallerMemberName] string memberName = "")
{
return memberName;
}
/// <summary>Get calling code's file path.</summary>
[MethodImpl(MethodImplOptions.NoInlining)]
public static string GetCallerFilePath([CallerFilePath] string filePath = "")
{
return filePath;
}
/// <summary>Get calling code's line number.</summary>
[MethodImpl(MethodImplOptions.NoInlining)]
public static int GetCallerLineNumber([CallerLineNumber] int lineNumber = 0)
{
return lineNumber;
}
//-------------------------------------------------------------------
// Construction.
private SysUtil () { }
/// <summary>Shortcut to GetCallerClassMethod() - returns [class.method] for calling code.</summary>
public static string Fn { get { return GetCallerClassMethod(2); } }
/// <summary>Return identity of calling method as [class.method].</summary>
[MethodImpl(MethodImplOptions.NoInlining)]
public static string GetCallerClassMethod(int stackFrameIdx = 1)
{
try
{
var stackFrame = new StackTrace().GetFrame(stackFrameIdx);
var methodInfo = stackFrame.GetMethod();
return (methodInfo.ReflectedType.Name + "." + methodInfo.Name).TrimWhitespace().Trim('.');
}
catch (Exception) { }
return "";
}
//-------------------------------------------------------------------
/// <summary>Return identity of calling method as [class.method:line].</summary>
[MethodImpl(MethodImplOptions.NoInlining)]
public static string GetCallerClassMethodLine()
{
try
{
var stackFrame = new StackTrace().GetFrame(1);
var methodInfo = stackFrame.GetMethod();
return (methodInfo.ReflectedType.Name + "." + methodInfo.Name + ":" + stackFrame.GetFileLineNumber()).TrimWhitespace().Trim('.');
}
catch (Exception) { }
return "";
}
//-------------------------------------------------------------------
}
//=======================================================================