Friday, November 19, 2021

Use Razor Pages, MVC, And Web API In A Single ASP.NET Core Application

 If you are worked with ASP.NET Core 2.0 before you are probably aware that Visual Studio 2017 offers three basic project templates for creating ASP.NET Core 2.0 projects. They are Web Application (Razor Pages), Web Application (MVC), and Web API (see below). Interestingly Web Application project defaults to Razor Pages.

It is important for the beginners to be aware that although these are three different project templates, you can have all these development options - Razor Pages, MVC, and Web API - inside a single ASP.NET Core web application. These three technologies work seamlessly with each other and can happily coexist in a single project. To that end the remainder of this article explains how to setup an Empty project to use all of them together.

Quick Background

When Microsoft released ASP.NET Core 1.0 it had only MVC based development. For developing web applications developers used MVC and for building services developers resorted to Web API. In ASP.NET Core 2.0 they introduced Razor Pages. When you are doing MVC style development the focus is in the controllers. It's the controller that prepares model and sends it to a view.

In Razor Pages the focus shifts to UI or the web pages. Razor Pages allow you to develop page focused application where each page is a sort of independent unit in itself. Razor Pages don't have any controller at all. The UI goes inside a .cshtml file and the code goes inside a Page Model file. The Page Model class contains actions that deal with HTTP verbs such as GET and POST. If you developed web applications using ASP.NET Web Forms (code behind approach) you will find Razor Pages approach familiar.

Web API continue to use a controller based development.

In spite of these differences you can create a single project that makes use of these three development options. Core features such as model binding, DI, sessions, and cache can be utilized in Razor Pages as well as MVC in the same way.

Create an empty project

To begin our example, create a new project using Visual Studio 2017 based on the Empty project template. Once the project is created open its Startup file and write the following code to it :

public void ConfigureServices
(IServiceCollection services)
{
    services.AddMvc();
}

public void Configure(
IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseDeveloperExceptionPage();
    app.UseStaticFiles();
    app.UseMvcWithDefaultRoute();
}

The ConfigureServices() calls AddMvc() to add the required services to DI container. The Configure() then calls UseMvcWithDefaultRoute() to add MVC middleware with default routing configured for us.

Setup for Razor Pages

Now that you have created the project, let's prepare it to use Razor Pages.

Begin by creating a folder named Pages under project's root folder. By default razor pages are stored inside Pages folder and can be accessed from the browser with Pages as their root. For example, if you have Index.cshtml housed inside Pages folder then it can be accessed as http://localhost:12345/Index

To add a razor page. right click on the Pages folder and then select Add > New Item.

Select Razor Page item and specify name as Index.cshtml. Click on the Add button. You will observe that two files - Index.cshtml and Index.cshtml.cs - get added to the Pages folder.

You can create further folder tree under Pages folder. According to the page's location its URL will change. For example, if you store Index2.cshtml under /Pages/MyFolder then you can access it at http://localhost:12345/MyFolder/Index2

Setup for MVC

Ok. Now let's prepare our project to use MVC.

Create three folders - Models, Views, and Controllers under project's root folder. Then create Home subfolder under Views folder.

Add a model class - Employee - inside Models folder. Add a controller - HomeController - under Controllers folder.

Also add Index.cshtml view under Views > Home folder.

Setup for Web API

Now add API folder under project's root. It's not required to isolate Web API in a separate folder, you can keep them in Controllers folder along with other MVC controllers. But for the sake of better organization I am storing the Web API inside the API folder.

Then add a Web API controller - ValuesController - inside the API folder. The values controller will contain Get() action that returns a couple of string values. Keep that intact since we need it for our testing.

To complete the project setup add Scripts folder under wwwroot and place jQuery library in it. We need jQuery to call the Web API.

At the end of all these steps your Solution Explorer should look like this :

 

Razor Page markup and code

So far so good. Now it's time to add a dash of markup and code to our application so that we can confirm its working.

Open Index.cshtml.cs PageModel class and write the following code to it :

public class IndexModel : PageModel
{
    public string FullName { get; set; }

    public void OnGet()
    {
        FullName = "Nancy Davolio";
        ViewData["heading"] = "Welcome 
to ASP.NET Core Razor Pages !!";
    }
}

The IndexModel class contains FullName public property. The OnGet() action assigns a value to FullName and also stores a heading inside the ViewData dictionary.

Now open Index.cshtml and add the following code to it :

@page
@model RazorPagesMvcWebApi.Pages.IndexModel

<script src="~/Scripts/jquery-3.2.1.min.js"></script>

<script>

    $(document).ready(function () {

        var options = {};
        options.url = "/api/values";
        options.type = "GET";
        options.dataType = "json";
        options.success = function (data) {

            data.forEach(function (element) {
                $("#result").append("<h3>" + element + "</h3>");
            });
        };
        options.error = function () {
            $("#msg").html("Error while calling the Web API!");
        };
        $.ajax(options);
     });


</script>


<h1>@ViewData["heading"]</h1>

<h2>@Model.FullName</h2>

<h2>Result of Web API call</h2>

<div id="result"></div>

The above markup outputs the FullName and heading from the Model and ViewData respectively. Moreover, it contains jQuery Ajax code to call the Web API. Notice that the Web API can be accessed at /api/values. The return values from the Web API are displayed in the result <div> element at the bottom of the page. I won't go into details of this code since it's a typical piece of code for making Ajax calls.

MVC markup and code

Now open Employee class from the Models folder and add FullName property to it :

public class Employee
{
    public string FullName { get; set; }
}

Then go to HomeController class and write the following code to the Index() action :

public IActionResult Index()
{
    Employee emp = new Employee();
    emp.FullName = "Nancy Davolio";
    ViewData["heading"] = "Welcome to ASP.NET Core MVC !!";
    return View(emp);
}

The above code prepares the Employee model object by setting its FullName property. It also stores the heading in ViewData dictionary. Finally, it passes the model to the Index view.

Finally, open the Index.cshtml from Views > Home folder and write the following code to it :

@model RazorPagesMvcWebApi.Models.Employee

<script src="~/Scripts/jquery-3.2.1.min.js"></script>

<script>
    $(document).ready(function () {
        var options = {};
        options.url = "/api/values";
        options.type = "GET";
        options.dataType = "json";
        options.success = function (data) {
            data.forEach(function (element) {
                $("#result").append("<h3>" + element + "</h3>");
            });
        };
        options.error = function () {
            $("#msg").html("Error while calling the Web API!");
        };
        $.ajax(options);
     });
</script>

<h1>@ViewData["heading"]</h1>

<h2>@ViewData["timestamp"]</h2>

<h2>@Model.FullName</h2>

<h2>Result of Web API call</h2>

<div id="result"></div>

This is basically the same that you wrote in the Index.cshtml razor page but uses Employee model class rather than a PageModel class.

Sample run of the application

Ok.  So, we have a razor page, an MVC controller, and a Web API controller housed in a single ASP.NET Core project. Let's see whether it works as expected.

Run the application and give hits to the following URLs:

http://localhost:12345/Index

http://localhost:12345/Home/Index

If all goes well your browser should look like (first URL) :

And like this (second URL) :

As you can see razor pages, MVC, and Web API are working happily in a single web application.

That's it for now ! Keep coding !!

No comments:

Post a Comment

No String Argument Constructor/Factory Method to Deserialize From String Value

  In this short article, we will cover in-depth the   JsonMappingException: no String-argument constructor/factory method to deserialize fro...