European ASP.NET MVC 4 and MVC 5 Hosting

BLOG about ASP.NET MVC 3, ASP.NET MVC 4, and ASP.NET MVC 5 Hosting and Its Technology - Dedicated to European Windows Hosting Customer

ASP.NET MVC 6 Hosting - HostForLIFE.eu :: How to Handle Multiple Submit Buttons in ASP.NET MVC 6?

clock July 30, 2020 13:16 by author Peter

Today, let me explain you how to handle multiple submit buttons in ASP.NET MVC 6. Sometimes you will need to handle multiple submit buttons on a similar form as as in the following picture.

As you can see on the above picture, we've got the three buttons Login, Register and Cancel. Here every button has totally different functionality. in this way every submit button will post a form to the server but will provide totally different values of every button.

Make a controller with one action method that accepts other parameters, one is for the model and the other is for determining the status of the button click.
[HttpPost] 
public ActionResult Index(Login model, string command) 

if (command=="Login") 

// do stuff 
return RedirectToAction("Home"); 

else if (command=="Register") 

// do stuff 
ViewBag.msg = "You have Clicked Register button"; 
return View(); 


else if (command=="Cancel") 

// do stuff 
ViewBag.msg = "You have Clicked Cancel Button"; 
return View(); 

else 

return View(); 



