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 :: Tips on How To Improve MVC Application Performance

clock December 10, 2013 07:32 by author Patrick

In this post we will cover a few tips and tricks to improve ASP.NET MVC Application Performance. While working on this site, I have tried to improve page loading speeds as much as possible. There are a lot of tricks that you can do to improve the speed of your site. I have constantly been learning new things by delving into the world of site performance.

These are a few of the steps that I took to speed up my site:

Run in Release mode

Make sure your production application always runs in release mode in the web.config

  <compilation debug="false"></compilation>

or change this in the machine.config on the production servers

<configuration>
    <system.web>
          <deployment retail="true"></deployment>
    </system.web>
</configuration>

Only use the View Engines that you require

protected void Application_Start()
{
    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new RazorViewEngine());
}

Use the CachedDataAnnotationsModelMetadataProvider

ModelMetadataProviders.Current = new CachedDataAnnotationsModelMetadataProvider();

Avoid passing null models to views

Because a NullReferenceException will be thrown when the expression gets evaluated, which .NET then has to handle gracefully.

// BAD
public ActionResult Profile()
{
    return View();
}

// GOOD
public ActionResult Profile()
{
    return View(new Profile());
}

Use OutputCacheAttribute when appropriate

For content that does not change often, use the OutputCacheAttribute to save unnecessary and action executions.

[OutputCache(VaryByParam = "none", Duration = 3600)]
public ActionResult Categories()
{
    return View(new Categories());
}

Use HTTP Compression

<system.webserver>
<urlcompression dodynamiccompression="true" dostaticcompression="true" dynamiccompressionbeforecache="true"></urlcompression>
</system.webserver>

Remove unused HTTP Modules

If you run into any problems after removing them, try adding them back in.

<httpmodules>
      <remove name="WindowsAuthentication"></remove>
      <remove name="PassportAuthentication"></remove>
      <remove name="Profile"></remove>
      <remove name="AnonymousIdentification"></remove>
</httpmodules>

Flush your HTML as soon as it is generated

<pages buffer="true" enableviewstate="false"></pages>

Turn off Tracing

<configuration>
     <system.web>
          <trace enabled="false"></trace>
     </system.web>
</configuration>

Remove HTTP Headers

This is more of a security thing

<system.web>
    <httpruntime enableversionheader="false"></httpruntime>
</system.web>

<httpprotocol>
 <customheaders>
  <remove name="X-Powered-By"></remove>
 </customheaders>
</httpprotocol>

Uninstall the URL Rewrite module if not required

This saves CPU cycles used to check the server variable for each request.

Go to "Add or Remove Programs" and find "Microsoft URL Rewrite Module" and select uninstall.



European ASP.NET MVC 4 Hosting :: How to Setup Scheduler in ASP.NET MVC 4

clock November 27, 2013 06:02 by author Scott

As always, we try to keep our Scheduler .NET control up-to-date and easy to use. Nowadays it supports all the latest .NET frameworks and IDEs, including ASP.NET 4.5 and Visual Studio 2012.

With regard to all recent updates, your remarks and fixed bugs, we decided to give you further setup instructions. This time we explain how Scheduler .NET setup process can be reduced to only 5 steps that you can cover in less than 5 minutes.

