Extract AspNetCore dependency to VAR.WebFormsCore.AspNetCore.

* Abstract HttpContext with IWebContext.
* Move AspNetCore dependant code to isolated classes.
* Downgrade VAR.WebFormsCore to netstandard2.0.
This commit is contained in:
2023-05-28 04:33:44 +02:00
parent f52d80e643
commit 1eb0fea182
53 changed files with 1847 additions and 1708 deletions

View File

@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using VAR.WebFormsCore.Code;
namespace VAR.WebFormsCore.AspNetCore.Code;
public class AspnetCoreWebContext : IWebContext
{
private readonly HttpContext _context;
public AspnetCoreWebContext(HttpContext context)
{
_context = context;
}
public string RequestPath => _context.Request.Path;
public string RequestMethod => _context.Request.Method;
private Dictionary<string, string?>? _requestHeader;
public Dictionary<string, string?> RequestHeader
{
get
{
if (_requestHeader == null)
{
_requestHeader = _context.Request.Headers
.ToDictionary(p => p.Key, p => p.Value[0]);
}
return _requestHeader;
}
}
private Dictionary<string, string?>? _requestQuery;
public Dictionary<string, string?> RequestQuery
{
get
{
if (_requestQuery == null)
{
_requestQuery = _context.Request.Query
.ToDictionary(p => p.Key, p => p.Value[0]);
}
return _requestQuery;
}
}
private Dictionary<string, string?>? _requestForm;
public Dictionary<string, string?> RequestForm
{
get
{
if (_requestForm == null)
{
if (_context.Request.Method == "POST")
{
_requestForm = _context.Request.Form
.ToDictionary(p => p.Key, p => p.Value[0]);
}
else
{
_requestForm = new Dictionary<string, string?>();
}
}
return _requestForm;
}
}
public void ResponseWrite(string text)
{
_context.Response.WriteAsync(text).GetAwaiter().GetResult();
}
public void ResponseWriteBin(byte[] content)
{
_context.Response.Body.WriteAsync(content).GetAwaiter().GetResult();
}
public void ResponseFlush()
{
_context.Response.Body.FlushAsync().GetAwaiter().GetResult();
}
public void ResponseRedirect(string url)
{
_context.Response.Redirect(url);
}
public bool ResponseHasStarted => _context.Response.HasStarted;
public int ResponseStatusCode
{
get => _context.Response.StatusCode;
set => _context.Response.StatusCode = value;
}
public string? ResponseContentType
{
get => _context.Response.ContentType;
set => _context.Response.ContentType = value;
}
public void SetResponseHeader(string key, string value)
{
_context.Response.Headers.SafeSet(key, value);
}
public void PrepareCacheableResponse()
{
const int secondsInDay = 86400;
_context.Response.Headers.SafeSet("Cache-Control", $"public, max-age={secondsInDay}");
string expireDate = DateTime.UtcNow.AddSeconds(secondsInDay)
.ToString("ddd, dd MMM yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
_context.Response.Headers.SafeSet("Expires", $"{expireDate} GMT");
}
public void PrepareUncacheableResponse()
{
_context.Response.Headers.SafeSet("Cache-Control", "max-age=0, no-cache, no-store");
string expireDate = DateTime.UtcNow.AddSeconds(-1500)
.ToString("ddd, dd MMM yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
_context.Response.Headers.SafeSet("Expires", $"{expireDate} GMT");
}
}

View File

@@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Http;
namespace VAR.WebFormsCore.AspNetCore.Code
{
public static class ExtensionMethods
{
#region IHeaderDictionary
public static void SafeSet(this IHeaderDictionary header, string key, string value) { header[key] = value; }
public static void SafeDel(this IHeaderDictionary header, string key)
{
if (header.ContainsKey(key)) { header.Remove(key); }
}
#endregion IHeaderDictionary
}
}

View File

@@ -0,0 +1,61 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using VAR.WebFormsCore.Code;
namespace VAR.WebFormsCore.AspNetCore.Code;
public class GlobalRouterMiddleware
{
private readonly GlobalRouter _globalRouter = new();
public GlobalRouterMiddleware(RequestDelegate next, IWebHostEnvironment env)
{
ServerHelpers.SetContentRoot(env.ContentRootPath);
}
public async Task Invoke(HttpContext httpContext)
{
httpContext.Response.Headers.SafeDel("Server");
httpContext.Response.Headers.SafeDel("X-Powered-By");
httpContext.Response.Headers.SafeSet("X-Content-Type-Options", "nosniff");
httpContext.Response.Headers.SafeSet("X-Frame-Options", "SAMEORIGIN");
httpContext.Response.Headers.SafeSet("X-XSS-Protection", "1; mode=block");
IWebContext webContext = new AspnetCoreWebContext(httpContext);
try
{
_globalRouter.RouteRequest(webContext);
await httpContext.Response.Body.FlushAsync();
}
catch (Exception ex)
{
if (IsIgnoreException(ex) == false)
{
// TODO: Implement better error logging
Console.WriteLine("!!!!!!!!!!");
Console.Write("Message: {0}\nStacktrace: {1}\n", ex.Message, ex.StackTrace);
GlobalErrorHandler.HandleError(webContext, ex);
}
}
}
private static bool IsIgnoreException(Exception ex) { return ex is ThreadAbortException; }
}
public static class GlobalRouterMiddlewareExtensions
{
public static IApplicationBuilder UseGlobalRouterMiddleware(
this IApplicationBuilder builder,
IWebHostEnvironment env
)
{
return builder.UseMiddleware<GlobalRouterMiddleware>(env);
}
}

View File

@@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace VAR.WebFormsCore.AspNetCore;
public static class DefaultMain
{
public static void WebFormCoreMain(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
private static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}

View File

@@ -0,0 +1,24 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection;
using VAR.WebFormsCore.AspNetCore.Code;
namespace VAR.WebFormsCore.AspNetCore;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// If using Kestrel:
services.Configure<KestrelServerOptions>(options =>
{
options.AddServerHeader = false;
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseGlobalRouterMiddleware(env);
}
}

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\VAR.WebFormsCore\VAR.WebFormsCore.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,3 +1,4 @@
using System;
using VAR.WebFormsCore.Code; using VAR.WebFormsCore.Code;
using VAR.WebFormsCore.Controls; using VAR.WebFormsCore.Controls;
using VAR.WebFormsCore.Pages; using VAR.WebFormsCore.Pages;

View File

@@ -1,17 +1,12 @@
namespace VAR.WebFormsCore.TestWebApp using VAR.WebFormsCore.AspNetCore;
{
public static class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
private static IHostBuilder CreateHostBuilder(string[] args) => namespace VAR.WebFormsCore.TestWebApp;
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => public static class Program
{ {
webBuilder.UseStartup<Startup>(); public static void Main(string[] args)
}); {
DefaultMain.WebFormCoreMain(args);
} }
} }

View File

@@ -1,22 +0,0 @@
using Microsoft.AspNetCore.Server.Kestrel.Core;
using VAR.WebFormsCore.Code;
namespace VAR.WebFormsCore.TestWebApp
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// If using Kestrel:
services.Configure<KestrelServerOptions>(options =>
{
options.AddServerHeader = false;
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseGlobalRouterMiddleware(env);
}
}
}

View File

@@ -1,3 +1,4 @@
using System.Collections.Generic;
using VAR.WebFormsCore.Code; using VAR.WebFormsCore.Code;
namespace VAR.WebFormsCore.TestWebApp; namespace VAR.WebFormsCore.TestWebApp;
@@ -14,12 +15,12 @@ public class TestWebAppGlobalConfig : IGlobalConfig
public List<string> AllowedExtensions { get; } = new() public List<string> AllowedExtensions { get; } = new()
{ ".png", ".jpg", ".jpeg", ".gif", ".ico", ".wav", ".mp3", ".ogg", ".mp4", ".webm", ".webp", ".mkv", ".avi" }; { ".png", ".jpg", ".jpeg", ".gif", ".ico", ".wav", ".mp3", ".ogg", ".mp4", ".webm", ".webp", ".mkv", ".avi" };
public bool IsUserAuthenticated(HttpContext context) public bool IsUserAuthenticated(IWebContext context)
{ {
return false; return false;
} }
public void UserDeauthenticate(HttpContext context) public void UserDeauthenticate(IWebContext context)
{ {
} }
} }

View File