In the preceding code snippet, assume you clicked on the Login button, then the command parameter can have the values Login, null, null respectively. Create a View for the preceding controller.
@model MvcMultipleSubmitButtons.Models.Login 
@{ 
ViewBag.Title = "Index"; 

<h2> 
Handling multiple submit buttons in MVC </h2> 
<h5 style="color: Red">@ViewBag.msg</h5> 
<form action="Home/Index" id="myform" method="post" >  
//here action name is Index, controller name is Home. So the action path is Home/Index 
<table> 
<tr> 
<td> 
UserName 
</td> 
<td> 

</td> 
<td>@Html.TextBoxFor(m => m.userName) 
</td> 
<td> 
@Html.ValidationMessageFor(m => m.userName) 
</td> 
</tr> 
<tr> 
<td> 
Password 
</td> 
<td> 

</td> 
<td>@Html.TextBoxFor(m => m.password) 
</td> 
<td> 
@Html.ValidationMessageFor(m => m.password) 
</td> 
</tr> 
</table> 
<br/> 

<div style="padding-left: 80px;"> 
<input type="submit" id="Login" value="Login" name="Command" title="Login" /> 
<input type="submit" id="Register" value="Register" name="Command" title="Register" /> 
<input type="submit" value="Cancel" name="Command" title="Cancel" /> 

</div> 
</form> 


You can declare the form tag in another way as within the following:
@using(Html.BeginForm("Index","Home",FormMethod.Post)) 
{  
//here action name is Index, controller name is Home and form method is post. 
}


Note: there's a relation between button name and action method parameter. for instance, the button name is “Command”, the action parameter name ought to be “command”.

You can have different names for each button. So in that case you need to handle it as in the following:
<input type="submit" id="Login" value="Login" name="Command1" title="Login" /> 
<input type="submit" id="Register" value="Register" name="Command2" title="Register" /> 
<input type="submit" value="Cancel" name="Command3" title="Cancel" /> 


Controller
public ActionResult Index(Login model, string command1, string command2, string command3) 

   // here command1 is for Login, command2 is for Register and command3 is for cancel 


Create a Model class with the name Login.
public class Login 

    public string userName { get; set; } 
    public string password { get; set; } 

I hope it helps for you!

HostForLIFE.eu ASP.NET MVC 6 Hosting
HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes. We have customers from around the globe, spread across every continent. We serve the hosting needs of the business and professional, government and nonprofit, entertainment and personal use market segments.



ASP.NET MVC 6 Hosting - HostForLIFE.eu :: Action Filter In MVC

clock July 3, 2020 14:12 by author Peter

Action filter in MVC provides the option to handle the situations after we would really like to perform an operation before and after the execution of a controller action. For this purpose, we create a custom class, which inherits the FilterAttribute class and implements the IActionFilter interface. when creating the filter, we simply apply the class name as an attribute on the controller.

Here, the FilterAttribute class makes it possible to use the class as an attribute and IActionFilter interface contains two methods named OnActionExecuting and OnActionExecuted. The OnActionExecuting is executed before the controller method is executed and OnActionExecuted is called after the execution of the controller method. This kind of technique is quite helpful for the logging purposes. Thus, let's see how we can use this filter.
 
Let's start by adding a new class named MyActionFilter.cs. Now, derive this class from the FilterAttribute and the IActionFilter. Implement the  OnActionExecuting and OnActionExecuted methods and add your custom logic into the methods.Thus, the code will look as shown below. 
    public class MyActionFilter : FilterAttribute, IActionFilter 
    { 
        public void OnActionExecuted(ActionExecutedContext filterContext) 
        { 
            //Fires after the method is executed 
        } 
     
        public void OnActionExecuting(ActionExecutingContext filterContext) 
        { 
            //Fires before the action is executed 
        } 
    } 


Simply, apply the class as an attribute on the controller. Add debuggers on both the methods as well as the controller method.
    public class HomeController : Controller 
    { 
        [MyActionFilter] 
        public ActionResult Index() 
        { 
            return View(); 
        } 
     
        public ActionResult About() 
        { 
            ViewBag.Message = "Your application description page."; 
            return View(); 
        } 
     
        public ActionResult Contact() 
        { 
            ViewBag.Message = "Your contact page."; 
            return View(); 
        } 
    } 


Run the Application and debug step by step to see the order of execution of the methods. First, the OnActionExecuting will be executed, then the controller method and finally the OnActionExecuted method.

HostForLIFE.eu ASP.NET MVC 6 Hosting
HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes. We have customers from around the globe, spread across every continent. We serve the hosting needs of the business and professional, government and nonprofit, entertainment and personal use market segments.



ASP.NET MVC 6 Hosting UK - HostForLIFE.eu :: How to Delete Multiple Items in ASP.NET with JSON?

clock June 26, 2020 13:15 by author Peter

Today, I want to show you how to delete multiple Items in ASP.NET with JSON. JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language. Now, open your project and write the following code:

View
<table class="table"> 
@foreach (var role in Model) { 
<tr> 
    <td> 
        <input id="responsable1" name="checkResp" value="@role.id" type="checkbox" /> 
        <strong>@role.Name</strong> 
    </td> 
</tr> 

</table> 
<input id="DeleteBtn" type="button" value="Delete Selected" /> 
<script> 
$("#DeleteBtn").on("click", function() { 
    var boxData = []; 
    $("input[name='checkResp']:checked").each(function() { 
        boxData.push($(this).val()); 
    }); 
    $.ajax({ 
        url: '/Roles/DeleteMultiple', 
        data: { 
            RoleId: boxData.join(",") 
        }, 
        cache: false, 
        type: "POST", 
        timeout: 10000, 
        dataType: "json", 
        success: function(result) { 
            window.location.reload(); 
        } 
    }); 
}); 
</script> 


Controller
[HttpPost] 
public JsonResult DeleteMultiple(string RoleId) { 
ApplicationDbContext db = new ApplicationDbContext(); 
var RoleIds = RoleId.Split(','); 
foreach(var id in RoleIds) { 
    int idConverted = Convert.ToInt32(id); 
    Roles roleid = db.Roles.Find(idConverted); 
    db.Roles.Remove(roleid); 

context.SaveChanges(); 
var message = "Selected roles have been deleted"; 
return Json(message); 


DeleteMultiple - Action Name
Roles - Controller Name

 

HostForLIFE.eu ASP.NET MVC 6 Hosting
HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes. We have customers from around the globe, spread across every continent. We serve the hosting needs of the business and professional, government and nonprofit, entertainment and personal use market segments.



ASP.NET MVC 6 Hosting - HostForLIFE.eu :: FileResult In ASP.NET Core MVC

clock May 13, 2020 09:18 by author Peter

This article is an overview of FileResult in ASP.Net Core MVC. The FileResult actions are used to read and write files. FileResult is the parent of all file-related action results. There is a method on ControllerBase class called File. This method accepts a set of parameters based on the type of file and its location, which maps directly to the more specific return types. I’ll discuss how to use all the FileResult actions available in ASP.Net Core MVC.

There are different type of file results in core MVC.
FileResult
FileContentResult
FileStreamResult
VirtualFileResult
PhysicalFileResult

FileResult

FileResult is the parent of all file-related action results. It is a base class that is used to send binary file content to the response. It represents an ActionResult that when executed will write a file as the response.

public FileResult DownloadFile() 

     return File("/Files/File Result.pdf", "text/plain", "File Result.pdf"); 


FileContentResult
FileContentResult is an ActionResult that when executed will write a binary file to the response.
public FileContentResult DownloadContent() 

            var myfile = System.IO.File.ReadAllBytes("wwwroot/Files/FileContentResult.pdf"); 
            return new FileContentResult(myfile, "application/pdf"); 


FileStreamResult

FileStreamResult Sends binary content to the response by using a Stream instance when we want to return the file as a FileStream.
public FileStreamResult CreateFile() 

   var stream = new MemoryStream(Encoding.ASCII.GetBytes("Hello World")); 
   return new FileStreamResult(stream, new MediaTypeHeaderValue("text/plain")) 
   { 
      FileDownloadName = "test.txt" 
   }; 


VirtualFileResult
A FileResult that on execution writes the file specified using a virtual path to the response using mechanisms provided by the host. You can use VirtualFileResult if you want to read a file from a virtual address and return it.
public VirtualFileResult VirtualFileResult() 

    return new VirtualFileResult("/Files/PhysicalFileResult.pdf", "application/pdf"); 


PhysicalFileResult
A FileResult on execution will write a file from disk to the response using mechanisms provided by the host.You can use PhysicalFileResult to read a file from a physical address and return it, as shown in PhysicalFileResult method.
public PhysicalFileResult PhysicalFileResult() 

   return new PhysicalFileResult(_environment.ContentRootPath + "/wwwroot/Files/PhysicalFileResult.pdf", "application/pdf"); 


Step 1
Open Visual Studio 2019 and select the ASP.NET Core Web Application template and click Next.

Step 2
Name the project FileResultActionsCoreMvc_Demo and click Create.

Step 3
Select Web Application (Model-View-Controller), and then select Create. Visual Studio used the default template for the MVC project you just created.

Step 4
In Solution Explorer, right-click the wwwroot folder. Select Add > New Folder. Name the folder Files. Add some files to work with them.

Complete controller code
using Microsoft.AspNetCore.Hosting; 
using Microsoft.AspNetCore.Mvc; 
using Microsoft.Net.Http.Headers; 
using System.IO; 
using System.Text; 
 
namespace FileResultActionsCoreMvc_Demo.Controllers 

    public class HomeController : Controller 
    { 
        private readonly IWebHostEnvironment _environment; 
 
        public HomeController(IWebHostEnvironment environment) 
        { 
            _environment = environment; 
        } 
        public IActionResult Index() 
        { 
            return View(); 
        } 
 
        public FileResult DownloadFile() 
        { 
            return File("/Files/File Result.pdf", "text/plain", "File Result.pdf"); 
        } 
 
        public FileContentResult DownloadContent() 
        { 
            var myfile = System.IO.File.ReadAllBytes("wwwroot/Files/FileContentResult.pdf"); 
            return new FileContentResult(myfile, "application/pdf"); 
        } 
 
        public FileStreamResult CreateFile() 
        { 
            var stream = new MemoryStream(Encoding.ASCII.GetBytes("Hello World")); 
            return new FileStreamResult(stream, new MediaTypeHeaderValue("text/plain")) 
            { 
                FileDownloadName = "test.txt" 
            }; 
        } 
        public VirtualFileResult VirtualFileResult() 
        { 
            return new VirtualFileResult("/Files/PhysicalFileResult.pdf", "application/pdf"); 
        } 
 
        public PhysicalFileResult PhysicalFileResult() 
        { 
            return new PhysicalFileResult(_environment.ContentRootPath + "/wwwroot/Files/PhysicalFileResult.pdf", "application/pdf"); 
        } 
 
    } 


Step 5
Open Index view which is in views folder under Home folder. Add the below code in Index view.
Index View
@{ 
    ViewData["Title"] = "Home Page"; 

 
<h3 class="text-center text-uppercase">FileResult Action in core mvc</h3> 
<ul class="list-group list-group-horizontal"> 
    <li class="list-group-item"><a asp-action="DownloadFile" asp-controller="Home">File Result</a></li> 
    <li class="list-group-item"><a asp-action="DownloadContent" asp-controller="Home" target="_blank">File Content Result</a></li> 
    <li class="list-group-item"><a asp-action="CreateFile" asp-controller="Home">File Stream Result</a></li> 
    <li class="list-group-item"><a asp-action="VirtualFileResult" asp-controller="Home" target="_blank">Virtual File Result</a></li> 
    <li class="list-group-item"><a asp-action="PhysicalFileResult" asp-controller="Home" target="_blank">Physical File Result</a></li> 
</ul> 


Step 6
Build and run your Project ctrl+F5



ASP.NET MVC 6 Hosting - HostForLIFE.eu :: HTML Helpers In ASP.NET MVC

clock April 9, 2020 05:10 by author Peter

What is an Html Helper?
Html helper is a method that is used to render HTML content in a view. Html helpers are implemented using an extension method. If you want to create an input text box with

id=email and name in email:
  <input type=text id=email name=email value=’’/> 


This is all the Html we need to write -- by using the helper method it becomes so easy:
  @Html.TextBox(‘email’) 

It will generate a textbox control whose name is the email.

If we want to assign the value of the textbox with some initial value then use the below method:
  @Html.TextBox(‘email’,’[email protected]’) 

If I want to set an initial style for textbox we can achieve this by using the below way:
  @Html.TextBox(‘email’,’[email protected]’,new {style=’your style here’ , title=’your title here’});  

Here the style we pass is an anonymous type.

If we have a reserved keyword like class readonly and we want to use this as an attribute  we will do this using the below method, which means append with @ symbol with the reserved word.
  @Html.TextBox(‘email’,’[email protected]’,new {@class=’class name’, @readonly=true}); 

If we want to generate label:
  @Html.Label(‘firstname’,’sagar’) 

For password use the below Html helper method to create password box:
  @Html.Password(“password”) 

If I want to generate a textarea then for this also we have a method:
  @Html.TextArea(“comments”,”,4,12,null)  

In the above code 4 is the number of rows and 12 is the number of columns.

To generate a hidden box:
  @Html.Hidden(“EmpID”) 

Hidden textboxes are not displayed on the web page but used for storing data and when we need to pass data to action method then we can use that.

Is it possible to create our Html helpers in asp.net MVC?

Yes, we can create our Html helpers in MVC.

Is it mandatory to use Html helpers?

No, we can use plain Html for that but Html helpers reduce a significant amount of Html code to write that view.
Also, your code is simple and maintainable and if you require some complicated logic to generate view then this is also possible.



ASP.NET MVC 6 Hosting - HostForLIFE.eu :: Partial View in MVC

clock March 20, 2020 12:00 by author Peter

Partial view in ASP.NET MVC is special view which renders a portion of view content. It is just like a user control of a web form application. Partial can be reusable in multiple views. It helps us to reduce code duplication. In other word a partial view enables us to render a view within the parent view.
 

The partial view is instantiated with its own copy of a ViewDataDictionary object which is available with the parent view so that partial view can access the data of the parent view. If we made the change in this data (ViewDataDictionary object), the parent view's data is not affected. Generally the Partial rendering method of the view is used when related data that we want to render in a partial view is part of our model.
 
Creating Partial View
To create a partial view, right-click on view -> shared folder and select Add -> View option. In this way we can add a partial view.
 

Creating Partial View
It is not mandatory to create a partial view in a shared folder but a partial view is mostly used as a reusable component, it is a good practice to put it in the "shared" folder.

HTML helper has two methods for rendering the partial view: Partial and RenderPartial.
    <div> 
        @Html.Partial("PartialViewExample") 
    </div> 
    <div> 
        @{ 
            Html.RenderPartial("PartialViewExample"); 
        } 
    </div>

@Html.RenderPartial
The result of the RenderPartial method is written directly into the HTTP response, it means that this method used the same TextWriter object as used by the current view. This method returns nothing.
 
@Html.Partial
This method renders the view as an HTML-encoded string. We can store the method result in a string variable.
 
The Html.RenderPartial method writes output directly to the HTTP response stream so it is slightly faster than the Html.Partial method.
 
Returning a Partial view from the Controller's Action method:
    public ActionResult PartialViewExample() 
    { 
        return PartialView(); 
    }

Render Partial View Using jQuery
Sometimes we need to load a partial view within a model popup at runtime, in this case we can render the partial view using JQuery element's load method.
    <script type="text/jscript"> 
            $('#partialView').load('/shared/PartialViewExample’); 
    </script>



ASP.NET MVC 6 Hosting - HostForLIFE.eu :: Modal Popup In MVC Application

clock February 28, 2020 11:15 by author Peter

In this post we will implement modal pop up to display the detailed information of user after clicking on detail anchor. So this is the view on which we are going to apply modal popup.

View code
Enumerable<CodeFirst.Models.FriendsInfo> 
 
@{ 
    ViewBag.Title = "Index"; 

 
<h2>Index</h2> 
 
<p> 
    @Html.ActionLink("View All", "Index") 
 
    @using (Html.BeginForm("Search", "Home", FormMethod.Post)) 
    { 
        <table> 
            <tr> 
                <td> 
                    <input type="text" id="txtName" name="searchparam" placeholder="type here to search" /> 
                </td> 
                <td> 
                    <input type="submit" id="btnSubmit" value="Search" /> 
                </td> 
            </tr> 
        </table> 
    } 
 
</p> 
<table class="table"> 
    <tr> 
        <th> 
            @Html.DisplayNameFor(model => model.Name) 
        </th> 
        <th> 
            @Html.DisplayNameFor(model => model.Mobile) 
        </th> 
        <th> 
            @Html.DisplayNameFor(model => model.Address) 
        </th> 
        <th></th> 
    </tr> 
 
    @foreach (var item in Model) 
    { 
        <tr> 
            <td> 
                @Html.DisplayFor(modelItem => item.Name) 
            </td> 
            <td> 
                @Html.DisplayFor(modelItem => item.Mobile) 
            </td> 
            <td> 
                @Html.DisplayFor(modelItem => item.Address) 
            </td> 
            <td> 
                @*@Html.ActionLink("Edit", "Edit", new { id=item.Id }) | 
                    @Html.ActionLink("Details", "Details", new { id=item.Id }) | 
                    @Html.ActionLink("Delete", "Delete", new { id=item.Id })*@ 
 
                <a href="javascript:void(0);" class="anchorDetail"  data-id="@item.Id">Details</a> 
 
            </td> 
        </tr> 
    } 
 
</table>  

As we can see we have detail anchor, with class anchorDetail and with data-id, which will get the id of clicked anchor and show the corresponding data to modal (detail view) on screen.

We have an Action method Details(int id) which will return the partial view.
public ActionResult Details(int Id) 

    FriendsInfo frnds = new FriendsInfo(); 
    frnds = db.FriendsInfo.Find(Id); 
    return PartialView("_Details",frnds); 
 

Here we added a partial view for this purpose to show detail view when user click on detail anchor in the list.

View Code
@model CodeFirst.Models.FriendsInfo 
 
<div> 
   
    <div class="modal-header"> 
        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> 
        <h4 class="modal-title" id="myModalLabel">FriendsInfo</h4> 
    </div>                
                 
     
    <hr /> 
    <dl class="dl-horizontal"> 
        <dt> 
            @Html.DisplayNameFor(model => model.Name) 
        </dt> 
 
        <dd> 
            @Html.DisplayFor(model => model.Name) 
        </dd> 
 
        <dt> 
            @Html.DisplayNameFor(model => model.Mobile) 
        </dt> 
 
        <dd> 
            @Html.DisplayFor(model => model.Mobile) 
        </dd> 
 
        <dt> 
            @Html.DisplayNameFor(model => model.Address) 
        </dt> 
 
        <dd> 
            @Html.DisplayFor(model => model.Address) 
        </dd> 
 
    </dl> 
</div> 


We have a div for modal pop-up.

<div id='myModal' class='modal'> 
    <div class="modal-dialog"> 
        <div class="modal-content"> 
            <div id='myModalContent'></div> 
        </div> 
    </div>  
     
</div>  


Here is the script for showing modal (partial view) on above div when user click on detail anchor. Here we used Ajax call for this purpose.

Script
@section scripts 

    <script src="~/Scripts/jquery-1.10.2.min.js"></script> 
    <script src="~/Scripts/bootstrap.js"></script> 
    <script src="~/Scripts/bootstrap.min.js"></script> 
<script> 
    var TeamDetailPostBackURL = '/Home/Details'; 
    $(function () { 
        $(".anchorDetail").click(function () { 
            debugger; 
            var $buttonClicked = $(this); 
            var id = $buttonClicked.attr('data-id'); 
            var options = { "backdrop": "static", keyboard: true }; 
            $.ajax({ 
                type: "GET", 
                url: TeamDetailPostBackURL, 
                contentType: "application/json; charset=utf-8", 
                data: { "Id": id }, 
                datatype: "json", 
                success: function (data) { 
                    debugger; 
                    $('#myModalContent').html(data); 
                    $('#myModal').modal(options); 
                    $('#myModal').modal('show');                   
 
                }, 
                error: function () { 
                    alert("Dynamic content load failed."); 
                } 
            }); 
        }); 
        //$("#closebtn").on('click',function(){ 
        //    $('#myModal').modal('hide');   
 
        $("#closbtn").click(function () { 
            $('#myModal').modal('hide'); 
        });       
    }); 
    
</script> 
 

HostForLIFE.eu ASP.NET MVC 6 Hosting
HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes. We have customers from around the globe, spread across every continent. We serve the hosting needs of the business and professional, government and nonprofit, entertainment and personal use market segments.



European ASP.NET Core Hosting - HostForLIFE.eu :: Multiple Models in Single View in MVC

clock February 7, 2020 10:31 by author Peter

In MVC we cannot pass multiple models from a controller to the single view. This article provides a workaround for multiple models in a single view in MVC.

Problem Statement

Suppose I have two models, Teacher and Student, and I need to display a list of teachers and students within a single view. How can we do this?

The following are the model definitions for the Teacher and Student classes.

public class Teacher  
{  
    public int TeacherId { get; set; }  
    public string Code { get; set; }  
    public string Name { get; set; }  
}   
  
public class Student  
{  
    public int StudentId { get; set; }  
    public string Code { get; set; }  
    public string Name { get; set; }  
    public string EnrollmentNo { get; set; }  
}  

The following are the methods that help us to get all the teachers and students.

private List<Teacher> GetTeachers()  
{  
    List<Teacher> teachers = new List<Teacher>();  
    teachers.Add(new Teacher { TeacherId = 1, Code = "TT", Name = "Peter" });  
    teachers.Add(new Teacher { TeacherId = 2, Code = "JT", Name = "Scott" });  
    teachers.Add(new Teacher { TeacherId = 3, Code = "RT", Name = "Paul" });  
    return teachers;  
}   
  
public List<Student> GetStudents()  
{  
    List<Student> students = new List<Student>();  
    students.Add(new Student { StudentId = 1, Code = "L0001", Name = "Thomas", EnrollmentNo = "201404150001" });  
    students.Add(new Student { StudentId = 2, Code = "L0002", Name = "Brian", EnrollmentNo = "201404150002" });  
    students.Add(new Student { StudentId = 3, Code = "L0003", Name = "Chester", EnrollmentNo = "201404150003" });  
    return students;  
}  

There are many ways to use multiple models with a single view. Here I will explain ways one by one.

1. Using Dynamic Model

ExpandoObject (the System.Dynamic namespace) is a class that was added to the .Net Framework 4.0 that allows us to dynamically add and remove properties onto an object at runtime. Using this ExpandoObject, we can create a new object and can add our list of teachers and students into it as a property. We can pass this dynamically created object to the view and render list of the teacher and student.

Controller Code

public class HomeController : Controller  
{  
    public ActionResult Index()  
    {  
        ViewBag.Message = "Welcome to my demo!";  
        dynamic mymodel = new ExpandoObject();  
        mymodel.Teachers = GetTeachers();  
        mymodel.Students = GetStudents();  
        return View(mymodel);  
    }  
}  

We can define our model as dynamic (not a strongly typed model) using the @model dynamic keyword.

View Code

@using MultipleModelInOneView;  
@model dynamic  
@{  
    ViewBag.Title = "Home Page";  
}  
<h2>@ViewBag.Message</h2>  
   
<p><b>Teacher List</b></p>  
   
<table>  
    <tr>  
        <th>Id</th>  
        <th>Code</th>  
        <th>Name</th>  
    </tr>  
    @foreach (Teacher teacher in Model.Teachers)  
    {  
        <tr>  
            <td>@teacher.TeacherId</td>  
            <td>@teacher.Code</td>  
            <td>@teacher.Name</td>  
        </tr>  
    }  
</table>  
   
<p><b>Student List</b></p>  
   
<table>  
    <tr>  
        <th>Id</th>  
        <th>Code</th>  
        <th>Name</th>  
        <th>Enrollment No</th>  
    </tr>  
    @foreach (Student student in Model.Students)  
    {  
        <tr>  
            <td>@student.StudentId</td>  
            <td>@student.Code</td>  
            <td>@student.Name</td>  
            <td>@student.EnrollmentNo</td>  
        </tr>  
    }  
</table>  

2. Using View Model

ViewModel is nothing but a single class that may have multiple models. It contains multiple models as a property. It should not contain any method. In the above example, we have the required View model with two properties. This ViewModel is passed to the view as a model. To get intellisense in the view, we need to define a strongly typed view.

public class ViewModel  
{  
    public IEnumerable<Teacher> Teachers { get; set; }  
    public IEnumerable<Student> Students { get; set; }  
}  

Controller code

public ActionResult IndexViewModel()  
{  
    ViewBag.Message = "Welcome to my demo!";  
    ViewModel mymodel = new ViewModel();  
    mymodel.Teachers = GetTeachers();  
    mymodel.Students = GetStudents();  
    return View(mymodel);  
}  

View code

@using MultipleModelInOneView;  
@model ViewModel   
@{  
    ViewBag.Title = "Home Page";  
}  
<h2>@ViewBag.Message</h2>  
   
<p><b>Teacher List</b></p>  
   
<table>  
    <tr>  
        <th>Id</th>  
        <th>Code</th>  
        <th>Name</th>  
    </tr>  
    @foreach (Teacher teacher in Model.Teachers)  
    {  
        <tr>  
            <td>@teacher.TeacherId</td>  
            <td>@teacher.Code</td>  
            <td>@teacher.Name</td>  
        </tr>  
    }  
</table>  
   
<p><b>Student List</b></p>  
   
<table>  
    <tr>  
        <th>Id</th>  
        <th>Code</th>  
        <th>Name</th>  
        <th>Enrollment No</th>  
    </tr>  
    @foreach (Student student in Model.Students)  
    {  
        <tr>  
            <td>@student.StudentId</td>  
            <td>@student.Code</td>  
            <td>@student.Name</td>  
            <td>@student.EnrollmentNo</td>  
        </tr>  
    }  
</table>  

3. Using ViewData
ViewData is used to transfer data from the controller to the view. ViewData is a dictionary object that may be accessible using a string as the key. Using ViewData, we can pass any object from the controller to the view. The Type Conversion code is required when enumerating in the view.
For the preceding example, we need to create ViewData to pass a list of teachers and students from the controller to the view.

Controller Code
public
 ActionResult IndexViewData()  

{  
    ViewBag.Message = "Welcome to my demo!";  
    ViewData["Teachers"] = GetTeachers();  
    ViewData["Students"] = GetStudents();  
    return View();  
}  

View Code

@using MultipleModelInOneView;  
@{  
    ViewBag.Title = "Home Page";  
}  
<h2>@ViewBag.Message</h2>  
 <p><b>Teacher List</b></p>   
@{  
  
   IEnumerable<Teacher> teachers = ViewData["Teachers"] as IEnumerable<Teacher>;  
   IEnumerable<Student> students = ViewData["Students"] as IEnumerable<Student>;  
}  
<table>  
    <tr>  
        <th>Id</th>  
        <th>Code</th>  
        <th>Name</th>  
    </tr>  
    @foreach (Teacher teacher in teachers)  
    {  
        <tr>  
            <td>@teacher.TeacherId</td>  
            <td>@teacher.Code</td>  
            <td>@teacher.Name</td>  
        </tr>  
    }  
</table>  
 <p><b>Student List</b></p>  
<table>  
    <tr>  
        <th>Id</th>  
        <th>Code</th>  
        <th>Name</th>  
        <th>Enrollment No</th>  
    </tr>  
    @foreach (Student student in students)  
    {  
        <tr>  
            <td>@student.StudentId</td>  
            <td>@student.Code</td>  
            <td>@student.Name</td>  
            <td>@student.EnrollmentNo</td>  
        </tr>  
    }  
</table>  

4. Using ViewBag
ViewBag is similar to ViewData and is also used to transfer data from the controller to the view. ViewBag is a dynamic property. ViewBag is just a wrapper around the ViewData.

Controller Code

public ActionResult IndexViewBag()  
{  
    ViewBag.Message = "Welcome to my demo!";  
    ViewBag.Teachers = GetTeachers();  
    ViewBag.Students = GetStudents();  
    return View();  
}  

View Code

@using MultipleModelInOneView;  
@{  
    ViewBag.Title = "Home Page";  
}  
<h2>@ViewBag.Message</h2>  
   
<p><b>Teacher List</b></p>  
   
<table>  
    <tr>  
        <th>Id</th>  
        <th>Code</th>  
        <th>Name</th>  
    </tr>  
    @foreach (Teacher teacher in ViewBag.Teachers)  
    {  
        <tr>  
            <td>@teacher.TeacherId</td>  
            <td>@teacher.Code</td>  
            <td>@teacher.Name</td>  
        </tr>  
    }  
</table>  
   
<p><b>Student List</b></p>  
   
<table>  
    <tr>  
        <th>Id</th>  
        <th>Code</th>  
        <th>Name</th>  
        <th>Enrollment No</th>  
    </tr>  
    @foreach (Student student in ViewBag.Students)  
    {  
        <tr>  
            <td>@student.StudentId</td>  
            <td>@student.Code</td>  
            <td>@student.Name</td>  
            <td>@student.EnrollmentNo</td>  
        </tr>  
    }  
</table> 

5. Using Tuple

A Tuple object is an immutable, fixed-size and ordered sequence object. It is a data structure that has a specific number and sequence of elements. The .NET framework supports tuples up to seven elements. Using this tuple object we can pass multiple models from the controller to the view.

Controller Code

public ActionResult IndexTuple() 
{  
    ViewBag.Message = "Welcome to my demo!";  
    var tupleModel = new Tuple<List<Teacher>, List<Student>>(GetTeachers(), GetStudents());  
    return View(tupleModel);  
}  

View Code

@using MultipleModelInOneView;  
@model Tuple <List<Teacher>, List <Student>>  
@{  
    ViewBag.Title = "Home Page";  
}  
<h2>@ViewBag.Message</h2>   
<p><b>Teacher List</b></p>  
<table>  
    <tr>  
        <th>Id</th>  
        <th>Code</th>  
        <th>Name</th>  
    </tr>  
    @foreach (Teacher teacher in Model.Item1)  
    {  
        <tr>  
            <td>@teacher.TeacherId</td>  
            <td>@teacher.Code</td>  
            <td>@teacher.Name</td>  
        </tr>  
    }  
</table>  
<p><b>Student List</b></p>  
<table>  
    <tr>  
        <th>Id</th>  
        <th>Code</th>  
        <th>Name</th>  
        <th>Enrollment No</th>  
    </tr>  
    @foreach (Student student in Model.Item2)  
    {  
        <tr>  
            <td>@student.StudentId</td>  
            <td>@student.Code</td>  
            <td>@student.Name</td>  
            <td>@student.EnrollmentNo</td>  
        </tr>  
    }  
</table>  

6. Using Render Action Method
A Partial View defines or renders a partial view within a view. We can render some part of a view by calling a controller action method using the Html.RenderAction method. The RenderAction method is very useful when we want to display data in the partial view. The disadvantages of this method is that there are only multiple calls of the controller.


In the following example, I have created a view (named partialView.cshtml) and within this view I called the html.RenderAction method to render the teacher and student list.

Controller Code

public ActionResult PartialView()  
{  
    ViewBag.Message = "Welcome to my demo!";  
    return View();  
}  
   
/// <summary>  
/// Render Teacher List  
/// </summary>  
/// <returns></returns>  
public PartialViewResult RenderTeacher()  
{  
    return PartialView(GetTeachers());  
}  
   
/// <summary>  
/// Render Student List  
/// </summary>  
/// <returns></returns>  
public PartialViewResult RenderStudent()  
{  
    return PartialView(GetStudents());  
 

View Code

@{ 
   ViewBag.Title = "PartialView";  
<h2>@ViewBag.Message</h2>  
<div>  
    @{  
        Html.RenderAction("RenderTeacher");  
        Html.RenderAction("RenderStudent");  
    }  
</div>  

RenderTeacher.cshtml

@using MultipleModelInOneView;  
@model IEnumerable<MultipleModelInOneView.Teacher>  
 <p><b>Teacher List</b></p>  
<table>  
    <tr>  
        <th>Id</th>  
        <th>Code</th>  
        <th>Name</th>  
    </tr>  
    @foreach (Teacher teacher in Model)  
    {  
        <tr>  
            <td>@teacher.TeacherId</td>  
            <td>@teacher.Code</td>  
            <td>@teacher.Name</td>  
        </tr>  
    }  
  1. </table>  

RenderStudent.cshtml

@using MultipleModelInOneView;  
@model IEnumerable<MultipleModelInOneView.Student>   
  
<p><b>Student List</b></p>  
<table>  
    <tr>  
        <th>Id</th>  
        <th>Code</th>  
        <th>Name</th>  
        <th>Enrollment No</th>  
    </tr>  
    @foreach (Student student in Model)  
    {  
        <tr>  
            <td>@student.StudentId</td>  
            <td>@student.Code</td>  
            <td>@student.Name</td>  
            <td>@student.EnrollmentNo</td>  
        </tr>  
    }  
</table> 

Conclusion

This article helps us to learn how to pass multiple models from the controller to the view. I hope this will be helpful for beginners.



European ASP.NET Core Hosting - HostForLIFE.eu :: Know Further About ASP.NET Core Endpoint Routing

clock January 29, 2020 08:49 by author Scott

Introduction

In this post I will explain the new Endpoint Routing feature that has been added to the ASP.NET Core middleware pipeline starting with version 2.2 and how it is evolving through to the upcoming version 3.0 that is at preview 3 at present time.

The motivation behind endpoint routing

Prior to endpoint routing the routing resolution for an ASP.NET Core application was done in the ASP.NET Core MVC middleware at the end of the HTTP request processing pipeline. This meant that route information, such as what controller action would be executed, was not available to middleware that processed the request before the MVC middleware in the middleware pipeline.

It is particularly useful to have this route information available for example in a CORS or authorization middleware to use the information as a factor in the authorization process.

Endpoint routing also allows us to decouple the route matching logic from the MVC middleware, moving it into its own middleware. It allows the MVC middleware to focus on its responsibility of dispatching the request to the particular controller action method that is resolved by the endpoint routing middleware.

The new Endpoint Routing middleware

Due to the above mentioned reasons, the endpoint routing feature was born to allow the route resolution to happen earlier in the pipeline in a separate endpoint routing middleware. This new middleware can be placed at any point in the pipeline after which other middleware in the pipeline can access the resolved route data.

The endpoint routing middleware API is evolving with the upcoming 3.0 version of the .NET Core framework. For that reason, the API that I will describe in the following sections may not be the final version of the feature. However the over all concept and understanding of how route resolution and dispatch work using endpoint routing should still apply.

In the following sections I will walk you through the current iterations of endpoint routing implementation from version 2.2 to version 3.0 preview 3, then I will note some changes that are coming based on the current ASP.NET Core source code.

The three core concepts involved in Endpoint Routing

There are three overall concepts that you need to understand to be able to understand how endpoint routing works.

These are the following:

  • Endpoint route resolution
  • Endpoint dispatch
  • Endpoint route mapping

Endpoint route resolution

The endpoint route resolution is the concept of looking at the incoming request and mapping the request to an endpoint using route mappings. An endpoint represents the controller action that the incoming request resolves to, along with other metadata attached to the route that matches the request.

The job of the route resolution middleware is to construct and Endpoint object using the route information from the route that it resolves based on the route mappings. The middleware then places that object into the http context where other middleware the come after the endpoint routing middleware in the pipeline can access the endpoint object and use the route information within.

Prior to endpoint routing, route resolution was done in the MVC middleware at the end of the middleware pipeline. The current 2.2 version of the framework adds a new endpoint route resolution middleware that can be placed at any point in the pipeline, but keeps the endpoint dispatch in the MVC middleware. This will change in the 3.0 version where the endpoint dispatch will happen in a separate endpoint dispatch middleware that will replace the MVC middleware.

Endpoint dispatch

Endpoint dispatch is the process of invoking the controller action method that corresponds to the endpoint that was resolved by the endpoint routing middleware.

The endpoint dispatch middleware is the last middleware in the pipeline that grabs the endpoint object from the http context and dispatches to particular controller action that the resolved endpoint specifies.

Currently in version 2.2 dispatching to the action method is done in the MVC middleware at the end of the pipeline.

In the version 3.0 preview 3, the MVC middleware is removed. Instead the endpoint dispatch happens at the end of the middleware pipeline by default. Because the MVC middleware is removed, the route map configuration that is usually passed to the MVC middleware, is instead passed to the endpoint route resolution middleware.

Based on the current source code, the upcoming 3.0 final release should have a new endpoint routing middleware that is placed at the end of the pipeline to make the endpoint dispatch explicit again. The route map configuration will be passed to this new middleware instead of the endpoint route resolution middleware as it is in version 3 preview 3.

Endpoint route mapping

When we define route middleware we can optionally pass in a lambda function that contains route mappings that override the default route mapping that ASP.NET Core MVC middleware extension method specifies.

Route mappings are used by the route resolution process to match the incoming request parameters to a route specified in the rout map.

With the new endpoint routing feature the ASP.NET Core team had to decide which middleware, the endpoint resolution or the endpoint dispatch middleware, should get the route mapping configuration lambda as a parameter.

In fact this is the part of the endpoint routing where the API is in flux. As I write this post, the route mapping is being moved from the route resolution middleware to the endpoint dispatcher middleware.

I will show you the route mapping API in version 3 preview 3 first, then show you the latest route mapping API in the ASP.NET Core source code. In the source code version, we will see that the route mapping is moved to the endpoint dispatcher middleware extension method.

Its important to note that the endpoint resolution happens during runtime request handling after the route mapping is setup during application startup configuration. Therefor the route resolution middleware has access to the route mappings during request handling regardless of which middleware the route map configuration is passed to. 

Accessing the resolved endpoint

Any Middleware after the endpoint route resolution middleware will be able to access the resolved endpoint through the HttpContext.

The following code snippet shows how this can be done in your own middleware:

//our custom middleware
app.Use((context, next) =>
{
    var endpointFeature = context.Features[typeof(Microsoft.AspNetCore.Http.Features.IEndpointFeature)]
                                           as Microsoft.AspNetCore.Http.Features.IEndpointFeature;

    Microsoft.AspNetCore.Http.Endpoint endpoint = endpointFeature?.Endpoint;

    //Note: endpoint will be null, if there was no
    //route match found for the request by the endpoint route resolver middleware
    if (endpoint != null)
    {
        var routePattern = (endpoint as Microsoft.AspNetCore.Routing.RouteEndpoint)?.RoutePattern
                                                                                   ?.RawText;

        Console.WriteLine("Name: " + endpoint.DisplayName);
        Console.WriteLine($"Route Pattern: {routePattern}");
        Console.WriteLine("Metadata Types: " + string.Join(", ", endpoint.Metadata));
    }
    return next();
});

As you can see I am accessing the resolved endpoint object through the IEndpointFeature or the Http Context. The framework provides wrapper methods to access the endpoint object without having to reach directly into the context as I have shown here.

Endpoint routing configuration

The middleware pipeline endpoint route resolver middleware, endpoint dispatcher middleware and endpoint route mapping lambda is setup in the Startup.Configure method of the Startup.cs file of ASP.NET Core project.

This configuration changed between 2.2 and 3.0 preview 3 versions and is still changing before the 3.0 release version. So in order to demonstrate the endpoint routing configuration I am going to declare the general form of the endpoint routing middleware configuration as pseudo code based on the three core concepts listed above:

//psuedocode that passes route map to endpoint resolver middleware
public void Configure(IApplicationBuilder app
                     , IHostingEnvironment env)
{
    //middleware configured before the UseEndpointRouteResolverMiddleware middleware
    //that does not have access to the endpoint object
    app.UseBeforeEndpointResolutionMiddleware();

    //middleware that inspects the incoming request, resolves a match to the route map
    //and stores the resolved endpoint object into the httpcontext
    app.UseEndpointRouteResolverMiddleware(routes =>
    {
        //This is the route mapping configuration passed to the endpoint resolver middleware
        routes.MapControllers();
    })

    //middleware after configured after the UseEndpointRouteResolverMiddleware middleware
    //that can access to the endpoint object
    app.UseAfterEndpointResolutionMiddleware();

    //The middleware at the end of the pipeline that dispatches the controler action method
    //will replace the current MVC middleware
    app.UseEndpointDispatcherMiddleware();
}

This version of our pseudo code shows the route mappings lambda passed as a parameter to the UseEndpointRouteResolverMiddleware endpoint route resolution middleware extension method.

An alternate version that matches what the current source code looks like, is shown below:

//psuedocode version 2 that passes route map to endpoint dispatch middleware
public void Configure(IApplicationBuilder app
                     , IHostingEnvironment env)
{
    app.UseBeforeEndpointResolutionMiddleware()

    //This is the endpoint route resolver middleware
    app.UseEndpointRouteResolverMiddleware();

    //This middleware can access the resolved endpoint object via HttpContext
    app.UseAfterEndpointResolutionMiddleware();

    //This is the endpoint dispatch middleware
    app.UseEndpointDispatcherMiddleware(routes =>
    {
        //This is the route mapping configuration passed to the endpoint dispatch middleware
        routes.MapControllers();
    });
}

In this version the route mapping configuration is passed as a parameter to the endpoint dispatch middleware extension method UseEndpointDispatcherMiddleware.

Either way the UseEndpointRouteResolverMiddleware() endpoint resolver middleware will have access to the route mappings at request handling time to do the route matching.

Once the route is matched by UseEndpointRouteResolverMiddleware an Endpoint object will be constructed with the route parameters and set to the httpcontext so that the middleware in the pipeline that follow, can access the Endpoint object and use it if needed.

In version 3 preview 3 version of this pseudo code, the route mapping is passed to UseEndpointRouteResolverMiddleware and there does not exist a UseEndpointDispatcherMiddleware at the end of the pipeline. This is because in this version the ASP.NET framework itself implicitly dispatches the resolved endpoint at the end of the request pipeline.

So the pseudo code representing version 3 preview 3 has the form below:

//pseudo code representing v3 preview 3 endpoint routing API
public void Configure(IApplicationBuilder app
                     , IHostingEnvironment env)
{
    app.UseBeforeEndpointResolutionMiddleware()

    //This is the endpoint route resolver middleware
    app.UseEndpointRouteResolverMiddleware(routes =>
    {
        //The route mapping configuration is passed to the endpoint resolution middleware
        routes.MapControllers();
    })

    //This middleware can access the resolved endpoint object via HttpContext
    app.UseAfterEndpointResolutionMiddleware()

    // The resolved endpoint is implicitly dispatched here at the end of the pipeline
    // and so there is no explicit call to a UseEndpointDispatcherMiddleware
}

This API looks to be changing with the 3.0 release version, as the current source code shows that the UseEndpointDispatcherMiddleware is added back in and it is the middleware that takes the route mappings as a parameter as illustrated by the second version of the pseudo code above.

Endpoint routing in version 2.2

If you create a Web API project using version 2.2 of the .NET Core SDK you will see the following code in the Startup.Configure method:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
        app.UseDeveloperExceptionPage();
    else
        app.UseHsts();

    app.UseHttpsRedirection();

    //By default endpoint routing is not added
    //the MVC middleware dispatches the controller action
    //and the MVC middleware configures the default route mapping
    app.UseMvc();
}

The MVC middleware is configured at the end of the middleware pipeline using the UseMvc() extension method. This method internally sets the default MVC route mapping configuration at startup configuration time and dispatches the controller action during request handling.

By default the out of the box template in v2.2 just configures the MVC dispatcher middleware. As such the MVC middleware also handles the route resolution based on the route map configuration and the incoming request data.

However we can add Endpoint Routing using some additional configuration as shown below:

using Microsoft.AspNetCore.Internal;

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
        app.UseDeveloperExceptionPage();
    else
        app.UseHsts();

    //added endpoint routing that will resolve the endpoint object
    app.UseEndpointRouting();

    //middleware below will have access to the Endpoint

    app.UseHttpsRedirection();

    //the MVC middleware dispatches the controller action
    //and the MVC middleware configures the default route mapping
    app.UseMvc();
}

Here we have added the namespace Microsoft.AspNetCore.Internal. Including it, enables an additional IApplicationBuilder extension method UseEndpointRouting that is the endpoint resolution middleware that resolves the route and adds the Endpoint object to the httpcontext.

You can check out the source code for UseEndpointRouting extension method in version 2.2 at:

https://github.com/aspnet/AspNetCore/blob/v2.2.4/src/Http/Routing/src/Internal/EndpointRoutingApplicationBuilderExtensions.cs

In version 2.2 the MVC middleware at the end of the pipeline acts as the endpoint dispatcher middleware. It will dispatch the resolved endpoint to the proper controller action.

The endpoint resolution middleware uses the route mappings configured by the MVC middleware.

Once we have enabled endpoint routing we can actually inspect the resolved endpoint object if we add our own custom middleware show below:

using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing;

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
        app.UseDeveloperExceptionPage();
    else
        app.UseHsts();

    app.UseEndpointRouting();

    app.UseHttpsRedirection();

    //our custom middlware
    app.Use((context, next) =>
    {
        var endpointFeature = context.Features[typeof(IEndpointFeature)] as IEndpointFeature;
        var endpoint = endpointFeature?.Endpoint;

        //note: endpoint will be null, if there was no resolved route
        if (endpoint != null)
        {
            var routePattern = (endpoint as RouteEndpoint)?.RoutePattern
                                                          ?.RawText;

            Console.WriteLine("Name: " + endpoint.DisplayName);
            Console.WriteLine($"Route Pattern: {routePattern}");
            Console.WriteLine("Metadata Types: " + string.Join(", ", endpoint.Metadata));
        }
        return next();
    });

    app.UseMvc();
}

As you can see we can inspect and print out the endpoint object that the endpoint routing resolution middleware UseEndpointRouting has resolved. The endpoint object will be null, if the resolver was not able to match the request to a mapped route. We needed to pull in two additional namespaces to access the endpoint routing features.

Endpoint routing in Version 3 preview 3

In version 3 preview 3, endpoint routing will become a full fledged citizen of ASP.NET Core and we will finally have separation between the MVC controller action dispatcher and the route resolution middleware.

Here is the endpoint startup configuration in version 3 preview 3.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
        app.UseDeveloperExceptionPage();
    else
        app.UseHsts();

    app.UseHttpsRedirection();

    app.UseRouting(routes =>
    {
        routes.MapControllers();
    });

    app.UseAuthorization();

    //No need to have a dispatcher middleware here.
    //The resolved endpoint is automatically dispatched to a controller action at the end
    //of the middleware pipeline
    //If an endpoint was not able to be resolved, a 404 not found is returned at the end
    //of the middleware pipeline
}

As you can see we have a app.UseRouting() method that configures the endpoint route resolution middleware. The method also takes a anonymous lambda function that configures the route mappings that the route resolver middleware will use to resolve the incoming request endpoint.

The routes.MapControllers() inside the mapping function configures the default MVC routes.

You will also notice that there is a app.UseAuthorization() after app.UseRouting() which configures the authorization middleware. This middleware will have access the httpcontext endpoint object set by the endpoint routing middleware.

Notice that we don’t have any MVC or endpoint dispatch middleware configured at the end of the method, after all other middleware configuration.

This is because the behavior of the version 3 preview 3 build is that the resolved endpoint will be implicitly dispatched to the controller action by the framework itself.

Similar to what we did for version 2.2 we can add the same custom middleware to inspect the resolved endpoint object.

using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing;

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
        app.UseDeveloperExceptionPage();
    else
        app.UseHsts();

    app.UseHttpsRedirection();

    app.UseRouting(routes =>
    {
        routes.MapControllers();
    });

    app.UseAuthorization();

    //our custom middleware
    app.Use((context, next) =>
    {
        var endpointFeature = context.Features[typeof(IEndpointFeature)] as IEndpointFeature;
        var endpoint = endpointFeature?.Endpoint;

        //note: endpoint will be null, if there was no
        //route match found for the request by the endpoint route resolver middleware
        if (endpoint != null)
        {
            var routePattern = (endpoint as RouteEndpoint)?.RoutePattern
                                                          ?.RawText;

            Console.WriteLine("Name: " + endpoint.DisplayName);
            Console.WriteLine($"Route Pattern: {routePattern}");
            Console.WriteLine("Metadata Types: " + string.Join(", ", endpoint.Metadata));
        }
        return next();
    });

    //the endpoint is dispatched by default at the end of the middleware pipeline
}

Endpoint routing in upcoming ASP.NET Core version 3.0 source code repository

As we approach the version 3.0 release of the framework, it looks like the team is trying to make endpoint routing more explicit by adding back in the call to endpoint dispatcher middleware configuration. They are also moving back the route mapping configuration option to the dispatcher middleware configuration method.

We can see how this is changed yet again by peeking at the current source code.

Here is a snippet from the source code for the version 3.0 sample application music store at:

https://github.com/aspnet/AspNetCore/blob/master/src/MusicStore/samples/MusicStore/Startup.cs

public void Configure(IApplicationBuilder app)
{
    // Configure Session.
    app.UseSession();

    // Add static files to the request pipeline
    app.UseStaticFiles();

    // Add the endpoint routing matcher middleware to the request pipeline
    app.UseRouting();

    // Add cookie-based authentication to the request pipeline
    app.UseAuthentication();

    // Add the authorization middleware to the request pipeline
    app.UseAuthorization();

    // Add endpoints to the request pipeline
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "areaRoute",
            pattern: "{area:exists}/{controller}/{action}",
            defaults: new { action = "Index" });

        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller}/{action}/{id?}",
            defaults: new { controller = "Home", action = "Index" });

        endpoints.MapControllerRoute(
            name: "api",
            pattern: "{controller}/{id?}");
    });
}

