European ASP.NET MVC Hosting

BLOG about Latest ASP.NET MVC Hosting and Its Technology - Dedicated to European Windows Hosting Customer

ASP.NET MVC 6 Hosting - HostForLIFE.eu :: Is MVC Replacing ASP.NET Web Forms?

clock September 18, 2018 09:53 by author Peter

We often think that one technology will be totally replaced by a new release or new version of technology. This article tries to dicuss that and similar issues and I will share my industry experience, not just what I have seen in India (the largest IT Solutions Provider to the world) but also in the USA.

I consider this to be a very hot topic and a good candidate of debate but I will try to share my thoughts on such a burning topic. This article does not highlight or defame any technology, I am just going to provide my perspective as I have seen, experienced and advised to various clients and software teams.

Why new Versions

The principle “Change is Constant” applies very well to the software industry and I respect this overflow of information. Because this gives me reason to “Keep Learning and stay ahead of the Curve”. By saying so I didn't mean that someone must learn anything and everything you can get your hands on. No, certainly not, but before I explain this any further let's take a step back and understand “Why new Versions” keep coming.

We are fortunate that we have seen complete transition of the software industry from Desktop to Web to Mobile, future generations may not witness this great and life changing shift. Also, I recall my days when I was working and studying software in 1995, no one imagined that there will be MVC, WPF, WCF, so many versions of .NET and SQL Server and so on. Industry was happy with Microsoft Access, FoxPro, C, C++ and Oracle and so on. But our needs keep changing, they evolved and then shell is broken to have huge expansion and today we have many kinds of software technology and server products from client-side to server-side to mobile and hand-held and many more. We moved from on premise to the Cloud and Machine Learning is helping to dictate patterns and suggest needs.

This is why software companies keep building the latest and newest technologies to enable and empower the world to build for the future. When they release a version of a technology or language and they discover some issues or new features in that then they release newer versions and this in a chain-reaction process and it will not stop.

Oh, then I will die Learning

As per Darwin's Evolution Theory “Survival of the Fittest”, "fit" refers to "best adapted to the current environment". Here you simply replace environment with the software industry. I am one of you and I am not saying that everyone must learn everything but what I suggest is to stick to your technology of choice and have good knowledge of the offered tools and technologies and various versions and when to use which one.

Also, you don't necessarily need to understand every single thing. For example, I only focus on .NET and related technologies, if anything falls beyond this area then I am not bothered. To be more precise, I don't understand Microsoft CRM, SharePoint, System Center, SQL Server Database Administration and few more things like that.

But this is not my weak point because “I continue to build my .NET Muscle” and continue to learn about what helps me build Enterprise solutions using Microsoft .NET.

So choose your area of interest and where you have invested and then keep learning in a similar field and then you will no longer find it challenging because if you observe, new versions come after every few years and that must be otherwise it will be no fun!

Hmm, so Isn't MVC Replacing ASP.NET Web Forms

Such decisions are not final and have no concrete answers. Yes, the industry changes their needs and so new technologies such as MVC and WPF takes over. This definitely doesn't mean that ASP.NET Web Forms is replaced or it's dead. If you understand the Microsoft Web fundamentals, MVC is based on ASP.NET and industry is trying to shift as and when they can from Web Forms to MVC and reap the benefits it offers.

Did you know that MVC is much older than ASP.NET? Yes, ASP.NET 1.0 was released in 2002 and MVC was created in 1979 originally named as “Thing-Model-View-Controller” but later simplified to be known as MVC.

In my view I consider that there are now two technologies to build Web Solutions using Microsoft and based on your needs you can pick one that works well for you. Usually such technology selections are made by architects assigned to the project.

So there is no such Golden Rule that every new or existing application must be either created using MVC or migrated to MVC because MVC is the latest and future the of web. Though it is.

Architectural Thinking: Brownfield Vs Greenfield Applications

All software applications you have worked or will work in future are either Brownfield or Greenfield.

  • Brownfield Development: When any existing or legacy applications need to have new features or changes to address business needs, it is known as brownfield. In such situations, unless you are building a new module or component, you have less, limited or no scope to use new architectural styles, patterns and so on. The very reason of such limitations is because those old applications are built using an old version of technologies and the latest versions of one technology/framework and many are not be compatible with old versions.
  • Greenfield Development: When a brand-new project is being envisioned and no previous work is done in that or a related area then it's called Greenfield. In the software industry it doesn't happen very often. But whenever it happens its the architect's responsibility to determine what the best technology is to address business needs.

Hence, it's not appropriate to say that because MVC is so new hence every new web application must be made using MVC or if WPF is available in addition to Windows Forms so every desktop application must be made using WPF. Whatever is the case neither ASP.NET Web Forms nor Windows Forms can be totally ignored.

Why and Why not the Latest Technologies should be chosen

First the reasons why not.

  1. It's Brownfield and new technology doesn't fit anywhere.
  2. If new technology or versions are introduced then it will cause many build errors due to outdated references of non-supported library references.
  3. Business goals and software quality are not compromised by continuing to use current and available technologies like ASP.NET Web Forms over MVC or Windows Forms over WPF.
  4. You are not investing money in any extra off-the-shelf tools to handle issues that could have been handled by the latest versions of similar area of technologies, for example MVC instead of ASP.NET Web Forms, or WPF over Windows Forms.
  5. Teams often might not have a certain skill set that allows them to proceed with development using new technology options
  6. Budget allocation from a client often may impact your decision to use and develop using the latest technologies.
  7. If the core/bestselling features of a new candidate technology (MVC or WPF) are not being used at least up to 50% then you have done nothing.
  8. Considering how soon the client and business wants to have an application ready, it turns being a major factor to dictate the technology of choice.
  9. The client and business doesn't care how you do it; what matters is the end-result and a workable / good-enough software.
  10. No way to use old legacy downstream applications with the latest available technologies.

