How To: Create a Simple Alert System Using Tag Helpers In Asp.Net Core Mvc

How To: Create a Simple Alert System Using Tag Helpers In Asp.Net Core Mvc

Create a simple alert system to enhance user experience.

In this post I’m gonna show you how to create an alert system using the tag helpers feature from the asp.net core mvc.

During this tutorial, I’ll be using a simple to do list project that I build, in order to experiment new stuff, you can download or clone this git repository.

The Problem

Feedback is important for the user, usually, is in form of messages on the screen. We could follow the client-side approach, by, creating an ajax request and showing a message after the response, or instead, follow the server-side approach, storing a message on a view bag, or even return a model with the message.

The asp.net core mvc has a new feature called tag helper, enabling us to create an alert system on the server-side.

Setting Up The Alert System

First, we need to configure the project to use session. With this in mind, we add the line services.AddSession();in the ConfigureServices method from the Startup class.

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ToDoDbContext>(
        options =>
            options.UseSqlServer(Configuration.GetConnectionString("SimpleToDo")));

    services.AddTransient<IToDoListService, ToDoListService>();
    services.AddTransient<IToDoListRepository, ToDoListRepository>();
    services.AddTransient<ITaskService, TaskService>();
    services.AddTransient<ITaskRepository, TaskRepository>();
            
    services.AddSession();
    services.AddMvc();
}

This line enables your asp.net core mvc project to use the TempData feature. The TempData _uses a session variable internally to store data between requests. We are going to use _TempData to store our alerts.

Now we’re going to create a class which will contain the message and the message type:

public class Alert
{
    public string Message;
    public string Type;

    public Alert(string message, string type)
    {
        Message = message;
        Type = type;
    }
}

To be able to store data in the TempData, we’re going to create a class that will contain extension methods, to add the alerts in the TempData.

public static class AlertExtensions
{
    private const string AlertKey = "SimpleToDo.Alert";

    public static void AddAlertSuccess(this Controller controller, string message)
    {
        var alerts = GetAlerts(controller);

        alerts.Add(new Alert(message, "alert-success"));

        controller.TempData[AlertKey] = JsonConvert.SerializeObject(alerts);
    }

    public static void AddAlertInfo(this Controller controller, string message)
    {
        var alerts = GetAlerts(controller);

        alerts.Add(new Alert(message, "alert-info"));

        controller.TempData[AlertKey] = JsonConvert.SerializeObject(alerts);
    }

    public static void AddAlertWarning(this Controller controller, string message)
    {
        var alerts = GetAlerts(controller);

        alerts.Add(new Alert(message, "alert-warning"));

        controller.TempData[AlertKey] = JsonConvert.SerializeObject(alerts);
    }

    public static void AddAlertDanger(this Controller controller, string message)
    {
        var alerts = GetAlerts(controller);

        alerts.Add(new Alert(message, "alert-danger"));

        controller.TempData[AlertKey] = JsonConvert.SerializeObject(alerts);
    }

    private static ICollection<Alert> GetAlerts(Controller controller)
    {
        if (controller.TempData[AlertKey] == null)
            controller.TempData[AlertKey] = JsonConvert.SerializeObject(new HashSet<Alert>());

        ICollection<Alert> alerts = JsonConvert.DeserializeObject<ICollection<Alert>>(controller.TempData[AlertKey].ToString());

        if (alerts == null)
        {
            alerts = new HashSet<Alert>();
        }
        return alerts;
    }
}

With this class we can add many alert types in the TempData.

First, we get all alerts stored in the TempData by a key, like a dictionary. They will be stored as a serialized JSON.

After that, we add the alert on the list. The type a bootstrap class that we’re using to apply style on the client-side. Finally, we serialize the list and store it again in the TempData.

One side note, in the asp.net core mvc the TempData has some trouble to store complex data like we’re doing, so the solution was to serialize the HashSet, and deserialize it when we need it.

The Alert Tag Helper

