Added SessionState Components
|
@ -1,7 +1,48 @@
|
|||
{
|
||||
"Version": 1,
|
||||
"WorkspaceRootPath": "C:\\Repos\\SummerBestWebForm2\\",
|
||||
"Documents": [],
|
||||
"Documents": [
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|c:\\repos\\summerbestwebform2\\components\\app.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|solutionrelative:components\\app.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|c:\\repos\\summerbestwebform2\\components\\_imports.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}",
|
||||
"RelativeMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|solutionrelative:components\\_imports.razor||{40D31677-CBC0-4297-A9EF-89D907823A98}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|c:\\repos\\summerbestwebform2\\sessionstate\\sessionmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|solutionrelative:sessionstate\\sessionmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|c:\\repos\\summerbestwebform2\\sessionstate\\sessionidmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|solutionrelative:sessionstate\\sessionidmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|c:\\repos\\summerbestwebform2\\classobj\\mdlsessioninfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|solutionrelative:classobj\\mdlsessioninfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|c:\\repos\\summerbestwebform2\\sessionstate\\mdlsession.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|solutionrelative:sessionstate\\mdlsession.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|c:\\repos\\summerbestwebform2\\appstate\\mdlappstate.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|solutionrelative:appstate\\mdlappstate.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|c:\\repos\\summerbestwebform2\\appstate\\cascadingappstate.razor.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|solutionrelative:appstate\\cascadingappstate.razor.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|c:\\repos\\summerbestwebform2\\appstate\\iappstate.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|solutionrelative:appstate\\iappstate.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
},
|
||||
{
|
||||
"AbsoluteMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|c:\\repos\\summerbestwebform2\\program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||
"RelativeMoniker": "D:0:0:{10E16044-8880-42A4-866B-B0461C450A71}|SummerBestWebForm2.csproj|solutionrelative:program.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||
}
|
||||
],
|
||||
"DocumentGroupContainers": [
|
||||
{
|
||||
"Orientation": 0,
|
||||
|
@ -9,7 +50,7 @@
|
|||
"DocumentGroups": [
|
||||
{
|
||||
"DockedWidth": 200,
|
||||
"SelectedChildIndex": -1,
|
||||
"SelectedChildIndex": 11,
|
||||
"Children": [
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
|
@ -54,6 +95,136 @@
|
|||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}"
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 0,
|
||||
"Title": "App.razor",
|
||||
"DocumentMoniker": "C:\\Repos\\SummerBestWebForm2\\Components\\App.razor",
|
||||
"RelativeDocumentMoniker": "Components\\App.razor",
|
||||
"ToolTip": "C:\\Repos\\SummerBestWebForm2\\Components\\App.razor",
|
||||
"RelativeToolTip": "Components\\App.razor",
|
||||
"ViewState": "AgIAACQAAAAAAAAAAAAYwFwAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2025-05-15T09:23:12.142Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 9,
|
||||
"Title": "Program.cs",
|
||||
"DocumentMoniker": "C:\\Repos\\SummerBestWebForm2\\Program.cs",
|
||||
"RelativeDocumentMoniker": "Program.cs",
|
||||
"ToolTip": "C:\\Repos\\SummerBestWebForm2\\Program.cs",
|
||||
"RelativeToolTip": "Program.cs",
|
||||
"ViewState": "AgIAABMAAAAAAAAAAAAAACsAAAAAAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-05-15T10:01:38.124Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 8,
|
||||
"Title": "IAppState.cs",
|
||||
"DocumentMoniker": "C:\\Repos\\SummerBestWebForm2\\AppState\\IAppState.cs",
|
||||
"RelativeDocumentMoniker": "AppState\\IAppState.cs",
|
||||
"ToolTip": "C:\\Repos\\SummerBestWebForm2\\AppState\\IAppState.cs",
|
||||
"RelativeToolTip": "AppState\\IAppState.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-05-15T10:03:35.861Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 7,
|
||||
"Title": "CascadingAppState.razor.cs",
|
||||
"DocumentMoniker": "C:\\Repos\\SummerBestWebForm2\\AppState\\CascadingAppState.razor.cs",
|
||||
"RelativeDocumentMoniker": "AppState\\CascadingAppState.razor.cs",
|
||||
"ToolTip": "C:\\Repos\\SummerBestWebForm2\\AppState\\CascadingAppState.razor.cs",
|
||||
"RelativeToolTip": "AppState\\CascadingAppState.razor.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAoAAAA6AAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-05-15T10:03:51.372Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 6,
|
||||
"Title": "MdlAppState.cs",
|
||||
"DocumentMoniker": "C:\\Repos\\SummerBestWebForm2\\AppState\\MdlAppState.cs",
|
||||
"RelativeDocumentMoniker": "AppState\\MdlAppState.cs",
|
||||
"ToolTip": "C:\\Repos\\SummerBestWebForm2\\AppState\\MdlAppState.cs",
|
||||
"RelativeToolTip": "AppState\\MdlAppState.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-05-15T10:04:02.184Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 5,
|
||||
"Title": "MdlSession.cs",
|
||||
"DocumentMoniker": "C:\\Repos\\SummerBestWebForm2\\SessionState\\MdlSession.cs",
|
||||
"RelativeDocumentMoniker": "SessionState\\MdlSession.cs",
|
||||
"ToolTip": "C:\\Repos\\SummerBestWebForm2\\SessionState\\MdlSession.cs",
|
||||
"RelativeToolTip": "SessionState\\MdlSession.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-05-15T10:04:06.197Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 4,
|
||||
"Title": "MdlSessionInfo.cs",
|
||||
"DocumentMoniker": "C:\\Repos\\SummerBestWebForm2\\ClassObj\\MdlSessionInfo.cs",
|
||||
"RelativeDocumentMoniker": "ClassObj\\MdlSessionInfo.cs",
|
||||
"ToolTip": "C:\\Repos\\SummerBestWebForm2\\ClassObj\\MdlSessionInfo.cs",
|
||||
"RelativeToolTip": "ClassObj\\MdlSessionInfo.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-05-15T10:04:10.974Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 3,
|
||||
"Title": "SessionIdManager.cs",
|
||||
"DocumentMoniker": "C:\\Repos\\SummerBestWebForm2\\SessionState\\SessionIdManager.cs",
|
||||
"RelativeDocumentMoniker": "SessionState\\SessionIdManager.cs",
|
||||
"ToolTip": "C:\\Repos\\SummerBestWebForm2\\SessionState\\SessionIdManager.cs",
|
||||
"RelativeToolTip": "SessionState\\SessionIdManager.cs",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-05-15T10:04:14.473Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 2,
|
||||
"Title": "SessionManager.cs",
|
||||
"DocumentMoniker": "C:\\Repos\\SummerBestWebForm2\\SessionState\\SessionManager.cs",
|
||||
"RelativeDocumentMoniker": "SessionState\\SessionManager.cs",
|
||||
"ToolTip": "C:\\Repos\\SummerBestWebForm2\\SessionState\\SessionManager.cs",
|
||||
"RelativeToolTip": "SessionState\\SessionManager.cs",
|
||||
"ViewState": "AgIAAAIAAAAAAAAAAAAAAAIAAAAcAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||
"WhenOpened": "2025-05-15T10:04:17.539Z",
|
||||
"EditorCaption": ""
|
||||
},
|
||||
{
|
||||
"$type": "Document",
|
||||
"DocumentIndex": 1,
|
||||
"Title": "_Imports.razor",
|
||||
"DocumentMoniker": "C:\\Repos\\SummerBestWebForm2\\Components\\_Imports.razor",
|
||||
"RelativeDocumentMoniker": "Components\\_Imports.razor",
|
||||
"ToolTip": "C:\\Repos\\SummerBestWebForm2\\Components\\_Imports.razor",
|
||||
"RelativeToolTip": "Components\\_Imports.razor",
|
||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAoAAAAiAAAAAAAAAA==",
|
||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000759|",
|
||||
"WhenOpened": "2025-05-15T10:07:58.031Z",
|
||||
"EditorCaption": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
@* @using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||
@rendermode InteractiveServer
|
||||
*@
|
||||
<CascadingValue Value="this">
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SummerBestWebForm2.AppState;
|
||||
|
||||
public partial class CascadingAppState : ComponentBase, IAppState
|
||||
{
|
||||
private readonly string StorageKey = "SummerBestWebForm2-MyCarHQ";
|
||||
[Parameter]
|
||||
public RenderFragment? ChildContent { get; set; }
|
||||
[Inject]
|
||||
ProtectedLocalStorage? localStorage { get; set; }
|
||||
[Inject]
|
||||
IHttpContextAccessor? httpContextAccessor { get; set; }
|
||||
|
||||
bool isLoaded = false;
|
||||
|
||||
public Guid SessionId { get; set; }
|
||||
|
||||
public bool isInit { get; set; }
|
||||
|
||||
//public CascadingAppState()
|
||||
//{
|
||||
// Load();
|
||||
//}
|
||||
|
||||
private string? _myIpAddress = string.Empty;
|
||||
public string? myIpAddress
|
||||
{
|
||||
get => _myIpAddress;
|
||||
set
|
||||
{
|
||||
_myIpAddress = value;
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
private DateTimeOffset _DateCreated = DateTimeOffset.Now;
|
||||
public DateTimeOffset DateCreated
|
||||
{
|
||||
get => _DateCreated;
|
||||
set
|
||||
{
|
||||
_DateCreated = value;
|
||||
Save();
|
||||
}
|
||||
}
|
||||
private DateTimeOffset _DateExpires = DateTimeOffset.Now;
|
||||
public DateTimeOffset DateExpires
|
||||
{
|
||||
get => _DateExpires;
|
||||
set
|
||||
{
|
||||
_DateExpires = value;
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
// (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O) / (o) (O)
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
if (firstRender)
|
||||
{
|
||||
await LoadAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void Save()
|
||||
{
|
||||
new Task(async () =>
|
||||
{
|
||||
await SaveAsync();
|
||||
}).Start();
|
||||
} //Save
|
||||
|
||||
public async Task SaveAsync()
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
|
||||
// serialize
|
||||
var state = (IAppState)this;
|
||||
var json = JsonSerializer.Serialize(state);
|
||||
// save
|
||||
await localStorage.SetAsync(StorageKey, json);
|
||||
} //SaveAsync
|
||||
|
||||
private void Load()
|
||||
{
|
||||
new Task(async () =>
|
||||
{
|
||||
await LoadAsync();
|
||||
}).Start();
|
||||
} //Load
|
||||
|
||||
public async Task LoadAsync()
|
||||
{
|
||||
string remoteIpAddr=string.Empty;
|
||||
try
|
||||
{
|
||||
remoteIpAddr = httpContextAccessor.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "";
|
||||
var data = await localStorage.GetAsync<string>(StorageKey);
|
||||
var state = JsonSerializer.Deserialize<MdlAppState>(data.Value);
|
||||
|
||||
if (state != null)
|
||||
{
|
||||
if (DateTimeOffset.Now < state.DateExpires)
|
||||
{
|
||||
// decide whether to set properties manually or with reflection
|
||||
|
||||
// comment to set properties manually
|
||||
//this.Message = state.Message;
|
||||
//this.Count = state.Count;
|
||||
|
||||
// set properties using Reflaction
|
||||
var t = typeof(IAppState);
|
||||
//var props = t.GetProperties();
|
||||
PropertyInfo[] props = t.GetProperties();
|
||||
foreach (var prop in props)
|
||||
{
|
||||
//if (!Regex.IsMatch(prop.Name, "isInit|SessionId|"))
|
||||
{
|
||||
var value = prop.GetValue(state, null);
|
||||
prop.SetValue(this, value, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// do something
|
||||
}
|
||||
isLoaded = true;
|
||||
DateExpires = DateTimeOffset.Now.AddHours(36);
|
||||
myIpAddress = remoteIpAddr;
|
||||
if (!isInit)
|
||||
{
|
||||
DateCreated = DateTimeOffset.Now;
|
||||
SessionId = Guid.NewGuid();
|
||||
isInit = true;
|
||||
await SaveAsync();
|
||||
}
|
||||
await InvokeAsync(() =>
|
||||
{
|
||||
StateHasChanged();
|
||||
});
|
||||
} //LoadAsync
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace SummerBestWebForm2.AppState;
|
||||
|
||||
public interface IAppState
|
||||
{
|
||||
bool isInit { get; set; }
|
||||
string? myIpAddress { get; set; }
|
||||
Guid SessionId { get; set; }
|
||||
DateTimeOffset DateCreated { get; set; }
|
||||
DateTimeOffset DateExpires { get; set; }
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace SummerBestWebForm2.AppState;
|
||||
|
||||
public class MdlAppState : IAppState
|
||||
{
|
||||
public bool isInit { get; set; }
|
||||
public string? myIpAddress { get; set; }
|
||||
public Guid SessionId { get; set; }
|
||||
public DateTimeOffset DateCreated { get; set; }
|
||||
public DateTimeOffset DateExpires { get; set; }
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
namespace SummerBestWebForm2;
|
||||
|
||||
public class MdlSessionInfo
|
||||
{
|
||||
public const string KEY_IPADDRESS = "IPAddress";
|
||||
public string IPAddress { get; set; } = null!;
|
||||
public bool isInit { get; set; } = false;
|
||||
public DateTimeOffset DateCreated { get; set; } = DateTimeOffset.MinValue;
|
||||
|
||||
public MdlSessionInfo()
|
||||
{
|
||||
// Have to have a blank ctor here for ProtectedSessionStorage
|
||||
}
|
||||
|
||||
}
|
|
@ -1,20 +1,92 @@
|
|||
<!DOCTYPE html>
|
||||
@inject IHttpContextAccessor httpContextAccessor
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<base href="/" />
|
||||
<link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="app.css" />
|
||||
<link rel="stylesheet" href="SummerBestWebForm2.styles.css" />
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<HeadOutlet @rendermode="InteractiveServer" />
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<base href="/" />
|
||||
<meta name="description" content="KeyMotive's Summer Best Customer Program Enrollment" />
|
||||
<meta name="author" content="KeyMotive LLC" />
|
||||
<meta name="Charset" content="US-ASCII" />
|
||||
<meta name="Distribution" content="Global" />
|
||||
<meta name="Rating" content="General" />
|
||||
<meta name="Robots" content="INDEX,FOLLOW" />
|
||||
<meta name="Revisit-after" content="14 Days" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin />
|
||||
<link href='https://fonts.googleapis.com/css?family=Roboto|Handlee|Candal|Exo 2|Armata|Poppins|Kalam:wght@300&display=swap' rel='stylesheet' type='text/css' />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/css/bootstrap.min.css" integrity="sha512-jnSuA4Ss2PkkikSOLtYs8BlYIeeIK1h99ty4YfvRPAlzr377vr3CXDb7sb7eEEBYjDtcYj+AjBH3FLv5uSJuXg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
<link rel="stylesheet" href="app.css" />
|
||||
<link rel="stylesheet" href="SummerBestWebForm2.styles.css" />
|
||||
<link rel="icon" type="image/png" sizes="512x512" href="/img/favico-512.png">
|
||||
<link rel="icon" type="image/png" sizes="256x256" href="/img/favico-256.png">
|
||||
<link rel="icon" type="image/png" sizes="128x128" href="/img/favico-128.png">
|
||||
<link rel="icon" type="image/png" sizes="64x64" href="/img/favico-64.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/img/favico-32.png">
|
||||
<style type="text/css">
|
||||
div.container {
|
||||
background-color: #fff;
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
<HeadOutlet @rendermode="InteractiveServer" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<Routes @rendermode="InteractiveServer" />
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
<Routes @rendermode="InteractiveServer" />
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.bundle.min.js" integrity="sha512-7Pi/otdlbbCR+LnW+F7PwFcSDJOuUJB3OxtEHbg4vSMvzvJjde4Po1v4BR9Gdc9aXNUNFVUY+SK51wWT8WF0Gg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/js/all.min.js" integrity="sha512-u3fPA7V8qQmhBPNT5quvaXVa1mnnLSXUep5PS1qo5NRzHwG19aHmNJnj1Q8hpA/nBWZtZD4r4AX6YOt5ynLN2g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script>
|
||||
window.WriteCookie = {
|
||||
WriteCookie: function (name, value, days) {
|
||||
var expires;
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
expires = "; expires=" + date.toGMTString();
|
||||
}
|
||||
else {
|
||||
expires = "";
|
||||
}
|
||||
document.cookie = name + "=" + value + expires + "; path=/";
|
||||
}
|
||||
}
|
||||
window.ReadCookie = {
|
||||
ReadCookie: function (cname) {
|
||||
var name = cname + "=";
|
||||
var decodedCookie = decodeURIComponent(document.cookie);
|
||||
var ca = decodedCookie.split(';');
|
||||
for (var i = 0; i < ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<pre>@errMsg</pre>
|
||||
@if (appState != null)
|
||||
{
|
||||
<pre style="font-size:.8em">
|
||||
SessionId: @appState.SessionId
|
||||
DateCreated: @appState.DateCreated
|
||||
DateExpires: @appState.DateExpires
|
||||
IPAddress: @appState.myIpAddress
|
||||
</pre>
|
||||
}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@code {
|
||||
[CascadingParameter]
|
||||
public CascadingAppState appState { get; set; }
|
||||
|
||||
private string errMsg = string.Empty;
|
||||
}
|
||||
|
|
|
@ -8,3 +8,4 @@
|
|||
@using Microsoft.JSInterop
|
||||
@using SummerBestWebForm2
|
||||
@using SummerBestWebForm2.Components
|
||||
@using SummerBestWebForm2.AppState
|
||||
|
|
73
Program.cs
|
@ -1,36 +1,65 @@
|
|||
using Microsoft.AspNetCore.ResponseCompression;
|
||||
using SummerBestWebForm2.Components;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace SummerBestWebForm2
|
||||
{
|
||||
public class Program
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents();
|
||||
// Add services to the container.
|
||||
builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents();
|
||||
|
||||
var app = builder.Build();
|
||||
builder.Services.AddResponseCompression(options =>
|
||||
{
|
||||
options.EnableForHttps = true;
|
||||
options.Providers.Add<BrotliCompressionProvider>();
|
||||
options.Providers.Add<GzipCompressionProvider>();
|
||||
});
|
||||
builder.Services.Configure<BrotliCompressionProviderOptions>(options =>
|
||||
{
|
||||
options.Level = CompressionLevel.Fastest;
|
||||
});
|
||||
builder.Services.Configure<GzipCompressionProviderOptions>(options =>
|
||||
{
|
||||
options.Level = CompressionLevel.SmallestSize;
|
||||
});
|
||||
builder.Services.AddDataProtection();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseExceptionHandler("/Error");
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
builder.Services.AddScoped<HttpContextAccessor>();
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
var app = builder.Build();
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseAntiforgery();
|
||||
// Configure the HTTP request pipeline.
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseExceptionHandler("/Error");
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.MapRazorComponents<App>()
|
||||
.AddInteractiveServerRenderMode();
|
||||
var webSocketOptions = new WebSocketOptions()
|
||||
{
|
||||
KeepAliveInterval = TimeSpan.FromSeconds(15)
|
||||
};
|
||||
app.UseWebSockets(webSocketOptions);
|
||||
app.UseResponseCompression();
|
||||
app.UseResponseCaching();
|
||||
|
||||
app.Run();
|
||||
}
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseAntiforgery();
|
||||
|
||||
app.MapRazorComponents<App>()
|
||||
.AddInteractiveServerRenderMode();
|
||||
|
||||
app.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
namespace SummerBestWebForm2.SessionState;
|
||||
|
||||
public class MdlSession : Dictionary<string, string>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Session Id value.
|
||||
/// </summary>
|
||||
public string SessionId { get; set; } = string.Empty;
|
||||
public string IPAddress { get; set; } = string.Empty;
|
||||
public bool IsCheckedOut { get; set; } = false;
|
||||
public DateTimeOffset dtExpires { get; set; } = DateTimeOffset.Now.AddHours(36);
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
namespace SummerBestWebForm2.SessionState;
|
||||
|
||||
// INTERFACE
|
||||
|
||||
public interface ISessionIdManager
|
||||
{
|
||||
Task<string?> GetSessionIdAsync();
|
||||
Task<string?> GetIPAddressAsync();
|
||||
}
|
||||
|
||||
// CODE
|
||||
|
||||
public class SessionIdManager(IHttpContextAccessor httpContextAccessor) : ISessionIdManager
|
||||
{
|
||||
private readonly IHttpContextAccessor HttpContextAccessor = httpContextAccessor;
|
||||
|
||||
public Task<string?> GetSessionIdAsync()
|
||||
{
|
||||
var httpContext = HttpContextAccessor.HttpContext;
|
||||
string? result;
|
||||
|
||||
if (httpContext != null)
|
||||
{
|
||||
if (httpContext.Request.Cookies.ContainsKey("sessionId"))
|
||||
{
|
||||
result = httpContext.Request.Cookies["sessionId"];
|
||||
}
|
||||
else
|
||||
{
|
||||
result = Guid.NewGuid().ToString();
|
||||
httpContext.Response.Cookies.Append("sessionId", result);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("No HttpContext available");
|
||||
}
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
public Task<string?> GetIPAddressAsync()
|
||||
{
|
||||
var httpContext = HttpContextAccessor.HttpContext;
|
||||
string? result;
|
||||
|
||||
if (httpContext != null)
|
||||
{
|
||||
result = httpContext.Connection.RemoteIpAddress?.ToString();// ?? "Not Set";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("No HttpContext available");
|
||||
}
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
using System.Net;
|
||||
|
||||
namespace SummerBestWebForm2.SessionState;
|
||||
|
||||
// INTERFACE
|
||||
|
||||
public interface ISessionManager
|
||||
{
|
||||
Task<MdlSession> GetSession();
|
||||
Task UpdateSession(MdlSession session);
|
||||
}
|
||||
|
||||
// CODE
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary containing per-user session objects, keyed
|
||||
/// by sessionId.
|
||||
/// </summary>
|
||||
public class SessionManager : ISessionManager
|
||||
{
|
||||
private Dictionary<Guid, MdlSession> _sessions = new Dictionary<Guid, MdlSession>();
|
||||
private readonly ISessionIdManager _sessionIdManager;
|
||||
private object syncLock1 = new();
|
||||
|
||||
public SessionManager(ISessionIdManager sessionIdManager)
|
||||
{
|
||||
_sessionIdManager = sessionIdManager;
|
||||
}
|
||||
|
||||
public async Task<MdlSession> GetSession()
|
||||
{
|
||||
string key = await _sessionIdManager.GetSessionIdAsync() ?? "";
|
||||
string ipAddress = await _sessionIdManager.GetIPAddressAsync() ?? "";
|
||||
Guid theSessionId;
|
||||
|
||||
if (!Guid.TryParse(key, out theSessionId))
|
||||
theSessionId = Guid.Empty;//Guid.Parse(key);
|
||||
|
||||
MdlSession session;
|
||||
bool needToCreateNew = false;
|
||||
|
||||
if (!_sessions.ContainsKey(theSessionId))
|
||||
{
|
||||
needToCreateNew = true;
|
||||
}
|
||||
else if (_sessions[theSessionId].dtExpires < DateTimeOffset.Now)
|
||||
needToCreateNew = true;
|
||||
|
||||
if (needToCreateNew)
|
||||
{
|
||||
session = new MdlSession() { SessionId = key, IPAddress = ipAddress };
|
||||
_sessions.Add(theSessionId, new MdlSession());
|
||||
}
|
||||
else
|
||||
session = _sessions[theSessionId];
|
||||
|
||||
// ensure session isn't checked out by wasm
|
||||
//while (session.IsCheckedOut)
|
||||
// await Task.Delay(5);
|
||||
var endTime = DateTime.UtcNow.AddSeconds(10);
|
||||
while (session.IsCheckedOut)
|
||||
{
|
||||
if (DateTime.UtcNow > endTime)
|
||||
throw new TimeoutException();
|
||||
await Task.Delay(5);
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
public async Task UpdateSession(MdlSession session)
|
||||
{
|
||||
if (session != null)
|
||||
{
|
||||
string key = await _sessionIdManager.GetSessionIdAsync() ?? "";
|
||||
string ipAddress = await _sessionIdManager.GetIPAddressAsync() ?? "";
|
||||
Guid theSessionId;
|
||||
|
||||
if (!Guid.TryParse(key, out theSessionId))
|
||||
theSessionId = Guid.Empty;//Guid.Parse(key);
|
||||
|
||||
if (_sessions.ContainsKey(theSessionId))
|
||||
{
|
||||
//session = new MdlSession() { SessionId = key, IPAddress = ipAddress };
|
||||
session.SessionId = key;
|
||||
session.dtExpires = DateTimeOffset.Now.AddHours(36); // Rolling expiration date
|
||||
_sessions[theSessionId] = session;
|
||||
_sessions[theSessionId].IsCheckedOut = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var sess = new MdlSession() { SessionId = key, IPAddress = ipAddress };
|
||||
_sessions[theSessionId] = session;
|
||||
}
|
||||
|
||||
// Remove stale sessions
|
||||
lock (syncLock1)
|
||||
{
|
||||
try
|
||||
{
|
||||
var lstRemove = new HashSet<Guid>();
|
||||
foreach (var kvp in _sessions)
|
||||
{
|
||||
if (kvp.Value.dtExpires < DateTimeOffset.Now && !lstRemove.Contains(kvp.Key))
|
||||
lstRemove.Add(kvp.Key);
|
||||
}
|
||||
foreach (var rmv in lstRemove)
|
||||
_sessions.Remove(rmv);
|
||||
lstRemove.Clear();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// do something
|
||||
}
|
||||
}
|
||||
}
|
||||
} //UpdateSession
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Replace the contents of oldSession with the items
|
||||
/// in newSession.
|
||||
/// </summary>
|
||||
/// <param name="newSession"></param>
|
||||
/// <param name="oldSession"></param>
|
||||
private void Replace(MdlSession newSession, MdlSession oldSession)
|
||||
{
|
||||
oldSession.Clear();
|
||||
foreach (var key in newSession.Keys)
|
||||
oldSession.Add(key, newSession[key]);
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ using System.Reflection;
|
|||
[assembly: System.Reflection.AssemblyCompanyAttribute("SummerBestWebForm2")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+92bc4657300f745b2cfa9a7b2055bd3fd4591564")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("SummerBestWebForm2")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("SummerBestWebForm2")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
|
|
@ -1 +1 @@
|
|||
98a44021c4ce1eb513aa177c5c56797f58eab237be1d5eb9823389d6970b0f70
|
||||
17e471ad6ef47e2a4bd7241cad398f501e58c3d66500f6f4af29608363c718b3
|
||||
|
|
|
@ -20,6 +20,10 @@ build_property._RazorSourceGeneratorDebug =
|
|||
build_property.EffectiveAnalysisLevelStyle = 8.0
|
||||
build_property.EnableCodeStyleSeverity =
|
||||
|
||||
[C:/Repos/SummerBestWebForm2/AppState/CascadingAppState.razor]
|
||||
build_metadata.AdditionalFiles.TargetPath = QXBwU3RhdGVcQ2FzY2FkaW5nQXBwU3RhdGUucmF6b3I=
|
||||
build_metadata.AdditionalFiles.CssScope =
|
||||
|
||||
[C:/Repos/SummerBestWebForm2/Components/App.razor]
|
||||
build_metadata.AdditionalFiles.TargetPath = Q29tcG9uZW50c1xBcHAucmF6b3I=
|
||||
build_metadata.AdditionalFiles.CssScope =
|
||||
|
|
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 50 KiB |