This article represents a new step-by-step guide on how to create a simple yet elegant Google-like calendar/scheduler in ASP.NET MVC3/MVC4 Razor (C#).

Follow the steps described below and you’ll get a nice-looking scheduler in ASP.NET with a rich user interface. It provides the following features:

- Day, week and month views 
- Convenient drag-and-drop
- Highlighting of the current day
- Ajax loading
- Easy data load and save

 

 

Create a New Project

Create a new project in Visual Studio by selecting ASP.NET MVC 3/ MVC4 Web Application from the list. The project template should be empty. The view engine is Razor by default.

We will create a simple scheduler in C#.

Set Up the Database

The next step is to set up a database. Right-click on ‘Your_project_name’ (e.g. SimpleScheduler) ->  Add -> Add ASP.NET Folder -> App_Data -> Add New Item and name it “Sample.mdf”. 

A new database has been created. 

Note: for ASP.NET MVC4 project the folder App_Data is created automatically.

Go to the Server Explorer to create a new Table “Events”. Right-click on the Table folder to add the following query. It creates a table with all necessary fields including primary key and identity column:

CREATE TABLE [dbo].[Events](
  [id] int IDENTITY(1,1) NOT NULL,
  [text] nvarchar(250) NULL,
  [start_date] datetime NOT NULL,
  [end_date] datetime NOT NULL,
  PRIMARY KEY (id)
)

Note: To see the updates, remember to refresh connection in the Server Explorer.

Scheduler Setup via NuGet

Right-click on you project name in the Solution Explorer to select “Manage NuGet Packages…”: 

For quick search type  ‘dhtmlx’ in the input. In a moment you’ll see DHMTLX Scheduler .NET library and the available samples: 

To save your time, install MVC3 Sample first. It contains the basic template of Scheduler .NET calendar control. The template includes a controller with three actions (initialization, data load and save) and view with a calendar.

Thus, the installed sample updates the project with:

- /Controllers/CalendarController.cs  -- a controller that needs updating;
- /Views/Calendar/Index.cshtml   -- a calendar page that requires no changes;
- /Models/CalendarEvent.cs  -- a sample model that can be deleted. 

Create Scheduler Model

The installed MVC3 Sample also contains a sample class model. You don’t need it and can delete it.

To create a new model right-click on the folder Models -> Add New Item. In the new opened window choose LINQ to SQL Classes and name it Sample.dbml. Double click it to open a visual editor and drag the Event table from the Server Explorer to the Editor.

Updating a Controller

As stated above, the controller has been created when you installed MVC3 Sample. It contains action templates for data load and save, working with static data.

Let’s update the methods in the CalendarController.cs to connect the controller with the newly created Model. 

First we need to load data from the Model. 

The default data load before update looks as follows:

public ContentResult Data()
{
    var data = new SchedulerAjaxData(
        new List<CalendarEvent>{
            new CalendarEvent{
                id = 1,
                text = "Sample Event",
                start_date = new DateTime(2012, 09, 03, 6, 00, 00),
                end_date = new DateTime(2012, 09, 03, 8, 00, 00)
            },
            ...
        });
    return (ContentResult)data;
}

Let’s update the DataAction to load data from SampleDataContext:

public ContentResult Data()
{
            var data = new SchedulerAjaxData(new SampleDataContext().Events);
            return (ContentResult)data;
}

Secondly, enable data save. The data save set by default is:

public ContentResult Save(int? id, FormCollection actionValues)
{
    var action = new DataAction(actionValues);             

    try
    {
        var changedEvent = (CalendarEvent)DHXEventsHelper.Bind(typeof(CalendarEvent), actionValues);
        switch (action.Type)
        {
            case DataActionTypes.Insert:
                //do insert
                action.TargetId = changedEvent.id;//assign postoperational id
                break;
            case DataActionTypes.Delete:
                //do delete
                break;
            default:// "update"                         
                //do update
                break;
        }
    }
}

Data save parses the request, contains a switch case for all types of operations and returns operation success. Let’s update it to enable save of actual changes:

public ContentResult Save(int? id, FormCollection actionValues)
{
     var action = new DataAction(actionValues); 

     var changedEvent = (Event)DHXEventsHelper.Bind(typeof(Event), actionValues); 

     var data = new SampleDataContext(); 

     try
     {
          switch (action.Type)
          {
              case DataActionTypes.Insert: // define here your Insert logic
                  data.Events.InsertOnSubmit(changedEvent);                             
                  break;
              case DataActionTypes.Delete: // define here your Delete logic
                  changedEvent = data.Events.SingleOrDefault(ev => ev.id == action.SourceId);
                  data.Events.DeleteOnSubmit(changedEvent);
                  break;
              default:// "update" // define here your Update logic
                  var eventToUpdate = data.Events.SingleOrDefault(ev => ev.id == action.SourceId);
                  DHXEventsHelper.Update(eventToUpdate, changedEvent, new List<string>() { "id" });//update all properties, except for id
                  break;
              }
              data.SubmitChanges();
              action.TargetId = changedEvent.id;
         }
     }
}