As you can see that we have something similar to my pseudo code implementation that I detailed above.

Particularly, we still have the app.UseRouting() middleware setup from the version 3 preview 3, but now we also have an explicit app.UseEndpoints() endpoint dispatch method that more aptly named for what it does.

The UseEndpoints is a new IApplicationBuilder extension method that provides the endpoint dispatch implementation.

You can check out the source code for the UseEndpoints and UseRouting methods here:

https://github.com/aspnet/AspNetCore/blob/master/src/Http/Routing/src/Builder/EndpointRoutingApplicationBuilderExtensions.cs

Also note that the route mapping configuration lambda have been moved from the UseRouting middleware to the new UseEndpoints middleware.

The UseRouting endpoint route resolver will still have access to the mappings to resolve the endpoint at request handling time. Even though they are passed to the UseEndpoints middleware during startup configuration.

Adding Endpoint routing middleware to the DI container

To use endpoint routing, we also need to add the middleware to the DI container in the Startup.ConfigureServices method.

ConfigureServices in Version 2.2

For version 2.2 of the framework we need to explicitly add the call to services.AddRouting() method shown below to add the endpoint routing feature to the DI container:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRouting()

    services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

ConfigureServices in Version 3 preview 3

For version 3 preview 3 build of the framework, endpoint routing already comes configured in the DI container under the covers in the AddMvc() extension method:

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