Why develop using Latest Technologies

  1. Greenfield software solution and no legacy or old piece of code is being used.
  2. Focus is more on Robustness, Testability, Object Oriented design and quality. (This doesn't mean previous technology can't accomplish these; it's about ease and in-built features and offerings).
  3. Amazing team with great skills to learn new technologies and adapt the changes.
  4. Company's vision is to showcase products build using latest technologies.
  5. Client themselves want the solution to be developed using latest technologies and have budget to support that.

Why MVC over ASP.NET Web Forms then

Note: this section assumes that you are aware of MVC benefits and the general technical terms used below.

  1. Separation of Concerns is the core of MVC.
  2. Single Responsibility Principle is done by default.
  3. Unified and even better framework to work on WebAPI, Mobile, HTML 5, CSS3, Security and Deployment (including Azure).
  4. Unit testing is easily done to have stable, robust and quality software solutions delivered continuously.
  5. Fast screen generation for CRUD operations via Scaffolding.
  6. Convention over configuration.

Summary
Based on my experience as an architect in the industry I would like to summarize that it's very hard for any organization to keep up with the latest version and technologies all the time because by the time you become comfortable with one version the newer is around the corner. So if you are working on MVC 4, then see if you can learn and try some application being developed on your own. Or if you just happen to be in the ASP.NET Web Forms world until now then I would encourage you to try converting that application to MVC for your personal benefit. This will force you to learn new technology and apply that learning. If you have made some progress in that then in the next interview you can proudly showcase your MVC knowledge and say that you have migrated ASP.NET Web Forms to MVC.



ASP.NET MVC 6 Hosting - HostForLIFE.eu :: Clickable Google Charts

clock September 7, 2018 11:52 by author Peter

Charts are an important aspect of reports as they make it simpler to understand a certain problem. Making charts clickable adds more reinforcement into the understanding of the problem.


Today, I shall be demonstrating clickable charts using Google Charts API in ASP.NET MVC5. Google Charts API is simple to use and provides a variety of options for customization of graphical chart reports for better analytical purposes.

Prerequisites
Following are some prerequisites before you proceed further in this tutorial.
Knowledge of Google charts API.
Knowledge of ASP.NET MVC5.
Knowledge of HTML.
Knowledge of JavaScript.
Knowledge of AJAX.
Knowledge of CSS.
Knowledge of Bootstrap.
Knowledge of C# programming.
Knowledge of C# LINQ.
Knowledge of jQuery.

You can download the complete source code for this tutorial or you can follow the step by step discussion below. The sample code is developed in Microsoft Visual Studio 2015 Enterprise. I am using SalesOrderDetail table extracted from Adventure Works Sample Database.

Let's begin now.

Step 1
Create a new MVC5 web application project and name it "Graphs".

Step 2
Open "Views\Shared\_Layout.cshtml" file and replace the following code in it.
<!DOCTYPE html> 
<html> 
<head> 
    <meta charset="utf-8" /> 
    <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
    <title>@ViewBag.Title</title> 
    @Styles.Render("~/Content/css") 
    @Scripts.Render("~/bundles/modernizr") 
 
    <!-- Font Awesome --> 
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" /> 
 
    @* Custom *@ 
    @Styles.Render("~/Content/css/custom-style") 
</head> 
<body> 
    <div class="navbar navbar-inverse navbar-fixed-top"> 
        <div class="container"> 
            <div class="navbar-header"> 
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> 
                    <span class="icon-bar"></span> 
                    <span class="icon-bar"></span> 
                    <span class="icon-bar"></span> 
                </button> 
            </div> 
        </div> 
    </div> 
    <div class="container body-content"> 
        @RenderBody() 
        <hr /> 
        <footer> 
            <center> 
                <p><strong>Copyright © @DateTime.Now.Year - <a href="http://www.asmak9.com/">Asma's Blog</a>.</strong> All rights reserved.</p> 
            </center> 
        </footer> 
    </div> 
 
    @Scripts.Render("~/bundles/jquery") 
    @Scripts.Render("~/bundles/bootstrap") 
 
    <!-- Graphs --> 
    <script type="text/javascript" src="https://www.google.com/jsapi"></script> 
    @Scripts.Render("~/bundles/Script-custom-graphs") 
 
    @RenderSection("scripts", required: false) 
</body> 
</html>


In the above code, I have simply created the basic layout structure of this web project and I have also add reference to the Google charts API.

Step 3

Create a new "Models\HomeViewModels.cs" file and replace with the following code in it.
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 
 
namespace Graphs.Models 

    public class SalesOrderDetail 
    { 
        public int Sr { get; set; } 
        public string OrderTrackNumber { get; set; } 
        public int Quantity { get; set; } 
        public string ProductName { get; set; } 
        public string SpecialOffer { get; set; } 
        public double UnitPrice { get; set; } 
        public double UnitPriceDiscount { get; set; } 
        public string Link { get; set; } 
    } 
}

In the above code, we have simply created our View Model which will map the data from text file into main memory as object. Also, notice that we have added "Link" property, which we will use as our clickable destination.

Step 4

Now, create "Controllers\HomeController.cs" file and replace the following code in it.
using Graphs.Models; 
using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Reflection; 
using System.Web; 
using System.Web.Mvc; 
 
namespace Graphs.Controllers 

    public class HomeController : Controller 
    { 
        #region Index method 
 
        /// <summary> 
        /// GET: Home/Index method. 
        /// </summary> 
        /// <returns>Returns - index view page</returns>  
        public ActionResult Index() 
        { 
            // Info. 
            return this.View(); 
        } 
 
        #endregion 
 
        #region Test Page method 
 
        /// <summary> 
        /// GET: Home/TestPage method. 
        /// </summary> 
        /// <returns>Returns - test page view page</returns>  
        public ActionResult TestPage() 
        { 
            // Info. 
            return this.View(); 
        } 
 
        #endregion 
 
        #region Get data method. 
 
        /// <summary> 
        /// GET: /Home/GetData 
        /// </summary> 
        /// <returns>Return data</returns> 
        public ActionResult GetData() 
        { 
            // Initialization. 
            JsonResult result = new JsonResult(); 
 
            try 
            { 
                // Loading. 
                List<SalesOrderDetail> data = this.LoadData(); 
 
                // Setting. 
                var graphData = data.GroupBy(p => new 
                                    { 
                                        p.ProductName, 
                                        p.Link, 
                                        p.UnitPrice 
                                    }) 
                                    .Select(g => new 
                                    { 
                                        g.Key.ProductName, 
                                        g.Key.Link, 
                                        g.Key.UnitPrice 
                                    }).OrderByDescending(q => q.UnitPrice).ToList(); 
 
                // Top 10 
                graphData = graphData.Take(2).Select(p => p).ToList(); 
 
                // Loading drop down lists. 
                result = this.Json(graphData, JsonRequestBehavior.AllowGet); 
            } 
            catch (Exception ex) 
            { 
                // Info 
                Console.Write(ex); 
            } 
 
            // Return info. 
            return result; 
        } 
 
        #endregion 
 
        #region Helpers 
 
        #region Load Data 
 
        /// <summary> 
        /// Load data method. 
        /// </summary> 
        /// <returns>Returns - Data</returns> 
        private List<SalesOrderDetail> LoadData() 
        { 
            // Initialization. 
            List<SalesOrderDetail> lst = new List<SalesOrderDetail>(); 
 
            try 
            { 
                // Initialization. 
                string line = string.Empty; 
                string srcFilePath = "Content/files/SalesOrderDetail.txt"; 
                var rootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase); 
                var fullPath = Path.Combine(rootPath, srcFilePath); 
                string filePath = new Uri(fullPath).LocalPath; 
                StreamReader sr = new StreamReader(new FileStream(filePath, FileMode.Open, FileAccess.Read)); 
 
                // Read file. 
                while ((line = sr.ReadLine()) != null) 
                { 
                    // Initialization. 
                    SalesOrderDetail infoObj = new SalesOrderDetail(); 
                    string[] info = line.Split(','); 
 
                    // Setting. 
                    infoObj.Sr = Convert.ToInt32(info[0].ToString()); 
                    infoObj.OrderTrackNumber = info[1].ToString(); 
                    infoObj.Quantity = Convert.ToInt32(info[2].ToString()); 
                    infoObj.ProductName = info[3].ToString(); 
                    infoObj.SpecialOffer = info[4].ToString(); 
                    infoObj.UnitPrice = Convert.ToDouble(info[5].ToString()); 
                    infoObj.UnitPriceDiscount = Convert.ToDouble(info[6].ToString()); 
                    infoObj.Link = this.Url.Action("TestPage", "Home"); 
 
                    // Adding. 
                    lst.Add(infoObj); 
                } 
 
                // Closing. 
                sr.Dispose(); 
                sr.Close(); 
            } 
            catch (Exception ex) 
            { 
                // info. 
                Console.Write(ex); 
            } 
 
            // info. 
            return lst; 
        } 
 
        #endregion 
 
        #endregion 
    } 
}


In the above code, I have created a simple index() & TestPage() action methods along with a helper method LoadData() for data loading from text file and finally, GetData() action method which will be called by Google charts API AJAX method in order to map the data on the chart. The GetData() action method will return top the top two rows only which are sorted by product and unit price and grouped by product name.