We have changed the Model class used in the method. We’ve also added the required methods from LINQ to SQL and a helper that updates all object properties in the data base (except for the id).

Notes.

The initial class model in the action used to be:

public ContentResult Save(int? id, FormCollection actionValues)
        {
            var action = new DataAction(actionValues);

If a new event is added to the data base, an id assigned to the new event in the data base should be returned to the client. It returns TargetId of the object itself.

action.TargetId = changedEvent.id;

This action is implemented after changes are submitted: data.SubmitChanges();

The full code will look like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; 

using DHTMLX.Scheduler;
using DHTMLX.Common;
using DHTMLX.Scheduler.Data;
using SimpleScheduler.Models;
namespace SimpleScheduler.Controllers
{
    public class CalendarController : Controller
    {
        public ActionResult Index()
        {
            var scheduler = new DHXScheduler(this); 

            scheduler.Skin = DHXScheduler.Skins.Terrace;
            scheduler.InitialDate = new DateTime(2012, 09, 03); 

            scheduler.Config.multi_day = true;//render multiday events 

            scheduler.LoadData = true;
            scheduler.EnableDataprocessor = true; 

            return View(scheduler);
        } 

        public ContentResult Data()
        {
            var data = new SchedulerAjaxData(
                    new SampleDataContext().Events
                ); 

            return (ContentResult)data;
        } 

        public ContentResult Save(int? id, FormCollection actionValues)
        {
            var action = new DataAction(actionValues);
            var changedEvent = (Event)DHXEventsHelper.Bind(typeof(Event), actionValues);
            var data = new SampleDataContext(); 

            try
            {
                switch (action.Type)
                {
                    case DataActionTypes.Insert: // define here your Insert logic
                        data.Events.InsertOnSubmit(changedEvent); 

                        break;
                    case DataActionTypes.Delete: // define here your Delete logic
                        changedEvent = data.Events.SingleOrDefault(ev => ev.id == action.SourceId);
                        data.Events.DeleteOnSubmit(changedEvent);
                        break;
                    default:// "update" // define here your Update logic
                        var eventToUpdate = data.Events.SingleOrDefault(ev => ev.id == action.SourceId);
                        DHXEventsHelper.Update(eventToUpdate, changedEvent, new List<string>() { "id" });//update all properties, except for id
                        break;
                }
                data.SubmitChanges();
                action.TargetId = changedEvent.id;
            }
            catch (Exception a)
            {
                action.Type = DataActionTypes.Error;
            }
            return (new AjaxSaveResponse(action));
        }
    }
}

Finally, update the route from ‘Home’ to ‘Calendar’ in Global.asax.cs as follows:

routes.MapRoute(
              "Default", // Route name
              "{controller}/{action}/{id}", // URL with parameters
              new { controller = "Calendar", action = "Index", id = UrlParameter.Optional } // Parameter defaults
          );

Note: ASP.NET MVC4 project creates App_Start directory with configuration files. The controller route is changed to "Calendar" in Route.Config.cs:

routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Calendar", action = "Index", id = UrlParameter.Optional }
            );

That’s it! The scheduler for ASP.NET MVC3/MVC4 Razor is ready to use.



European ASP.NET MVC Hosting :: How to Send Email Using ASP.NET MVC

clock November 12, 2013 11:53 by author Scott

Introduction

Sending email is a very common task in any web application for many purposes. In daily development we need to add some mail functionality to our project to send e-mail to the customer or another in our web site.

Using the code

For sending mail from ASP.NET MVC we use the "System.Net.Mail" namespace. Let's see how to do this.

Open Visual Studio

"File" -> "New" -> "Project..."

Choose Visual C#- Web then select ASP.NET MVC4 Web Application

Add a new Internet Application then click OK

Step 1: Create a new Model Class in the model folder.