Setting up Endpoint Authorization using endpoint routing and route mappings

When working with the version 3 preview 3 release we can attach authorization metadata to an endpoint. We do this using the route mappings configuration fluent API RequireAuthorization method.

The endpoint routing resolver will access this metadata when processing a request and add it to the Endpoint object that it sets on the httpcontext.

Any middleware in the pipeline after the route resolution middleware can access this authorization data by accessing the resolved Endpoint object.

In particular the authorization middleware can use this data to make authorization decisions.

Currently the route mapping configuration parameters are passed into the endpoint route resolver middleware, but as previously mentioned, in the future releases, the route mapping configuration will be passed into the endpoint dispatcher middleware.

Either way the attached authorization metadata will be available for the endpoint resolver middleware to use.

Below is an example of the version 3 preview 3 Startup.Configure method where I have added a new /secret route to the endpoint resolver middleware route map configuration lambda parameter:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
        app.UseDeveloperExceptionPage();
    else
        app.UseHsts();

    app.UseHttpsRedirection();

    app.UseRouting(routes =>
    {
        routes.MapControllers();

        //Mapped route that gets attached authorization metadata using the RequireAuthorization extension method.
        //This metadata will be added to the resolved endpoint for this route by the endpoint resolver
        //The app.UseAuthorization() middleware later in the pipeline will get the resolved endpoint
        //for the /secret route and use the authorization metadata attached to the endpoint
        routes.MapGet("/secret", context =>
        {
            return context.Response.WriteAsync("secret");
        }).RequireAuthorization(new AuthorizeAttribute(){ Roles = "admin" });
    });

    app.UseAuthentication();

    //the Authorization middleware check the resolved endpoint object
    //to see if it requires authorization. If it does as in the case of
    //the "/secret" route, then it will authorize the route, if it the user is in the admin role
    app.UseAuthorization();

    //the framework implicitly dispatches the endpoint at the end of the pipeline.
}