Tag Helpers enable the server-side to create and render HTML in razor files, enabling custom html tags creation. You can read more about tag helpers here.

To create our own Alert tag helper, we need to create a new class extending the TagHelper class.

public class AlertsTagHelper : TagHelper
{
    private const string AlertKey = "SimpleToDo.Alert";

    [ViewContext]
    public ViewContext ViewContext { get; set; }

    protected ITempDataDictionary TempData => ViewContext.TempData;

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = "div";

        if (TempData[AlertKey] == null)
            TempData[AlertKey] = JsonConvert.SerializeObject(new HashSet<Alert>());

        var alerts = JsonConvert.DeserializeObject<ICollection<Alert>>(TempData[AlertKey].ToString());

        var html = string.Empty;

        foreach (var alert in alerts)
        {
            html += $"<div class='alert {alert.Type}' id='inner-alert' role='alert'>" +
                        $"<button type='button' class='close' data-dismiss='alert' aria-label='Close'>" +
                            $"<span aria-hidden='true'>&times;</span>" +
                        $"</button>" +
                        $"{alert.Message}" +
                    $"</div>";
        }

        output.Content.SetHtmlContent(html);
    }
}

The class’ name is AlertsTagHelper, is important to use this kind of nomenclature in tag helper, like, “TagName” + “TagHelper”. The “TagName” will be our custom tag, as I’m going to show later.

We can use dependency injection in the tag helper, for this reason, we create public properties and these properties will be injected. In our case we have one property, the ViewContext, which is responsible to get the current view’s context. The TempData property is just a way to access the ViewContext’s TempData more easily.

To create the html output, we have to override the Process method, which is the only thing that we have to do to set the output. The Process method has two arguments, the context and output, we’re going to use only the output in this case.

In the Process method we set the output’s TagName as “div”, meaning that a div will embrace the html produce in the output. We get all the alerts stored in the TempData and create a string which will contain all the html produced. We iterate through all alerts, concatenating each alert with the html alert template from bootstrap 3, you can check it here. The Type is used to set the bootstrap alert class and the Message will be showed on the screen. After that, we set the html output as our variable containing all the alerts.

The last thing that we need to do is to make the project recognize our tag helper. To do this, we have register the tag helper dependency in the _ViewImports.cshtml file:

_ViewImport.cshtml

By adding the @addTagHelper *, SimpleToDo.Webline in the file, we say to the asp.net core mvc to look for tag helpers on the web project. Now our custom html tag, alert, will be recognized as a html tag and also we’ll have intellisense.

The Usage

Use the tag helper is pretty simple, basically we need to put the tag <alerts> in a view. My choice was to put the tag on the layout page, by doing this, the alerts will be available for every page.

Alerts tag usage in the _Layout.cshtml

The only thing left is to add the alerts on the TempData, for this reason, we’re going to use those extensions methods that we created before.

For example, we could add an alert when we successfully add a task in a list:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("TaskId,ListId,Name,Description,Done")] Task task)
{
    if (ModelState.IsValid)
    {
        await _taskService.CreateTask(task);

        this.AddAlertSuccess($"{task.Name} created successfully.");

        return RedirectToAction(nameof(Index), new { listId = task.ListId });
    }

    return View(new TaskCreateEditViewModel
    {
        ListId = task.ListId,
        Name = task.Name,
        Description = task.Description
    });
}

The line this.AddAlertSuccess($"{task.Name} created successfully.");do the trick. Now when we run the project and add a task, as a result, the alert will show up on the screen:

As you can see, the alert is showing up on the screen after the postback and the redirect to the list page. Every time that a postback/redirect/refresh happens on the page, the alerts tag helper will be called and check if there’s alerts to show.

That’s all what I have for this tutorial, there’s some details in the project’s implementation which I omit, because I wanted to show only the tag helper details, you can check all the project’s code here.

This was an example of the tag helper usage. There’s some much more room to explore in this new asp.net core mvc functionality.


© 2021. All rights reserved.

Powered by Hydejack v9.1.6