The following is the code for the new Model

MailModel.cs

public class MailModel

{
   
 public string From { get; set; }
   
 public string To { get; set; }
   
 public string Subject { get; set; }
   
 public string Body { get; set; }
}

Step 2: Create a New SendMailerController in the Controller folder.

The following is the code for the design of the new Controller.

SendMailerController.cs

using System;

using System.Collections.Generic;
using
 System.Linq;
using
 System.Net.Mail;
using
 System.Web;
using
 System.Web.Mvc; 

namespace SendMail.Controllers

{
   
 public class SendMailerController : Controller
    {
       
 //
       
 // GET: /SendMailer/  
       
 public ActionResult Index()
        {
           
 return View();
        } 
 
        [HttpPost]
       
 public ViewResult Index(SendMail.Models.MailModel _objModelMail)
       {
           
 if (ModelState.IsValid)
            {
               
 MailMessage mail = new MailMessage();
                mail.To.Add(_objModelMail.To);
                mail.From =
 new MailAddress(_objModelMail.From);
                mail.Subject = _objModelMail.Subject;
               
 string Body = _objModelMail.Body;
                mail.Body = Body;
                mail.IsBodyHtml =
 true;
               
 SmtpClient smtp = new SmtpClient();
                smtp.Host =
 "smtp.gmail.com";
                smtp.Port = 587;
                smtp.UseDefaultCredentials =
 false;
                smtp.Credentials =
 new System.Net.NetworkCredential
                ("username",
 "password");// Enter seders User name and password
                smtp.EnableSsl =
 true;
                smtp.Send(mail);
               
 return View("Index", _objModelMail);
            }
           
 else
            {
               
 return View();
            }
        }
    }

}

Index.cshtml

@model SendMail.Models.MailModel
@{
ViewBag.Title =
 "Index";
}
<h2>Index</h2>
<fieldset>
<legend>
Send Email
</legend>
@using (Html.BeginForm())
{
@Html.ValidationSummary()
<
p>From:
 </p>
<p>
@Html.TextBoxFor(m=>m.From)</p>
 <p>To:
 </p>
<p>
@Html.TextBoxFor(m=>m.To)</p>
<p>Subject:
 </p>
<p>
@Html.TextBoxFor(m=>m.Subject)</p>
 <p>Body:
 </p>
<p>
@Html.TextAreaFor(m=>m.Body)</p>
<input
 type ="submit" value ="Send" />
}
  </fieldset>

In the code above we have the following 3 fields:

  • To
  • Subject
  • Message

When the user clicks the "Send" button, the mail will be sent to the specified mail address that you provide in the To TextBox. So add the following code for the [HttpPost] Method for the send button click.

SendMailerController.cs

using System;

using System.Collections.Generic;
using
 System.Linq;
using
 System.Net.Mail;
using
 System.Web;
using
 System.Web.Mvc; 

namespace SendMail.Controllers

{
   
 public class SendMailerController : Controller
    {
       
 //
       
 // GET: /SendMailer/ 
 
       
 public ActionResult Index()
        {
           
 return View();
        } 

        [HttpPost]

       public ViewResult Index(SendMail.Models.MailModel _objModelMail)
        {
           
 if (ModelState.IsValid)
            {
               
 MailMessage mail = new MailMessage();
                mail.To.Add(_objModelMail.To);
                mail.From =
 new MailAddress(_objModelMail.From);
               mail.Subject = _objModelMail.Subject;
               
 string Body = _objModelMail.Body;
                mail.Body = Body;
                mail.IsBodyHtml =
 true;
               
 SmtpClient smtp = new SmtpClient();
                smtp.Host =
 "smtp.gmail.com";
                smtp.Port = 587;
                smtp.UseDefaultCredentials =
 false;
                smtp.Credentials =
 new System.Net.NetworkCredential
                ("username",
 "password");// Enter seders User name and password 
 
                smtp.EnableSsl =
 true;
                smtp.Send(mail);
               
 return View("Index", _objModelMail);
            }
          
 else
            {
               
 return View();
            }
        }
    }

}