You can see that I am using the RequireAuthorization method to add an AuthorizeAttribute attribute to the /secret route. This route will then only be authorized to be dispatched for a user in the admin role, by the authorization middleware, that comes before the endpoint dispatch occurs.

As I showed for version 3.3 preview 3 that we can add middleware to inspect the resolved endpoint object in httpcontext so can we here to inspect the AuthorizeAttribute added to the endpoint metadata:

using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Authorization;

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
        app.UseDeveloperExceptionPage();
    else
        app.UseHsts();

    app.UseHttpsRedirection();

    app.UseRouting(routes =>
    {
        routes.MapControllers();

        routes.MapGet("/secret", context =>
        {
            return context.Response.WriteAsync("secret");
        }).RequireAuthorization(new AuthorizeAttribute(){ Roles = "admin" });
    });

    app.UseAuthentication();

    //our custom middleware
    app.Use((context, next) =>
    {
        var endpointFeature = context.Features[typeof(IEndpointFeature)] as IEndpointFeature;
        var endpoint = endpointFeature?.Endpoint;

        //note: endpoint will be null, if there was no
        //route match found for the request by the endpoint route resolver middleware
        if (endpoint != null)
        {
            var routePattern = (endpoint as RouteEndpoint)?.RoutePattern
                                                          ?.RawText;

            Console.WriteLine("Name: " + endpoint.DisplayName);
            Console.WriteLine($"Route Pattern: {routePattern}");
            Console.WriteLine("Metadata Types: " + string.Join(", ", endpoint.Metadata));
        }
        return next();
    });

    app.UseAuthorization();

    //the framework implicitly dispatches the endpoint here.
}

