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 !!