Understanding the Code

In the code above we have a:

ViewResult Index(SendMail.Models.MailModel _objModelMail)

user defined method. In this method, we have a parameter of our MailModel object. Now we create a MailMessage object.

MailMessage mail = new MailMessage();

MailMessage is the main class for sending mail, it is in the System.Net.Mail namespace.

The MailMessage class has properties, the important ones are:

  • To
  • From
  • Cc
  • Bcc
  • Subject
  • Body

So we add our data into specified properties.

For sending mail we need a SMTP Server, so in ASP.Net we have the SmtpClient class, we set the SMTP settings using the properties of that class.

SmtpClient smtp = new SmtpClient();

The SMTPClient class has these basic properties:

  • Host
  • Port
  • UseDefaultCredential
  • Credentials
  • EnableSsl
  • Send

smtp.Host = "smtp.gmail.com";
smtp.Port = 587;
smtp.UseDefaultCredentials = false;
smtp.Credentials = new System.Net.NetworkCredential("username", "password");
smtp.EnableSsl = true;

In the code above is:

smtp.Host = "smtp.gmail.com";

That is the SMTP Host address of Gmail, if you want to use any other SMTP host service then please add a different SMTP host protocol, for example for Hotmail it is smtp.live.com.

For example, in:

Smtp.Port=587

587 is the port for Gmail, so for any other service port you need to change the port correspondingly.

smtp.Credentials = new System.Net.NetworkCredential("username""password");

Smtp.Credentials specifies the Network Crendentials of your Gmail id so please add your username and password instead of ("username", "password");

The following is for a secure mail server, so you enable your SSL layer.

smtp.EnableSsl = true;

Smtp.Send sends the mail so please add your MailMesssage object here. Then, based on the properties, your mail will be sent



European ASP.NET MVC 4 Hosting :: Preventing Cross Site Scripting Attacks in ASP.NET MVC 4

clock November 8, 2013 08:14 by author Scott

A website is exposed to various types of attacks and one of the most common types of attack is what is known as Cross Site Scripting (XSS). In a cross site scripting attack, malicious markup and script is entered in the web pages that are viewed by other users. If proper care is not taken to filter this malicious piece of markup, the script gets stored in the system and also rendered on web pages. Depending on the script injected by the hacker it can cause damage ranging from annoying popups to stolen credentials to accessing data stored in cookies. Therefore, it is important for ASP.NET MVC developers to prevent these types of attacks. Luckily, ASP.NET MVC offers a helping hand in safeguarding your websites. This article discusses some of the basics involved in the process.

What is Cross Site Scripting Attack?

In order to understand what a cross site scripting attack is, let's develop a simple ASP.NET MVC website that accepts some user input. Suppose that you are developing a blog engine and users are allowed to leave comments on blog posts. The following figure shows how the comments might be accepted:

As you might have guessed, the user can enter any text in the textbox and the textarea, including HTML markup tags and script fragments! Once the form is submitted the posted data is saved in the database as shown below:

public ActionResult SaveData(FormCollection form)

{
   
BlogEntities1 db = new BlogEntities1();
   
Comment comment = new Comment();
    comment
.UserName = form["username"];
    comment
.UserComment = form["usercomment"];
    comment
.PostedOn = DateTime.Now;
    db
.Comments.Add(comment);
    db
.SaveChanges();
   
return View("Index");
}

As shown above, the form is submitted to the SaveData() action method. The SaveData() method saves the data in a SQL Server database table named Comments. So far so good. Now assume that a use enters the following text in the comments textarea:

<h1>Hello   World!</h1>
<script>
alert('Cross   site scripting attack!');
</script>  

When such a user posts the above content it gets saved in the database. Later when this saved content is rendered on a web page it executes the script!

What the above example illustrates is a very mild version of a cross site scripting attack. Imagine what would happen if a clever hacker loads a malicious script from some different location and stole end user cookies or loaded undesirable content. That is why it is important for you to prevent cross site scripting attacks.