This time I have added the custom middleware before the Authorization middleware and pulled in two additional namespaces.

Navigating to the /secret route and inspecting the metadata, you can see that it contains the Microsoft.AspNetCore.Authorization.AuthorizeAttribute type in addition to the Microsoft.AspNetCore.Routing.HttpMethodMetadata type.

References used for this article

The following articles contain source material that I used as a reference for this article:

https://devblogs.microsoft.com/aspnet/aspnet-core-3-preview-2/

Update for version 3 preview 4

Around the time I published this article, ASP.NET Core 3.0 preview 4 was released. It adds the changes that I described in the latest source code as can be seen in the code snippet from Startup.cs file below when creating a new webapi project:

//code from Startup.cs file in a webapi project template

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
            .AddNewtonsoftJson();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
        app.UseDeveloperExceptionPage();
    else
        app.UseHsts();

    app.UseHttpsRedirection();

    //add endpoint resolution middlware
    app.UseRouting();

    app.UseAuthorization();

    //add endpoint dispatch middleware
    app.UseEndpoints(endpoints =>
    {
        //route map configuration
        endpoints.MapControllers();

        //route map I added to show Authorization setup
        endpoints.MapGet("/secret", context =>
        {
            return context.Response.WriteAsync("secret");
        }).RequireAuthorization(new AuthorizeAttribute(){ Roles = "admin" }); 
    });
}

