DEV Community

Cover image for Getting Started with Redis, Elastic Beanstalk, and Razor Pages (.NET 6)

Getting Started with Redis, Elastic Beanstalk, and Razor Pages (.NET 6)

Hello! How are you today? I'm going to share my exploration of Redis, Elastic Beanstalk, and Razor Pages in ASP.NET 6. So, let's check it out.

Required Tools

You will be required these tools. Please download and install it.

  1. .NET 6
  2. Docker
  3. VS Code (Optional)

Project Preparation

You will need to prepare the project of Razor Pages. You can follow the steps below.

  • Generate the .gitignore. This will be useful when you are using a changes tracker like git.


dotnet new gitignore


Enter fullscreen mode Exit fullscreen mode

Generate .gitignore

  • Generate the Razor Project


dotnet new razor -o RedisSample


Enter fullscreen mode Exit fullscreen mode

Generate Project

  • Generate the solution to link the root repository to the project directory.


dotnet new sln


Enter fullscreen mode Exit fullscreen mode

Generate sln

  • Add the project to the solution.


dotnet sln add RedisSample


Enter fullscreen mode Exit fullscreen mode

Add to sln

  • Install Redis.OM to the project.


dotnet add .\RedisSample\ package Redis.OM --version 0.2.1


Enter fullscreen mode Exit fullscreen mode

Add Redis.OM

  • Try to build, so we know the process is already done.


dotnet build


Enter fullscreen mode Exit fullscreen mode

Try build

Time to Code!

  • If you want skip the step by step of coding steps, you may use this repository.

GitHub logo bervProject / redis-sample

Redis sample app

Redis Sample

Sample App using Redis as main databases.

Demo

Tools

  1. .NET 6
  2. Docker
  3. VS Code (Optional)

Install Dependencies

dotnet restore
Enter fullscreen mode Exit fullscreen mode

How to Run

  • Normal Run
dotnet run --project RedisSample
Enter fullscreen mode Exit fullscreen mode
  • With File Watcher
dotnet watch --project RedisSample
Enter fullscreen mode Exit fullscreen mode

Build

dotnet build
Enter fullscreen mode Exit fullscreen mode

Publish

dotnet publish -o PublishedRedisSample
Enter fullscreen mode Exit fullscreen mode

LICENSE

MIT






  • Update the Program.cs like this.


using Redis.OM;
using RedisSample.HostedService;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton(new RedisConnectionProvider(builder.Configuration["REDIS_CONNECTION_STRING"]));
builder.Services.AddHostedService<CreateIndexService>();

// Add services to the container.
builder.Services.AddRazorPages();

// the rest of the codes

// ...

app.Run();


Enter fullscreen mode Exit fullscreen mode

Full file

  • Create the model file: Models/Note.cs. This model will be used to define the redis data model.


using Redis.OM.Modeling;

namespace RedisSample.Models;

[Document(StorageType = StorageType.Json, Prefixes = new[] { "Note" })]
public class Note
{
    [RedisIdField]
    public Ulid Id { get; set; }
    [Indexed]
    public string Title { get; set; }

    [Indexed]
    public string Message { get; set; }
}


Enter fullscreen mode Exit fullscreen mode

Full file

  • Create file HostedServices/CreateIndexService.cs. This class will be used to create the index of the model.


using Redis.OM;
using RedisSample.Models;

namespace RedisSample.HostedService;

public class CreateIndexService : IHostedService
{
  private readonly RedisConnectionProvider _redisConnectionProvider;
  public CreateIndexService(RedisConnectionProvider redisConnectionProvider)
  {
    _redisConnectionProvider = redisConnectionProvider;
  }

  public Task StartAsync(CancellationToken cancellationToken)
  {
    _redisConnectionProvider.Connection.CreateIndex(typeof(Note));
    return Task.CompletedTask;
  }

  public Task StopAsync(CancellationToken cancellationToken)
  {
    return Task.CompletedTask;
  }
}


Enter fullscreen mode Exit fullscreen mode

Full file

  • Now, let's go the Pages directory. We will update Index.cshtml and Index.cshtml.cs also create new file AddNote.cshtml, AddNote.cshtml.cs, EditNote.cshtml, EditNote.cshtml.cs. Here we go. You may check the files in here.

  • Index.cshtml




@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div>
    <a class="btn btn-primary" asp-area="" asp-page="/AddNote" role="button">Add Note</a>
    <p>Total Notes: @Model.NoteList.Count</p>
    <div class="container">
        <div class="row gy-3">
            @foreach (var note in Model.NoteList)
            {
                <div class="col-6">
                    <div class="card">
                        <div class="card-body">
                            <p class="h1">@note.Title</p>
                            <p>@note.Message</p>
                            <div class="row">
                                <div class="col-2">
                                    <a class="btn btn-secondary" asp-area="" asp-page="/EditNote" asp-route-id="@note.Id"
                                    role="button">Edit</a>
                                </div>
                                <div class="col-2">
                                    <form method="post">
                                        <button class="btn btn-danger" type="submit" asp-page-handler="DeleteNote"
                                        asp-route-id="@note.Id">Delete</button>
                                    </form>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            }
        </div>
    </div>
</div>


Enter fullscreen mode Exit fullscreen mode
  • Index.cshtml.cs


sing Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Redis.OM;
using Redis.OM.Searching;
using RedisSample.Models;

namespace RedisSample.Pages;

public class IndexModel : PageModel
{
  private readonly ILogger<IndexModel> _logger;
  private readonly IRedisCollection<Note> _notes;
  public List<Note> NoteList { get; set; } = new List<Note>();