Step 5
Create a new "Scripts\script-custom-graphs.js" script file and replace the following code in it.
// Load the Visualization API and the piechart package. 
google.load('visualization', '1.0', { 'packages': ['corechart'] }); 
 
// Set a callback to run when the Google Visualization API is loaded. 
$(document).ready(function () 

    $.ajax( 
    { 
        type: 'POST', 
        dataType: 'JSON', 
        url: '/Home/GetData', 
        success: 
            function (response) 
            { 
                // Set chart options 
                var options = 
                    { 
                        width: 1100, 
                        height: 900, 
                        sliceVisibilityThreshold: 0, 
                        legend: { position: "top", alignment: "end" }, 
                        chartArea: { left: 370, top: 50, height: "90%" }, 
 
                        bar: { groupWidth: "50%" }, 
                    }; 
 
                // Draw. 
                drawGraph(response, options, 'graphId'); 
            } 
    }); 
}); 
 
// Callback that creates and populates a data table, 
// instantiates the pie chart, passes in the data and 
// draws it. 
function drawGraph(dataValues, options, elementId) { 
    // Initialization. 
    var data = new google.visualization.DataTable(); 
 
    // Setting. 
    data.addColumn('string', 'Product Name'); 
    data.addColumn('number', 'Unit Price'); 
    data.addColumn('string', 'Link'); 
 
    // Processing. 
    for (var i = 0; i < dataValues.length; i++) 
    { 
        // Setting. 
        data.addRow([dataValues[i].ProductName, dataValues[i].UnitPrice, dataValues[i].Link]); 
    } 
 
    // Setting label. 
    var view = new google.visualization.DataView(data); 
    view.setColumns([0, 1, 
        { 
            calc: "stringify", 
            sourceColumn: 1, 
            type: "string", 
            role: "annotation" 
        } 
    ]); 
 
    // Instantiate and draw our chart, passing in some options. 
    var chart = new google.visualization.ColumnChart(document.getElementById(elementId)); 
 
    // Draw chart. 
    chart.draw(view, options); 
 
    // Link interaction. 
    var selectHandler = function (e) 
    { 
        // Verification. 
        if (chart.getSelection() != null && 
             chart.getSelection()[0] != null && 
             chart.getSelection()[0]['row'] != null && 
             chart.getSelection().length > 0) 
        { 
            if (chart.getSelection()[0]['column'] == 1) 
            { 
                // Setting. 
                var link = data.getValue(chart.getSelection()[0]['row'], 2) 
                window.open(link, '_blank'); 
            } 
        } 
    } 
 
    // Add our selection handler. 
    google.visualization.events.addListener(chart, 'select', selectHandler); 
}


Let's break down the code chunk by chunk. First, I have loaded the Google Charts API charts visualization package.
// Load the Visualization API and the piechart package. 
google.load('visualization', '1.0', { 'packages': ['corechart'] });


Then, I call the GetData() server side method via AJAX call and after successfully receiving the data, I simply set the default chart options then pass those options to a user-define JavaScript method "drawGraph(...)".
// Set a callback to run when the Google Visualization API is loaded. 
$(document).ready(function () 

    $.ajax( 
    { 
        type: 'POST', 
        dataType: 'JSON', 
        url: '/Home/GetData', 
        success: 
            function (response) 
            { 
                // Set chart options 
                var options = 
                    { 
                        width: 1100, 
                        height: 900, 
                        sliceVisibilityThreshold: 0, 
                        legend: { position: "top", alignment: "end" }, 
                        chartArea: { left: 370, top: 50, height: "90%" }, 
                        hAxis: 
                            { 
                                slantedText: true, 
                                slantedTextAngle: 18 
                            }, 
                        bar: { groupWidth: "50%" }, 
                    }; 
 
                // Draw. 
                drawGraph(response, options, 'graphId'); 
            } 
    }); 
});


Now, in the below drawGraph(...) method code, I add three new columns per row, the zero column will be the name of the products which will be shown on the chart axis, the first column will be the unit price of the product which will be shown on the graph for each product. After adding the column metadata for the chart, I will convert the received data from the server into DataTables data type accepted by the chart. Then I will set the annotation option for the first chart column which will display the correspondent values on the chart columns per each product. Then, I will draw the ColumnChart by calling Google charts API method. Next, I add the selection handler which will map target link to the target chart display column. Finally, I add the listener event which will call our selection handler method and open the link in a new window as we have coded in the selection handler; i.e.:

// Callback that creates and populates a data table, 
// instantiates the pie chart, passes in the data and 
// draws it. 
function drawGraph(dataValues, options, elementId) { 
    // Initialization. 
    var data = new google.visualization.DataTable(); 
 
    // Setting. 
    data.addColumn('string', 'Product Name'); 
    data.addColumn('number', 'Unit Price'); 
    data.addColumn('string', 'Link'); 
 
    // Processing. 
    for (var i = 0; i < dataValues.length; i++) 
    { 
        // Setting. 
        data.addRow([dataValues[i].ProductName, dataValues[i].UnitPrice, dataValues[i].Link]); 
    } 
 
    // Setting label. 
    var view = new google.visualization.DataView(data); 
    view.setColumns([0, 1, 
        { 
            calc: "stringify", 
            sourceColumn: 1, 
            type: "string", 
            role: "annotation" 
        } 
    ]); 
 
    // Instantiate and draw our chart, passing in some options. 
    var chart = new google.visualization.ColumnChart(document.getElementById(elementId)); 
 
    // Draw chart. 
    chart.draw(view, options); 
 
    // Link interaction. 
    var selectHandler = function (e) 
    { 
        // Verification. 
        if (chart.getSelection() != null && 
             chart.getSelection()[0] != null && 
             chart.getSelection()[0]['row'] != null && 
             chart.getSelection().length > 0) 
        { 
            if (chart.getSelection()[0]['column'] == 1) 
            { 
                // Setting. 
                var link = data.getValue(chart.getSelection()[0]['row'], 2) 
                window.open(link, '_blank'); 
            } 
        } 
    } 
 
    // Add our selection handler. 
    google.visualization.events.addListener(chart, 'select', selectHandler); 
}


Step 6
Create "Views\Home\_ViewGraphPartial.cshtml" & "Views\Home\Index.cshtml" files and replace following code in it.
Views\Home\_ViewGraphPartial.cshtml
<section> 
    <div class="well bs-component"> 
        <div class="row"> 
            <div class="col-xs-12"> 
                <!-- CHART --> 
                <div class="box box-primary"> 
                    <div class="box-header with-border"> 
                        <h3 class="box-title custom-heading">Product wise Graph</h3> 
                    </div> 
                    <div class="box-body"> 
                        <div class="chart"> 
                            <div id="graphId" style="width: 1100px; height: 900px; margin:auto;"></div> 
                        </div> 
                    </div><!-- /.box-body --> 
                </div><!-- /.box --> 
            </div> 
        </div> 
    </div> 
</section>