As you can see this version adds the explicit UseEndpoints middleware extension method at the end of the pipeline that adds the endpoint dispatch middleware. Also the route configuration parameter has been moved from the UseRouting method in preview 3 to the UseEndpoints in preview 4.

Conclusion

Endpoint routing allows ASP.NET Core applications to determine the endpoint that will be dispatched, early on in the middleware pipeline, so that later middleware can use that information to provide features not possible with the current pipeline configuration.

This makes the ASP.NET Core framework more flexible since it decouples the route matching and resolution functionality from the endpoint dispatching functionality, which until now was all bundled in with the MVC middleware.



ASP.NET MVC Hosting - HostForLIFE.eu :: Display Mode Provider in MVC 5 Application

clock January 22, 2020 10:19 by author Peter

This article will solve a problem. Display modes in ASP.NET MVC 5 provide a way of separating page content from the way it is rendered on various devices, like web, mobile, iPhone, iPod and Windows Phones. All you need to do is to define a display mode for each device, or class of devices.

First you create a model and context class. We create an Employee class that has the following properties like.
    public class Employee 
    { 
        public Guid ID { get; set; } 
        [Display(Name="First Name")] 
        public string FirstName { get; set; } 
        [Display(Name = "Last Name")] 
        public string LastName { get; set; } 
        [Display(Name = "Department")] 
        public string Department { get; set; } 
        [Display(Name = "Salary")] 
        public double Salary { get; set; } 
        [Display(Name = "Address")] 
        public string Address { get; set; } 
    }


