Advanced Ajapa Dhyana Yoga for Software Developers : Tap the power of breath, mantra, mudra, and meditation for improved focus, peace of mind, and blissful inner connection.


CRUD using fetch() and Razor Pages in ASP.NET Core -- Part 1

In the previous article we discussed the basics of the browser's fetch() API. We also fetched HTML page from the server using GET verb. Now it's time to do something more interesting -- CRUD operations using fetch() and Razor Pages.

The fetch() API is a client side technique to send requests to server side resources. You can send the requests using any of the supported HTTP verbs such as GET, POST, PUT, and DELETE. Of course, the server needs to know how to deal with these requests.

As an example, in this article we will use fetch() in combination with Razor Pages. The Razor Page contains page handlers that deal with GET, POST, PUT, and DELETE verbs. The UI sends the CRUD requests using fetch(). The data transfer between page handlers and UI happens using JSON objects. The following figure shows how the UI looks like:

As you can see, the UI consists of a dropdown list, four textboxes, and three buttons. When the page loads in the browser, the dropdown list shows a list of all the CustomerIDs from the Customers table of Northwind database. Upon selecting a particular CustomerID, its CompanyName, ContactName, and Country are displayed into the corresponding textboxes.

To add a new customer, you will enter a new CustomerID in the textbox placed besides the dropdown list. You will also fill the the three textboxes and then click on the Insert button. To update a customer, you will select its CustomerID in the dropdown list, modify its existing details and then hit the Update button. Finally, to delete a customer you will select its CustomerID in the dropdown list and click the Delete button. You could have added many features to this UI such as validations and prompts but to keep things simple and to keep our focus on the main topic of this article, we will only have basic data entry functionality.

To build this example, open the same project (or create a new one if you want) that you created in the previous article. In the previous article we created an MVC app. So, you need to configure a few things to use it for Razor Pages. We also need Customer entity class and a DbContext class.

So, let's get going.

Add a new folder named DataAccess inside the project root. Then add a class called Customer to the DataAccess project. The Customer class is shown below:

public class Customer
{
    [Key]
    [Required]
    public string CustomerID { get; set; }

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

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

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

As you can see, the Customer class contains four public properties namely CustomerID, CompanyName, ContactName, and Country. These properties correspond to the respective columns in the Customers table.

Then add another class named AppDbContext in the DataAccess folder and write the following code in it.

public class AppDbContext:DbContext
{
    public DbSet<Customer> Customers { get; set; }

    public AppDbContext(DbContextOptions
    <AppDbContext> options):base(options)
    {

    }
}    

This is custom DbContext class and inherits from DbContext base class. Inside, there is Customers property and a constructor to support dependency injection.

Now open appsettings.json file and place the database connection string in it.

"ConnectionStrings": {
    "AppDb": "data source=.;initial catalog=Northwind;
    integrated security=true;Encrypt=False"
    }    

Notice that the connection string name is AppDb and it points to the local installation of the Northwind database. Make sure to change this connection string as per your development setup.

Next, open Program.cs file and add the following code in it.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<AppDbContext>
(o => o.UseSqlServer(builder.Configuration
.GetConnectionString("AppDb")));
builder.Services.AddAntiforgery(o => 
o.HeaderName = "MY-XSRF-TOKEN");

builder.Services.AddControllers();
builder.Services.AddControllersWithViews();

builder.Services.AddRazorPages();

var app = builder.Build();
app.UseStaticFiles();
app.UseRouting();
app.MapDefaultControllerRoute();

app.MapRazorPages();

app.Run();    

Notice the code marked in bold letters. We register the AppDbContext with the DI container so that it can be injected in the Razor Pages. We also use AddAntiforgery() method to specify that the anti-forgery token will be passed using an HTTP header instead of request body. This is required for Razor Pages because they automatically emit and validate the anti-forgery token. And this token must be included in the fetch() request header since full page post back is not happening (fetch() is an Ajax request). The header name MY-XSRF-TOKEN can be substituted with any other custom name of your choice.

We then call AddRazorPages() and MapRazorPages() to enable Razor Pages in our MVC project.

Now add Pages folder immediately under the project's root folder. And add a new Razor Page named Index.cshtml. This will also add its page model class Index.cshtml.cs.

Then open the Page Model class and inject the AppDbContext as shown below:

private readonly AppDbContext db;

public IndexModel(AppDbContext db)
{
    this.db = db;
}    

The injected AppDbContext is used by all the page handlers to do the CRUD operations. The first two page handlers deal with the GET request and take care of returning all the customers and a customer with a specific ID to the UI. They are shown below:

public IActionResult OnGetSelectAll()
{
    List<Customer> data = db.Customers.ToList();
    return new JsonResult(data);
}

public IActionResult OnGetSelectByID(string id)
{
    Customer data = db.Customers.Find(id);
    return new JsonResult(data);
}    

Notice that both the page handlers begin with "OnGet" indicating that they are dealing with the GET requests. What follows -- SelectAll and SelectByID -- is the page handler name and will be used while making the fetch() calls from the UI. Also, notice that the SelectByID page handler accepts CustomerID to retrieve through the id parameter.

Inside, we retrieve the desired data and return that data to the client using JsonResult object. This way the client will receive Customers in JSON format. SelectAll handler returns a list of Customer objects whereas SelectByID handler returns a single Customer object.

Next, we add a page handler that handles the POST requests:

public IActionResult OnPostInsert
([FromBody] Customer obj)
{
    db.Customers.Add(obj);
    db.SaveChanges();
    return new JsonResult
    ("Customer Added Successfully!");
}    

Note that the OnPostInsert() page handler accepts a Customer object from the request body. It then tries to add that object to the Customers table using Add() and SaveChanges() methods. The handler returns a success message to the caller.

The PUT request handler follows a similar pattern:

public IActionResult OnPutUpdate(string id, 
[FromBody] Customer obj)
{
    db.Customers.Update(obj);
    db.SaveChanges();
    return new JsonResult
    ("Customer Modified Successfully!");
}    

The OnPutUpdate() accepts a CustomerID to be updated and the modified Customer details. Inside, it tries to update the Customers table using the Update() and SaveChanges() methods. As before, a success message is sent back to the client.

Finally, we add a page handler to deal with the DELETE requests.

public IActionResult OnDeleteDelete(string id)
{
    db.Customers.Remove(db.Customers.Find(id));
    db.SaveChanges();
    return new JsonResult
    ("Customer Deleted Successfully!");
}    

The OnDeleteDelete() page handler receives a CustomerID to be deleted and attempts to delete that Customer using Find(), Remove() and SaveChanges() methods. And also sends a success message to the client.

This completes the Page Model class. Although our project will compile and run successfully, it won't do anything meaningful because we haven't added the UI and fetch() calls yet. We will do that in the next part of this article.

That's it for now! Keep coding!!


Bipin Joshi is an independent software consultant and trainer by profession specializing in Microsoft web development technologies. Having embraced the Yoga way of life he is also a meditation teacher and spiritual guide to his students. He is a prolific author and writes regularly about software development and yoga on his websites. He is programming, meditating, writing, and teaching for over 27 years. To know more about his ASP.NET online courses go here. More details about his Ajapa Japa and Shambhavi Mudra online course are available here.

Posted On : 31 January 2023







Advanced Ajapa Yoga Kriyas and Meditations for Software Developers : Tap the power of breath, mantra, mudra, and dhyana for improved focus, peace of mind, and blissful inner connection.