View\Home\Index.cshtml
@{ 
    ViewBag.Title = "ASP.NET MVC5 - Clickable Google Charts"; 

 
<div class="row"> 
    <div class="panel-heading"> 
        <div class="col-md-8  custom-heading3"> 
            <h3> 
                <i class="fa fa-pie-chart"></i> 
                <span>ASP.NET MVC5 - Clickable Google Charts</span> 
            </h3> 
        </div> 
    </div> 
</div> 
 
<div class="row"> 
    <section class="col-md-12 col-md-push-0"> 
        @Html.Partial("_ViewGraphPartial") 
    </section> 
</div>


In the above code, I have simply created the view code for the page which will display the chart. I have divided the page into two parts for better manageability.

Step 7
Now, create new "Views\Home\TestPage.cshtml" file and replace following code in it.
@{ 
    ViewBag.Title = "ASP.NET MVC5 - Clickable Google Charts"; 

 
<div class="row"> 
    <div class="panel-heading"> 
        <div class="col-md-8  custom-heading3"> 
            <h3> 
                <i class="fa fa-pie-chart"></i> 
                <span>ASP.NET MVC5 - Clickable Google Charts</span> 
            </h3> 
        </div> 
    </div> 
</div> 
 
<div class="row"> 
    <section class="col-md-12 col-md-push-0"> 
        <div class="well bs-component"> 
            <div class="row"> 
                <div class="col-xs-12"> 
                    <h1>Hello! I am Clickable Test Page</h1> 
                </div> 
            </div> 
        </div> 
    </section> 
</div>


In the above code, I have simply added a new page structure for the chart click event target.

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 :: How to Extend ASP.NET MVC AuthorizeAttribute?

clock August 24, 2018 11:17 by author Peter

Today, I will show you how to Extend ASP.NET MVC AuthorizeAttribute and how to Unit Test with ControllerActionInvoker. The reason for extending the AuthorizeAttribute class is that we might decide to store user credential information in a variety of differently data sources such as Active Directory, a database, an encrypted text file, etc…Or we might add custom logic to authorize a user.

OK, now we have set up our premises, let’s dive straight into the code for the subclass of AuthorizeAttribute:
    namespace SecurityDemo.Classes 
    { 
        [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] 
        public class CustomAuthorizeAttribute: AuthorizeAttribute 
        { 
            public override voidOnAuthorization(AuthorizationContextfilterContext) 
            { 
                if (!filterContext.HttpContext.User.Identity.IsAuthenticated) 
                //the user is not allowed to execute the Action. An Unauthorized result is raised. 
                filterContext.Result = newHttpUnauthorizedResult(); 
                var roles = GetAuthorizedRoles(); 
                stringwindowLoginName = filterContext.HttpContext.User.Identity.Name; 
                //windowLoginName and ADGroup is expected to have this format "ABC\\XYZ" 
                stringdomainName = windowLoginName.Contains(@ "\") ?windowLoginName.Substring(0, windowLoginName.IndexOf(@"\ 
                ", System.StringComparison.OrdinalIgnoreCase)) : windowLoginName; 
                windowLoginName = windowLoginName.Contains(@ "\") ? windowLoginName.Substring(windowLoginName.LastIndexOf(@ "\", System.StringComparison.OrdinalIgnoreCase) + 1): windowLoginName; boolisValidUser = false; 
                if (roles.Any(role => ADClass.IsUserInADGroup(windowLoginName, role.Substring(role.LastIndexOf(@ "\", System.StringComparison.OrdinalIgnoreCase) + 1), domainName))) //if window login belongs to AD group from config 
                { 
                    isValidUser = true; 
                } 
                elseif (roles.Any(role => windowLoginName.ToLower().Equals(role.Substring(role.LastIndexOf(@ "\", System.StringComparison.OrdinalIgnoreCase) + 1).ToLower()))) //if window login belongs to a user from config 
                { 
                    isValidUser = true; 
                } 
                if (isValidUser) 
                { 
                    return; 
                } 
                else 
                { 
                    HandleUnauthorizedRequest(filterContext); 
                } 
            } 
            protected override void HandleUnauthorizedRequest(AuthorizationContextfilterContext) 
            { 
                filterContext.Result = newViewResult 
                { 
                    ViewName = "~/Views/Shared/UnAuthorized.cshtml" 
                }; 
            } 
            //get list of authorized Active Directory groups and windows users from 
            // web.config 
            privateIEnumerable < string > GetAuthorizedRoles() 
            { 
                var appSettings = ConfigurationManager.AppSettings[this.Roles]; 
                if (string.IsNullOrEmpty(appSettings)) 
                { 
                    return new[] 
                    { 
                        "" 
                    }; 
                } 
                IEnumerable < string > rolesEnumerable = appSettings.Split(',').Select(s => s.Trim()); 
                return rolesEnumerable; 
            } 
        } 
    } 

 
In the sublassCustomAuthorizeAttribute above we override the OnAuthorization(Authorization Context filterContext) method and provide the logic to identify the windows login user, check the person against the list of authorized Active Directory groups and Windows users from web.config. We also override against the HandleUnauthorizedRequest(AuthorizationContextfilterContext) method to return a view for access denied. Of course, as mentioned, the authorization logic can be made as flexible and complex as possible according to specific business needs.

To use the extended attribute in a controller, we just apply to attribute to a method or class as in the below code snippet:
    public class ProductController: Controller 
    { 
        [CustomAuthorize(Roles = SystemRole.Administrators)] 
        public ActionResultIndex() 
        { 
            return View("Index"); 
        } 
        [CustomAuthorize(Roles = SystemRole.Administrators)] 
        public ActionResultDetails(int Id) 
        { 
            return View("Details"); 
        } 
    } 
    // a helper class to define roles 
    public class SystemRole 
    { 
        public const string Administrators = "Administrators"; 
        public cons tstring Sales = "Sales"; 
    } 

There we have it, we have come up with how to implement custom security as an attribute to be applied to a controller.

Unit Testing:
We can simply test our new security feature by launching the web application through the web browser after providing the access list in the web.config as mentioned in the beginning of the article. There is nothing wrong with that. However, if we need to get more fancy and methodical by doing some full unit testing using NUnit or Microsoft UnitTestFramework (which I’ll be using in this article) then there are a few challenges we’ll be facing. First is we’ll need to simulate a browser session with a full HttpContext with widows login, session, etc… and the way to do it is to use Mock object. The second challenge is how to invoke the action methods of a controller with our CustomAuthorizeAttribute applied. The way to do it is to extend a class calledControllerActionInvoker and override a method called InvokeActionResult(). Also if you need to invoke an action method with router parameters you also need to override the GetParameterValues() method as well. Well, one picture is worth a thousand words, so I present to you a “picture” of all the code (words) involved for the unit test:
    namespace UnitTestSecurityDemo 
    { 
        public class ActionInvokerExpecter < TResult > : ControllerActionInvokerwhereTResult: ActionResult 
        { 
            public boolIsUnAuthorized = false; 
            ///<summary> 
            /// override to get ViewName of controller in action 
            ///</summary> 
            ///<param name="controllerContext"></param> 
            ///<param name="actionResult"></param> 
            protected override voidInvokeActionResult(ControllerContextcontrollerContext, ActionResultactionResult) 
                { 
                    string viewName = ((System.Web.Mvc.ViewResult) actionResult).ViewName; 
                    IsUnAuthorized = viewName.ToLower().Contains("unauthorized"); 
                } 
                ///// <summary> 
                ///// override to get Routedata of controller in action 
                ///// </summary> 
                ///// <param name="controllerContext"></param> 
                ///// <param name="actionDescriptor"></param> 
                ///// <returns></returns> 
            protected overrideIDictionary < string, object > GetParameterValues(ControllerContextcontrollerContext, ActionDescriptoractionDescriptor) 
            { 
                return controllerContext.RouteData.Values; 
            } 
        } 
    } 
    namespace UnitTestSecurityDemo 
    { 
        [TestClass] 
        public class UnitTest1 
        { 
            [TestMethod] 
            public void TestIndexView() 
            { 
                var controller = new ProductController(); 
                MockAuthenticatedControllerContext(controller, @ "abc\jolndoe"); 
                ConfigurationManager.AppSettings.Set("Administrators", @ "abc\Group-ABC-App, abc\jolndoe1"); 
                ActionInvokerExpecter < ViewResult > a = newActionInvokerExpecter < ViewResult > (); 
                a.InvokeAction(controller.ControllerContext, "Index"); 
                Assert.IsTrue(a.IsUnAuthorized); 
            } 
            [TestMethod] 
            public void TestDetailsView() 
            { 
                //since the Details() action method of the controller has a router parameter, we need to pass 
                //router data in as below 
                var controller = newProductController(); 
                varrouteData = newRouteData(); 
                routeData.Values.Add("id", 3); 
                MockAuthenticatedControllerContextWithRouteData(controller, @ "abc\jolndoe", routeData); 
                ConfigurationManager.AppSettings.Set("Administrators", @ "abc\Group-ABC-App, abc\jolndoe"); 
                ActionInvokerExpecter < ViewResult > a = newActionInvokerExpecter < ViewResult > (); 
                a.InvokeAction(controller.ControllerContext, "Details"); 
                Assert.IsTrue(a.IsUnAuthorized); 
            } 
            private static void MockAuthenticatedControllerContext(ProductController controller, stringuserName) 
            { 
                HttpContextBasehttpContext = FakeAuthenticatedHttpContext(userName); 
                ControllerContext context = newControllerContext(newRequestContext(httpContext, newRouteData()), controller); 
                controller.ControllerContext = context; 
            } 
            private static void MockAuthenticatedControllerContextWithRouteData(ProductController controller, stringuserName, RouteDatarouteData) 
            { 
                HttpContextBasehttpContext = FakeAuthenticatedHttpContext(userName); 
                ControllerContext context = newControllerContext(newRequestContext(httpContext, routeData), controller); 
                controller.ControllerContext = context; 
            } 
            public static HttpContextBaseFakeAuthenticatedHttpContext(string username) 
            { 
                Mock < HttpContextBase > context = newMock < HttpContextBase > (); 
                Mock < HttpRequestBase > request = newMock < HttpRequestBase > (); 
                Mock < HttpResponseBase > response = newMock < HttpResponseBase > (); 
                Mock < HttpSessionStateBase > session = newMock < HttpSessionStateBase > (); 
                Mock < HttpServerUtilityBase > server = newMock < HttpServerUtilityBase > (); 
                Mock < IPrincipal > user = newMock < IPrincipal > (); 
                Mock < IIdentity > identity = newMock < IIdentity > (); 
                context.Setup(ctx => ctx.Request).Returns(request.Object); 
                context.Setup(ctx => ctx.Response).Returns(response.Object); 
                context.Setup(ctx => ctx.Session).Returns(session.Object); 
                context.Setup(ctx => ctx.Server).Returns(server.Object); 
                context.Setup(ctx => ctx.User).Returns(user.Object); 
                user.Setup(ctx => ctx.Identity).Returns(identity.Object); 
                identity.Setup(id => id.IsAuthenticated).Returns(true); 
                identity.Setup(id => id.Name).Returns(username); 
                returncontext.Object; 
            } 
        } 
    } 

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 :: Using HttpContext Outside An MVC Controller In .Net Core 2.1

clock August 21, 2018 11:24 by author Peter

Last Friday, while working on a web application based on ASP.Net Core 2.1, I came across a scenario where I had to put some data into memory. While that's not a problem, the catch is that the data has to be unique for each HTTP Session. Consider it as keeping a key that is to be used across different views to display some information related to that particular session.

The only possible solution satisfying my needs was to keep the "key" in session. However, the last point in the code that has access to the key is a simple helper class and not an MVC Controller. And we had no intentions to expose the "key" to our controller. So, the question remains: how do we save the key in session without exposing it to the controller?

Sample Code
In the following code, we have a very basic MVC application with our HomeController. We also have a RequestHandler that takes care of all the background logic making our controller clean and light.

using HttpContextProject.Helpers; 
using HttpContextProject.Models; 
using Microsoft.AspNetCore.Mvc; 
using System.Diagnostics; 
 
namespace HttpContextProject.Controllers 

    public class HomeController : Controller 
    { 
        public IActionResult Index() 
        { 
            return View(); 
        } 
 
        public IActionResult About() 
        { 
            // handle the request and do something 
            var requestHandler = new RequestHandler(); 
            requestHandler.HandleAboutRequest(); 
 
            ViewData["Message"] = "This is our default message for About Page!"; 
            return View(); 
        } 
    } 

 
 
namespace HttpContextProject.Helpers 

    public class RequestHandler 
    { 
        internal void HandleAboutRequest() 
        { 
            // do something here 
        } 
    } 


As it can be seen in the above code, we are simply setting a message in the ViewData and rendering it on the view. Nothing fancy so far. Now, let's see how we can set our message in Http Session from RequestHandler and later access it inside the controller.

Using HttpContext in a Helper Class

With .Net Core 2.1 we can not access the HttpContext outside a controller, however, we can use the IHttpContextAccessor to access the current session outside a controller. In order to do so, we need to add the Session and HttpContextAccessor middle-ware to ConfigureServices method of our Startup class as shown in the code below,

using HttpContextProject.Helpers; 
using Microsoft.AspNetCore.Builder; 
using Microsoft.AspNetCore.Hosting; 
using Microsoft.AspNetCore.Http; 
using Microsoft.AspNetCore.Mvc; 
using Microsoft.Extensions.Configuration; 
using Microsoft.Extensions.DependencyInjection; 
 
namespace HttpContextProject 

    public class Startup 
    { 
        public IConfiguration Configuration { get; } 
        public Startup(IConfiguration configuration) 
        { 
            Configuration = configuration; 
        }        
 
        public void ConfigureServices(IServiceCollection services) 
        { 
            services.Configure<CookiePolicyOptions>(options => { 
                options.CheckConsentNeeded = context => true; 
                options.MinimumSameSitePolicy = SameSiteMode.None; 
            }); 
            services.AddSession(); 
            services.AddSingleton<RequestHandler>(); 
            services.AddHttpContextAccessor(); 
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); 
        } 
 
        public void Configure(IApplicationBuilder app, IHostingEnvironment env) 
        { 
            if (env.IsDevelopment()) { 
                app.UseDeveloperExceptionPage(); 
            } 
            else { 
                app.UseExceptionHandler("/Home/Error"); 
            } 
            app.UseSession(); 
            app.UseMvc(routes => { 
                routes.MapRoute( 
                    name: "default", 
                    template: "{controller=Home}/{action=Index}/{id?}"); 
            }); 
        } 
    } 


The next thing we need to do is to add a dependency of IHttpContextAccessor in the RequestHandler. This allows us to access the HttpContext inside the request handler. After we have done required processing for the request, we can now set the message in session, using the Session.SetString(key, value) method. Please refer to the code below,

using Microsoft.AspNetCore.Http; 
 
namespace HttpContextProject.Helpers 

    public class RequestHandler 
    { 
        IHttpContextAccessor _httpContextAccessor; 
        public RequestHandler(IHttpContextAccessor httpContextAccessor) 
        { 
            _httpContextAccessor = httpContextAccessor; 
        } 
 
        internal void HandleAboutRequest() 
        { 
            // handle the request 
            var message = "The HttpContextAccessor seems to be working!!"; 
            _httpContextAccessor.HttpContext.Session.SetString("message", message); 
        } 
    } 


Now, that we have our RequestHandler all set, it's time to make some changes in the HomeController. Currently, the "new" RequestHandler  is inside the action method, which is not a good practice. So, I will decouple the handler from the controller and rather inject it as a dependency in the constructor. Next thing we do is to set the message in ViewData from the session, as shown in the code below,

using HttpContextProject.Helpers; 
using HttpContextProject.Models; 
using Microsoft.AspNetCore.Mvc; 
using System.Diagnostics; 
 
namespace HttpContextProject.Controllers 

    public class HomeController : Controller 
    { 
        private readonly RequestHandler _requestHandler; 
 
        public HomeController(RequestHandler requestHandler) 
        { 
            _requestHandler = requestHandler; 
        } 
 
        public IActionResult About() 
        { 
            _requestHandler.HandleAboutRequest(); 
            ViewData["Message"] = HttpContext.Session.GetStringValue("message"); 
            return View(); 
        } 
    } 


Note that I'm using Sesseion.GetStringValue(key) which is an extension method that I have added to retrieve data from the session, however, it's not really required. You can simply use the Session.TryGetValue(key, value) as well.

In case you have not figured it out already, I must tell you that we need to register our RequestHandler in the ConfigureServices method of the Startup class so that the dependency for our controller can be resolved.

Summary
With the above changes in place, we can now access the HttpContext.Session inside our request handler and the same can be done for any other class as well. However, there is one thing that I don't like about this approach. For every single component where we need to access the session, we have to inject a dependency of IHttpContextAccessor.

While for one or two components it's not a problem, it can be very daunting if we have to do the same over and over again. There is a way to achieve the same accessibility without having to inject any dependency, but that's a story for another day and I will write about that in my next post.

 



ASP.NET MVC 6 Hosting - HostForLIFE.eu :: Charts In ASP.NET MVC Using Chart.js

clock August 10, 2018 11:36 by author Peter

This article demonstrates how to create charts in ASP.NET MVC using Chart.js and C#. This article starts with how to use Chart.js in your MVC project. After that, it demonstrates how to add charts to a View.

Using Chart.js in your ASP.NET MVC project (C#)

Chart.js is a JavaScript charting tool for web developers. The latest version can be downloaded from GitHub or can use CDN.

In this article, Chart.js CDN (v2.6.0) is used for demonstration purposes.
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js" type="text/javascript"></script> 

In the View (*.cshtml), add the Chart.js CDN along with jQuery CDN (recommended) in the head section if you haven’t mentioned those in layout pages.
@section head 

    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js" type="text/javascript"></script> 
    <script src="https://code.jquery.com/jquery-1.11.3.min.js"></script> 


Adding chart to a View
In the following example, the <canvas> tag is used to hold the chart in View’s <body> section.
<div Style="font-family: Corbel; font-size: small ;text-align:center " class="row"> 
    <div  style="width:100%;height:100%"> 
            <canvas id="myChart" style="padding: 0;margin: auto;display: block; "> </canvas> 
    </div> 
</div> 

Now, in the Controller class, let’s add a method to return the data for the chart that we added in the View. In this example, we are using JSON format for the source data.
[HttpPost] 
public JsonResult NewChart() 

    List<object> iData = new List<object>(); 
    //Creating sample data 
    DataTable dt = new DataTable() ; 
    dt.Columns.Add("Employee",System.Type.GetType("System.String")); 
    dt.Columns.Add("Credit",System.Type.GetType("System.Int32")); 
 
    DataRow dr = dt.NewRow(); 
    dr["Employee"] = "Sam"; 
    dr["Credit"] = 123; 
    dt.Rows.Add(dr); 
 
    dr = dt.NewRow(); 
    dr["Employee"] = "Alex"; 
    dr["Credit"] = 456; 
    dt.Rows.Add(dr); 
 
    dr = dt.NewRow(); 
    dr["Employee"] = "Michael"; 
    dr["Credit"] = 587; 
    dt.Rows.Add(dr); 
    //Looping and extracting each DataColumn to List<Object> 
    foreach (DataColumn dc in dt.Columns) 
    { 
        List<object> x = new List<object>(); 
        x = (from DataRow drr in dt.Rows select drr[dc.ColumnName]).ToList(); 
        iData.Add(x); 
    } 
    //Source data returned as JSON 
    return Json(iData, JsonRequestBehavior.AllowGet); 


The data from the source table is processed in such a way that each column in the result table is made to separate list. The first column is expected to have the X-axis data of the chart, whereas the consequent columns hold the data for Y-axis. (Chart.js expects the Axis labels in separate list. Please check the AJAX call section.)

The data for axises is combined to a single List<Object>, and returned from the method as JSON.

AJAX calls are used in the <script> section of View to call the method in Controller to get the chart data.
<script> 
    $.ajax({ 
        type: "POST", 
        url: "/Chart/NewChart", 
        contentType: "application/json; charset=utf-8", 
        dataType: "json", 
        success: function (chData) { 
        var aData = chData; 
        var aLabels = aData[0]; 
        var aDatasets1 = aData[1]; 
        var dataT = { 
            labels: aLabels, 
            datasets: [{ 
                label: "Test Data", 
                data: aDatasets1, 
                fill: false, 
                backgroundColor: ["rgba(54, 162, 235, 0.2)", "rgba(255, 99, 132, 0.2)", "rgba(255, 159, 64, 0.2)", "rgba(255, 205, 86, 0.2)", "rgba(75, 192, 192, 0.2)", "rgba(153, 102, 255, 0.2)", "rgba(201, 203, 207, 0.2)"], 
                borderColor: ["rgb(54, 162, 235)", "rgb(255, 99, 132)", "rgb(255, 159, 64)", "rgb(255, 205, 86)", "rgb(75, 192, 192)", "rgb(153, 102, 255)", "rgb(201, 203, 207)"], 
                borderWidth: 1 
                }] 
            }; 
        var ctx = $("#myChart").get(0).getContext("2d"); 
        var myNewChart = new Chart(ctx, { 
            type: 'bar', 
            data: dataT, 
            options: { 
                responsive: true, 
                title: { display: true, text: 'CHART.JS DEMO CHART' }, 
                legend: { position: 'bottom' }, 
                scales: { 
                xAxes: [{ gridLines: { display: false }, display: true, scaleLabel: { display: false, labelString: '' } }], 
                yAxes: [{ gridLines: { display: false }, display: true, scaleLabel: { display: false, labelString: '' }, ticks: { stepSize: 50, beginAtZero: true } }] 
            }, 
        } 
        }); 
    } 
}); 
</script> 


aData[0] has the data for X-Axis labels and aData[1] has the data for Y-Axis correspondingly.

As in the code, the AJAX call is made to the Controller method ’/Chart/NewChart’ where ‘Chart’ is the name of the Controller class and ‘NewChart’ is the method which returns the source data for the chart in JSON format.

AJAX call, when returned successfully, processes the returned JSON data.
The JSON data is processed to extract the labels and axis data for the chart preparation. The 2D context of the canvas ‘myChart’ is created using ‘getContext("2d")’ method, and then the context is used to create the chart object in ‘new Chart()’ method inside the script.

 



ASP.NET MVC 6 Hosting - HostForLIFE.eu :: ASP.NET Core 2.0 MVC View Components

clock August 7, 2018 09:51 by author Peter

How to reuse parts of web pages using View Components in ASP.NET Core MVC.

Solution
In an empty project, update Startup class to add services and middleware for MVC.
public void ConfigureServices( 
IServiceCollection services) 

services.AddScoped<IAddressFormatter, AddressFormatter>(); 
services.AddMvc(); 


public void Configure( 
IApplicationBuilder app, 
IHostingEnvironment env) 

app.UseMvc(routes => 

routes.MapRoute( 
    name: "default", 
    template: "{controller=Home}/{action=Index}/{id?}"); 
}); 


Add a Model to display in the View.
public class EmployeeViewModel 

public int Id { get; set; } 
public string Firstname { get; set; } 
public string Surname { get; set; } 


Add a Controller with action method returning ViewResult.
public IActionResult Index() 

var model = new EmployeeViewModel 

   Id = 1, 
   Firstname = "James", 
   Surname = "Bond" 
}; 
return View(model); 


Add a parent View named Index.cshtml.
@using Fiver.Mvc.ViewComponents.Models.Home 
@model EmployeeViewModel 

<div style="border: 1px solid black; margin: 5px"> 
<strong>Employee Details (view)</strong> 

<p>Id: @Model.Id</p> 
<p>Firstname: @Model.Firstname</p> 
<p>Surname: @Model.Surname</p> 

@await Component.InvokeAsync("Address", new { employeeId = Model.Id }) 
</div> 

@await Component.InvokeAsync("UserInfo") 

Add a View Component’s Model.

public class AddressViewModel 

public int EmployeeId { get; set; } 
public string Line1 { get; set; } 
public string Line2 { get; set; } 
public string Line3 { get; set; } 
public string FormattedValue { get; set; } 


Add a View Component’s class.
[ViewComponent(Name = "Address")] 
public class AddressComponent : ViewComponent 

private readonly IAddressFormatter formatter; 

public AddressComponent(IAddressFormatter formatter) 

  this.formatter = formatter; 


public async Task InvokeAsync(int employeeId) 

  var model = new AddressViewModel 
  { 
      EmployeeId = employeeId, 
      Line1 = "Secret Location", 
      Line2 = "London", 
      Line3 = "UK" 
  }; 
  model.FormattedValue =  
      this.formatter.Format(model.Line1, model.Line2, model.Line3); 
  return View(model); 



Add a View Component’s View named as Default.cshtml.
@using Fiver.Mvc.ViewComponents.Models.Home 
@model AddressViewModel 

<div style="border: 1px dashed red; margin: 5px"> 
<strong>Address Details (view component in Views/Home)</strong> 

<p>Employee: @Model.EmployeeId</p> 
<p>Line1: @Model.Line1</p> 
<p>Line2: @Model.Line2</p> 
<p>Line3: @Model.Line3</p> 
<p>Full Address: @Model.FormattedValue</p> 
</div>

Discussion
View Components are special type of Views rendered inside other Views. They are useful for reusing parts of a View or splitting a large View into smaller components. Unlike Partial Views, View Components do not rely on Controllers. They have their own class to implement the logic to build component’s model and Razor View page to display HTML/CSS.

I like to think of them as mini-controllers, although this is not strictly correct but helps conceptualize their usage. Unlike Controllers, they do not handle HTTP requests or have Controller lifecycle, which means they can’t rely on filters or model binding.

View Components can utilize dependency injection, which makes them powerful and testable.

Creating
There are a few ways to create View Components. I’ll discuss the most commonly used (and best in my view) option.
1. Create a class (anywhere in your project) and inherit from ViewComponent abstract class.

  • Name of the class, by convention, ends with ViewComponent.

2. Create a method called InvokedAsync() that returns Task<IViewComponentResult>.

  • This method can take any number of parameters, which will be passed when invoking the component (see Invoking section below).

3. Create Model e.g. via database etc.
4. Call IViewComponentResult by calling the View() method of base ViewComponent. You could pass your model to this method.

  • Optionally you could specify the name of razor page (see Discovery section below).

The base ViewComponent class gives access to useful details (via properties) like HttpContext, RouteData, IUrlHelper, IPrincipal, and ViewData.

Invoking
View Components can be invoked by either,

  1. Calling @await Component.InvokeAsync(component, parameters) from the razor view.
  2. Returning ViewComponent(component, parameters) from a controller.

Here, “component” is a string value refereeing to the component class.
InvokeAsync() method can take any number of parameters and is passed using an anonymous object when invoking the View Component.

Below is an example of second option above. Notice that the second action method doesn’t work because the Razor page for the component is not under Controller’s Views folder,
public class ComponentsController : Controller 

public IActionResult UserInfo() 

 // works: this component's view is in Views/Shared 
 return ViewComponent("UserInfo"); 


public IActionResult Address() 

 // doesn't works: this component's view is NOT in Views/ 
 return ViewComponent("Address", new { employeeId = 5 }); 

}

Discovery
MVC will search for the razor page for View Component in the following sequence,
Views/[controller]/Components/[component]/[view].cshtml
Views/Shared/Components/[component]/[view].cshtml

Here matches either,
Name of the component class, minus the ViewComponent suffix if used.
Value specified in [ViewComponent] attribute applied to component class.

Also, [view] by default is Default.cshtml, however, it can be overwritten by returning a different name from the component class. Below the component returns a view named Info.cshtml,
public class UserInfoViewComponent : ViewComponent 

public async Task InvokeAsync() 

 var model = new UserInfoViewModel 
 { 
     Username = "[email protected]", 
     LastLogin = DateTime.Now.ToString() 
 }; 
 return View("info", model); 

}


jQuery
You could access View Components via jQuery as well. To do so enable the use of Static Files in Startup,
public void Configure( 
IApplicationBuilder app, 
IHostingEnvironment env) 

app.UseStaticFiles(); 
app.UseMvc(routes => 

  routes.MapRoute( 
      name: "default", 
      template: "{controller=Home}/{action=Index}/{id?}"); 
}); 


Add jQuery script file to wwwroot and use it in a page
<html> 
<head> 
<meta name="viewport" content="width=device-width" /> 
<title>ASP.NET Core View Components</title> 

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

</head> 
<body> 
<div> 
<strong>ASP.NET Core View Components</strong> 

<input type="button" id="GetViewComponent" value="Get View Component" /> 

<div id="result"></div> 
</div> 
<script> 
$(function () { 
    $("#GetViewComponent").click(function () { 

        $.ajax({ 
            method: 'GET', 
            url: '@Url.Action("UserInfo", "Components")' 
        }).done(function (data, statusText, xhdr) { 
            $("#result").html(data); 
        }).fail(function (xhdr, statusText, errorText) { 
            $("#result").text(JSON.stringify(xhdr)); 
        }); 

    }); 
}); 
</script> 
</body> 
</html>



ASP.NET MVC 6 Hosting - HostForLIFE.eu :: Check Your ASP.NET MVC Version Installed In Your System Using Code During Runtime

clock August 3, 2018 11:17 by author Peter

Create an Application named MVC version

Look at an example for better reference i.e. RouteConfig.cs

Create A Controller named “Home” .

Add the code given below in HomeController.cs for better results, as expected.using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.Mvc; 
namespace Mvc_Version.Controllers { 
    public class HomeController: Controller { 
        // 
        // GET: /Home/ 
        public string Version() { 
            return "<h2>The Installed Mvc Version In your System Is : " + typeof(Controller).Assembly.GetName().Version.ToString() + "</h2>"; 
        } 
    } 
}   

We mentioned the controller action method version In HomeController.Cs

For this, we should change the action method name in RouteConfig.cs for better loading of the page. For the first time, we will make it a start page.

Add the highlighted code in your file of RouteConfig.Cs. 

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.Mvc; 
using System.Web.Routing; 
namespace Mvc_Version { 
    public class RouteConfig { 
        public static void RegisterRoutes(RouteCollection routes) { 
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
            routes.MapRoute(name: "Default", url: "{controller}/{action}/{id}", defaults: new { 
                controller = "Home", action = "Version", id = UrlParameter.Optional 
            }); 
        } 
    } 
}  

Output

The expected output is shown below.

http://localhost:49952/Home/Version

Home - Controller name
Version - Controller action method



ASP.NET MVC 6 Hosting - HostForLIFE.eu :: Understanding Produces And Consumes Attribute In MVC 6

clock July 31, 2018 11:41 by author Peter

Produces and Consumes Attributes are newly introduced in MVC 6 (ASP.NET Core) to control the content negotiation.

What is Content Negotiation?
The process of picking the correct output format is known as Content Negotiation. Generally, Frameworks will accept two types of input/output formats those are JSON and XML. Nowadays, every framework by default accepts and returns in JSON format because of its advantages. If the user wants to control this default behavior, he should send an Accept Header with an appropriate format in GET or POST request from a client such that Framework will make sure to use the given format.

If a user doesn’t provide any Accept-Header, then the framework will decide which format it should use based on its settings. Some of the most popular browsers such as Chrome and Firefox will by default add Accept Header as application/xml and that is the reason when we call the web API from the browser will display the output in XML format if we don’t explicitly set the output format as JSON. Below are the sample requests generated from Chrome and IE where can observe the Accept Headers for these two browsers.

Chrome
GET / HTTP/1.1
Host: localhost:8080
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

IE
GET / HTTP/1.1
Accept: text/html, application/xhtml+xml, */*


If you want to see the output in JSON format, it's preferred to use any tools like fiddler, browser dev tools etc.
To control this and let the user be given full control of how to receive and sent the data format, Produces and Consumes Attribute is introduced in new ASP.NET MVC Core.

Produces Attribute
This attribute helps the user to inform the framework to generate and send the output result always in given content type as follows.
[Produces("application/json")]  

The above line is saying to the framework to use JSON as output format. This attribute can be decorated at controller level as well as Action level. Action level will be taken as the first priority if it is declared at both controller level as well as Action level.

Consumes Attribute
An Attribute helps the user to inform the framework to accept the input always in given content type as follows.
[Consumes("application/json")]  

The above line is saying to the framework to use JSON as input format. This attribute can be decorated at controller level as well as Action level. Action level will be taken as the first priority if it is declared at both controller level as well as Action level.

If you want to control it globally, you can set this while configuring MVC in ConfigureServices method as follows.
Configure<MvcOptions>(options =>  
   Filters.Add(newProducesAttribute(“application/json”))  
); 



ASP.NET MVC 6 Hosting - HostForLIFE.eu :: How to Call A C# Function With jQuery AJAX In ASP.NET MVC?

clock July 27, 2018 11:42 by author Peter

jQuery AJAX method is a very powerful function for doing asynchronous operations from the Web pages. It helps to update parts of a Web page without reloading the whole page. This increases the Website's speed and reduces the load. It can be used with any Web technology like HTML, ASP.NET, ASP.NET MVC, PHP, Ruby or any other. With jQuery AJAX method, you can create high performance features in our Website. Let me show you how to use this method in  ASP.NET MVC page.

ASP.NET MVC Page
To understand the working of jQuery AJAX, I will create a login feature in ASP.NET MVC page. The page will have 2 input controls to enter the username and the password. There will also be a button to submit the two values for checking from the database.
When the username and password are correct, the secured information of the user is shown, else the “wrong username and password” is shown.
The main attraction here is that I will use jQuery AJAX method to check the username and the password. There will be no page reloading during checking.
To start learning jQuery AJAX method, I would suggest you check – jQuery AJAX. Also, look for the syntax and the key-value pairs that can be passed to this method.

The Controller Code
Start with creating a “Controller” in your ASP.NET MVC Application. Now, add a C# function “GetSecuredData” into the controller.
[HttpPost] 
public string GetSecuredData(string userName, string password) 

    string securedInfo = ""; 
    if ((userName == "admin") && (password == "admin")) 
        securedInfo = "Hello admin, your secured information is ......."; 
    else 
        securedInfo = "Wrong username or password, please retry."; 
    return securedInfo; 
}
 

The C# function given above will be called by jQuery AJAX method. As you can see, this function has 2 parameters, “username” and “password”. In these 2 parameters, it receives the username and the password values. It then checks them and shows the secured information, if they are the correct ones.

You can also change the code given above to include the database operation, where the username and the password are checked against the ones stored in the database.

The View code
Now, create a view for the Controller. This view will contain the two input controls for the username and password. There will be a button, which when clicked will call jQuery AJAX function.
<h3>Enter the Username and Password:</h3> 
(enter "admin" for both username and password) 
<input type="text" id="usernameInput" placeholder="Username" /> 
<input type="text" id="passwordInput" placeholder="Password" /> 
<button id="submit">Submit</button> 
<div id="dataDiv"></div> 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script> 
<script> 
    $(document).ready(function () { 
        $("#submit").click(function (e) { 
            if ($("#usernameInput").val() == "") 
                alert("Username cannot be empty"); 
            else if ($("#passwordInput").val() == "") 
                alert("Password cannot be empty"); 
            else { 
                $.ajax({ 
                    type: "POST", 
                    url: "/Home/GetSecuredData", 
                    contentType: "application/json; charset=utf-8", 
                    data: '{"userName":"' + $("#usernameInput").val() + '","password":"' + $("#passwordInput").val() + '"}', 
                    dataType: "html", 
                    success: function (result, status, xhr) { 
                        $("#dataDiv").html(result); 
                    }, 
                    error: function (xhr, status, error) { 
                        $("#dataDiv").html("Result: " + status + " " + error + " " + xhr.status + " " + xhr.statusText) 
                    } 
                }); 
            } 
            return false; 
        }); 
    }); 
</script> 


The button click event will call jQuery AJAX event. We pass the “controller name/function name” to the URL field. The jQuery AJAX event will call the C# function which gets the username and password values in its parameters.

Finally in the success function we will show the returned value from the C# function.



ASP.NET MVC 6 Hosting - HostForLIFE.eu :: How To Open PDF File In New Tab In MVC Using C# ?

clock July 24, 2018 07:46 by author Peter

In this post, we will learn about how to open PDF or other files in a new tab using C#. For this example, first we need to return a file from MVC Controller then open the file in a new tab from view. For this, I will set return type "FileResult" from MVC controller and return "File" with a byte Array of the file and its content type. Let's start coding.

Step 1
First, create a new project of MVC from File -> New -> Project.

Step 2
Select ASP.NET Web Application (.Net Framework) for creating an MVC application and set Name and Location of Project.

Step 3
After setting the name and location of the project, open another dialog. From this dialog select MVC project and click OK.

After creating a project create one controller method inside the home controller and name that "GetReport". and write the below code in this method.

Controller
public FileResult GetReport() 

    string ReportURL = "{Your File Path}"; 
    byte[] FileBytes = System.IO.File.ReadAllBytes(ReportURL); 
    return File(FileBytes, "application/pdf"); 
}


Above method returns FileBytes, and Content type is "application/pdf".

View
Create one function for an open PDF file in a new tab.
function GetClientReport() { 
    window.open('/{ControllerName}/GetReport, "_blank"); 
};


The above function will open a new tab in the browser and call controller GetReport() method and this method returns file ,and browser is displayed in an opened tab.



About HostForLIFE

HostForLIFE 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 2019 Hosting, ASP.NET 5 Hosting, ASP.NET MVC 6 Hosting and SQL 2019 Hosting.


Month List

Tag cloud

Sign in