And second is the context class like this that inherits the DbContext class.
    public class DBConnectionContext:DbContext 
    {         
       public DBConnectionContext(): base("name=dbContext") 
       { 
             Database.SetInitializer(new DropCreateDatabaseIfModelChanges 
             <DBConnectionContext>()); 
       } 
            public DbSet<Employee> Employees { get; set; } 
    }


If you want to recreate data every time the model changes, add these lines of code.
    Database.SetInitializer(new DropCreateDatabaseIfModelChanges<DbConnectionContext>());

You also have a web config file. We configure connectionStrings in the Web.Config file.
    <connectionStrings> 
    <add name="dbContext" connectionString="Data Source=localhost; Initial Catalog=CommonDataBase; Integrated Security=true"  
          providerName="System.Data.SqlClient" /> 
     </connectionStrings>


Then you create a controller class in a controller folder and edit the name as HomeController. Add a Scaffold to select a MVC 5 Controller with Views, using Entity Framework.

DisplayModes

DisplayModes give you another level of flexibility on top of the default capabilities we saw in the last section. DisplayModes can also be used along with the previous feature so we will simply build off of the site we just created. Let's say we wanted to show an alternate view for the Windows Phone 8, iPhone, iPod or Android.

Windows Phone 8 DisplayMode

Now that you have made the override files, you can use a DisplayMode to show them for the appropriate phones.

The best time to set this up is when the application starts. Here is our global.asax.cs, with the DisplayMode setup.
    DisplayModeProvider.Instance.Modes.Insert(1, new DefaultDisplayMode("WP") 
    { 
        ContextCondition = (ctx => ctx.GetOverriddenUserAgent() 
        .IndexOf("Windows Phone OS", StringComparison.OrdinalIgnoreCase) > 0)   
     }); 
      
    DisplayModeProvider.Instance.Modes.Insert(1, new DefaultDisplayMode("iPhone") 
    { 
        ContextCondition = (ctx => ctx.GetOverriddenUserAgent() 
        .IndexOf("iPhone", StringComparison.OrdinalIgnoreCase) > 0)   
    }); 
      
    DisplayModeProvider.Instance.Modes.Insert(1, new DefaultDisplayMode("Android") 
    { 
        ContextCondition = (ctx => ctx.GetOverriddenUserAgent() 
        .IndexOf("Android", StringComparison.OrdinalIgnoreCase) > 0)   
    }); 

The DisplayModeProvider Class
DisplayModeProvider holds a list of DefaultDisplayMode obejects, each representing display mode. And the provider holds the two display modes, default and mobile. The default display mode in an empty string and the second holds the mobile string.


We just create multiple View with [View].Android.cshtml, [View].iPhone.cshtml and so on for every device such as:

We create an index for iPhone and create a new employee in iPhone Index.iPhone.cshtml and Create.iPhone.cshtml.


We create an index for Windows Phone and create a new employee in the Windows Phone Index.WP.cshtml Create.WP.cshtml.


We create an index for Android and create a new employee in Windows Phone Index.Android.cshtml Create.Android.cshtml.



About HostForLIFE.eu

HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2016 Hosting, ASP.NET Core 2.2.1 Hosting, ASP.NET MVC 6 Hosting and SQL 2017 Hosting.


Tag cloud

Sign in