namespace Framework.App
{
using Framework.Json;
using Framework.Session;
using Framework.Server;
using Microsoft.AspNetCore.Http;
using System;
using System.Threading.Tasks;
using System.Linq;
using Framework.Config;
using System.Collections.Generic;
using System.Text.Json;
using System.IO;
///
/// Create AppJson or deserialize from server session. Process request. Serialize AppJson to server session and angular client.
///
internal class AppSelector
{
///
/// Constructor.
///
public AppSelector()
{
List result = new List();
string requestDomainName = UtilServer.RequestDomainName();
this.ConfigServer = ConfigServer.Load();
foreach (var website in ConfigServer.WebsiteList)
{
foreach (var item in website.DomainNameList)
{
if (item.DomainName == requestDomainName)
{
result.Add(website);
}
}
}
// Make sure Website has been found
if (result.Count == 0)
{
if (!File.Exists(ConfigServer.FileName))
{
throw new Exception("File ConfigServer.json not found! Make sure cli (wpx) did run at least once.");
}
// Run command cli env name=dev
throw new Exception(string.Format("Website not found! See also file: ConfigServer.json (Domain={0}; Environment={1};)", requestDomainName, this.ConfigServer.EnvironmentName));
}
if (result.Count > 1)
{
throw new Exception(string.Format("More than one website found! See also file: ConfigServer.json ({0})", requestDomainName));
}
this.ConfigWebsite = result.Single();
this.ConfigDomain = ConfigWebsite.DomainNameList.Where(item => item.DomainName == requestDomainName).Single();
this.AppTypeName = ConfigDomain.AppTypeName;
}
///
/// Gets ConfigServer. Currently loaded config.
///
public readonly ConfigServer ConfigServer;
///
/// Gets ConfigWebsite. This is the currently requested Website.
///
public readonly ConfigServerWebsite ConfigWebsite;
///
/// Gets ConfigDomain. This is the currently requested domain.
///
public readonly ConfigServerWebsiteDomain ConfigDomain;
///
/// Gets AppTypeName. This is the currently requested App.
///
public readonly string AppTypeName;
///
/// Returns JsonClient. Create AppJson and process request.
///
internal async Task ProcessAsync(HttpContext context, AppJson appJson)
{
if (appJson == null)
{
// Create AppJson with session data.
appJson = await CreateAppJsonSession(context);
}
// Process
try
{
await appJson.ProcessInternalAsync(appJson, this);
}
catch (Exception exception)
{
new Alert(appJson, UtilFramework.ExceptionToString(exception), AlertEnum.Error);
appJson.IsReload = true;
context.Response.Cookies.Delete(StartupFramework.CookieName); // Delete session cookie to request new session.
}
// Version tag
RenderVersion(appJson);
// RequestCount
appJson.RequestCount = appJson.RequestJson.RequestCount;
// ResponseCount
appJson.ResponseCount += 1;
// SerializeSession, SerializeClient
UtilSession.Serialize(appJson, out string jsonClientResponse);
return jsonClientResponse;
}
///
/// Create AppJson with session data.
///
internal async Task CreateAppJsonSession(HttpContext context)
{
// Deserialize RequestJson
RequestJson requestJson;
string requestJsonText = await UtilServer.StreamToString(context.Request.Body);
if (requestJsonText != null)
{
requestJson = JsonSerializer.Deserialize(requestJsonText);
requestJson.Origin = RequestOrigin.Browser;
foreach (var command in requestJson.CommandList)
{
command.GridCellText = UtilFramework.StringNull(command.GridCellText); // Sanitize incomming request.
}
}
else
{
requestJson = new RequestJson(null) { RequestCount = 1 };
}
// Deserialize AppJson (Session) or init
var appJson = UtilSession.Deserialize();
// IsExpired
bool isSessionExpired = appJson == null && requestJson.RequestCount > 1;
bool isBrowserRefresh = appJson != null && requestJson.RequestCount == 1 && requestJson.RequestCount != appJson.RequestCount + 1;
bool isBrowserTabSwitch = !isBrowserRefresh && (appJson != null && requestJson.ResponseCount != appJson.ResponseCount);
bool isException = appJson?.IsReload == true; // After exception has been thrown recycle session.
// New session
if (appJson == null || isBrowserTabSwitch || isException)
{
// New AppJson (Session)
bool isInit = false;
if (appJson == null || UtilServer.Context.Request.Method == "GET")
{
appJson = CreateAppJson();
isInit = true;
}
appJson.RequestUrlHost = UtilServer.RequestUrlHost();
appJson.IsSessionExpired = isSessionExpired;
// New RequestJson
string browserNavigatePath = requestJson.BrowserNavigatePath;
requestJson = new RequestJson(null) { RequestCount = requestJson.RequestCount, BrowserNavigatePathPost = requestJson.BrowserNavigatePathPost }; // Reset RequestJson.
appJson.RequestJson = requestJson;
// Add navigate command to queue
if (UtilServer.Context.Request.Method == "POST" || browserNavigatePath == "/")
{
appJson.Navigate(browserNavigatePath, isAddHistory: false); // User clicked backward or forward button in browser.
}
// New session init
if (isInit)
{
await appJson.InitInternalAsync();
}
}
else
{
appJson.IsSessionExpired = false;
}
// Set RequestJson
appJson.RequestJson = requestJson;
return appJson;
}
///
/// Create AppJson without session data.
///
public AppJson CreateAppJson()
{
Type type;
try
{
type = UtilFramework.TypeFromName(AppTypeName);
}
catch
{
throw new Exception(string.Format("AppTypeName does not exist! See also file: ConfigServer.json ({0})", AppTypeName));
}
AppJson result = (AppJson)Activator.CreateInstance(type);
return result;
}
private void RenderVersion(AppJson appJson)
{
// Version
appJson.Version = UtilFramework.Version;
appJson.VersionBuild = UtilFramework.VersionBuild;
// Session
appJson.Session = UtilServer.Session.Id;
if (string.IsNullOrEmpty(appJson.SessionApp))
{
appJson.SessionApp = UtilServer.Session.Id;
}
}
}
}