ma.citi

A Coder's Blog

Razor pages and Entity Framework core as an In-Memory DB.

Recently I installed Visual Studio 2017 and I wanted to try Razor Pages, a new feature of ASP.NET Core 2. According to Microsoft it makes coding page-focused scenarios easier and more productive.

For my test I decided to create a simple web page with a simple form where a user can subscribe to a website inserting name and email address. The same page will also show the list of users already registered.

With the introduction of Entity Framework Core 1.0 it is possible to use an in-memory data provider, this will spare us to use a local or external database.

Installation

For this test I downloaded and installed VS 2017 community edition. visual studio downloads

and I downloaded and installed from github .net core 2.0 .net core 2.0

Create new project

In Visual Studio 2017 create a new .NET Core Project..

razor screenshot

..select ASP.NET Core 2.0 and Web Application

razor screenshot

Now the project has been created. Via Nuget packages I installed Microsoft.EntityFrameworkCore.InMemory

razor screenshot

Create the DB Model and the DBContext

I created a new folder called DbModels, and I created the first class representing the user subscribing the service

razor screenshot

    public class Subscriber
    {
        public int Id { get; set; }

        [Required]
        public string Name { get; set; }

        [Required]
        [RegularExpression(@"^([\w\.\-]+)@([\w\-]+)((\.(\w){2,3})+)$", ErrorMessage = "Email field must be a valid email address")]
        public string Email { get; set; }
    }

I created my DbContext for Entity Framework, it implements DbContext class, and it contains the entity set “Subscribers”

razor screenshot

    public class InMemoryDbContext : DbContext
    {
        public InMemoryDbContext(DbContextOptions<InMemoryDbContext> opts) : base(opts) { }

        public DbSet<Subscriber> Subscribers { get; set; }
    }

The last step is to initialize the DbContext in the Startup.cs file, adding the following line inside the ConfigureServices method

services.AddDbContext<InMemoryDbContext>(options => options.UseInMemoryDatabase("myFirstInMemDB"));

Create new Razor Page

Righ click on pages folder and add a new Razor Page. I called this page “Subscribe”

razor screenshot

razor screenshot

A SubscribeModel class is created automatically in the Subscrive.cshtml.cs file.

I’ve added a read-only field that represents my in-memory DB context and initialize it in the constructor.

 

private readonly InMemoryDbContext _dbContext;

public SubscribeModel(InMemoryDbContext dbContext)
{
    _dbContext = dbContext;
}

I also added a property Subscriber with a BindProperty attribute for the model binding when I’m going to post using a form the subscriber details.

I also needed a List of all subscribers to show in the page

 

[BindProperty]
public Subscriber Subscriber { get; set; }

public IEnumerable<Subscriber> Subscribers { get; private set; } 

I created a method that handle the post of a new subscriber (The naming convention is OnPost[handler])

 

public PageResult OnPostAdd()
{
    if (!ModelState.IsValid)
        return Page();

    _dbContext.Subscribers.Add(Subscriber);

    _dbContext.SaveChanges();

    Subscribers = _dbContext.Subscribers.ToList();

    return Page();
}

The Html form

The last step is to write the client part in the Subscribe.cshtml

The form:

 

<div class="alert-danger">@Html.ValidationSummary()</div>
<form method="post">
	<div asp-validation-summary="All" class="alert-danger"></div>
	<input asp-for="Subscriber.Name" placeholder="Name" /><br />
	<input asp-for="Subscriber.Email" placeholder="Email" /><br />
	<input type="submit" asp-page-handler="add" value="Submit" />
</form>

@Html.ValidationSummary() to show server side validation errors, asp-validation-summary=”All” for client side ones. On the submit input field I need to specify the name of the handler asp-page-handler=”add” (OnPost[handler])

I also wanted to display all the previous subscribers

 

<h3>Subscribers:</h3>
<table class="table">
	<thead>
		<tr>
			<th>ID</th>
			<th>Name</th>
			<th>Email</th>
		</tr>
	</thead>
	<tbody>
		@foreach (var sub in Model.Subscribers)
		{
			<tr>
				<td>@sub.Id</td>
				<td>@sub.Name</td>
				<td>@sub.Email</td>
			</tr>
		}
	</tbody>
</table>

The last step is to populate the Subscribers property in the OnGet method

 

    public void OnGet()
    {
        Subscribers = _dbContext.Subscribers.ToList();
    }
		

To test it http://yourmachine/Subscribe