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>