v1.2.11.2
This commit is contained in:
@@ -41,13 +41,23 @@ namespace Saxonite.Net.Core.Web.Base.App
|
||||
protected SaxApplication_Web()
|
||||
{
|
||||
WebApp = this;
|
||||
System_Web = new SaxSystem_Web();
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
WebApp = null;
|
||||
System_Web = null;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public override SaxSystem System { get { return System_Web; } }
|
||||
public SaxSystem_Web System_Web { get; protected set; }
|
||||
// Globals.
|
||||
public static SaxApplication_Web WebApp { get; private set; }
|
||||
public override SaxSystem System { get { return System_Web; } }
|
||||
public SaxSystem_Web System_Web { get; private set; }
|
||||
// Application instance.
|
||||
public override Sax.InstanceType InstanceType { get { return instanceType; } }
|
||||
public override String EnvironmentName { get { return environmentName; } }
|
||||
@@ -57,7 +67,6 @@ namespace Saxonite.Net.Core.Web.Base.App
|
||||
public abstract String SessionCookieName { get; }
|
||||
public virtual SaxSessionContext SessionContext { get; protected set; }
|
||||
public abstract SaxAppConfig AppConfig { get; }
|
||||
public override SaxConsoleHelper ConsoleHelper { get { return ConsoleHelper_Web; } }
|
||||
public SaxConsoleHelper_Web ConsoleHelper_Web { get; protected set; }
|
||||
public override IDatabaseInfo CreateDbInfo(SaxSessionContext sessionContext, Sax.Database databaseType) { return new DbDataItem.DatabaseInfo(GetDatabase(sessionContext, databaseType)); }
|
||||
// Configuration.
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace Saxonite.Net.Core.Web.Base.App
|
||||
opts => { opts.ResourcesPath = resourcesPath; })
|
||||
.AddDataAnnotationsLocalization()
|
||||
// Ignore null values during object serisliation.
|
||||
.AddJsonOptions(options => { options.JsonSerializerOptions.IgnoreNullValues = true; });
|
||||
.AddJsonOptions(options => { options.JsonSerializerOptions.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull; });
|
||||
|
||||
// Configure localisation middleware.
|
||||
config.services.Configure<RequestLocalizationOptions>
|
||||
|
||||
@@ -13,6 +13,10 @@ namespace Saxonite.Net.Core.Web.Base.Consoles
|
||||
protected SaxConsoleHelper_Web()
|
||||
{
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Sacs.Web.Components;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
@@ -34,7 +35,7 @@ using System.Web;
|
||||
namespace Saxonite.Net.Core.Web.Base.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaxController_Base : Controller
|
||||
public abstract class SaxController_Base : SaController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
@@ -44,7 +45,6 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
|
||||
// Protected construction.
|
||||
protected SaxController_Base(SaxLocaliser localiser)
|
||||
{
|
||||
CreatedAt = DateTime.Now;
|
||||
Localiser = localiser;
|
||||
|
||||
// Initialise console (debug) logging listener.
|
||||
@@ -62,43 +62,14 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public DateTime CreatedAt { get; }
|
||||
public bool DebugMode { get; } = SacsSystem.DebugMode;
|
||||
protected SaxApplication_Web App { get { return SaxApplication_Web.WebApp; } }
|
||||
public SaxAppConfig AppConfig { get { return App.AppConfig; } }
|
||||
public SaxSessionContext SessionContext { get { return App.SessionContext; } }
|
||||
public SaxLocaliser Localiser { get; }
|
||||
/// <summary>
|
||||
/// Indicate whether session data should be stored by action.
|
||||
/// <para>Any action that might modify the session data must store it.</para>
|
||||
/// <para>Some actions such as scoring a password's complexity don't need to.</para>
|
||||
/// </summary>
|
||||
public virtual bool StoreSessionData { get; protected set; } = true;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Culture.
|
||||
private CultureInfo sessionCulture;
|
||||
private CultureInfo RequestCulture { get { return Request.HttpContext.Features.Get<IRequestCultureFeature>().RequestCulture.Culture ?? CultureInfo.InvariantCulture; } }
|
||||
public CultureInfo SessionCulture
|
||||
{
|
||||
get
|
||||
{
|
||||
if (sessionCulture == null)
|
||||
{
|
||||
sessionCulture = RequestCulture;
|
||||
// ToDo Adjust culture if needed.
|
||||
}
|
||||
return sessionCulture;
|
||||
}
|
||||
}
|
||||
private string LanguageIso2
|
||||
{
|
||||
get
|
||||
{
|
||||
var feature = HttpContext.Features.Get<IRequestCultureFeature>();
|
||||
return feature.RequestCulture.UICulture.TwoLetterISOLanguageName.ToLower();
|
||||
}
|
||||
}
|
||||
// Globals.
|
||||
protected SaxConsoleHelper ConsoleHelper { get { return SaxGlobals.ConsoleHelper; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Business components.
|
||||
@@ -138,36 +109,6 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
|
||||
public SaEmailConfig EmailConfig { get { return App.EmailConfig; } }
|
||||
public SaxEmailConsole EmailConsole { get { return Internals.EmailConsole; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Redirection locations.
|
||||
//-------------------------------------------------------------------
|
||||
public static readonly String ParamName_SessionExpired = "SessionExpired";
|
||||
public enum RedirectLocation
|
||||
{
|
||||
WebAppBase,
|
||||
WebAppHome,
|
||||
WebAppHome_SessionExpired,
|
||||
}
|
||||
public String GetRedirectLocation(RedirectLocation redirectLocation)
|
||||
{
|
||||
string protocol = Request.Scheme;
|
||||
var parameters = new RouteValueDictionary();
|
||||
String homeAction = Url.Action("Index", "Home", parameters, protocol);
|
||||
switch (redirectLocation)
|
||||
{
|
||||
case RedirectLocation.WebAppBase:
|
||||
return Regex.Replace(homeAction, "\\/$", "") + "/";
|
||||
case RedirectLocation.WebAppHome:
|
||||
return homeAction;
|
||||
case RedirectLocation.WebAppHome_SessionExpired:
|
||||
// Set the session expired parameter so that the page can report it.
|
||||
// NB Paramater must have a value to be included in the URL query string.
|
||||
parameters.Add(ParamName_SessionExpired, "1");
|
||||
return homeAction;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Action execution events.
|
||||
//-------------------------------------------------------------------
|
||||
@@ -212,7 +153,6 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
|
||||
Response.Headers.Add(HeaderNames.Expires, "0");
|
||||
}
|
||||
|
||||
|
||||
base.OnActionExecuted(filterContext);
|
||||
}
|
||||
|
||||
@@ -244,78 +184,22 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
|
||||
//private static String Base64IV_RequestPassword_Generated_Online { get; } = SacsEncryptionHelper.InitSymmetricEncryptionIV(Base64Key_RequestPassword_Online);
|
||||
protected static String Base64IV_RequestPassword_Online { get; } = "1VAWYTW6d72n/6HDNhbqow==";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public static String EncryptParameters(NameValueCollection parameters, String base64IV, String base64Key)
|
||||
{
|
||||
String fn = nameof(ControllerBase) + ".EncryptParameters";
|
||||
try
|
||||
{
|
||||
// Copy the list of parameters and sort the keys.
|
||||
NameValueCollection parametersToEncrypt = new NameValueCollection(parameters);
|
||||
String[] paramKeys = parametersToEncrypt.AllKeys;
|
||||
Array.Sort(paramKeys);
|
||||
|
||||
// Serialise parameters as if in a URL query string - so that they can be deserialised in DecryptParameters() below.
|
||||
// Start with a random length parameter name at start of list to obscure the encryption.
|
||||
string queryString = SacsRandomHelper.getRandomLengthNumber(4) + "&";
|
||||
queryString += String.Join("&", paramKeys.Select(a => a + "=" + HttpUtility.UrlEncode(parametersToEncrypt[a])));
|
||||
|
||||
// Encrypt data.
|
||||
String encrypted = SacsEncryptionHelper.Encrypt(queryString, base64IV, base64Key);
|
||||
//if (SacsSystem.DebugMode) SaLogger.Debug(fn + "\n\tData: " + queryString + " \n\tEncrypted: " + encrypted);
|
||||
return encrypted;
|
||||
}
|
||||
catch (Exception exc) { SaLogger.Warn(fn + " " + ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return "";
|
||||
}
|
||||
public static NameValueCollection DecryptParameters(String encrypted, String base64IV, String base64Key)
|
||||
{
|
||||
String fn = nameof(ControllerBase) + ".DecryptParameters";
|
||||
try
|
||||
{
|
||||
String queryString = SacsEncryptionHelper.Decrypt(encrypted, base64IV, base64Key);
|
||||
//if (SacsSystem.DebugMode) SaLogger.Debug(fn + " \n\tEncrypted: " + encrypted + "\n\tData: " + queryString);
|
||||
return HttpUtility.ParseQueryString(queryString);
|
||||
}
|
||||
catch (Exception exc) { SaLogger.Warn(fn + " " + ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return new NameValueCollection();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Cookies.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Retrieve the value from the named request cookie.</summary>
|
||||
public String GetRequestCookie(String key)
|
||||
{
|
||||
if (Request.Cookies.ContainsKey(key))
|
||||
return Request.Cookies[key];
|
||||
return null;
|
||||
}
|
||||
/// <summary>Set the value against the named response cookie.</summary>
|
||||
public void SetResponseCookie(string key, string value, DateTime? expiresAt = null, bool isEssential = false)
|
||||
{
|
||||
CookieOptions options = new CookieOptions();
|
||||
options.HttpOnly = true;
|
||||
options.Secure = true;
|
||||
options.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict;
|
||||
if (expiresAt.HasValue)
|
||||
options.Expires = expiresAt;
|
||||
if (isEssential)
|
||||
options.IsEssential = true;
|
||||
Response.Cookies.Append(key, value, options);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Session.
|
||||
//-------------------------------------------------------------------
|
||||
private bool UserActiveRecorded { get; set; } = false;
|
||||
public bool ValidUserSession
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SessionData == null || !SessionData.ValidUserSession) return false;
|
||||
SaxSessionDataConsole sessionDataConsole = SessionDataConsole;
|
||||
if (sessionDataConsole != null)
|
||||
if (sessionDataConsole != null && !UserActiveRecorded)
|
||||
{
|
||||
// Record the user as active once per request.
|
||||
sessionDataConsole.RecordUserActive(SessionUserAccountId, CreatedAt);
|
||||
UserActiveRecorded = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -403,240 +287,6 @@ namespace Saxonite.Net.Core.Web.Base.Controllers
|
||||
}
|
||||
protected abstract SaxSessionData DeserializeSessionData(String sessionDataJson);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Ajax actions.
|
||||
//-------------------------------------------------------------------
|
||||
protected static readonly Encoding ajaxResponseEncoding = Encoding.UTF8;
|
||||
protected IActionResult GetAjaxResult_GoHome(AjaxResponse_Base responseData)
|
||||
{
|
||||
responseData.SetGoHome();
|
||||
return Json(responseData);
|
||||
}
|
||||
protected IActionResult GetAjaxResult_InvalidSession(AjaxResponse_Base responseData)
|
||||
{
|
||||
responseData.SetGoHome();
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Response data.
|
||||
// Null values are ignored by JSON serialisation.
|
||||
// - See Saxonite.Net.Core.Web.Base.App.SaxStartup.ConfigureServices()
|
||||
// - Ref. config.services.AddMvc(...).AddJsonOptions(options => { options.JsonSerializerOptions.IgnoreNullValues = true; });
|
||||
//-------------------------------------------------------------------
|
||||
// Base response data - for simple responses.
|
||||
public class AjaxResponse_Base
|
||||
{
|
||||
// Response status.
|
||||
public bool? Success { get; set; } = null;
|
||||
public bool? Error { get; set; } = null;
|
||||
public bool? SessionExpired { get; protected set; } = null;
|
||||
public bool? GoHome { get; protected set; } = null;
|
||||
public AjaxResponse_Base SetSessionExpired(String title, String text)
|
||||
{
|
||||
SessionExpired = true;
|
||||
return SetMessage(title, text);
|
||||
}
|
||||
public AjaxResponse_Base SetGoHome()
|
||||
{
|
||||
GoHome = true;
|
||||
return this;
|
||||
}
|
||||
public AjaxResponse_Base SetGoHome(String title, String text)
|
||||
{
|
||||
GoHome = true;
|
||||
return SetMessage(title, text);
|
||||
}
|
||||
// Message - displays alert popup.
|
||||
public class MessageData
|
||||
{
|
||||
public String Title { get; set; }
|
||||
public String Text { get; set; }
|
||||
}
|
||||
public MessageData Message { get; private set; }
|
||||
public AjaxResponse_Base SetMessage(String title, String text)
|
||||
{
|
||||
if (!StringUtil.IsEmpty(text))
|
||||
Message = new MessageData() { Title = title, Text = text };
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public class AjaxResponse_Data : AjaxResponse_Base
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
// Construction.
|
||||
protected AjaxResponse_Data(SaxModel_Base model)
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
/// <summary>Item data - Common properties for data items.</summary>
|
||||
public class ItemData_Base
|
||||
{
|
||||
// Common item properties.
|
||||
public String Id { get; set; }
|
||||
public String Notes { get; set; }
|
||||
public String StatusCode { get; set; }
|
||||
public String StatusDesc { get; set; }
|
||||
// Flags for common status values.
|
||||
// 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? Active { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Active)) ? true : (bool?)null; } }
|
||||
public bool? Inactive { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Inactive)) ? true : (bool?)null; } }
|
||||
public bool? Deleted { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Deleted)) ? true : (bool?)null; } }
|
||||
/// <summary>Created on date - YYYYMMDD</summary>
|
||||
public String CreatedOn { get; set; }
|
||||
/// <summary>Created on date - formatted per locale</summary>
|
||||
public String CreatedOnFmt { get; set; }
|
||||
/// <summary>Updated on date - YYYYMMDD</summary>
|
||||
public String UpdatedOn { get; set; }
|
||||
/// <summary>Updated on date - formatted per locale</summary>
|
||||
public String UpdatedOnFmt { get; set; }
|
||||
}
|
||||
/// <summary>Contact Method properties.</summary>
|
||||
public class ContactMethodData
|
||||
{
|
||||
public String Method { get; set; }
|
||||
public String MethodCaption { get; set; }
|
||||
public String Value { get; set; }
|
||||
}
|
||||
/// <summary>Address properties.</summary>
|
||||
public class AddressData : ItemData_Base
|
||||
{
|
||||
public String Line1 { get; set; }
|
||||
public String Line2 { get; set; }
|
||||
public String Line3 { get; set; }
|
||||
public String Town { get; set; }
|
||||
public String RegionIdProvince { get; set; }
|
||||
public String RegionNameProvince { get; set; }
|
||||
public String RegionIdCountry { get; set; }
|
||||
public String RegionNameCountry { get; set; }
|
||||
public String PostalCode { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Item data with label and value.
|
||||
/// </summary>
|
||||
public class ItemLabelValue
|
||||
{
|
||||
public String Label { get; set; }
|
||||
public String Value { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Item data with just Id and name.
|
||||
/// <para>- Id is String to allow for obfuscated values.</para>
|
||||
/// </summary>
|
||||
public class ItemIdName
|
||||
{
|
||||
public String Id { get; set; }
|
||||
public String Name { get; set; }
|
||||
}
|
||||
/// <summary>Item code and desc values.</summary>
|
||||
public class ItemCodeDesc
|
||||
{
|
||||
public String Code { get; set; }
|
||||
public String Desc { get; set; }
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Form data.
|
||||
public class FormControlValue
|
||||
{
|
||||
public FormControlValue(String controlName, String value, String error)
|
||||
{
|
||||
ControlName = controlName;
|
||||
Value = value;
|
||||
Error = error;
|
||||
}
|
||||
public String ControlName { get; }
|
||||
public String Value { get; set; }
|
||||
public String Error { get; set; }
|
||||
}
|
||||
private readonly Dictionary<String, FormControlValue> controlValues = new Dictionary<String, FormControlValue>();
|
||||
public List<FormControlValue> ControlValues { get { return controlValues.Count > 0 ? controlValues.Values.ToList() : null; } }
|
||||
public void SetControlValue(String controlName, String value, String error = null)
|
||||
{
|
||||
if (controlValues.ContainsKey(controlName))
|
||||
{
|
||||
// Modify existing entry in the list.
|
||||
FormControlValue controlValue = controlValues[controlName];
|
||||
if (value != null) controlValue.Value = value;
|
||||
if (error != null) controlValue.Error = error;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add new control to list.
|
||||
controlValues.Add(controlName, new FormControlValue(controlName, value, error));
|
||||
}
|
||||
}
|
||||
/// <summary>Assign the error to the control by name and return this response data.</summary>
|
||||
public AjaxResponse_Data SetControlError(String controlName, String error)
|
||||
{
|
||||
return SetControlError(controlName, error, this);
|
||||
}
|
||||
/// <summary>
|
||||
/// Assign the error to the control by name and return the specified value.
|
||||
/// <para>- Allows alternative return values to be specified (eg. 'false') to avoid separate return statement in calling routine.</para>
|
||||
/// </summary>
|
||||
public T SetControlError<T>(String controlName, String error, T returnValue)
|
||||
{
|
||||
SetControlValue(controlName, null, error);
|
||||
return returnValue;
|
||||
}
|
||||
public bool HasControlErrors()
|
||||
{
|
||||
foreach (FormControlValue controlValue in controlValues.Values)
|
||||
{
|
||||
if (!StringUtil.IsEmpty(controlValue.Error)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Notification - briefly displays after response received.
|
||||
public class NotificationData
|
||||
{
|
||||
public String Title { get; set; }
|
||||
public String Message { get; set; }
|
||||
}
|
||||
public NotificationData Notification { get; private set; }
|
||||
public AjaxResponse_Data SetNotification(String title, String message)
|
||||
{
|
||||
Notification = new NotificationData() { Title = title, Message = message };
|
||||
return this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Paged data.
|
||||
public class PagingData
|
||||
{
|
||||
public PagingData(SaxModel_Base model) :
|
||||
this(model.Paging.PageNo, model.Paging.PageLength, model.Paging.ItemCount, model.Paging.ItemTotal)
|
||||
{ }
|
||||
public PagingData(uint pageNo, ushort pageLength, ushort itemCount, ulong itemTotal)
|
||||
{
|
||||
PageNo = pageNo;
|
||||
PageLength = pageLength;
|
||||
ItemCount = itemCount;
|
||||
ItemTotal = itemTotal;
|
||||
}
|
||||
public bool Paged { get { return (PageNo > 0 && PageLength > 0 && ItemTotal > PageLength); } }
|
||||
public uint PageNo { get; } = 0;
|
||||
public ushort PageLength { get; } = 0;
|
||||
public uint PageCount { get { return (PageLength > 0 ? (uint)Math.Ceiling((decimal)ItemTotal / PageLength) : 0); } }
|
||||
public ushort ItemCount { get; } = 0;
|
||||
public ulong ItemTotal { get; } = 0;
|
||||
}
|
||||
public PagingData Paging { get; private set; }
|
||||
public void SetPaging(SaxModel_Base model)
|
||||
{
|
||||
Paging = new PagingData(model);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Saxonite.Net.Core.Web.Base.Middleware
|
||||
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
// NoOp task to avoid compiler warning.
|
||||
await Task.Yield();
|
||||
await Task.CompletedTask;
|
||||
Context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||
return AuthenticateResult.NoResult();
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ namespace Saxonite.Net.Core.Web.Base.Middleware
|
||||
/// </summary>
|
||||
protected override void SetProperty(ModelBindingContext bindingContext, string modelName, ModelMetadata propertyMetadata, ModelBindingResult result)
|
||||
{
|
||||
string fn = GetType().Name + ".SetProperty";
|
||||
//if (SaxSystem.DebugMode) Logger.Debug(fn + " Form property " + modelName + ": '" + result.Model.ToString() + ".");
|
||||
object originalValue = result.Model;
|
||||
// Exclude properties that retain leading/trailing whitespace.
|
||||
@@ -91,8 +90,8 @@ namespace Saxonite.Net.Core.Web.Base.Middleware
|
||||
result = ModelBindingResult.Success(value);
|
||||
}
|
||||
}
|
||||
if (result.Model != null && SaxSystem.DebugMode)
|
||||
SaLogger.Debug(fn + " Form property " + modelName + ": '" + result.Model.ToString() + "'." + (originalValue != null && !originalValue.Equals(result.Model) ? " Original value: '" + originalValue.ToString() + "'" : ""));
|
||||
if (result.Model != null && !result.Model.ToString().Equals(result.Model.GetType().FullName) && SaxSystem.DebugMode)
|
||||
SaLogger.Debug(SysUtil.Fn + " Form property " + modelName + ": '" + result.Model.ToString() + "'." + (originalValue != null && !originalValue.Equals(result.Model) ? " Original value: '" + originalValue.ToString() + "'" : ""));
|
||||
base.SetProperty(bindingContext, modelName, propertyMetadata, result);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Saxonite.Net.Core.Web.Base.Middleware
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + ExceptionUtil.GetLogMessage(exc));
|
||||
throw exc;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Sacs.Web.Components;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
@@ -22,14 +23,11 @@ using static Saxonite.Net.Standard.Base.App.Sax;
|
||||
namespace Saxonite.Net.Core.Web.Base.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxModel_Base
|
||||
public class SaxModel_Base : SaModel
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private SaxInternals internals;
|
||||
private readonly List<String> infoMessages = new List<string>();
|
||||
private readonly List<String> warningMessages = new List<string>();
|
||||
private readonly List<String> errorMessages = new List<string>();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
@@ -45,7 +43,6 @@ namespace Saxonite.Net.Core.Web.Base.Models
|
||||
protected SaxSystem_Web System { get { return App.System_Web; } }
|
||||
public String SessionCookieName { get { return App.SessionCookieName; } }
|
||||
public SaxLocaliser Localiser { get; }
|
||||
public bool DebugMode { get { return SaxSystem.DebugMode; } }
|
||||
// Session properties.
|
||||
public SaxSessionData SessionData { get; set; }
|
||||
public SaxSessionContext SessionContext { get { return SessionData?.SessionContext ?? App.SessionContext; } }
|
||||
@@ -56,25 +53,7 @@ namespace Saxonite.Net.Core.Web.Base.Models
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Page configuration.
|
||||
public bool OK { get { return !HasMessages(); } }
|
||||
public virtual bool ProhibitCache { get; set; } = true;
|
||||
public String PageCaption { get; set; }
|
||||
public String InstanceVersion { get { return !StringUtil.IsEmpty(App.AppConfig.Instance) ? App.AppConfig.Instance + " v" + Sax.Version.GetFullVersion() : "v" + Sax.Version.GetAppVersion(); } }
|
||||
public bool IncludeGoogleAnalytics { get; set; } = false;
|
||||
// Views can be registered to avoid multiple inclusions in a page.
|
||||
private HashSet<String> registeredViews = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
|
||||
/// <summary>
|
||||
/// Views can be registered to avoid multiple inclusions in a page.
|
||||
/// <para>Only generate view content if this method returns true.</para>
|
||||
/// </summary>
|
||||
public bool RegisterView(String viewName)
|
||||
{
|
||||
#if DEBUG
|
||||
if (registeredViews.Contains(viewName))
|
||||
SaLogger.Warn(this.GetType().Name + ".RegisterView View already registered: " + viewName);
|
||||
#endif
|
||||
return registeredViews.Add(viewName);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Business components.
|
||||
@@ -156,33 +135,6 @@ namespace Saxonite.Net.Core.Web.Base.Models
|
||||
return new SelectList(items, "Code", "Desc");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Version parameter for includes.
|
||||
public String HrefVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
DateTime versionDate = SaxSystem.AssemblyBuildAt;
|
||||
if (!DateUtil.IsValid(versionDate) || SaxSystem.DebugMode)
|
||||
versionDate = DateTime.Now;
|
||||
return DateUtil.Format(versionDate, "yyyyMMdd" /*+ (SacsSystem.Debug ? "HHmm" : "")*/);
|
||||
}
|
||||
}
|
||||
// Additional includes.
|
||||
public HashSet<String> AdditionalFiles_CSS { get; set; } = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
public HashSet<String> AdditionalFiles_JS { get; set; } = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Redirection locations.
|
||||
public class RedirectLocationData
|
||||
{
|
||||
// Properties populated in Controller_Base.OnActionExecuted.
|
||||
public String Base { get; internal set; }
|
||||
public String Home { get; internal set; }
|
||||
public String Home_SessionExpired { get; internal set; }
|
||||
}
|
||||
public RedirectLocationData RedirectLocation { get; } = new RedirectLocationData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Link URLs.
|
||||
public class LinksData
|
||||
@@ -204,42 +156,6 @@ namespace Saxonite.Net.Core.Web.Base.Models
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Paging properties.
|
||||
public class DataPaging
|
||||
{
|
||||
private DbQuery.Paging paging { get; } = new DbQuery.Paging();
|
||||
public void PopulatePagingTo(DbQuery.Paging resultsPaging)
|
||||
{
|
||||
resultsPaging.PageLength = paging.PageLength;
|
||||
resultsPaging.PageNo = paging.PageNo;
|
||||
}
|
||||
public bool IsPaged { get { return paging.Paged; } }
|
||||
public uint PageNo { get { return paging.PageNo; } set { paging.PageNo = value; } }
|
||||
public String PageNoValue { get { return paging.PageNo.ToString(); } set { paging.PageNo = (uint)StringUtil.ToInt(value); } }
|
||||
public ushort PageLength { get { return paging.PageLength; } set { paging.PageLength = value; } }
|
||||
public String PageLengthValue { get { return paging.PageLength.ToString(); } set { paging.PageLength = (ushort)StringUtil.ToShort(value); } }
|
||||
public uint PageCount { get { return (PageLength > 0 ? (uint)Math.Ceiling((decimal)ItemTotal / paging.PageLength) : 0); } }
|
||||
public ushort ItemCount { get; set; }
|
||||
private ulong itemTotal = 0;
|
||||
public ulong ItemTotal
|
||||
{
|
||||
get { return itemTotal; }
|
||||
set
|
||||
{
|
||||
itemTotal = value;
|
||||
// Check whether the total number of items is less than the current page and reduce page no if needed.
|
||||
if (IsPaged && (PageNo - 1) * PageLength > itemTotal)
|
||||
PageNo = (uint)((itemTotal - 1) / PageLength + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
public DataPaging Paging { get; } = new DataPaging();
|
||||
public void PopulatePagingTo(DbQuery.Paging resultsPaging)
|
||||
{
|
||||
Paging.PopulatePagingTo(resultsPaging);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Form control value max length.
|
||||
@@ -487,35 +403,6 @@ namespace Saxonite.Net.Core.Web.Base.Models
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Messages.
|
||||
//-------------------------------------------------------------------
|
||||
public bool HasMessages()
|
||||
{
|
||||
return infoMessages.Count > 0 || warningMessages.Count > 0 || errorMessages.Count > 0;
|
||||
}
|
||||
public List<String> InfoMessages { get { return new List<string>(infoMessages); } }
|
||||
public List<String> WarningMessages { get { return new List<string>(warningMessages); } }
|
||||
public List<String> ErrorMessages { get { return new List<string>(errorMessages); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Form messages.
|
||||
public void AddInfoMessage(String message)
|
||||
{
|
||||
if (StringUtil.IsEmpty(StringUtil.TrimAll(message))) return;
|
||||
infoMessages.Add(message);
|
||||
}
|
||||
public void AddWarningMessage(String message)
|
||||
{
|
||||
if (StringUtil.IsEmpty(StringUtil.TrimAll(message))) return;
|
||||
warningMessages.Add(message);
|
||||
}
|
||||
public void AddErrorMessage(String message)
|
||||
{
|
||||
if (StringUtil.IsEmpty(StringUtil.TrimAll(message))) return;
|
||||
errorMessages.Add(message);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Procs.Data
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Object to persist upload file after request has terminated, and the Form File has been disposed.
|
||||
/// <para>- Too allow async processes to access the file after request completed.</para>
|
||||
/// </summary>
|
||||
public class UploadFileData
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
public UploadFileData(IFormFile dataFile)
|
||||
{
|
||||
ContentDisposition = dataFile.ContentDisposition;
|
||||
ContentType = dataFile.ContentType;
|
||||
FileName = dataFile.FileName;
|
||||
Length = dataFile.Length;
|
||||
Name = dataFile.Name;
|
||||
foreach (var header in dataFile.Headers)
|
||||
Headers.Add(header.Key, header.Value.ToString());
|
||||
// Load file data.
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
dataFile.CopyTo(stream);
|
||||
FileData = stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
/// <summary>Gets the raw Content-Disposition header of the uploaded file.</summary>
|
||||
public String ContentDisposition { get; }
|
||||
|
||||
/// <summary>Gets the raw Content-Type header of the uploaded file.</summary>
|
||||
public String ContentType { get; }
|
||||
|
||||
/// <summary>Gets the file name from the Content-Disposition header.</summary>
|
||||
public String FileName { get; }
|
||||
|
||||
/// <summary>Gets the header dictionary of the uploaded file.</summary>
|
||||
public Dictionary<String, String> Headers { get; } = new Dictionary<String, String>();
|
||||
|
||||
/// <summary>Gets the file length in bytes.</summary>
|
||||
public long Length { get; }
|
||||
|
||||
/// <summary>Gets the form field name from the Content-Disposition header.</summary>
|
||||
public String Name { get; }
|
||||
|
||||
/// <summary>File data.</summary>
|
||||
public byte[] FileData { get; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>Saxonite.Net.Core.Web</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user