@@ -3,10 +3,10 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\VAR.WebFormsCore.AspNetCore\VAR.WebFormsCore.AspNetCore.csproj" />
<ProjectReference Include="..\VAR.WebFormsCore\VAR.WebFormsCore.csproj" /> <ProjectReference Include="..\VAR.WebFormsCore\VAR.WebFormsCore.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -4,6 +4,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VAR.WebFormsCore", "VAR.Web
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VAR.WebFormsCore.TestWebApp", "VAR.WebFormsCore.TestWebApp\VAR.WebFormsCore.TestWebApp.csproj", "{0D81464B-802D-4ECA-92C8-427F481A4583}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VAR.WebFormsCore.TestWebApp", "VAR.WebFormsCore.TestWebApp\VAR.WebFormsCore.TestWebApp.csproj", "{0D81464B-802D-4ECA-92C8-427F481A4583}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VAR.WebFormsCore.AspNetCore", "VAR.WebFormsCore.AspNetCore\VAR.WebFormsCore.AspNetCore.csproj", "{378B98EF-9269-4B96-B894-1B0F9B24EEC2}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -18,5 +20,9 @@ Global
{0D81464B-802D-4ECA-92C8-427F481A4583}.Debug|Any CPU.Build.0 = Debug|Any CPU {0D81464B-802D-4ECA-92C8-427F481A4583}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D81464B-802D-4ECA-92C8-427F481A4583}.Release|Any CPU.ActiveCfg = Release|Any CPU {0D81464B-802D-4ECA-92C8-427F481A4583}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D81464B-802D-4ECA-92C8-427F481A4583}.Release|Any CPU.Build.0 = Release|Any CPU {0D81464B-802D-4ECA-92C8-427F481A4583}.Release|Any CPU.Build.0 = Release|Any CPU
{378B98EF-9269-4B96-B894-1B0F9B24EEC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{378B98EF-9269-4B96-B894-1B0F9B24EEC2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{378B98EF-9269-4B96-B894-1B0F9B24EEC2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{378B98EF-9269-4B96-B894-1B0F9B24EEC2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@@ -3,105 +3,103 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using Microsoft.AspNetCore.Http;
namespace VAR.WebFormsCore.Code namespace VAR.WebFormsCore.Code;
public class Bundler
{ {
public class Bundler #region Declarations
private readonly Assembly? _assembly;
private readonly string? _assemblyNamespace;
private List<string>? _assemblyFiles;
private readonly string? _absolutePath;
private List<string>? _absoluteFiles;
#endregion Declarations
#region Properties
private List<string> AssemblyFiles
{ {
#region Declarations get
private readonly Assembly? _assembly;
private readonly string? _assemblyNamespace;
private List<string>? _assemblyFiles;
private readonly string? _absolutePath;
private List<string>? _absoluteFiles;
#endregion Declarations
#region Properties
private List<string> AssemblyFiles
{ {
get if (_assemblyFiles != null) { return _assemblyFiles; }
if (_assembly == null || string.IsNullOrEmpty(_assemblyNamespace))
{ {
if (_assemblyFiles != null) { return _assemblyFiles; } _assemblyFiles = new List<string>();
if (_assembly == null || string.IsNullOrEmpty(_assemblyNamespace))
{
_assemblyFiles = new List<string>();
return _assemblyFiles;
}
string assemblyPath = string.Concat(_assembly.GetName().Name, ".", _assemblyNamespace, ".");
_assemblyFiles = _assembly.GetManifestResourceNames().Where(r => r.StartsWith(assemblyPath)).ToList();
return _assemblyFiles; return _assemblyFiles;
} }
string assemblyPath = string.Concat(_assembly.GetName().Name, ".", _assemblyNamespace, ".");
_assemblyFiles = _assembly.GetManifestResourceNames().Where(r => r.StartsWith(assemblyPath)).ToList();
return _assemblyFiles;
} }
}
private List<string> AbsoluteFiles private List<string> AbsoluteFiles
{
get
{ {
get if (_absoluteFiles != null) { return _absoluteFiles; }
if (string.IsNullOrEmpty(_absolutePath))
{ {
if (_absoluteFiles != null) { return _absoluteFiles; } _absoluteFiles = new List<string>();
if (string.IsNullOrEmpty(_absolutePath))
{
_absoluteFiles = new List<string>();
return _absoluteFiles;
}
DirectoryInfo dir = new DirectoryInfo(_absolutePath);
FileInfo[] files = dir.GetFiles();
_absoluteFiles = files.OrderBy(file => file.FullName).Select(file2 => file2.FullName).ToList();
return _absoluteFiles; return _absoluteFiles;
} }
DirectoryInfo dir = new DirectoryInfo(_absolutePath);
FileInfo[] files = dir.GetFiles();
_absoluteFiles = files.OrderBy(file => file.FullName).Select(file2 => file2.FullName).ToList();
return _absoluteFiles;
} }
#endregion Properties
#region Creator
public Bundler(Assembly? assembly = null, string? assemblyNamespace = null, string? absolutePath = null)
{
_assembly = assembly;
_assemblyNamespace = assemblyNamespace;
_absolutePath = absolutePath;
}
#endregion Creator
#region Public methods
private static readonly Encoding Utf8Encoding = new UTF8Encoding();
public void WriteResponse(HttpResponse response, string contentType)
{
StringWriter textWriter = new StringWriter();
response.ContentType = contentType;
foreach (string fileName in AssemblyFiles)
{
Stream? resourceStream = _assembly?.GetManifestResourceStream(fileName);
if (resourceStream != null)
{
string fileContent = new StreamReader(resourceStream).ReadToEnd();
textWriter.Write(fileContent);
}
textWriter.Write("\n\n");
}
foreach (string fileName in AbsoluteFiles)
{
string fileContent = File.ReadAllText(fileName);
textWriter.Write(fileContent);
textWriter.Write("\n\n");
}
byte[] byteObject = Utf8Encoding.GetBytes(textWriter.ToString());
response.Body.WriteAsync(byteObject).GetAwaiter().GetResult();
}
#endregion Public methods
} }
#endregion Properties
#region Creator
public Bundler(Assembly? assembly = null, string? assemblyNamespace = null, string? absolutePath = null)
{
_assembly = assembly;
_assemblyNamespace = assemblyNamespace;
_absolutePath = absolutePath;
}
#endregion Creator
#region Public methods
private static readonly Encoding Utf8Encoding = new UTF8Encoding();
public void WriteResponse(IWebContext context, string contentType)
{
StringWriter textWriter = new StringWriter();
context.ResponseContentType = contentType;
foreach (string fileName in AssemblyFiles)
{
Stream? resourceStream = _assembly?.GetManifestResourceStream(fileName);
if (resourceStream != null)
{
string fileContent = new StreamReader(resourceStream).ReadToEnd();
textWriter.Write(fileContent);
}
textWriter.Write("\n\n");
}
foreach (string fileName in AbsoluteFiles)
{
string fileContent = File.ReadAllText(fileName);
textWriter.Write(fileContent);
textWriter.Write("\n\n");
}
byte[] byteObject = Utf8Encoding.GetBytes(textWriter.ToString());
context.ResponseWriteBin(byteObject);
}
#endregion Public methods
} }

View File

@@ -1,66 +1,45 @@
using System;
using System.Text; using System.Text;
using Microsoft.AspNetCore.Http;
using VAR.Json; using VAR.Json;
namespace VAR.WebFormsCore.Code namespace VAR.WebFormsCore.Code;
{
public static class ExtensionMethods
{
#region HttpContext
public static string GetRequestParameter(this HttpContext context, string parameter) public static class ExtensionMethods
{
#region IWebContext
public static string GetRequestParameter(this IWebContext context, string parameter)
{
if (context.RequestMethod == "POST")
{ {
if (context.Request.Method == "POST") foreach (string key in context.RequestForm.Keys)
{ {
foreach (string key in context.Request.Form.Keys) if (string.IsNullOrEmpty(key) == false && key == parameter)
{ {
if (string.IsNullOrEmpty(key) == false && key == parameter) { return context.Request.Form[key][0] ?? string.Empty; } return context.RequestForm[key] ?? string.Empty;
} }
} }
}
foreach (string key in context.Request.Query.Keys) foreach (string key in context.RequestQuery.Keys)
{
if (string.IsNullOrEmpty(key) == false && key == parameter)
{ {
if (string.IsNullOrEmpty(key) == false && key == parameter) { return context.Request.Query[key][0] ?? string.Empty; } return context.RequestQuery[key] ?? string.Empty;
} }
return string.Empty;
} }
private static readonly Encoding Utf8Encoding = new UTF8Encoding(); return string.Empty;
public static void ResponseObject(this HttpContext context, object obj, string contentType = "text/json")
{
context.Response.ContentType = contentType;
string strObject = JsonWriter.WriteObject(obj);
byte[] byteObject = Utf8Encoding.GetBytes(strObject);
context.Response.Body.WriteAsync(byteObject).GetAwaiter().GetResult();
}
public static void SafeSet(this IHeaderDictionary header, string key, string value) { header[key] = value; }
public static void SafeDel(this IHeaderDictionary header, string key)
{
if (header.ContainsKey(key)) { header.Remove(key); }
}
public static void PrepareCacheableResponse(this HttpResponse response)
{
const int secondsInDay = 86400;
response.Headers.SafeSet("Cache-Control", $"public, max-age={secondsInDay}");
string expireDate = DateTime.UtcNow.AddSeconds(secondsInDay)
.ToString("ddd, dd MMM yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
response.Headers.SafeSet("Expires", expireDate + " GMT");
}
public static void PrepareUncacheableResponse(this HttpResponse response)
{
response.Headers.SafeSet("Cache-Control", "max-age=0, no-cache, no-store");
string expireDate = DateTime.UtcNow.AddSeconds(-1500)
.ToString("ddd, dd MMM yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
response.Headers.SafeSet("Expires", expireDate + " GMT");
}
#endregion HttpContext
} }
private static readonly Encoding Utf8Encoding = new UTF8Encoding();
public static void ResponseObject(this IWebContext context, object obj, string contentType = "text/json")
{
context.ResponseContentType = contentType;
string strObject = JsonWriter.WriteObject(obj);
byte[] byteObject = Utf8Encoding.GetBytes(strObject);
context.ResponseWriteBin(byteObject);
}
#endregion IWebContext
} }

View File

@@ -1,54 +1,52 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.AspNetCore.Http;
namespace VAR.WebFormsCore.Code namespace VAR.WebFormsCore.Code;
public static class GlobalConfig
{ {
public static class GlobalConfig private static IGlobalConfig? _globalConfig;
public static IGlobalConfig Get()
{ {
private static IGlobalConfig? _globalConfig; if (_globalConfig != null) { return _globalConfig; }
public static IGlobalConfig Get() Type iGlobalConfig = typeof(IGlobalConfig);
Type? foundGlobalConfig = AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(x => x.GetTypes())
.FirstOrDefault(
x =>
x is { IsAbstract: false, IsInterface: false, IsPublic: true } &&
iGlobalConfig.IsAssignableFrom(x)
);
if(foundGlobalConfig != null)
{ {
if (_globalConfig != null) { return _globalConfig; } _globalConfig = ObjectActivator.CreateInstance(foundGlobalConfig) as IGlobalConfig;
Type iGlobalConfig = typeof(IGlobalConfig);
Type? foundGlobalConfig = AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(x => x.GetTypes())
.FirstOrDefault(
x =>
x is { IsAbstract: false, IsInterface: false, IsPublic: true } &&
iGlobalConfig.IsAssignableFrom(x)
);
if(foundGlobalConfig != null)
{
_globalConfig = ObjectActivator.CreateInstance(foundGlobalConfig) as IGlobalConfig;
}
return _globalConfig ??= new DefaultGlobalConfig();
} }
// TODO: Better default global config return _globalConfig ??= new DefaultGlobalConfig();
private class DefaultGlobalConfig : IGlobalConfig }
// TODO: Better default global config
private class DefaultGlobalConfig : IGlobalConfig
{
public string Title => string.Empty;
public string TitleSeparator => string.Empty;
public string Author => string.Empty;
public string Copyright => string.Empty;
public string DefaultHandler => string.Empty;
public string LoginHandler => string.Empty;
public List<string> AllowedExtensions { get; } = new();
public bool IsUserAuthenticated(IWebContext context)
{ {
public string Title => string.Empty; return false;
public string TitleSeparator => string.Empty; }
public string Author => string.Empty;
public string Copyright => string.Empty;
public string DefaultHandler => string.Empty;
public string LoginHandler => string.Empty;
public List<string> AllowedExtensions { get; } = new();
public bool IsUserAuthenticated(HttpContext context) public void UserDeauthenticate(IWebContext context)
{ {
return false;
}
public void UserDeauthenticate(HttpContext context)
{
}
} }
} }
} }

View File

@@ -1,66 +1,64 @@
using System; using System;
using System.Text; using System.Text;
using Microsoft.AspNetCore.Http;
using VAR.WebFormsCore.Pages; using VAR.WebFormsCore.Pages;
namespace VAR.WebFormsCore.Code namespace VAR.WebFormsCore.Code;
public static class GlobalErrorHandler
{ {
public static class GlobalErrorHandler #region Private methods
private static void ShowInternalError(IWebContext context, Exception ex)
{ {
#region Private methods try
private static void ShowInternalError(HttpContext context, Exception ex)
{ {
try context.ResponseStatusCode = 500;
StringBuilder sbOutput = new StringBuilder();
sbOutput.Append("<h2>Internal error</h2>");
Exception? exAux = ex;
while (exAux != null)
{ {
context.Response.StatusCode = 500; sbOutput.Append($"<p><b>Message:</b> {exAux.Message}</p>");
sbOutput.Append($"<p><b>StackTrace:</b></p> <pre><code>{exAux.StackTrace}</code></pre>");
StringBuilder sbOutput = new StringBuilder(); exAux = exAux.InnerException;
sbOutput.Append("<h2>Internal error</h2>");
Exception? exAux = ex;
while (exAux != null)
{
sbOutput.Append($"<p><b>Message:</b> {exAux.Message}</p>");
sbOutput.Append($"<p><b>StackTrace:</b></p> <pre><code>{exAux.StackTrace}</code></pre>");
exAux = exAux.InnerException;
}
// Fill response to 512 bytes to avoid browser "beauty" response of errors.
long fillResponse = 512 - sbOutput.Length;
if (fillResponse > 0)
{
sbOutput.Append("<!--");
for (int i = 0; i < fillResponse; i++) { sbOutput.Append("A"); }
sbOutput.Append("-->");
}
context.Response.WriteAsync(sbOutput.ToString()).GetAwaiter().GetResult();
context.Response.Body.FlushAsync().GetAwaiter().GetResult();
} }
catch
// Fill response to 512 bytes to avoid browser "beauty" response of errors.
long fillResponse = 512 - sbOutput.Length;
if (fillResponse > 0)
{ {
/* Nom nom nom */ sbOutput.Append("<!--");
for (int i = 0; i < fillResponse; i++) { sbOutput.Append("A"); }
sbOutput.Append("-->");
} }
context.ResponseWrite(sbOutput.ToString());
context.ResponseFlush();
} }
catch
#endregion Private methods
#region Public methods
public static void HandleError(HttpContext context, Exception ex)
{ {
try /* Nom nom nom */
{
IHttpHandler frmError = new FrmError(ex);
//context.Response.Clear();
//context.Handler = frmError;
frmError.ProcessRequest(context);
context.Response.Body.FlushAsync().GetAwaiter().GetResult();
}
catch { ShowInternalError(context, ex); }
} }
#endregion Public methods
} }
#endregion Private methods
#region Public methods
public static void HandleError(IWebContext context, Exception ex)
{
try
{
IHttpHandler frmError = new FrmError(ex);
//context.Response.Clear();
//context.Handler = frmError;
frmError.ProcessRequest(context);
context.ResponseFlush();
}
catch { ShowInternalError(context, ex); }
}
#endregion Public methods
} }

View File

@@ -0,0 +1,111 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace VAR.WebFormsCore.Code;
public class GlobalRouter
{
public void RouteRequest(IWebContext context)
{
string path = context.RequestPath;
string file = Path.GetFileName(path);
if (string.IsNullOrEmpty(file)) { file = GlobalConfig.Get().DefaultHandler; }
// Pass allowed extensions requests
string extension = Path.GetExtension(path).ToLower();
if (GlobalConfig.Get().AllowedExtensions.Contains(extension))
{
string filePath = ServerHelpers.MapContentPath(path);
if (File.Exists(filePath))
{
StaticFileHelper.ResponseStaticFile(context, filePath);
return;
}
else
{
// TODO: FrmNotFound
throw new Exception($"NotFound: {path}");
}
}
IHttpHandler? handler = GetHandler(file);
if (handler == null)
{
// TODO: FrmNotFound
throw new Exception($"NotFound: {path}");
}
// Use handler
handler.ProcessRequest(context);
}
private static readonly Dictionary<string, Type> Handlers = new();
private static IHttpHandler? GetHandler(string typeName)
{
if (string.IsNullOrEmpty(typeName)) { return null; }
Type? type;
lock (Handlers)
{
if (Handlers.TryGetValue(typeName, out type))
{
IHttpHandler? handler = ObjectActivator.CreateInstance(type) as IHttpHandler;
return handler;
}
}
// Search type on executing assembly
Assembly asm = Assembly.GetExecutingAssembly();
Type[] types = asm.GetTypes();
foreach (Type typeAux in types)
{
if (typeAux.FullName?.EndsWith(typeName) == true)
{
type = typeAux;
break;
}
}
// Search type on all loaded assemblies
if (type == null)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly asmAux in assemblies)
{
types = asmAux.GetTypes();
foreach (Type typeAux in types)
{
if (typeAux.FullName?.EndsWith(typeName) != true) { continue; }
type = typeAux;
break;
}
if (type != null) { break; }
}
}
// Use found type
if (type != null)
{
IHttpHandler? handler = ObjectActivator.CreateInstance(type) as IHttpHandler;
if (handler != null)
{
lock (Handlers)
{
if (Handlers.ContainsKey(typeName) == false)
{
Handlers.Add(typeName, type);
}
}
}
return handler;
}
return null;
}
}

View File

@@ -1,158 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
namespace VAR.WebFormsCore.Code
{
public class GlobalRouterMiddleware
{
public GlobalRouterMiddleware(RequestDelegate next, IWebHostEnvironment env)
{
ServerHelpers.SetContentRoot(env.ContentRootPath);
}
public async Task Invoke(HttpContext httpContext)
{
httpContext.Response.Headers.SafeDel("Server");
httpContext.Response.Headers.SafeDel("X-Powered-By");
httpContext.Response.Headers.SafeSet("X-Content-Type-Options", "nosniff");
httpContext.Response.Headers.SafeSet("X-Frame-Options", "SAMEORIGIN");
httpContext.Response.Headers.SafeSet("X-XSS-Protection", "1; mode=block");
try
{
RouteRequest(httpContext);
await httpContext.Response.Body.FlushAsync();
}
catch (Exception ex)
{
if (IsIgnoreException(ex) == false)
{
// TODO: Implement better error logging
Console.WriteLine("!!!!!!!!!!");
Console.Write("Message: {0}\nStacktrace: {1}\n", ex.Message, ex.StackTrace);
GlobalErrorHandler.HandleError(httpContext, ex);
}
}
}
private static bool IsIgnoreException(Exception ex) { return ex is ThreadAbortException; }
private void RouteRequest(HttpContext context)
{
string path = context.Request.Path;
string file = Path.GetFileName(path);
if (string.IsNullOrEmpty(file)) { file = GlobalConfig.Get().DefaultHandler; }
// Pass allowed extensions requests
string extension = Path.GetExtension(path).ToLower();
if (GlobalConfig.Get().AllowedExtensions.Contains(extension))
{
string filePath = ServerHelpers.MapContentPath(path);
if (File.Exists(filePath))
{
StaticFileHelper.ResponseStaticFile(context, filePath);
return;
}
else
{
// TODO: FrmNotFound
throw new Exception($"NotFound: {path}");
}
}
IHttpHandler? handler = GetHandler(file);
if (handler == null)
{
// TODO: FrmNotFound
throw new Exception($"NotFound: {path}");
}
// Use handler
handler.ProcessRequest(context);
}
private static readonly Dictionary<string, Type> Handlers = new();
private static IHttpHandler? GetHandler(string typeName)
{
if (string.IsNullOrEmpty(typeName)) { return null; }
Type? type;
lock (Handlers)
{
if (Handlers.TryGetValue(typeName, out type))
{
IHttpHandler? handler = ObjectActivator.CreateInstance(type) as IHttpHandler;
return handler;
}
}
// Search type on executing assembly
Assembly asm = Assembly.GetExecutingAssembly();
Type[] types = asm.GetTypes();
foreach (Type typeAux in types)
{
if (typeAux.FullName?.EndsWith(typeName) == true)
{
type = typeAux;
break;
}
}
// Search type on all loaded assemblies
if (type == null)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly asmAux in assemblies)
{
types = asmAux.GetTypes();
foreach (Type typeAux in types)
{
if (typeAux.FullName?.EndsWith(typeName) != true) { continue; }
type = typeAux;
break;
}
if (type != null) { break; }
}
}
// Use found type
if (type != null)
{
IHttpHandler? handler = ObjectActivator.CreateInstance(type) as IHttpHandler;
if (handler != null)
{
lock (Handlers)
{
Handlers.TryAdd(typeName, type);
}
}
return handler;
}
return null;
}
}
public static class GlobalRouterMiddlewareExtensions
{
public static IApplicationBuilder UseGlobalRouterMiddleware(
this IApplicationBuilder builder,
IWebHostEnvironment env
)
{
return builder.UseMiddleware<GlobalRouterMiddleware>(env);
}
}
}

View File

@@ -1,19 +1,17 @@
using System.Collections.Generic; using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
namespace VAR.WebFormsCore.Code namespace VAR.WebFormsCore.Code;
public interface IGlobalConfig
{ {
public interface IGlobalConfig string Title { get; }
{ string TitleSeparator { get; }
string Title { get; } string Author { get; }
string TitleSeparator { get; } string Copyright { get; }
string Author { get; } string DefaultHandler { get; }
string Copyright { get; } string LoginHandler { get; }
string DefaultHandler { get; } List<string> AllowedExtensions { get; }
string LoginHandler { get; }
List<string> AllowedExtensions { get; }
bool IsUserAuthenticated(HttpContext context); bool IsUserAuthenticated(IWebContext context);
void UserDeauthenticate(HttpContext context); void UserDeauthenticate(IWebContext context);
}
} }

View File

@@ -1,9 +1,6 @@
using Microsoft.AspNetCore.Http; namespace VAR.WebFormsCore.Code;
namespace VAR.WebFormsCore.Code public interface IHttpHandler
{ {
public interface IHttpHandler void ProcessRequest(IWebContext context);
{
void ProcessRequest(HttpContext context);
}
} }

View File

@@ -0,0 +1,25 @@
using System.Collections.Generic;
namespace VAR.WebFormsCore.Code;
public interface IWebContext
{
string RequestPath { get; }
string RequestMethod { get; }
Dictionary<string, string?> RequestForm { get; }
Dictionary<string, string?> RequestQuery { get; }
Dictionary<string, string?> RequestHeader { get; }
void ResponseWrite(string text);
void ResponseWriteBin(byte[] content);
void ResponseFlush();
void ResponseRedirect(string url);
bool ResponseHasStarted { get; }
int ResponseStatusCode { get; set; }
string? ResponseContentType { get; set; }
void SetResponseHeader(string key, string value);
void PrepareCacheableResponse();
void PrepareUncacheableResponse();
}

View File

@@ -2,95 +2,94 @@
using System.IO; using System.IO;
using VAR.Json; using VAR.Json;
namespace VAR.WebFormsCore.Code namespace VAR.WebFormsCore.Code;
public static class MultiLang
{ {
public static class MultiLang private static string GetPrivatePath(string baseDir, string fileName)
{ {
private static string GetPrivatePath(string baseDir, string fileName) string currentDir = Directory.GetCurrentDirectory();
string privatePath = Path.Combine(currentDir, baseDir);
while (Directory.Exists(privatePath) == false)
{ {
string currentDir = Directory.GetCurrentDirectory(); DirectoryInfo? dirInfo = Directory.GetParent(currentDir);
string privatePath = Path.Combine(currentDir, baseDir); if (dirInfo == null) { break; }
while (Directory.Exists(privatePath) == false)
{
DirectoryInfo? dirInfo = Directory.GetParent(currentDir);
if (dirInfo == null) { break; }
currentDir = dirInfo.FullName; currentDir = dirInfo.FullName;
privatePath = Path.Combine(currentDir, baseDir); privatePath = Path.Combine(currentDir, baseDir);
}
return Path.Combine(privatePath, fileName);
} }
private static Dictionary<string, Dictionary<string, object>?>? _literals; return Path.Combine(privatePath, fileName);
}
private static void InitializeLiterals() private static Dictionary<string, Dictionary<string, object>?>? _literals;
private static void InitializeLiterals()
{
_literals = new Dictionary<string, Dictionary<string, object>?>();
JsonParser jsonParser = new JsonParser();
foreach (string lang in new[] {"en", "es"})
{ {
_literals = new Dictionary<string, Dictionary<string, object>?>(); string filePath = GetPrivatePath("Resources", $"Literals.{lang}.json");
if (File.Exists(filePath) == false) { continue; }
JsonParser jsonParser = new JsonParser(); string strJsonLiteralsLanguage = File.ReadAllText(filePath);
foreach (string lang in new[] {"en", "es"}) object result = jsonParser.Parse(strJsonLiteralsLanguage);
{ _literals.Add(lang, result as Dictionary<string, object>);
string filePath = GetPrivatePath("Resources", $"Literals.{lang}.json");
if (File.Exists(filePath) == false) { continue; }
string strJsonLiteralsLanguage = File.ReadAllText(filePath);
object result = jsonParser.Parse(strJsonLiteralsLanguage);
_literals.Add(lang, result as Dictionary<string, object>);
}
}
private const string DefaultLanguage = "en";
private static string GetUserLanguage()
{
// TODO: Needs replacement for ctx.Request.UserLanguages
//HttpContext ctx = HttpContext.Current;
//if (ctx != null)
//{
// if (ctx.Items["UserLang"] != null)
// {
// return (string)ctx.Items["UserLang"];
// }
// IEnumerable<string> userLanguages = ctx.Request.UserLanguages
// .Select(lang =>
// {
// if (lang.Contains(";"))
// {
// lang = lang.Split(';')[0];
// }
// if (lang.Contains("-"))
// {
// lang = lang.Split('-')[0];
// }
// return lang.ToLower();
// })
// .Where(lang => _literals.ContainsKey(lang));
// string userLang = userLanguages.FirstOrDefault() ?? _defaultLanguage;
// ctx.Items["UserLang"] = userLang;
// return userLang;
//}
return DefaultLanguage;
}
public static string GetLiteral(string resource, string? culture = null)
{
if (_literals == null) { InitializeLiterals(); }
culture ??= GetUserLanguage();
if (_literals == null || _literals.ContainsKey(culture) == false) { return resource; }
Dictionary<string, object>? literalCurrentCulture = _literals[culture];
if (literalCurrentCulture == null || literalCurrentCulture.ContainsKey(resource) == false)
{
return resource;
}
return (literalCurrentCulture[resource] as string) ?? resource;
} }
} }
private const string DefaultLanguage = "en";
private static string GetUserLanguage()
{
// TODO: Needs replacement for ctx.Request.UserLanguages
//HttpContext ctx = HttpContext.Current;
//if (ctx != null)
//{
// if (ctx.Items["UserLang"] != null)
// {
// return (string)ctx.Items["UserLang"];
// }
// IEnumerable<string> userLanguages = ctx.Request.UserLanguages
// .Select(lang =>
// {
// if (lang.Contains(";"))
// {
// lang = lang.Split(';')[0];
// }
// if (lang.Contains("-"))
// {
// lang = lang.Split('-')[0];
// }
// return lang.ToLower();
// })
// .Where(lang => _literals.ContainsKey(lang));
// string userLang = userLanguages.FirstOrDefault() ?? _defaultLanguage;
// ctx.Items["UserLang"] = userLang;
// return userLang;
//}
return DefaultLanguage;
}
public static string GetLiteral(string resource, string? culture = null)
{
if (_literals == null) { InitializeLiterals(); }
culture ??= GetUserLanguage();
if (_literals == null || _literals.ContainsKey(culture) == false) { return resource; }
Dictionary<string, object>? literalCurrentCulture = _literals[culture];
if (literalCurrentCulture == null || literalCurrentCulture.ContainsKey(resource) == false)
{
return resource;
}
return (literalCurrentCulture[resource] as string) ?? resource;
}
} }

View File

@@ -2,32 +2,31 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq.Expressions; using System.Linq.Expressions;
namespace VAR.WebFormsCore.Code namespace VAR.WebFormsCore.Code;
public static class ObjectActivator
{ {
public static class ObjectActivator private static readonly Dictionary<Type, Func<object>> Creators = new();
private static Func<object> GetLambdaNew(Type type)
{ {
private static readonly Dictionary<Type, Func<object>> Creators = new(); lock (Creators)
private static Func<object> GetLambdaNew(Type type)
{ {
lock (Creators) if (Creators.TryGetValue(type, out var creator)) { return creator; }
{
if (Creators.TryGetValue(type, out var creator)) { return creator; }
NewExpression newExp = Expression.New(type); NewExpression newExp = Expression.New(type);
LambdaExpression lambda = Expression.Lambda(typeof(Func<object>), newExp); LambdaExpression lambda = Expression.Lambda(typeof(Func<object>), newExp);
Func<object> compiledLambdaNew = (Func<object>) lambda.Compile(); Func<object> compiledLambdaNew = (Func<object>) lambda.Compile();
Creators.Add(type, compiledLambdaNew); Creators.Add(type, compiledLambdaNew);
return Creators[type]; return Creators[type];
}
}
public static object CreateInstance(Type type)
{
Func<object> creator = GetLambdaNew(type);
return creator();
} }
} }
public static object CreateInstance(Type type)
{
Func<object> creator = GetLambdaNew(type);
return creator();
}
} }

View File

@@ -1,23 +1,21 @@
using System.Reflection; using System.Reflection;
using Microsoft.AspNetCore.Http;
namespace VAR.WebFormsCore.Code namespace VAR.WebFormsCore.Code;
public class ScriptsBundler : IHttpHandler
{ {
public class ScriptsBundler : IHttpHandler #region IHttpHandler
public void ProcessRequest(IWebContext context)
{ {
#region IHttpHandler Bundler bundler = new Bundler(
assembly: Assembly.GetExecutingAssembly(),
public void ProcessRequest(HttpContext context) assemblyNamespace: "Scripts",
{ absolutePath: ServerHelpers.MapContentPath("Scripts")
Bundler bundler = new Bundler( );
assembly: Assembly.GetExecutingAssembly(), context.PrepareCacheableResponse();
assemblyNamespace: "Scripts", bundler.WriteResponse(context, "text/javascript");
absolutePath: ServerHelpers.MapContentPath("Scripts")
);
context.Response.PrepareCacheableResponse();
bundler.WriteResponse(context.Response, "text/javascript");
}
#endregion IHttpHandler
} }
#endregion IHttpHandler
} }

View File

@@ -1,118 +1,117 @@
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
namespace VAR.WebFormsCore.Code namespace VAR.WebFormsCore.Code;
public static class ServerHelpers
{ {
public static class ServerHelpers private static string? _contentRoot;
public static void SetContentRoot(string contentRoot)
{ {
private static string? _contentRoot; _contentRoot = contentRoot;
}
public static void SetContentRoot(string contentRoot) public static string MapContentPath(string path)
{
string mappedPath = string.Concat(_contentRoot, "/", path);
return mappedPath;
}
public static string HtmlEncode(string text)
{
if (string.IsNullOrEmpty(text))
{ {
_contentRoot = contentRoot; return text;
} }
public static string MapContentPath(string path) StringBuilder sbResult = new();
foreach (var ch in text)
{ {
string mappedPath = string.Concat(_contentRoot, "/", path); switch (ch)
return mappedPath;
}
public static string HtmlEncode(string text)
{
if (string.IsNullOrEmpty(text))
{ {
return text; case '<':
} sbResult.Append("&lt;");
break;
StringBuilder sbResult = new(); case '>':
sbResult.Append("&gt;");
foreach (var ch in text) break;
{ case '"':
switch (ch) sbResult.Append("&quot;");
break;
case '\'':
sbResult.Append("&#39;");
break;
case '&':
sbResult.Append("&amp;");
break;
default:
{ {
case '<': if (ch > 127)
sbResult.Append("&lt;");
break;
case '>':
sbResult.Append("&gt;");
break;
case '"':
sbResult.Append("&quot;");
break;
case '\'':
sbResult.Append("&#39;");
break;
case '&':
sbResult.Append("&amp;");
break;
default:
{ {
if (ch > 127) sbResult.Append("&#");
{ sbResult.Append(((int)ch).ToString(NumberFormatInfo.InvariantInfo));
sbResult.Append("&#"); sbResult.Append(';');
sbResult.Append(((int)ch).ToString(NumberFormatInfo.InvariantInfo));
sbResult.Append(';');
}
else
{
sbResult.Append(ch);
}
break;
} }
else
{
sbResult.Append(ch);
}
break;
} }
} }
return sbResult.ToString();
} }
public static string UrlEncode(string text) return sbResult.ToString();
}
public static string UrlEncode(string text)
{
if (string.IsNullOrEmpty(text))
{ {
if (string.IsNullOrEmpty(text)) return text;
{
return text;
}
StringBuilder sbResult = new();
foreach (var ch in text)
{
if (ch == ' ')
{
sbResult.Append('+');
}
else if (IsUrlSafe(ch) == false)
{
sbResult.Append($"%{ch:X02}");
}
else
{
sbResult.Append(ch);
}
}
return sbResult.ToString();
} }
private static bool IsUrlSafe(char ch) StringBuilder sbResult = new();
foreach (var ch in text)
{ {
if ( if (ch == ' ')
(ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') ||
ch == '-' ||
ch == '_' ||
ch == '.' ||
ch == '!' ||
ch == '*' ||
ch == '(' ||
ch == ')')
{ {
return true; sbResult.Append('+');
}
else if (IsUrlSafe(ch) == false)
{
sbResult.Append($"%{ch:X02}");
}
else
{
sbResult.Append(ch);
} }
return false;
} }
return sbResult.ToString();
}
private static bool IsUrlSafe(char ch)
{
if (
(ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') ||
ch == '-' ||
ch == '_' ||
ch == '.' ||
ch == '!' ||
ch == '*' ||
ch == '(' ||
ch == ')')
{
return true;
}
return false;
} }
} }

View File

@@ -1,84 +1,82 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using Microsoft.AspNetCore.Http;
namespace VAR.WebFormsCore.Code namespace VAR.WebFormsCore.Code;
public static class StaticFileHelper
{ {
public static class StaticFileHelper private static readonly Dictionary<string, string> MimeTypeByExtension = new()
{ {
private static readonly Dictionary<string, string> MimeTypeByExtension = new() {".aac", "audio/aac"},
{ {".abw", "application/x-abiword"},
{".aac", "audio/aac"}, {".arc", "application/octet-stream"},
{".abw", "application/x-abiword"}, {".avi", "video/x-msvideo"},
{".arc", "application/octet-stream"}, {".azw", "application/vnd.amazon.ebook"},
{".avi", "video/x-msvideo"}, {".bin", "application/octet-stream"},
{".azw", "application/vnd.amazon.ebook"}, {".bz", "application/x-bzip"},
{".bin", "application/octet-stream"}, {".bz2", "application/x-bzip2"},
{".bz", "application/x-bzip"}, {".csh", "application/x-csh"},
{".bz2", "application/x-bzip2"}, {".css", "text/css"},
{".csh", "application/x-csh"}, {".csv", "text/csv"},
{".css", "text/css"}, {".doc", "application/msword"},
{".csv", "text/csv"}, {".epub", "application/epub+zip"},
{".doc", "application/msword"}, {".gif", "image/gif"},
{".epub", "application/epub+zip"}, {".htm", "text/html"},
{".gif", "image/gif"}, {".html", "text/html"},
{".htm", "text/html"}, {".ico", "image/x-icon"},
{".html", "text/html"}, {".ics", "text/calendar"},
{".ico", "image/x-icon"}, {".jar", "application/java-archive"},
{".ics", "text/calendar"}, {".jpg", "image/jpeg"},
{".jar", "application/java-archive"}, {".jpeg", "image/jpeg"},
{".jpg", "image/jpeg"}, {".js", "application/javascript"},
{".jpeg", "image/jpeg"}, {".json", "application/json"},
{".js", "application/javascript"}, {".mid", "audio/midi"},
{".json", "application/json"}, {".midi", "audio/midi"},
{".mid", "audio/midi"}, {".mpeg", "video/mpeg"},
{".midi", "audio/midi"}, {".mpkg", "application/vnd.apple.installer+xml"},
{".mpeg", "video/mpeg"}, {".odp", "application/vnd.oasis.opendocument.presentation"},
{".mpkg", "application/vnd.apple.installer+xml"}, {".ods", "application/vnd.oasis.opendocument.spreadsheet"},
{".odp", "application/vnd.oasis.opendocument.presentation"}, {".odt", "application/vnd.oasis.opendocument.text"},
{".ods", "application/vnd.oasis.opendocument.spreadsheet"}, {".oga", "audio/ogg"},
{".odt", "application/vnd.oasis.opendocument.text"}, {".ogv", "video/ogg"},
{".oga", "audio/ogg"}, {".ogx", "application/ogg"},
{".ogv", "video/ogg"}, {".png", "image/png"},
{".ogx", "application/ogg"}, {".pdf", "application/pdf"},
{".png", "image/png"}, {".ppt", "application/vnd.ms-powerpoint"},
{".pdf", "application/pdf"}, {".rar", "application/x-rar-compressed"},
{".ppt", "application/vnd.ms-powerpoint"}, {".rtf", "application/rtf"},
{".rar", "application/x-rar-compressed"}, {".sh", "application/x-sh"},
{".rtf", "application/rtf"}, {".svg", "image/svg+xml"},
{".sh", "application/x-sh"}, {".swf", "application/x-shockwave-flash"},
{".svg", "image/svg+xml"}, {".tar", "application/x-tar"},
{".swf", "application/x-shockwave-flash"}, {".tiff", "image/tiff"},
{".tar", "application/x-tar"}, {".tif", "image/tiff"},
{".tiff", "image/tiff"}, {".ttf", "font/ttf"},
{".tif", "image/tiff"}, {".vsd", "application/vnd.visio"},
{".ttf", "font/ttf"}, {".wav", "audio/x-wav"},
{".vsd", "application/vnd.visio"}, {".weba", "audio/webm"},
{".wav", "audio/x-wav"}, {".webm", "video/webm"},
{".weba", "audio/webm"}, {".webp", "image/webp"},
{".webm", "video/webm"}, {".woff", "font/woff"},
{".webp", "image/webp"}, {".woff2", "font/woff2"},
{".woff", "font/woff"}, {".xhtml", "application/xhtml+xml"},
{".woff2", "font/woff2"}, {".xls", "application/vnd.ms-excel"},
{".xhtml", "application/xhtml+xml"}, {".xml", "application/xml"},
{".xls", "application/vnd.ms-excel"}, {".xul", "application/vnd.mozilla.xul+xml"},
{".xml", "application/xml"}, {".zip", "application/zip"},
{".xul", "application/vnd.mozilla.xul+xml"}, {".7z", "application/x-7z-compressed"},
{".zip", "application/zip"}, };
{".7z", "application/x-7z-compressed"},
};
public static void ResponseStaticFile(HttpContext context, string filePath) public static void ResponseStaticFile(IWebContext context, string filePath)
{ {
string extension = Path.GetExtension(filePath).ToLower(); string extension = Path.GetExtension(filePath).ToLower();
MimeTypeByExtension.TryGetValue(extension, out string? contentType); MimeTypeByExtension.TryGetValue(extension, out string? contentType);
if (string.IsNullOrEmpty(contentType) == false) { context.Response.ContentType = contentType; } if (string.IsNullOrEmpty(contentType) == false) { context.ResponseContentType = contentType; }
context.Response.PrepareCacheableResponse(); context.PrepareCacheableResponse();
byte[] fileData = File.ReadAllBytes(filePath); byte[] fileData = File.ReadAllBytes(filePath);
context.Response.Body.WriteAsync(fileData).GetAwaiter().GetResult(); context.ResponseWriteBin(fileData);
}
} }
} }

View File

@@ -1,23 +1,21 @@
using System.Reflection; using System.Reflection;
using Microsoft.AspNetCore.Http;
namespace VAR.WebFormsCore.Code namespace VAR.WebFormsCore.Code;
public class StylesBundler : IHttpHandler
{ {
public class StylesBundler : IHttpHandler #region IHttpHandler
public void ProcessRequest(IWebContext context)
{ {
#region IHttpHandler Bundler bundler = new Bundler(
assembly: Assembly.GetExecutingAssembly(),
public void ProcessRequest(HttpContext context) assemblyNamespace: "Styles",
{ absolutePath: ServerHelpers.MapContentPath("Styles")
Bundler bundler = new Bundler( );
assembly: Assembly.GetExecutingAssembly(), context.PrepareCacheableResponse();
assemblyNamespace: "Styles", bundler.WriteResponse(context, "text/css");
absolutePath: ServerHelpers.MapContentPath("Styles")
);
context.Response.PrepareCacheableResponse();
bundler.WriteResponse(context.Response, "text/css");
}
#endregion IHttpHandler
} }
#endregion IHttpHandler
} }

View File

@@ -1,28 +1,27 @@
namespace VAR.WebFormsCore.Code namespace VAR.WebFormsCore.Code;
public class Unit
{ {
public class Unit private readonly int _value;
private readonly UnitType _unitType;
public Unit(int value, UnitType type)
{ {
private readonly int _value; _value = value;
private readonly UnitType _unitType; _unitType = type;
public Unit(int value, UnitType type)
{
_value = value;
_unitType = type;
}
public override string ToString()
{
if (_unitType == UnitType.Pixel) { return $"{_value}px"; }
if (_unitType == UnitType.Percentage) { return $"{_value}%"; }
return string.Empty;
}
} }
public enum UnitType public override string ToString()
{ {
Pixel, Percentage, if (_unitType == UnitType.Pixel) { return $"{_value}px"; }
if (_unitType == UnitType.Percentage) { return $"{_value}%"; }
return string.Empty;
} }
} }
public enum UnitType
{
Pixel, Percentage,
}

View File

@@ -1,42 +1,41 @@
using System; using System;
using System.IO; using System.IO;
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public class Button : Control, IReceivePostbackEvent
{ {
public class Button : Control, IReceivePostbackEvent public Button() { CssClass = "button"; }
private string _text = string.Empty;
public string Text
{ {
public Button() { CssClass = "button"; } get => _text;
set => _text = value;
private string _text = string.Empty;
public string Text
{
get => _text;
set => _text = value;
}
public string OnClientClick { get; set; } = string.Empty;
public string CommandArgument { get; set; } = string.Empty;
public event EventHandler? Click;
protected override void Render(TextWriter textWriter)
{
textWriter.Write("<input type=\"submit\" ");
RenderAttributes(textWriter);
RenderAttribute(textWriter, "value", _text);
if (string.IsNullOrEmpty(OnClientClick) == false)
{
RenderAttribute(textWriter, "onclick", OnClientClick);
}
textWriter.Write(">");
base.Render(textWriter);
textWriter.Write("</input>");
}
public void ReceivePostBack() { Click?.Invoke(this, EventArgs.Empty); }
} }
public string OnClientClick { get; set; } = string.Empty;
public string CommandArgument { get; set; } = string.Empty;
public event EventHandler? Click;
protected override void Render(TextWriter textWriter)
{
textWriter.Write("<input type=\"submit\" ");
RenderAttributes(textWriter);
RenderAttribute(textWriter, "value", _text);
if (string.IsNullOrEmpty(OnClientClick) == false)
{
RenderAttribute(textWriter, "onclick", OnClientClick);
}
textWriter.Write(">");
base.Render(textWriter);
textWriter.Write("</input>");
}
public void ReceivePostBack() { Click?.Invoke(this, EventArgs.Empty); }
} }

View File

@@ -3,193 +3,192 @@ using System.Collections.Generic;
using System.Text; using System.Text;
using VAR.Json; using VAR.Json;
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public class CTextBox : Control, INamingContainer, IValidableControl
{ {
public class CTextBox : Control, INamingContainer, IValidableControl #region Declarations
private readonly TextBox _txtContent = new();
private HiddenField? _hidSize;
private const string CssClassBase = "textBox";
private string _cssClassExtra = "";
private bool _allowEmpty = true;
private string _placeHolder = string.Empty;
private bool _markedInvalid;
private Control? _nextFocusOnEnter;
private bool _keepSize;
#endregion Declarations
#region Properties
public string CssClassExtra
{ {
#region Declarations get => _cssClassExtra;
set => _cssClassExtra = value;
}
private readonly TextBox _txtContent = new(); public bool AllowEmpty
{
get => _allowEmpty;
set => _allowEmpty = value;
}
private HiddenField? _hidSize; public string PlaceHolder
{
get => _placeHolder;
set => _placeHolder = value;
}
private const string CssClassBase = "textBox"; public bool MarkedInvalid
private string _cssClassExtra = ""; {
get => _markedInvalid;
set => _markedInvalid = value;
}
private bool _allowEmpty = true; public Control? NextFocusOnEnter
{
get => _nextFocusOnEnter;
set => _nextFocusOnEnter = value;
}
private string _placeHolder = string.Empty; public bool KeepSize
{
get => _keepSize;
set => _keepSize = value;
}
private bool _markedInvalid; public string Text
{
get => _txtContent.Text;
set => _txtContent.Text = value;
}
private Control? _nextFocusOnEnter; public TextBoxMode TextMode
{
get => _txtContent.TextMode;
set => _txtContent.TextMode = value;
}
private bool _keepSize; #endregion Properties
#endregion Declarations #region Control life cycle
#region Properties public CTextBox()
{
Init += CTextBox_Init;
PreRender += CTextBox_PreRender;
}
public string CssClassExtra private void CTextBox_Init(object? sender, EventArgs e)
{
Controls.Add(_txtContent);
if (TextMode == TextBoxMode.MultiLine)
{ {
get => _cssClassExtra; if (_keepSize)
set => _cssClassExtra = value;
}
public bool AllowEmpty
{
get => _allowEmpty;
set => _allowEmpty = value;
}
public string PlaceHolder
{
get => _placeHolder;
set => _placeHolder = value;
}
public bool MarkedInvalid
{
get => _markedInvalid;
set => _markedInvalid = value;
}
public Control? NextFocusOnEnter
{
get => _nextFocusOnEnter;
set => _nextFocusOnEnter = value;
}
public bool KeepSize
{
get => _keepSize;
set => _keepSize = value;
}
public string Text
{
get => _txtContent.Text;
set => _txtContent.Text = value;
}
public TextBoxMode TextMode
{
get => _txtContent.TextMode;
init => _txtContent.TextMode = value;
}
#endregion Properties
#region Control life cycle
public CTextBox()
{
Init += CTextBox_Init;
PreRender += CTextBox_PreRender;
}
private void CTextBox_Init(object? sender, EventArgs e)
{
Controls.Add(_txtContent);
if (TextMode == TextBoxMode.MultiLine)
{ {
if (_keepSize) _hidSize = new HiddenField();
{ Controls.Add(_hidSize);
_hidSize = new HiddenField();
Controls.Add(_hidSize);
}
string strCfgName = $"{ClientID}_cfg";
Dictionary<string, object> cfg = new()
{
{"txtContent", _txtContent.ClientID}, {"hidSize", _hidSize?.ClientID ?? string.Empty}, {"keepSize", _keepSize},
};
StringBuilder sbCfg = new StringBuilder();
sbCfg.AppendFormat("<script>\n");
sbCfg.Append($"var {strCfgName} = {JsonWriter.WriteObject(cfg)};\n");
sbCfg.Append($"CTextBox_Multiline_Init({strCfgName});\n");
sbCfg.AppendFormat("</script>\n");
LiteralControl liScript = new LiteralControl(sbCfg.ToString());
Controls.Add(liScript);
}
}
private void CTextBox_PreRender(object? sender, EventArgs e)
{
_txtContent.CssClass = CssClassBase;
if (string.IsNullOrEmpty(_cssClassExtra) == false)
{
_txtContent.CssClass = $"{CssClassBase} {_cssClassExtra}";
} }
if (Page?.IsPostBack == true && (_allowEmpty == false && IsEmpty()) || _markedInvalid) string strCfgName = $"{ClientID}_cfg";
Dictionary<string, object> cfg = new()
{ {
_txtContent.CssClass += " textBoxInvalid"; {"txtContent", _txtContent.ClientID}, {"hidSize", _hidSize?.ClientID ?? string.Empty}, {"keepSize", _keepSize},
} };
StringBuilder sbCfg = new StringBuilder();
sbCfg.AppendFormat("<script>\n");
sbCfg.Append($"var {strCfgName} = {JsonWriter.WriteObject(cfg)};\n");
sbCfg.Append($"CTextBox_Multiline_Init({strCfgName});\n");
sbCfg.AppendFormat("</script>\n");
LiteralControl liScript = new LiteralControl(sbCfg.ToString());
Controls.Add(liScript);
}
}
_txtContent.Attributes.Add("onchange", "ElementRemoveClass(this, 'textBoxInvalid');"); private void CTextBox_PreRender(object? sender, EventArgs e)
{
if (string.IsNullOrEmpty(_placeHolder) == false) _txtContent.CssClass = CssClassBase;
{ if (string.IsNullOrEmpty(_cssClassExtra) == false)
_txtContent.Attributes.Add("placeholder", _placeHolder); {
} _txtContent.CssClass = $"{CssClassBase} {_cssClassExtra}";
if (_nextFocusOnEnter != null)
{
_txtContent.Attributes.Add(
"onkeydown",
$"if(event.keyCode==13){{document.getElementById('{_nextFocusOnEnter.ClientID}').focus(); return false;}}"
);
}
} }
#endregion Control life cycle if (Page?.IsPostBack == true && (_allowEmpty == false && IsEmpty()) || _markedInvalid)
#region Public methods
private bool IsEmpty() { return string.IsNullOrEmpty(_txtContent.Text); }
public bool IsValid() { return _allowEmpty || (string.IsNullOrEmpty(_txtContent.Text) == false); }
public int? GetClientsideHeight()
{ {
if (string.IsNullOrEmpty(_hidSize?.Value)) { return null; } _txtContent.CssClass += " textBoxInvalid";
JsonParser jsonParser = new JsonParser();
Dictionary<string, object>? sizeObj = jsonParser.Parse(_hidSize.Value) as Dictionary<string, object>;
if (sizeObj == null) { return null; }
if (sizeObj.ContainsKey("height") == false) { return null; }
return (int) sizeObj["height"];
} }
public void SetClientsideHeight(int? height) _txtContent.Attributes.Add("onchange", "ElementRemoveClass(this, 'textBoxInvalid');");
if (string.IsNullOrEmpty(_placeHolder) == false)
{ {
if (height == null) _txtContent.Attributes.Add("placeholder", _placeHolder);
{ }
if (_hidSize != null)
{
_hidSize.Value = string.Empty;
}
return;
}
Dictionary<string, object?>? sizeObj = null; if (_nextFocusOnEnter != null)
if (string.IsNullOrEmpty(_hidSize?.Value) == false) {
{ _txtContent.Attributes.Add(
JsonParser jsonParser = new JsonParser(); "onkeydown",
sizeObj = jsonParser.Parse(_hidSize.Value) as Dictionary<string, object?>; $"if(event.keyCode==13){{document.getElementById('{_nextFocusOnEnter.ClientID}').focus(); return false;}}"
} );
sizeObj ??= new Dictionary<string, object?> { { "height", height }, { "width", null }, { "scrollTop", null }, }; }
}
#endregion Control life cycle
#region Public methods
private bool IsEmpty() { return string.IsNullOrEmpty(_txtContent.Text); }
public bool IsValid() { return _allowEmpty || (string.IsNullOrEmpty(_txtContent.Text) == false); }
public int? GetClientsideHeight()
{
if (string.IsNullOrEmpty(_hidSize?.Value)) { return null; }
JsonParser jsonParser = new JsonParser();
Dictionary<string, object>? sizeObj = jsonParser.Parse(_hidSize?.Value) as Dictionary<string, object>;
if (sizeObj == null) { return null; }
if (sizeObj.ContainsKey("height") == false) { return null; }
return (int) sizeObj["height"];
}
public void SetClientsideHeight(int? height)
{
if (height == null)
{
if (_hidSize != null) if (_hidSize != null)
{ {
_hidSize.Value = JsonWriter.WriteObject(sizeObj); _hidSize.Value = string.Empty;
} }
return;
} }
#endregion Public methods Dictionary<string, object?>? sizeObj = null;
if (string.IsNullOrEmpty(_hidSize?.Value) == false)
{
JsonParser jsonParser = new JsonParser();
sizeObj = jsonParser.Parse(_hidSize?.Value) as Dictionary<string, object?>;
}
sizeObj ??= new Dictionary<string, object?> { { "height", height }, { "width", null }, { "scrollTop", null }, };
if (_hidSize != null)
{
_hidSize.Value = JsonWriter.WriteObject(sizeObj);
}
} }
#endregion Public methods
} }

View File

@@ -5,194 +5,193 @@ using System.Text;
using VAR.WebFormsCore.Code; using VAR.WebFormsCore.Code;
using VAR.WebFormsCore.Pages; using VAR.WebFormsCore.Pages;
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public class Control
{ {
public class Control public event EventHandler? PreInit;
protected void OnPreInit(EventArgs e)
{ {
public event EventHandler? PreInit; PreInit?.Invoke(this, e);
foreach (Control control in Controls) { control.OnPreInit(e); }
}
protected void OnPreInit(EventArgs e) public event EventHandler? Init;
protected void OnInit(EventArgs e)
{
Init?.Invoke(this, e);
foreach (Control control in Controls) { control.OnInit(e); }
}
public event EventHandler? Load;
protected virtual void Process() { }
protected void OnLoad(EventArgs e)
{
Process();
Load?.Invoke(this, e);
foreach (Control control in Controls) { control.OnLoad(e); }
}
public event EventHandler? PreRender;
protected void OnPreRender(EventArgs e)
{
PreRender?.Invoke(this, e);
foreach (Control control in Controls) { control.OnPreRender(e); }
}
private string? _id;
public string? ID
{
get => _id;
set
{ {
PreInit?.Invoke(this, e); _id = value;
foreach (Control control in Controls) { control.OnPreInit(e); } _clientID = null;
}
public event EventHandler? Init;
protected void OnInit(EventArgs e)
{
Init?.Invoke(this, e);
foreach (Control control in Controls) { control.OnInit(e); }
}
public event EventHandler? Load;
protected virtual void Process() { }
protected void OnLoad(EventArgs e)
{
Process();
Load?.Invoke(this, e);
foreach (Control control in Controls) { control.OnLoad(e); }
}
public event EventHandler? PreRender;
protected void OnPreRender(EventArgs e)
{
PreRender?.Invoke(this, e);
foreach (Control control in Controls) { control.OnPreRender(e); }
}
private string? _id;
public string? ID
{
get => _id;
set
{
_id = value;
_clientID = null;
}
}
private string? _clientID;
public string ClientID
{
get { return _clientID ??= GenerateClientID(); }
}
private Control? _parent;
public Control? Parent
{
get => _parent;
set
{
_parent = value;
_clientID = null;
}
}
private ControlCollection? _controls;
public string CssClass { get; set; } = string.Empty;
public ControlCollection Controls
{
get { return _controls ??= new ControlCollection(this); }
}
private Page? _page;
public Page? Page
{
get => _page;
set
{
_page = value;
foreach (Control control in Controls) { control.Page = value; }
}
}
public bool Visible { get; set; } = true;
private string GenerateClientID()
{
StringBuilder sbClientID = new();
if (string.IsNullOrEmpty(_id) == false) { sbClientID.Insert(0, _id); }
else
{
string currentID = $"ctl{Index:00}";
sbClientID.Insert(0, currentID);
}
Control? parent = Parent;
while (parent != null)
{
if (parent is INamingContainer)
{
sbClientID.Insert(0, "_");
if (string.IsNullOrEmpty(parent.ID) == false) { sbClientID.Insert(0, parent.ID); }
else
{
string parentID = $"ctl{parent.Index:00}";
sbClientID.Insert(0, parentID);
}
}
parent = parent.Parent;
}
return sbClientID.ToString();
}
public Dictionary<string, string> Style { get; } = new();
public Dictionary<string, string> Attributes { get; } = new();
public int Index { get; set; }
protected virtual void Render(TextWriter textWriter)
{
foreach (Control control in Controls)
{
if (control.Visible == false) { continue; }
control.Render(textWriter);
}
}
protected static void RenderAttribute(TextWriter textWriter, string key, string value)
{
textWriter.Write(" {0}=\"{1}\"", key, ServerHelpers.HtmlEncode(value));
}
protected void RenderAttributes(TextWriter textWriter, bool forceId = false)
{
if (string.IsNullOrEmpty(_id) == false || forceId)
{
RenderAttribute(textWriter, "id", ClientID);
RenderAttribute(textWriter, "name", ClientID);
}
if (string.IsNullOrEmpty(CssClass) == false) { RenderAttribute(textWriter, "class", CssClass); }
foreach (KeyValuePair<string, string> attributePair in Attributes)
{
RenderAttribute(textWriter, attributePair.Key, attributePair.Value);
}
if (Style.Count > 0)
{
StringBuilder sbStyle = new();
foreach (KeyValuePair<string, string> stylePair in Style)
{
sbStyle.Append($"{stylePair.Key}: {stylePair.Value};");
}
RenderAttribute(textWriter, "style", sbStyle.ToString());
}
}
protected List<Control> ChildsOfType<T>(List<Control>? controls = null)
{
controls ??= new List<Control>();
if (this is T) { controls.Add(this); }
if (_controls != null)
{
foreach (Control child in _controls)
{
child.ChildsOfType<T>(controls);
}
}
return controls;
} }
} }
private string? _clientID;
public string ClientID
{
get { return _clientID ??= GenerateClientID(); }
}
private Control? _parent;
public Control? Parent
{
get => _parent;
set
{
_parent = value;
_clientID = null;
}
}
private ControlCollection? _controls;
public string CssClass { get; set; } = string.Empty;
public ControlCollection Controls
{
get { return _controls ??= new ControlCollection(this); }
}
private Page? _page;
public Page? Page
{
get => _page;
set
{
_page = value;
foreach (Control control in Controls) { control.Page = value; }
}
}
public bool Visible { get; set; } = true;
private string GenerateClientID()
{
StringBuilder sbClientID = new();
if (string.IsNullOrEmpty(_id) == false) { sbClientID.Insert(0, _id); }
else
{
string currentID = $"ctl{Index:00}";
sbClientID.Insert(0, currentID);
}
Control? parent = Parent;
while (parent != null)
{
if (parent is INamingContainer)
{
sbClientID.Insert(0, "_");
if (string.IsNullOrEmpty(parent.ID) == false) { sbClientID.Insert(0, parent.ID); }
else
{
string parentID = $"ctl{parent.Index:00}";
sbClientID.Insert(0, parentID);
}
}
parent = parent.Parent;
}
return sbClientID.ToString();
}
public Dictionary<string, string> Style { get; } = new();
public Dictionary<string, string> Attributes { get; } = new();
public int Index { get; set; }
protected virtual void Render(TextWriter textWriter)
{
foreach (Control control in Controls)
{
if (control.Visible == false) { continue; }
control.Render(textWriter);
}
}
protected static void RenderAttribute(TextWriter textWriter, string key, string value)
{
textWriter.Write(" {0}=\"{1}\"", key, ServerHelpers.HtmlEncode(value));
}
protected void RenderAttributes(TextWriter textWriter, bool forceId = false)
{
if (string.IsNullOrEmpty(_id) == false || forceId)
{
RenderAttribute(textWriter, "id", ClientID);
RenderAttribute(textWriter, "name", ClientID);
}
if (string.IsNullOrEmpty(CssClass) == false) { RenderAttribute(textWriter, "class", CssClass); }
foreach (KeyValuePair<string, string> attributePair in Attributes)
{
RenderAttribute(textWriter, attributePair.Key, attributePair.Value);
}
if (Style.Count > 0)
{
StringBuilder sbStyle = new();
foreach (KeyValuePair<string, string> stylePair in Style)
{
sbStyle.Append($"{stylePair.Key}: {stylePair.Value};");
}
RenderAttribute(textWriter, "style", sbStyle.ToString());
}
}
protected List<Control> ChildsOfType<T>(List<Control>? controls = null)
{
controls ??= new List<Control>();
if (this is T) { controls.Add(this); }
if (_controls != null)
{
foreach (Control child in _controls)
{
child.ChildsOfType<T>(controls);
}
}
return controls;
}
} }

View File

@@ -1,21 +1,20 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public class ControlCollection : List<Control>
{ {
public class ControlCollection : List<Control> private readonly Control _parent;
private int _index;
public ControlCollection(Control parent) { _parent = parent; }
public new void Add(Control control)
{ {
private readonly Control _parent; control.Page = _parent.Page;
private int _index; control.Parent = _parent;
control.Index = _index;
public ControlCollection(Control parent) { _parent = parent; } _index++;
base.Add(control);
public new void Add(Control control)
{
control.Page = _parent.Page;
control.Parent = _parent;
control.Index = _index;
_index++;
base.Add(control);
}
} }
} }

View File

@@ -1,33 +1,32 @@
using System.IO; using System.IO;
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public class HiddenField : Control
{ {
public class HiddenField : Control private string _value = string.Empty;
public string Value
{ {
private string _value = string.Empty; get => _value;
set => _value = value;
}
public string Value protected override void Process()
{
if (Page?.IsPostBack == true && Page?.Context?.RequestForm.ContainsKey(ClientID) == true)
{ {
get => _value; Value = Page?.Context.RequestForm[ClientID] ?? string.Empty;
set => _value = value;
}
protected override void Process()
{
if (Page?.IsPostBack == true && Page?.Context?.Request.Form.ContainsKey(ClientID) == true)
{
Value = Page?.Context.Request.Form[ClientID][0] ?? string.Empty;
}
}
protected override void Render(TextWriter textWriter)
{
textWriter.Write("<input type=\"hidden\" ");
RenderAttributes(textWriter, forceId: true);
if (string.IsNullOrEmpty(Value) == false) { RenderAttribute(textWriter, "value", _value); }
textWriter.Write(">");
textWriter.Write("</input>");
} }
} }
protected override void Render(TextWriter textWriter)
{
textWriter.Write("<input type=\"hidden\" ");
RenderAttributes(textWriter, forceId: true);
if (string.IsNullOrEmpty(Value) == false) { RenderAttribute(textWriter, "value", _value); }
textWriter.Write(">");
textWriter.Write("</input>");
}
} }

View File

@@ -1,7 +1,6 @@
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public class HtmlBody : HtmlGenericControl
{ {
public class HtmlBody : HtmlGenericControl public HtmlBody() : base("body") { }
{
public HtmlBody() : base("body") { }
}
} }

View File

@@ -1,7 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using Microsoft.Extensions.Primitives;
using VAR.WebFormsCore.Code; using VAR.WebFormsCore.Code;
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls
@@ -28,15 +27,15 @@ namespace VAR.WebFormsCore.Controls
StringBuilder sbAction = new(); StringBuilder sbAction = new();
sbAction.Append(Page?.GetType().Name); sbAction.Append(Page?.GetType().Name);
if ((Page?.Context?.Request.Query.Count ?? 0) <= 0) { return sbAction.ToString(); } if ((Page?.Context?.RequestQuery.Count ?? 0) <= 0) { return sbAction.ToString(); }
sbAction.Append('?'); sbAction.Append('?');
if (Page?.Context?.Request.Query != null) if (Page?.Context?.RequestQuery != null)
{ {
foreach (KeyValuePair<string, StringValues> queryParam in Page.Context.Request.Query) foreach (KeyValuePair<string, string?> queryParam in Page.Context.RequestQuery)
{ {
string key = ServerHelpers.UrlEncode(queryParam.Key); string key = ServerHelpers.UrlEncode(queryParam.Key);
string value = ServerHelpers.UrlEncode(queryParam.Value[0] ?? string.Empty); string value = ServerHelpers.UrlEncode(queryParam.Value ?? string.Empty);
sbAction.Append($"&{key}={value}"); sbAction.Append($"&{key}={value}");
} }
} }

View File

@@ -1,22 +1,21 @@
using System.IO; using System.IO;
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public class HtmlGenericControl : Control
{ {
public class HtmlGenericControl : Control private readonly string _tagName;
public HtmlGenericControl(string tag) { _tagName = tag; }
protected override void Render(TextWriter textWriter)
{ {
private readonly string _tagName; textWriter.Write("<{0} ", _tagName);
RenderAttributes(textWriter);
textWriter.Write(">");
public HtmlGenericControl(string tag) { _tagName = tag; } base.Render(textWriter);
protected override void Render(TextWriter textWriter) textWriter.Write("</{0}>", _tagName);
{
textWriter.Write("<{0} ", _tagName);
RenderAttributes(textWriter);
textWriter.Write(">");
base.Render(textWriter);
textWriter.Write("</{0}>", _tagName);
}
} }
} }

View File

@@ -1,22 +1,21 @@
using System.IO; using System.IO;
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public class HtmlHead : Control
{ {
public class HtmlHead : Control public string Title { get; set; } = string.Empty;
protected override void Render(TextWriter textWriter)
{ {
public string Title { get; set; } = string.Empty; textWriter.Write("<head ");
RenderAttributes(textWriter);
textWriter.Write(">");
protected override void Render(TextWriter textWriter) if (string.IsNullOrEmpty(Title) == false) { textWriter.Write("<title>{0}</title>", Title); }
{
textWriter.Write("<head ");
RenderAttributes(textWriter);
textWriter.Write(">");
if (string.IsNullOrEmpty(Title) == false) { textWriter.Write("<title>{0}</title>", Title); } base.Render(textWriter);
base.Render(textWriter); textWriter.Write("</head>");
textWriter.Write("</head>");
}
} }
} }

View File

@@ -1,24 +1,23 @@
using System.IO; using System.IO;
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public class HtmlMeta : Control
{ {
public class HtmlMeta : Control public string Name { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
public string HttpEquiv { get; set; } = string.Empty;
protected override void Render(TextWriter textWriter)
{ {
public string Name { get; init; } = string.Empty; textWriter.Write("<meta ");
public string Content { get; init; } = string.Empty; RenderAttributes(textWriter);
public string HttpEquiv { get; internal init; } = string.Empty; if (string.IsNullOrEmpty(Name) == false) { textWriter.Write(" name=\"{0}\"", Name); }
protected override void Render(TextWriter textWriter) if (string.IsNullOrEmpty(Content) == false) { textWriter.Write(" content=\"{0}\"", Content); }
{
textWriter.Write("<meta ");
RenderAttributes(textWriter);
if (string.IsNullOrEmpty(Name) == false) { textWriter.Write(" name=\"{0}\"", Name); }
if (string.IsNullOrEmpty(Content) == false) { textWriter.Write(" content=\"{0}\"", Content); } if (string.IsNullOrEmpty(HttpEquiv) == false) { textWriter.Write(" http-equiv=\"{0}\"", HttpEquiv); }
if (string.IsNullOrEmpty(HttpEquiv) == false) { textWriter.Write(" http-equiv=\"{0}\"", HttpEquiv); } textWriter.Write(" />");
textWriter.Write(" />");
}
} }
} }

View File

@@ -1,25 +1,24 @@
using System.IO; using System.IO;
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public class HyperLink : Control
{ {
public class HyperLink : Control public string NavigateUrl { get; set; } = string.Empty;
public string Text { get; set; } = string.Empty;
protected override void Render(TextWriter textWriter)
{ {
public string NavigateUrl { get; set; } = string.Empty; textWriter.Write("<a ");
public string Text { get; init; } = string.Empty; RenderAttributes(textWriter);
if (string.IsNullOrEmpty(NavigateUrl) == false) { textWriter.Write(" href=\"{0}\"", NavigateUrl); }
protected override void Render(TextWriter textWriter) textWriter.Write(">");
{
textWriter.Write("<a ");
RenderAttributes(textWriter);
if (string.IsNullOrEmpty(NavigateUrl) == false) { textWriter.Write(" href=\"{0}\"", NavigateUrl); }
textWriter.Write(">"); if (string.IsNullOrEmpty(Text) == false) { textWriter.Write(Text); }
if (string.IsNullOrEmpty(Text) == false) { textWriter.Write(Text); } base.Render(textWriter);
base.Render(textWriter); textWriter.Write("</a>");
textWriter.Write("</a>");
}
} }
} }

View File

@@ -1,6 +1,5 @@
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public interface INamingContainer
{ {
public interface INamingContainer
{
}
} }

View File

@@ -1,7 +1,6 @@
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public interface IReceivePostbackEvent
{ {
public interface IReceivePostbackEvent void ReceivePostBack();
{
void ReceivePostBack();
}
} }

View File

@@ -1,7 +1,6 @@
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public interface IValidableControl
{ {
public interface IValidableControl bool IsValid();
{
bool IsValid();
}
} }

View File

@@ -1,45 +1,44 @@
using System.IO; using System.IO;
using VAR.WebFormsCore.Code; using VAR.WebFormsCore.Code;
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public class Label : Control
{ {
public class Label : Control #region Properties
private string _tagName = "span";
public string Tag
{ {
#region Properties get => _tagName;
set => _tagName = value;
private string _tagName = "span";
public string Tag
{
get => _tagName;
set => _tagName = value;
}
private string _text = string.Empty;
public string Text
{
get => _text;
set => _text = value;
}
#endregion Properties
#region Life cycle
protected override void Render(TextWriter textWriter)
{
textWriter.Write("<{0} ", _tagName);
RenderAttributes(textWriter);
textWriter.Write(">");
textWriter.Write(ServerHelpers.HtmlEncode(_text));
base.Render(textWriter);
textWriter.Write("</{0}>", _tagName);
}
#endregion Life cycle
} }
private string _text = string.Empty;
public string Text
{
get => _text;
set => _text = value;
}
#endregion Properties
#region Life cycle
protected override void Render(TextWriter textWriter)
{
textWriter.Write("<{0} ", _tagName);
RenderAttributes(textWriter);
textWriter.Write(">");
textWriter.Write(ServerHelpers.HtmlEncode(_text));
base.Render(textWriter);
textWriter.Write("</{0}>", _tagName);
}
#endregion Life cycle
} }

View File

@@ -1,14 +1,13 @@
using System.IO; using System.IO;
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public class LiteralControl : Control
{ {
public class LiteralControl : Control public string Content { get; set; } = string.Empty;
{
public string Content { get; set; } = string.Empty;
public LiteralControl() { } public LiteralControl() { }
public LiteralControl(string content) { Content = content; } public LiteralControl(string content) { Content = content; }
protected override void Render(TextWriter textWriter) { textWriter.Write(Content); } protected override void Render(TextWriter textWriter) { textWriter.Write(Content); }
}
} }

View File

@@ -1,7 +1,6 @@
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public class Panel : HtmlGenericControl, INamingContainer
{ {
public class Panel : HtmlGenericControl, INamingContainer public Panel() : base("div") { }
{
public Panel() : base("div") { }
}
} }

View File

@@ -1,55 +1,54 @@
using System.IO; using System.IO;
using VAR.WebFormsCore.Code; using VAR.WebFormsCore.Code;
namespace VAR.WebFormsCore.Controls namespace VAR.WebFormsCore.Controls;
public class TextBox : Control
{ {
public class TextBox : Control public string Text { get; set; } = string.Empty;
public TextBoxMode TextMode { get; set; } = TextBoxMode.Normal;
protected override void Process()
{ {
public string Text { get; set; } = string.Empty; if (Page?.IsPostBack == true && Page?.Context?.RequestForm.ContainsKey(ClientID) == true)
public TextBoxMode TextMode { get; set; } = TextBoxMode.Normal;
protected override void Process()
{ {
if (Page?.IsPostBack == true && Page?.Context?.Request.Form.ContainsKey(ClientID) == true) Text = Page?.Context.RequestForm[ClientID] ?? string.Empty;
{
Text = Page?.Context.Request.Form[ClientID][0] ?? string.Empty;
}
}
protected override void Render(TextWriter textWriter)
{
if (TextMode == TextBoxMode.MultiLine)
{
textWriter.Write("<textarea ");
RenderAttributes(textWriter, forceId: true);
textWriter.Write(">");
textWriter.Write(ServerHelpers.HtmlEncode(Text));
textWriter.Write("</textarea>");
}
else if (TextMode == TextBoxMode.Normal)
{
textWriter.Write("<input type=\"text\" ");
RenderAttributes(textWriter, forceId: true);
if (string.IsNullOrEmpty(Text) == false) { RenderAttribute(textWriter, "value", Text); }
textWriter.Write(">");
textWriter.Write("</input>");
}
else if (TextMode == TextBoxMode.Password)
{
textWriter.Write("<input type=\"password\" ");
RenderAttributes(textWriter, forceId: true);
if (string.IsNullOrEmpty(Text) == false) { RenderAttribute(textWriter, "value", Text); }
textWriter.Write(">");
textWriter.Write("</input>");
}
} }
} }
public enum TextBoxMode protected override void Render(TextWriter textWriter)
{ {
Normal, Password, MultiLine, if (TextMode == TextBoxMode.MultiLine)
{
textWriter.Write("<textarea ");
RenderAttributes(textWriter, forceId: true);
textWriter.Write(">");
textWriter.Write(ServerHelpers.HtmlEncode(Text));
textWriter.Write("</textarea>");
}
else if (TextMode == TextBoxMode.Normal)
{
textWriter.Write("<input type=\"text\" ");
RenderAttributes(textWriter, forceId: true);
if (string.IsNullOrEmpty(Text) == false) { RenderAttribute(textWriter, "value", Text); }
textWriter.Write(">");
textWriter.Write("</input>");
}
else if (TextMode == TextBoxMode.Password)
{
textWriter.Write("<input type=\"password\" ");
RenderAttributes(textWriter, forceId: true);
if (string.IsNullOrEmpty(Text) == false) { RenderAttribute(textWriter, "value", Text); }
textWriter.Write(">");
textWriter.Write("</input>");
}
} }
} }
public enum TextBoxMode
{
Normal, Password, MultiLine,
}

View File

@@ -1,66 +1,65 @@
using VAR.WebFormsCore.Controls; using VAR.WebFormsCore.Controls;
namespace VAR.WebFormsCore.Pages namespace VAR.WebFormsCore.Pages;
public static class FormUtils
{ {
public static class FormUtils public static Control CreatePanel(string cssClass, Control? ctrl = null)
{ {
public static Control CreatePanel(string cssClass, Control? ctrl = null) Panel pnl = new Panel();
if (ctrl != null) { pnl.Controls.Add(ctrl); }
if (string.IsNullOrEmpty(cssClass) == false) { pnl.CssClass = cssClass; }
return pnl;
}
public static Control CreateField(string label, Control fieldControl)
{
Panel pnlRow = new Panel {CssClass = "formRow"};
Panel pnlLabelContainer = new Panel {CssClass = "formLabel width25pc"};
pnlRow.Controls.Add(pnlLabelContainer);
if (string.IsNullOrEmpty(label) == false)
{ {
Panel pnl = new Panel(); Label lblField = new Label {Text = label};
if (ctrl != null) { pnl.Controls.Add(ctrl); } pnlLabelContainer.Controls.Add(lblField);
if (string.IsNullOrEmpty(cssClass) == false) { pnl.CssClass = cssClass; }
return pnl;
} }
public static Control CreateField(string label, Control fieldControl) Panel pnlFieldContainer = new Panel {CssClass = "formField width75pc"};
pnlRow.Controls.Add(pnlFieldContainer);
pnlFieldContainer.Controls.Add(fieldControl);
return pnlRow;
}
public static bool Control_IsValid(Control control)
{
return (control as IValidableControl)?.IsValid() != false;
}
public static bool Controls_AreValid(ControlCollection controls)
{
bool valid = true;
foreach (Control control in controls)
{ {
Panel pnlRow = new Panel {CssClass = "formRow"}; if (Control_IsValid(control))
Panel pnlLabelContainer = new Panel {CssClass = "formLabel width25pc"};
pnlRow.Controls.Add(pnlLabelContainer);
if (string.IsNullOrEmpty(label) == false)
{ {
Label lblField = new Label {Text = label}; if (Controls_AreValid(control.Controls) == false)
pnlLabelContainer.Controls.Add(lblField);
}
Panel pnlFieldContainer = new Panel {CssClass = "formField width75pc"};
pnlRow.Controls.Add(pnlFieldContainer);
pnlFieldContainer.Controls.Add(fieldControl);
return pnlRow;
}
public static bool Control_IsValid(Control control)
{
return (control as IValidableControl)?.IsValid() != false;
}
public static bool Controls_AreValid(ControlCollection controls)
{
bool valid = true;
foreach (Control control in controls)
{
if (Control_IsValid(control))
{
if (Controls_AreValid(control.Controls) == false)
{
valid = false;
break;
}
}
else
{ {
valid = false; valid = false;
break; break;
} }
} }
else
return valid; {
valid = false;
break;
}
} }
return valid;
} }
} }

View File

@@ -1,20 +1,21 @@
using Microsoft.AspNetCore.Http; using VAR.Json;
using VAR.Json;
using VAR.WebFormsCore.Code; using VAR.WebFormsCore.Code;
namespace VAR.WebFormsCore.Pages namespace VAR.WebFormsCore.Pages;
public class FrmEcho : IHttpHandler
{ {
public class FrmEcho : IHttpHandler #region IHttpHandler
public void ProcessRequest(IWebContext context)
{ {
#region IHttpHandler context.ResponseContentType = "text/html";
context.ResponseWrite("<pre><code>");
public void ProcessRequest(HttpContext context) context.ResponseWrite($"Header:{JsonWriter.WriteObject(context.RequestHeader, indent: true)}\n");
{ context.ResponseWrite($"Query:{JsonWriter.WriteObject(context.RequestQuery, indent: true)}\n");
context.Response.WriteAsync("<pre><code>").GetAwaiter().GetResult(); context.ResponseWrite($"Form:{JsonWriter.WriteObject(context.RequestForm, indent: true)}\n");
context.Response.WriteAsync(JsonWriter.WriteObject(context.Request, indent: true)).GetAwaiter().GetResult(); context.ResponseWrite("</code></pre>");
context.Response.WriteAsync("</code></pre>").GetAwaiter().GetResult();
}
#endregion IHttpHandler
} }
#endregion IHttpHandler
} }

View File

@@ -2,60 +2,59 @@
using System.Web; using System.Web;
using VAR.WebFormsCore.Controls; using VAR.WebFormsCore.Controls;
namespace VAR.WebFormsCore.Pages namespace VAR.WebFormsCore.Pages;
public class FrmError : PageCommon
{ {
public class FrmError : PageCommon #region Declarations
private readonly Exception _ex;
#endregion Declarations
#region Page life cycle
public FrmError(Exception ex)
{ {
#region Declarations MustBeAuthenticated = false;
_ex = ex;
private readonly Exception _ex; Init += FrmError_Init;
#endregion Declarations
#region Page life cycle
public FrmError(Exception ex)
{
MustBeAuthenticated = false;
_ex = ex;
Init += FrmError_Init;
}
private void FrmError_Init(object? sender, EventArgs e) { InitializeControls(); }
#endregion Page life cycle
#region Private methods
private void InitializeControls()
{
Title = "Application Error";
Label lblErrorTitle = new Label {Text = Title, Tag = "h2"};
Controls.Add(lblErrorTitle);
Exception? exAux = _ex;
//if (exAux is HttpUnhandledException && exAux.InnerException != null) { exAux = exAux.InnerException; }
while (exAux != null)
{
LiteralControl lblMessage = new LiteralControl($"<p><b>Message:</b> {HttpUtility.HtmlEncode(exAux.Message)}</p>");
Controls.Add(lblMessage);
LiteralControl lblStacktraceTitle = new LiteralControl("<p><b>Stacktrace:</b></p>");
Controls.Add(lblStacktraceTitle);
Panel pnlStacktrace = new Panel
{
CssClass = "divCode"
};
Controls.Add(pnlStacktrace);
LiteralControl litStackTrace = new LiteralControl(
$"<pre><code>{HttpUtility.HtmlEncode(exAux.StackTrace)}</code></pre>");
pnlStacktrace.Controls.Add(litStackTrace);
exAux = exAux.InnerException;
}
}
#endregion Private methods
} }
private void FrmError_Init(object? sender, EventArgs e) { InitializeControls(); }
#endregion Page life cycle
#region Private methods
private void InitializeControls()
{
Title = "Application Error";
Label lblErrorTitle = new Label {Text = Title, Tag = "h2"};
Controls.Add(lblErrorTitle);
Exception? exAux = _ex;
//if (exAux is HttpUnhandledException && exAux.InnerException != null) { exAux = exAux.InnerException; }
while (exAux != null)
{
LiteralControl lblMessage = new LiteralControl($"<p><b>Message:</b> {HttpUtility.HtmlEncode(exAux.Message)}</p>");
Controls.Add(lblMessage);
LiteralControl lblStacktraceTitle = new LiteralControl("<p><b>Stacktrace:</b></p>");
Controls.Add(lblStacktraceTitle);
Panel pnlStacktrace = new Panel
{
CssClass = "divCode"
};
Controls.Add(pnlStacktrace);
LiteralControl litStackTrace = new LiteralControl(
$"<pre><code>{HttpUtility.HtmlEncode(exAux.StackTrace)}</code></pre>");
pnlStacktrace.Controls.Add(litStackTrace);
exAux = exAux.InnerException;
}
}
#endregion Private methods
} }

View File

@@ -2,76 +2,75 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text; using System.Text;
using Microsoft.AspNetCore.Http;
using VAR.WebFormsCore.Code; using VAR.WebFormsCore.Code;
using VAR.WebFormsCore.Controls; using VAR.WebFormsCore.Controls;
namespace VAR.WebFormsCore.Pages namespace VAR.WebFormsCore.Pages;
public class Page : Control, IHttpHandler
{ {
public class Page : Control, IHttpHandler protected string Title { get; set; } = string.Empty;
public IWebContext? Context { get; private set; }
private static readonly Encoding Utf8Encoding = new UTF8Encoding();
public void ProcessRequest(IWebContext context)
{ {
protected string Title { get; set; } = string.Empty; try
public HttpContext? Context { get; private set; }
private static readonly Encoding Utf8Encoding = new UTF8Encoding();
public void ProcessRequest(HttpContext context)
{ {
try StringWriter stringWriter = new();
Context = context;
Page = this;
if (context.RequestMethod == "POST") { _isPostBack = true; }
OnPreInit(EventArgs.Empty);
if (context.ResponseHasStarted) { return; }
OnInit(EventArgs.Empty);
if (context.ResponseHasStarted) { return; }
OnLoad(EventArgs.Empty);
if (context.ResponseHasStarted) { return; }
if (_isPostBack)
{ {
StringWriter stringWriter = new(); List<Control> controls = ChildsOfType<IReceivePostbackEvent>();
foreach (Control control in controls)
Context = context;
Page = this;
if (context.Request.Method == "POST") { _isPostBack = true; }
OnPreInit(EventArgs.Empty);
if (context.Response.HasStarted) { return; }
OnInit(EventArgs.Empty);
if (context.Response.HasStarted) { return; }
OnLoad(EventArgs.Empty);
if (context.Response.HasStarted) { return; }
if (_isPostBack)
{ {
List<Control> controls = ChildsOfType<IReceivePostbackEvent>(); string clientID = control.ClientID;
foreach (Control control in controls) if (context.RequestForm.ContainsKey(clientID))
{ {
string clientID = control.ClientID; (control as IReceivePostbackEvent)?.ReceivePostBack();
if (context.Request.Form.ContainsKey(clientID)) if (context.ResponseHasStarted) { return; }
{
(control as IReceivePostbackEvent)?.ReceivePostBack();
if (context.Response.HasStarted) { return; }
}
} }
} }
OnPreRender(EventArgs.Empty);
if (context.Response.HasStarted) { return; }
Render(stringWriter);
if (context.Response.HasStarted) { return; }
context.Response.Headers.SafeSet("Content-Type", "text/html");
byte[] byteObject = Utf8Encoding.GetBytes(stringWriter.ToString());
context.Response.Body.WriteAsync(byteObject).GetAwaiter().GetResult();
} }
catch (Exception ex)
{
// TODO: Implement better error logging
Console.WriteLine("!!!!!!!!!!");
Console.Write("Message: {0}\nStacktrace: {1}\n", ex.Message, ex.StackTrace);
GlobalErrorHandler.HandleError(context, ex); OnPreRender(EventArgs.Empty);
} if (context.ResponseHasStarted) { return; }
Render(stringWriter);
if (context.ResponseHasStarted) { return; }
//context.SetResponseHeader("Content-Type", "text/html");
context.ResponseContentType = "text/html";
byte[] byteObject = Utf8Encoding.GetBytes(stringWriter.ToString());
context.ResponseWriteBin(byteObject);
} }
catch (Exception ex)
{
// TODO: Implement better error logging
Console.WriteLine("!!!!!!!!!!");
Console.Write("Message: {0}\nStacktrace: {1}\n", ex.Message, ex.StackTrace);
private bool _isPostBack; GlobalErrorHandler.HandleError(context, ex);
}
public bool IsPostBack => _isPostBack;
} }
private bool _isPostBack;
public bool IsPostBack => _isPostBack;
} }

View File

@@ -3,147 +3,146 @@ using System.Reflection;
using VAR.WebFormsCore.Code; using VAR.WebFormsCore.Code;
using VAR.WebFormsCore.Controls; using VAR.WebFormsCore.Controls;
namespace VAR.WebFormsCore.Pages namespace VAR.WebFormsCore.Pages;
public class PageCommon : Page
{ {
public class PageCommon : Page #region Declarations
private readonly HtmlHead _head = new();
private readonly HtmlBody _body = new();
private readonly HtmlForm _form = new() {ID = "formMain"};
private readonly Panel _pnlContainer = new();
private readonly Button _btnPostback = new();
private readonly Button _btnLogout = new();
private bool _isAuthenticated;
#endregion Declarations
#region Properties
public new ControlCollection Controls => _pnlContainer.Controls;
public bool MustBeAuthenticated { get; set; } = true;
#endregion Properties
#region Life cycle
public PageCommon()
{ {
#region Declarations PreInit += PageCommon_PreInit;
Init += PageCommon_Init;
private readonly HtmlHead _head = new(); PreRender += PageCommon_PreRender;
private readonly HtmlBody _body = new();
private readonly HtmlForm _form = new() {ID = "formMain"};
private readonly Panel _pnlContainer = new();
private readonly Button _btnPostback = new();
private readonly Button _btnLogout = new();
private bool _isAuthenticated;
#endregion Declarations
#region Properties
public new ControlCollection Controls => _pnlContainer.Controls;
public bool MustBeAuthenticated { get; init; } = true;
#endregion Properties
#region Life cycle
public PageCommon()
{
PreInit += PageCommon_PreInit;
Init += PageCommon_Init;
PreRender += PageCommon_PreRender;
}
private void PageCommon_PreInit(object? sender, EventArgs e)
{
Context?.Response.PrepareUncacheableResponse();
if (Context != null)
{
_isAuthenticated = GlobalConfig.Get().IsUserAuthenticated(Context);
}
if (MustBeAuthenticated && _isAuthenticated == false)
{
Context?.Response.Redirect(GlobalConfig.Get().LoginHandler);
}
}
private void PageCommon_Init(object? sender, EventArgs e) { CreateControls(); }
private void PageCommon_PreRender(object? sender, EventArgs e)
{
_head.Title = string.IsNullOrEmpty(Title)
? GlobalConfig.Get().Title
: string.Concat(Title, GlobalConfig.Get().TitleSeparator, GlobalConfig.Get().Title);
_btnLogout.Visible = _isAuthenticated;
}
#endregion Life cycle
#region UI Events
private void btnLogout_Click(object? sender, EventArgs e)
{
if(Context != null)
{
GlobalConfig.Get().UserDeauthenticate(Context);
}
if (MustBeAuthenticated) { Context?.Response.Redirect(GlobalConfig.Get().LoginHandler); }
}
#endregion UI Events
#region Private methods
private void CreateControls()
{
//Context.Response.Charset = Encoding.UTF8.WebName;
var doctype = new LiteralControl("<!DOCTYPE html>\n");
base.Controls.Add(doctype);
var html = new HtmlGenericControl("html");
base.Controls.Add(html);
html.Controls.Add(_head);
_head.Controls.Add(new HtmlMeta {HttpEquiv = "X-UA-Compatible", Content = "IE=Edge"});
_head.Controls.Add(new HtmlMeta {HttpEquiv = "content-type", Content = "text/html; charset=utf-8"});
_head.Controls.Add(new HtmlMeta {Name = "author", Content = GlobalConfig.Get().Author});
_head.Controls.Add(new HtmlMeta {Name = "Copyright", Content = GlobalConfig.Get().Copyright});
_head.Controls.Add(
new HtmlMeta
{
Name = "viewport",
Content = "width=device-width, initial-scale=1, maximum-scale=4, user-scalable=1"
}
);
string? version = Assembly.GetExecutingAssembly().GetName().Version?.ToString();
_head.Controls.Add(
new LiteralControl($"<script type=\"text/javascript\" src=\"ScriptsBundler?v={version}\"></script>\n")
);
_head.Controls.Add(
new LiteralControl($"<link href=\"StylesBundler?v={version}\" type=\"text/css\" rel=\"stylesheet\"/>\n")
);
html.Controls.Add(_body);
_body.Controls.Add(_form);
var pnlHeader = new Panel {CssClass = "divHeader"};
_form.Controls.Add(pnlHeader);
HyperLink lnkTitle = new HyperLink {NavigateUrl = "."};
pnlHeader.Controls.Add(lnkTitle);
var lblTitle = new Label {Text = GlobalConfig.Get().Title, Tag = "h1"};
lnkTitle.Controls.Add(lblTitle);
_btnPostback.ID = "btnPostback";
_btnPostback.Text = "Postback";
pnlHeader.Controls.Add(_btnPostback);
_btnPostback.Style.Add("display", "none");
var pnlUserInfo = new Panel {CssClass = "divUserInfo"};
pnlHeader.Controls.Add(pnlUserInfo);
_btnLogout.ID = "btnLogout";
_btnLogout.Text = MultiLang.GetLiteral("Logout");
_btnLogout.Click += btnLogout_Click;
_btnLogout.Attributes.Add(
"onclick",
$"return confirm('{MultiLang.GetLiteral("ConfirmExit")}');"
);
pnlUserInfo.Controls.Add(_btnLogout);
_pnlContainer.CssClass = "divContent";
_form.Controls.Add(_pnlContainer);
}
#endregion Private methods
} }
private void PageCommon_PreInit(object? sender, EventArgs e)
{
Context?.PrepareUncacheableResponse();
if (Context != null)
{
_isAuthenticated = GlobalConfig.Get().IsUserAuthenticated(Context);
}
if (MustBeAuthenticated && _isAuthenticated == false)
{
Context?.ResponseRedirect(GlobalConfig.Get().LoginHandler);
}
}
private void PageCommon_Init(object? sender, EventArgs e) { CreateControls(); }
private void PageCommon_PreRender(object? sender, EventArgs e)
{
_head.Title = string.IsNullOrEmpty(Title)
? GlobalConfig.Get().Title
: string.Concat(Title, GlobalConfig.Get().TitleSeparator, GlobalConfig.Get().Title);
_btnLogout.Visible = _isAuthenticated;
}
#endregion Life cycle
#region UI Events
private void btnLogout_Click(object? sender, EventArgs e)
{
if(Context != null)
{
GlobalConfig.Get().UserDeauthenticate(Context);
}
if (MustBeAuthenticated) { Context?.ResponseRedirect(GlobalConfig.Get().LoginHandler); }
}
#endregion UI Events
#region Private methods
private void CreateControls()
{
//Context.Response.Charset = Encoding.UTF8.WebName;
var doctype = new LiteralControl("<!DOCTYPE html>\n");
base.Controls.Add(doctype);
var html = new HtmlGenericControl("html");
base.Controls.Add(html);
html.Controls.Add(_head);
_head.Controls.Add(new HtmlMeta {HttpEquiv = "X-UA-Compatible", Content = "IE=Edge"});
_head.Controls.Add(new HtmlMeta {HttpEquiv = "content-type", Content = "text/html; charset=utf-8"});
_head.Controls.Add(new HtmlMeta {Name = "author", Content = GlobalConfig.Get().Author});
_head.Controls.Add(new HtmlMeta {Name = "Copyright", Content = GlobalConfig.Get().Copyright});
_head.Controls.Add(
new HtmlMeta
{
Name = "viewport",
Content = "width=device-width, initial-scale=1, maximum-scale=4, user-scalable=1"
}
);
string? version = Assembly.GetExecutingAssembly().GetName().Version?.ToString();
_head.Controls.Add(
new LiteralControl($"<script type=\"text/javascript\" src=\"ScriptsBundler?v={version}\"></script>\n")
);
_head.Controls.Add(
new LiteralControl($"<link href=\"StylesBundler?v={version}\" type=\"text/css\" rel=\"stylesheet\"/>\n")
);
html.Controls.Add(_body);
_body.Controls.Add(_form);
var pnlHeader = new Panel {CssClass = "divHeader"};
_form.Controls.Add(pnlHeader);
HyperLink lnkTitle = new HyperLink {NavigateUrl = "."};
pnlHeader.Controls.Add(lnkTitle);
var lblTitle = new Label {Text = GlobalConfig.Get().Title, Tag = "h1"};
lnkTitle.Controls.Add(lblTitle);
_btnPostback.ID = "btnPostback";
_btnPostback.Text = "Postback";
pnlHeader.Controls.Add(_btnPostback);
_btnPostback.Style.Add("display", "none");
var pnlUserInfo = new Panel {CssClass = "divUserInfo"};
pnlHeader.Controls.Add(pnlUserInfo);
_btnLogout.ID = "btnLogout";
_btnLogout.Text = MultiLang.GetLiteral("Logout");
_btnLogout.Click += btnLogout_Click;
_btnLogout.Attributes.Add(
"onclick",
$"return confirm('{MultiLang.GetLiteral("ConfirmExit")}');"
);
pnlUserInfo.Controls.Add(_btnLogout);
_pnlContainer.CssClass = "divContent";
_form.Controls.Add(_pnlContainer);
}
#endregion Private methods
} }

View File

@@ -1,27 +0,0 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:58454/",
"sslPort": 44386
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"VAR.WebFormsCore": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}

View File

@@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>10</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>