Add a post on alerts in ASP.NET Core
This commit is contained in:
parent
ed004bfd8a
commit
c2812ffce2
197
src/posts/AspNetCoreAlerts.md
Normal file
197
src/posts/AspNetCoreAlerts.md
Normal file
|
@ -0,0 +1,197 @@
|
|||
---
|
||||
title: ASP.NET Core Alerts
|
||||
description: Tools to display alerts across redirects
|
||||
tags: [ Programming, C#, ASP.NET Core ]
|
||||
---
|
||||
|
||||
This code allows you to store alerts that will be displayed the next time the user is served a page. This is useful for when you want to display an alert after a redirect.
|
||||
|
||||
## How To Use
|
||||
|
||||
To add an alert use one of the extension methods to add an alert to the session:
|
||||
|
||||
```csharp
|
||||
return this.RedirectToPage("/Things/Index")
|
||||
.WithSuccess("Did the thing!");
|
||||
```
|
||||
|
||||
Then to display the alerts, add something like this to the `_Layout.cshtml`:
|
||||
|
||||
```csharp
|
||||
@{
|
||||
Alert[] alerts = this.TempData.GetAlerts();
|
||||
}
|
||||
|
||||
@if (alerts != null && alerts.Any())
|
||||
{
|
||||
foreach (Alert alert in alerts)
|
||||
{
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that calling `TempData.GetAlerts()` will also remove all current alerts from the session so they won't be displayed on following page loads.
|
||||
|
||||
## Code
|
||||
|
||||
The alerts class:
|
||||
|
||||
```csharp
|
||||
public class Alert
|
||||
{
|
||||
public AlertType AlertType { get; set; }
|
||||
public string Text { get; set; }
|
||||
|
||||
public Alert(AlertType alertType, string text)
|
||||
{
|
||||
this.AlertType = alertType;
|
||||
this.Text = text;
|
||||
}
|
||||
}
|
||||
|
||||
public enum AlertType
|
||||
{
|
||||
Success,
|
||||
Info,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
```
|
||||
|
||||
The `AlertActionResult` To wrap the return `ActionResult` and actually add the alert to the session:
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// This is a wrapper around another action result. When executed, this adds the given alert to
|
||||
/// TempData and executes the inner ActionResult
|
||||
/// </summary>
|
||||
public class AlertActionResult : ActionResult
|
||||
{
|
||||
public ActionResult InnerResult { get; set; }
|
||||
public Alert Alert { get; set; }
|
||||
|
||||
public AlertActionResult(ActionResult innerResult, Alert alert)
|
||||
{
|
||||
this.InnerResult = innerResult;
|
||||
this.Alert = alert;
|
||||
}
|
||||
|
||||
public AlertActionResult(ActionResult innerResult, AlertType alertType, string alertText)
|
||||
{
|
||||
this.InnerResult = innerResult;
|
||||
this.Alert = new Alert(alertType, alertText);
|
||||
}
|
||||
|
||||
public override void ExecuteResult(ActionContext context)
|
||||
{
|
||||
ITempDataDictionary tempData = context.HttpContext.RequestServices
|
||||
.GetService<ITempDataDictionaryFactory>()
|
||||
.GetTempData(context.HttpContext);
|
||||
|
||||
tempData.AddAlert(this.Alert);
|
||||
|
||||
this.InnerResult.ExecuteResult(context);
|
||||
}
|
||||
|
||||
public override async Task ExecuteResultAsync(ActionContext context)
|
||||
{
|
||||
ITempDataDictionary tempData = context.HttpContext.RequestServices
|
||||
.GetService<ITempDataDictionaryFactory>()
|
||||
.GetTempData(context.HttpContext);
|
||||
|
||||
tempData.AddAlert(this.Alert);
|
||||
|
||||
if (this.InnerResult is PageResult pageResult)
|
||||
{
|
||||
// Need to do some additional setup for Razor Pages
|
||||
// See https://stackoverflow.com/questions/55989209/
|
||||
|
||||
PageContext pageContext = context as PageContext
|
||||
?? throw new ArgumentException("The context must be a PageContext for Razor Pages",
|
||||
nameof(context));
|
||||
|
||||
Func<PageContext, ViewContext, object> pageFactory = pageContext.HttpContext.RequestServices
|
||||
.GetRequiredService<IPageFactoryProvider>()
|
||||
.CreatePageFactory(pageContext.ActionDescriptor);
|
||||
|
||||
ViewContext viewContext = new(
|
||||
pageContext,
|
||||
NullView.Instance,
|
||||
pageContext.ViewData,
|
||||
tempData,
|
||||
TextWriter.Null,
|
||||
new HtmlHelperOptions())
|
||||
{
|
||||
ExecutingFilePath = pageContext.ActionDescriptor.RelativePath
|
||||
};
|
||||
|
||||
pageResult.ViewData = viewContext.ViewData;
|
||||
pageResult.Page = (PageBase)pageFactory(pageContext, viewContext);
|
||||
}
|
||||
|
||||
await this.InnerResult.ExecuteResultAsync(context);
|
||||
}
|
||||
|
||||
private class NullView : IView
|
||||
{
|
||||
public static readonly NullView Instance = new();
|
||||
|
||||
public string Path => string.Empty;
|
||||
|
||||
public Task RenderAsync(ViewContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context, nameof(context));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And some extension methods for adding and getting alerts:
|
||||
|
||||
```csharp
|
||||
public static class AspNetExtensions
|
||||
{
|
||||
private static readonly string _alertsTempDataKey = "atticAlerts";
|
||||
|
||||
public static Alert[] GetAlerts(this ITempDataDictionary tempData)
|
||||
{
|
||||
if (!tempData.ContainsKey(_alertsTempDataKey))
|
||||
tempData[_alertsTempDataKey] = JsonSerializer.Serialize(Array.Empty<Alert>());
|
||||
|
||||
return JsonSerializer.Deserialize<Alert[]>(tempData[_alertsTempDataKey] as string);
|
||||
}
|
||||
|
||||
public static void AddAlert(this ITempDataDictionary tempData, Alert alert)
|
||||
{
|
||||
Alert[] currentAlerts = tempData.GetAlerts();
|
||||
|
||||
currentAlerts = currentAlerts
|
||||
.Concat(new Alert[] { alert })
|
||||
.ToArray();
|
||||
tempData[_alertsTempDataKey] = JsonSerializer.Serialize(currentAlerts);
|
||||
}
|
||||
|
||||
public static ActionResult WithSuccess(this ActionResult actionResult, string alertText)
|
||||
{
|
||||
return new AlertActionResult(actionResult, AlertType.Success, alertText);
|
||||
}
|
||||
|
||||
public static ActionResult WithInfo(this ActionResult actionResult, string alertText)
|
||||
{
|
||||
return new AlertActionResult(actionResult, AlertType.Info, alertText);
|
||||
}
|
||||
|
||||
public static ActionResult WithWarning(this ActionResult actionResult, string alertText)
|
||||
{
|
||||
return new AlertActionResult(actionResult, AlertType.Warning, alertText);
|
||||
}
|
||||
|
||||
public static ActionResult WithError(this ActionResult actionResult, string alertText)
|
||||
{
|
||||
return new AlertActionResult(actionResult, AlertType.Error, alertText);
|
||||
}
|
||||
}
|
||||
```
|
Loading…
Reference in a new issue