  public IndexModel(ILogger<IndexModel> logger, RedisConnectionProvider redisConnection)
  {
    _logger = logger;
    _notes = redisConnection.RedisCollection<Note>();
  }

  public async Task OnGetAsync()
  {
    var notes = await _notes.ToListAsync();
    NoteList.AddRange(notes);
  }

  public async Task<IActionResult> OnPostDeleteNoteAsync(string id)
  {
    var note = await _notes.FindByIdAsync(id);

    _logger.LogDebug($"...... data: {note}");

    if (note == null)
    {
      return NotFound();
    }

    await _notes.DeleteAsync(note);
    await _notes.SaveAsync();

    return RedirectToPage();
  }
}


Enter fullscreen mode Exit fullscreen mode
  • AddNote.cshtml


@page
@model AddNoteModel
@{
    ViewData["Title"] = "Add Note";
}

<h1>Add Note</h1>

<div class="card">
    <div class="card-body">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Note!.Title" class="control-label">Title</label>
                <input asp-for="Note!.Title" class="form-control" placeholder="Enter the title of notes">
                <span asp-validation-for="Note!.Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Note!.Message">Message</label>
                <textarea class="form-control" asp-for="Note!.Message" placeholder="Enter the message of notes here"> </textarea>
                <span asp-validation-for="Note!.Message" class="text-danger"></span>
            </div>
            <button type="submit" class="btn btn-primary">Submit</button>
        </form>
    </div>

</div>


Enter fullscreen mode Exit fullscreen mode
  • AddNote.cshtml.cs


using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Redis.OM;
using Redis.OM.Searching;
using RedisSample.Models;

namespace RedisSample.Pages;

public class AddNoteModel : PageModel
{
    private readonly ILogger<AddNoteModel> _logger;
    private readonly IRedisCollection<Note> _notes;

    [BindProperty]
    public Note? Note { get; set; }

    public AddNoteModel(ILogger<AddNoteModel> logger, RedisConnectionProvider redisConnection)
    {
        _logger = logger;
        _notes = redisConnection.RedisCollection<Note>();
    }

    public void OnGet()
    {

    }

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        if (Note != null)
        {
            await _notes.InsertAsync(Note);
        }
        await _notes.SaveAsync();
        return Redirect("/");
    }
}


Enter fullscreen mode Exit fullscreen mode
  • EditNote.cshtml


page "{id}"
@model EditNoteModel
@{
    ViewData["Title"] = "Edit Note";
}

<h1>Edit Note</h1>

<div class="card">
    <div class="card-body">
        <form method="post">
            <input type="hidden" asp-for="Note!.Id" />
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Note!.Title" class="control-label">Title</label>
                <input asp-for="Note!.Title" class="form-control" placeholder="Enter the title of notes">
                <span asp-validation-for="Note!.Title" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Note!.Message">Message</label>
                <textarea class="form-control" asp-for="Note!.Message" placeholder="Enter the message of notes here"> </textarea>
                <span asp-validation-for="Note!.Message" class="text-danger"></span>
            </div>
            <button type="submit" class="btn btn-primary">Submit</button>
        </form>
    </div>

</div>


Enter fullscreen mode Exit fullscreen mode
  • EditNote.cshtml.cs


using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Redis.OM;
using Redis.OM.Searching;
using RedisSample.Models;

namespace RedisSample.Pages;

public class EditNoteModel : PageModel
{
  private readonly ILogger<AddNoteModel> _logger;
  private readonly IRedisCollection<Note> _notes;

  [BindProperty]
  public Note? Note { get; set; }

  public EditNoteModel(ILogger<AddNoteModel> logger, RedisConnectionProvider redisConnection)
  {
    _logger = logger;
    _notes = redisConnection.RedisCollection<Note>();
  }

  public async Task<IActionResult> OnGetAsync(string id)
  {
    Note = await _notes.FindByIdAsync(id);
    if (Note == null)
    {
      return NotFound();
    }
    return Page();
  }

  public async Task<IActionResult> OnPostAsync()
  {
    if (!ModelState.IsValid)
    {
      return Page();
    }

    if (Note != null)
    {
      await _notes.UpdateAsync(Note);
    }
    await _notes.SaveAsync();
    return Redirect("/");
  }
}


Enter fullscreen mode Exit fullscreen mode

Test our code locally

Finally done! Now, let's start to try our code. But, we will need to host the Redis Stack first. We will run the Redis Stack using docker. You can check this link for more details. Basically you can run using this command.



docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 redis/redis-stack:6.2.2-v4


Enter fullscreen mode Exit fullscreen mode

Ok, let's try our code. You can run the project using this command dotnet run --project RedisSample or dotnet watch --project RedisSample.

Now, let's explore your website! You can check this video for the demo.

You might need to check the RedisInsight for more details about the stored data.

Redis Insight

Preparing Redis Stack

I think it will not be enough if we just implement it locally. So we will need to host it somewhere else. We will deploy it to Elastic Beanstalk, but I will host the Redis Stack using Redis Enterprise since they have options to host in AWS! For more details on how I set up the Redis Enterprise, you may check this video.

Preparing Elastic Beanstalk

Now, since the Redis Stack is ready. We will move to set up Elastic Beanstalk. Please check this video.

Testing Your App

Finally, we test our code that is hosted in Elastic Beanstalk. Here's my video.

Why I didn't use ElastiCache? So, when I'm exploring the ElastiCache, seems the ElastiCache doesn't have the RediSearch module, so I can't create the index. Like this error logs.

error logs

Thank you

Thank you for reading and watching. If you have any comments and suggestions, please feel free to comment in the comment section and tell me about your suggestion.

Yay GIF

Top comments (0)