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

European ASP.NET MVC 4 Hosting - Amsterdam :: ValidateInput and AllowHtml attribute in MVC4

clock October 28, 2013 09:43 by author Scott

Sometimes, your required to save Html data in the database. By default Asp.Net MVC doesn't allow a user to submit html for avoiding Cross Site Scripting attack to your application. Suppose you have below form and you can submit the Html in description textarea.

If you do this and try to submit it you will get the error below

However, if you want to do this, you can achieve it by using ValidateInput attribute and AllowHtml attribute.

ValidateInput Attribute

This is the simple way to allow the submission of HTML. This attribute can enable or disable input validation at the controller level or at any action method.

ValidateInput at Controller Level

[ValidateInput(false)]
public class HomeController : Controller
{
public ActionResult AddArticle()
{
return View();
}

[HttpPost]
public ActionResult AddArticle(BlogModel blog)
{
if (ModelState.IsValid)
{

}
return View();
}
}

Now, the user can submit Html for this Controller successfully.

ValidateInput at Action Method Level

public class HomeController : Controller
{
public ActionResult AddArticle()
{
return View();
}

[ValidateInput(false)]
[HttpPost]
public ActionResult AddArticle(BlogModel blog)
{
if (ModelState.IsValid)
{

}
return View();
}
}

Now, the user can submit Html for this action method successfully.

Limitation of ValidateInput attribute

This attribute also has the issue since this allow the Html input for all the properties and that is unsafe. Since you have enable Html input for only one-two properties then how to do this. To allow Html input for a single property, you should useAllowHtml attribute.

AllowHtml Attribute

This is the best way to allow the submission of HTML for a particular property. This attribute will be added to the property of a model to bypass input validation for that property only. This explicit declaration is more secure than the ValidateInput attribute.

using System.ComponentModel.DataAnnotations;
using System.Web.Mvc; 

public class BlogModel
{
[Required]
[Display(Name = "Title")]
public string Title { get; set; } 

[AllowHtml]
[Required]
[Display(Name = "Description")]
public string Description{ get; set; } 

}

Make sure, you have removed the ValidateInput attribute from Conroller or Action method. Now, the user can submit Html only for the Description property successfully.



European ASP.NET MVC 4 Hosting - Amsterdam :: How to Create Async Controllers with MVC 4

clock August 9, 2013 08:59 by author Scott

In this post I will show how to create async controllers in MVC 4.

The way to build asynchronous controllers has been completely changed compared to how it was done in MVC3 with the AsyncController superclass. This class and the inherent complexity in using it are gone in MVC4.

Start Visual Studio 2012 and create an MVC4 Web Application and choose the Internet template. Create a folder called “Services” in the solution. Insert two classes in this folder: DatabaseService and CalculationService. They represent long running calls to external services and have the following content:

DatabaseService.cs:

public class DatabaseService
    {
        public string GetData()
        {
            StringBuilder dataBuilder = new StringBuilder();
            dataBuilder.Append("Starting GetData on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(". ");
            Thread.Sleep(2000);
            dataBuilder.Append("Results from the database. ").Append(Environment.NewLine);
            dataBuilder.Append("Finishing GetData on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(".");
            return dataBuilder.ToString();
        }
    }

CalculationService.cs:

public class CalculationService
    {
        public string GetResult()
        {
            StringBuilder resultBuilder = new StringBuilder();
            resultBuilder.Append("Starting GetResult on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(". ");
            Thread.Sleep(2000);
            resultBuilder.Append("This is the result of a long running calculation. ");
            resultBuilder.Append("Finishing GetResult on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(".");
            return resultBuilder.ToString();
        }
    }

There should be nothing complicated in either class implementation.

Create another folder in the solution called ViewModels. Add a class called HomePageViewModel in that folder:

public class HomePageViewModel
    {
        public List<String> Messages { get; set; } 

        public void AddMessage(string message)
        {
            if (Messages == null)
            {
                Messages = new List<string>();
            }
            Messages.Add(message);
        }
    }

Navigate to the Index action of the Home controller and modify it as follows:

public ActionResult Index()
        {
            DateTime startDate = DateTime.UtcNow; 

            HomePageViewModel viewModel = new HomePageViewModel();
            viewModel.AddMessage(string.Concat("Starting Action on thread id ", Thread.CurrentThread.ManagedThreadId));
            CalculationService calcService = new CalculationService();
            DatabaseService dataService = new DatabaseService(); 
            viewModel.AddMessage(calcService.GetResult());
            viewModel.AddMessage(dataService.GetData()); 

            DateTime endDate = DateTime.UtcNow;
            TimeSpan diff = endDate - startDate; 

            viewModel.AddMessage(string.Concat("Finishing Action on thread id ", Thread.CurrentThread.ManagedThreadId));
            viewModel.AddMessage(string.Concat("Action processing time: ", diff.TotalSeconds));
            return View(viewModel);
        }

Nothing complicated here either: we’re just adding messages to the view model, show the thread ids and measure the time it takes to complete the action.

Modify Index.cshtml of the Home view as follows:

@model Mvc4.ViewModels.HomePageViewModel
@{
    ViewBag.Title = "Home Page";


<ul>
    @foreach (String message in Model.Messages)
    {
        <li>@message</li>
    }
</ul>

So when you run the web page you should see an output similar to the following:

It’s easy to see the following:

  • The Index() action blocks the thread when it calls CalculationService and DatabaseService
  • The total processing time took about 4 seconds in total
  • All involved methods executed on the same thread

Now our goal is to make this process more efficient: as it stands now the main thread is only sitting idle for most of the processing time. This can be a serious problem if we’re intending to build a scalable and responsive application.

We need to make a couple of changes to our code:

  • The Index() action needs to return a Task of type ActionResult and turned to an async method: we do not directly return an ActionResult but a Task that represents an ActionResult
  • Remember that if an action is of type async then it needs to have its pair ‘await’ somewhere in the method body
  • We have two long running method calls within the Index() action, so we’ll instruct MVC4 to await them
  • Since we’ll await those two method calls we need to insert async versions of DatabaseService.GetData() and CalculationService.GetResult() as well: they in turn must also return Tasks of type string instead of plain string

Using our experience from the Console app in the previous post we’ll include an async version of GetResult() in CalculationService.cs:

public async Task<String> GetResultAsync()
        {
            StringBuilder resultBuilder = new StringBuilder();
            resultBuilder.Append("Starting GetResult on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(". ");
            await Task.Delay(2000);
            resultBuilder.Append("This is the result of a long running calculation. ");
            resultBuilder.Append("Finishing GetResult on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(".");
            return resultBuilder.ToString();
        }

We’ll also insert a GetDataAsync() in DatabaseService.cs:

public async Task<String> GetDataAsync()
        {
            StringBuilder dataBuilder = new StringBuilder();
            dataBuilder.Append("Starting GetData on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(". ");
            await Task.Delay(2000);
            dataBuilder.Append("Results from the database. ").Append(Environment.NewLine);
            dataBuilder.Append("Finishing GetData on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(".");
            return dataBuilder.ToString();
        }

Update the Index action of the Home controller to call the async method versions of the services:

public async Task Index()
        {
            DateTime startDate = DateTime.UtcNow; 

            HomePageViewModel viewModel = new HomePageViewModel();
            viewModel.AddMessage(string.Concat("Starting Action on thread id ", Thread.CurrentThread.ManagedThreadId));
            CalculationService calcService = new CalculationService();
            DatabaseService dataService = new DatabaseService(); 

            string calculationResult = await calcService.GetResultAsync();
            string databaseResult = await dataService.GetDataAsync(); 

            viewModel.AddMessage(calculationResult);
            viewModel.AddMessage(databaseResult); 

            DateTime endDate = DateTime.UtcNow;
            TimeSpan diff = endDate - startDate; 

            viewModel.AddMessage(string.Concat("Finishing Action on thread id ", Thread.CurrentThread.ManagedThreadId));
            viewModel.AddMessage(string.Concat("Action processing time: ", diff.TotalSeconds));
            return View(viewModel);
        }

Run the web app now and you may see an output similar to the following:

Note the following:

  • The Index action started on thread id 10
  • The same thread enters GetResultAsync
  • The main thread exits GetResultAsync at the await keyword and thread 9 takes over
  • Thread 9 enters GetDataAsync and exits at the await keyword and thread 5 takes over
  • Thread 5 finished Index()
  • The total processing time is still about 4 seconds, but remember from the previous post: if you want to couple asynchronous methods with concurrency you need to include the TPL as well. This will be resolved later in this post.

The output on your screen may be different when you run the sample. It is not guaranteed that 3 different threads will be involved throughout the lifetime of the Index() action. It depends on the availability of threads, may only be 2 in total.

If you are working with WCF services and add a service reference to your project then you’ll have the option to generate the Async() versions of the service calls automatically. Make sure to select the ‘Allow generation of asynchronous operations’ checkbox and the ‘Generate task-based operations’ radiobutton in the Service Reference Settings window.

.NET4.5 is now interspersed with built-in async versions of long running and/or remote methods. Typical examples include: HttpClient.SendAsync that returns a Task of type HttpResponseMessage, or HttpContent.ReadAsStringAsync that returns a Task of type String.

We can now introduce TPL to make the service calls run in parallel. As it stands now the Index action first waits for GetResultAsync to finish before it goes on with GetDataAsync. Ideally Index should wait for both actions to complete in parallel and not one after the other. We will basically hold a reference to the Task values returned by the services and await them both together.

Update the Index action as follows:

public async Task<ActionResult> Index()
        {
            DateTime startDate = DateTime.UtcNow; 

            HomePageViewModel viewModel = new HomePageViewModel();
            viewModel.AddMessage(string.Concat("Starting Action on thread id ", Thread.CurrentThread.ManagedThreadId));
            CalculationService calcService = new CalculationService();
            DatabaseService dataService = new DatabaseService(); 

            Task<String> calculationResultTask = calcService.GetResultAsync();
            Task<String> databaseResultTask = dataService.GetDataAsync(); 

            await Task.WhenAll(calculationResultTask, databaseResultTask); 

            viewModel.AddMessage(calculationResultTask.Result);
            viewModel.AddMessage(databaseResultTask.Result); 

            DateTime endDate = DateTime.UtcNow;
            TimeSpan diff = endDate - startDate; 

            viewModel.AddMessage(string.Concat("Finishing Action on thread id ", Thread.CurrentThread.ManagedThreadId));
            viewModel.AddMessage(string.Concat("Action processing time: ", diff.TotalSeconds));
            return View(viewModel);
        }

Note the following:

  • We do not await the two service calls one by one
  • Both of them will be awaited using Task.WhenAll
  • Task.WhenAll accepts an array of Task objects that should run in parallel
  • Task.WhenAll will block until all tasks in the array have finished
  • The await keyword will make sure that Index will wait upon all tasks to complete in the array
  • To retrieve the returned value from the service calls just use the Result property of the Task object: this will be populated if the Task has a return value i.e. it is a Task of some type

When you run the updated Index page you may see something like this:

Again, your results will almost certainly differ. Which thread is allocated to which task is up to the thread scheduler. Refresh the page a couple of times to see some different results.



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