Note: 
By default ASP.NET 4.5 throws an exception if potentially dangerous content is detected in the request. However, you may need to deviate from this default mechanism in certain cases. In certain legitimate cases it is perfectly acceptable for the user to submit markup. For example, a web page where a blog owner enters the content of a blog post should accept HTML tags. In such cases you can skip the default checking performed by ASP.NET. You can either set requestValidationMode in web.config or use the [ValidateInput] attribute on action methods.

Preventing Cross Site Scripting Attacks

Most of the cross site scripting attacks can be prevented if you encode all the user input properly. You need to ensure that strings are encoded properly at two distinct places as far as ASP.NET MVC applications are concerned:

- Views
- Controllers or classes

In order to encode strings in views you can use the Html.Encode() method as shown below:

<%= Html.Encode(c.UserComment) %>

As you can see the view that displays the user comment now encodes the comment using the Html.Encode() method; this way all of the special characters such as <, > and & are encoded properly. For example, once Encode() method is in place the same malicious input by the end user is encoded and then rendered on the page as shown below:

As you can see the script is no longer executed even if the comment saved in the database contains the <script> tag. Instead the HTML markup is encoded and then displayed on the page.

There is also a shortcut to using the Html.Encode(), you can use <%: and %> block instead of <%= and %>. The following code shows how:

<%: c.UserComment %>

The <%: and %> block HTML encodes the string and then emits on the page.

The above code takes care of displaying content on the page by HTML encoding it. Here the encoding happens at the View level but the database still contains the malicious markup and script. Wouldn't it be nice if you HTML encode the content before saving it into the database? You can do so in your controllers or other classes using the Server.HtmlEncode() method.

comment.UserComment   = Server.HtmlEncode(form["usercomment"]);
...
db.SaveChanges();
...

As you can see the HtmlEncode() method of Server object accepts the raw string and returns an HTML encoded version of the same. The database now stores the HTML encoded version of the comments rather than the raw version. If you need to decode the HTML encoded version back you can use Server.HtmlDecode() method.

In addition to the HTML output displayed on a web page, you may also consider encoding attributes and URLs. Encoding attribute values is important if you are dynamically changing them based on user input. For example, you might be accepting a user's website URL and then setting the href attribute of an anchor tag dynamically. In such cases it is better to encode attribute values using the Html.AttributeEncode() method. On the same lines you can encode URL values using the  Url.Encode() method.

Using AntiXssEncoder to Encode Strings

The techniques to prevent cross site scripting attacks that we covered so far are traditional techniques that have roots in the core ASP.NET framework. In some cases where security is extremely important you may want to use an even more secure technique of encoding. Luckily, System.Web.Security.AntiXss namespace provides a class - AntiXssEncoder - that can be used to encode HTML content and attribute values. The major difference between the default encoder used by ASP.NET and the AntiXssEncoder class is that the former uses a blacklist of a set of prohibited characters whereas the later uses a whitelist of a set of allowed characters making it more secure.

The following code shows how AntiXssEncoder class can be used in a controller:

public   ActionResult SaveData(FormCollection form)
{
     BlogEntities1 db = new BlogEntities1();
     Comment comment = new Comment();
 comment.UserName   = AntiXssEncoder.HtmlEncode(form["username"], false);   comment.UserComment =   AntiXssEncoder.HtmlEncode(form["usercomment"], false);    comment.PostedOn =   DateTime.Now;
     db.Comments.Add(comment);
     db.SaveChanges();
     return View("Index");
}

As you can see, AntiXssEncoder class has static methods such as HtmlEncode() and HtmlAttributeEncode() that can be used to encode form data.

By default, methods such as Server.HtmlEncode() use the HttpEncoder class for performing the encoding. You can override this default with the AntiXssEncoder class by adding the following markup in the web.config file:

<httpRuntime encoderType="System.Web.Security.AntiXss.AntiXssEncoder" />

As shown above, the encoderType attribute of the <httpRuntime> tag is set to System.Web.Security.AntiXss.AntiXssEncoder so that the default encoder class is now set to AntiXssEncoder.



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