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 :: Securely Verify and Validate Image Uploads in ASP.NET and ASP.NET MVC

clock September 17, 2013 10:01 by author Ronny

One of the more interesting things had to do as part of building XAPFest was handle bulk image uploads for screenshots for applications and user / app icons. Most of the challenges here are UI-centric ones (which resolved using jQuery File-Upload) but the one security challenge that remains outstanding is ensuring that the content uploaded to your servers is safe for your users to consume.

Fortunately this problem isn't too hard to solve and doesn't require much code in C#.

Flawed Approaches to Verifying Image Uploads

Here's what usually see when developers try to allow only web-friendly image uploads:

  1. File extension validation (i.e. only allow images with .png, .jp[e]g, and .gif to be uploaded) and
  2. MIME type validation.


So what's wrong with these techniques? The issue is that both the file extension and MIME type can be spoofed, so there's no guarantee that a determined hacker might not take a js. file, slap an extra .png extension somewhere in the mix and spoof the MIME type.

Stronger Approach to Verifying Image Uploads: GDI+ Format Checking

Every file format has to follow a particular codec / byte order convention in order to be read and executed by software. This is as true for proprietary formats like .pptx as it is for .png and .gif.

You can use these codecs to your advantage and quickly tell if a file is really what it says it is - you quickly check the contents of the file against the supported formats codecs to see if the content fits into any of those specifications.

Luckily GDI+ (System.Drawing.Imaging), the graphics engine which powers Windows, has some super-simple functions we can use to perform this validation. Here's a bit of source you can use to validate a file against PNG, JPEG, and GIF formats:

using System.Drawing.Imaging;
using System.IO;
using System.Drawing;
namespace XAPFest.Providers.Security
{
    ///
    /// Utility class used to validate the contents of uploaded files  
    ///
    public static class FileUploadValidator  
    {    
     public static bool FileIsWebFriendlyImage(Stream stream)   
     {
            try
            {
                //Read an image from the stream...
                var i = Image.FromStream(stream);
                 //Move the pointer back to the beginning of the stream
                stream.Seek(0, SeekOrigin.Begin);
                 if (ImageFormat.Jpeg.Equals(i.RawFormat))
                    return true;
                return ImageFormat.Png.Equals(i.RawFormat)|| ImageFormat.Gif.Equals(i.RawFormat);
            }
            catch
            {
                return false;
            }
        }
     }
}

All this code does is read the Stream object returned for each posted file into an Image object, and then verifies that the Image supports one of three supported codecs. This source code has not been tested by security experts, so use it at your own risk. If you have any questions about how this code works or want to learn more, please drop me a line in the comments below or on Twitter.

How Do Make Sure Files Are below [X] Filesize

Since had this source code lying around anyway, We thought we would share it: 

Super-simple, like we said, but it gets the job done. Express the maximum allowable size as a long and compare it against the length of the stream

public static bool FileIsWebFriendlyImage(Stream stream, long size)
        {
            return stream.Length <= size && FileIsWebFriendlyImage(stream);
        }
    }
The other important catch to note here is that move the Stream's pointer back to the front of the stream, so it can be read again by the caller which passed the reference to this function.



European ASP.NET MVC 4 Hosting - Amsterdam :: Asynchronous Controllers in ASP.NET MVC 4

clock September 6, 2013 12:01 by author Scott

One of the most important features of ASP.NET MVC 4 is the introduction of the new ASP.NET Web API, which simplifies REST programming with a strongly typed HTTP object model. In addition, ASP.NET MVC 4 takes advantage of the new asynchronous programming model introduced with .NET Framework 4.5 to allow developers to write asynchronous action methods. It is important to understand the advantages and disadvantages of the new asynchronous methods to use them whenever they will provide a benefit.

(ASP.NET MVC 4 also includes many enhancements focused on mobile development, such as jQuery Mobile support and selecting views based on which mobile browser makes requests. If you work with previous ASP.NET MVC versions and you target multiple mobile devices, the new display modes are worth moving to ASP.NET MVC 4. In addition, the bundling and minification framework makes it simpler to reduce HTTP requests for each page without having to use third-party tools.)

Asynchronous controllers ASP.NET MVC 4

Asynchronous execution is the future of Windows development : it has been largely demonstrated during the //Build conference two weeks ago.

In previous versions of ASP.NET MVC it was possible to create asynchronous controllers by inheriting the AsyncController class and using some conventions :

- MyActionAsync : method that returns void and launches an asynchronous process
- MyActionCompleted : method that returns an ActionResult (the result of the MVC action “MyAction”, in this case)

To allow the MVC engine to manage asynchronous operations and pass the result to the view engine, developers had to use the propery AsyncManager of the AsyncController. The “completed” method parameters was passed by the MVC engine through this object.

For example, the controller that is defined bellow allows to get a Json-serialized list of movies – asynchronously – from an OData service :

public class MoviesController : AsyncController
{
    public ActionResult Index()
    {
        return View();
    } 

    public void GetJsonMoviesAsync(int? page)
    {
        const int pageSize = 20;
        int skip = pageSize * ((page ?? 1) - 1);
        string url = string.Format("http://odata.netflix.com/[…]&$skip={0}&$top={1}",
            skip, pageSize); 

        //the asynchronous operation is declared
        AsyncManager.OutstandingOperations.Increment(); 

        var webClient = new WebClient();
        webClient.DownloadStringCompleted += OnWebClientDownloadStringCompleted;
        webClient.DownloadStringAsync(new Uri(url));//the asynchronous process is launched
    } 

    private void OnWebClientDownloadStringCompleted(object sender,
        DownloadStringCompletedEventArgs e)
    {
        //the asynchronous process ends
        //"movies" result is added to the parameters of the AsyncManager
        //NB : it's the name of the parameter that is take by the
        //GetJsonMoviesCompleted method
        List<Movie> movies = null;
        if (AsyncManager.Parameters.ContainsKey("movies"))
        {
            movies = (List<Movie>)AsyncManager.Parameters["movies"];
            movies.Clear();
        }
        else
        {
            movies = new List<Movie>();
            AsyncManager.Parameters["movies"] = movies;
        } 

        movies.AddRange(Movie.FromXml(e.Result)); 

        //the ends of the asynchronous operation (launches the call of "Action"Completed)
        AsyncManager.OutstandingOperations.Decrement();
    } 

    public ActionResult GetJsonMoviesCompleted(List<Movie> movies)
    {
        //on retourne le résultat Json
        return Json(movies, JsonRequestBehavior.AllowGet);
    }
}

It’s not really complicated to create an asynchronous controller but ASP.NET MVC 4 and C# 5 with the new async and await keywords will make it easier !

public class MoviesController : AsyncController
{
    public ActionResult Index()
    {
        return View();
    } 

    public async Task<ActionResult> GetJsonMovies(int? page)
    {
        const int pageSize = 20;
        int skip = pageSize * ((page ?? 1) - 1);
        string.Format("http://odata.netflix.com/[…]&$skip={0}&$top={1}",
                    skip, pageSize); 

        var webClient = new WebClient();
        string xmlResult = await webClient.DownloadStringTaskAsync(url);
        return Json(Movie.FromXml(xmlResult), JsonRequestBehavior.AllowGet);
    }
}

As you can see in the previous code snippet, in ASP.NET MVC 4 you always should inherits from AsyncController but there is no more naming conventions, no more Async/Completed methods, no more AsyncManager and the action returns a Task instead of an ActionResult !

 



European ASP.NET MVC 4 Hosting - Amsterdam :: What is PRG and Using PRG on MVC 4

clock June 18, 2013 06:55 by author Scott

Hellooo….. Today post I will talk about what is PRG in ASP.NET MVC 4 and how to use it. Before we start, the question is what is PRG?

What is the PRG Pattern ?

  • PRG stands for "Post/Redirect/Get"
  • Instead of returning an HTML page directly,
  • The POST operation returns a redirection command (using the HTTP 303 response code (sometimes 302)
  • together with the HTTP "Location" response header),
  • Instructing the browser to load a different page using an HTTP GET request
  • The result page can then safely be bookmarked or reloaded without unexpected side effects

How to Explain this by using an Example ?

  • Here I'm going to use User Registration function as an example
  • If the Registration attempt is Successful, the user should be redirected to his Home page
  • Otherwise they should be redirected back to the Registration page

Image 1 : Shows Action Methods Interaction When do Registration

AccountController.cs        

Code for the Register Action Method (Get) for Displaying Register View is as below

        /// <summary>
        /// for displaying Register View
        /// </summary>
        [HttpGet]
        [AllowAnonymous]
        public ActionResult Register()
        {
            return View();
              }

Image 2 : Register View

Code for the Register Action Method (Post) for Processing the Registration and Shows Register Page again is as below

        /// <summary>
        /// for Registering the User
        /// </summary>
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Register(RegisterModel model)
        {
          if (ModelState.IsValid)
          {
            // Attempt to register the user
            try
             {
               WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
               WebSecurity.Login(model.UserName, model.Password);
               ViewBag.Message = "Successfully Registered!";
               return View(model);//PRG has not been Maintained
             }
              catch (MembershipCreateUserException e)
             {
                 ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
             }
          }
            // If we got this far, something failed, redisplay form
            return View(model);
        }

Image 3 : New user has been Created



- At this point If you try to Refresh (F5) or Reload the Page,You'll see below mentioned kind of Security Alert Message Box

Image 4 : Register form with "Confirm Form Resubmission" Message Box



- After that If you try to press "Continue" Button, You'll see below mentioned Run time exception
- But for another situation this may be Data Duplication issue etc.

Image 5 : Run time Exception

How to Get Rid Of this Issue ?

  • You have to maintain PRG Pattern with your Return type, After finishing the Successful Registration
  • To properly perform PRG you must return a redirecting ViewResult from your Action
  • Such as RedirectToAction, otherwise you'll get the dialog box pictured above (i.e. Image 4)

Code for the Properly Perform PRG Pattern is Maintaining Register Action Method is as below

    /// <summary>
    /// for Registering the User
    /// </summary>
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public ActionResult Register(RegisterModel model)
     {
      if (ModelState.IsValid)
      {
       // Attempt to register the user
       try
       {
         WebSecurity.CreateUserAndAccount(model.UserName, model.Password);
         WebSecurity.Login(model.UserName, model.Password);
         ViewBag.Message = "Successfully Registered!";
         return RedirectToAction("Index""Home");//PRG has been Maintained
        }
        catch (MembershipCreateUserException e)
        {
          ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
        }
      }
       // If we got this far, something failed, redisplay form
       return View(model);
     }

Image 6 : Home page

DONE!!



European ASP.NET MVC 4 Hosting - Amsterdam :: Revisiting IBundleTransform ASP.NET 4.5 and MVC 4

clock May 13, 2013 10:26 by author Scott

Web optimization frameworks include two defaults transform type JsMinify and CssMinify which is used by ScriptBundle and StyleBundle respectively. However we can create our own custom transform type to processe references as per our need. To create custom transform type, we need to create class which implements IBundleTransform interface.

IBundleTransform interface define a method named Process which process bundle response. In developer preview version, Process method had only one parameter of type BundleResponse, however onwards RC release, Process method introduced one more parameter of type BundleContext. In this post, we will see how we can utilize this additional parameter while creating our custom transform type.

BundleContext

As name suggest, with BundleContext, we can get information about bundles which could include existing bundle information, bundle url, HTTP context for bundle, etc. Following is the list of all property of BundleContext.

- BundleContext.BundleCollection : We can get collection of all bundles including default and custom bundle in application through this property.

- BundleContext.BundleVirtualPath : This property expose virtual bundle url i.e. ~/bundles/MyBundle.

- BundleContext.HttpContext : This property is type of HttpContextBase, and we can have access of HTTP context through this property. This is very much useful property when we are creating transform type which generate dynamic response. For e.g. we can access query string parameter passed to bundle url (~/bundles/MyBundle?id=123) through this property (context.HttpContext.Request.QueryString["id"]) and we can use it to create dynamic bundle response.

- BundleContext.UseServerCache : Default value of this property is true. It means only first request to bundle url will be intercepted by transform types and once response is generated it will be stored in server cache and further request to bundle url will be served from server cache without processing it. This will help to reduce bundle processing time and to increase performance. If we set BundleContext.UseServerCache to false then all request will be processed by transform type this is only necessary when bundle url are generating dynamic response. See detailed walkthrough later in this post showing how to use this property in accordance with BundleResponse.Cacheability.

- BundleContext.EnableInstrumentation : Default value of this property is false. This is used for tracing and analysis purpose. We can check value of this property and can write tracing code accordingly. We can also set true to this property to enable instrumentation for further lifecycle of Web optimization frameworks for current bundle request.

BundleResponse

BundleResponse is used to retrieve list of files included in bundle so we can process it and generate response for bundle. As BundleResponse is used to generate response of bundles, it needs to take care of two primary properties of generated response. One is response content type and another one is HTTP Cache-Control header. So BundleResponse also expose properties for the same. Following is the list of all properties in BundleResponse class.

- BundleResponse.Files : This is IEnumerable collection of files which is included in bundle. We can iterate through this collection and process file content to generate bundle response.

- BundleResponse.ContentType : Through this property, we can set content type for bundle so that browser can render it appropriately. Default content type "text/html".

- BundleResponse.Cacheability : We can use this property to set Cache-Control HTTP header of bundled response. Default value of this property is Public.

- BundleResponse.Content : Anything which we set as a value of this property, that content will be sent back to browser as a response of bundle.

Following is the complete code which shows how to create custom transform type and how we can use it with bundling.

public class CustomTransformType : IBundleTransform
{
    public void Process(BundleContext context, BundleResponse response)
    {
        string strBundleResponse = string.Empty;
        foreach (FileInfo file in response.Files)
        {
            // PROCESS FILE CONTENT
        }
        response.Content = strBundleResponse;
    }


Bundle myBundle = new Bundle("~/bundles/MyBundle", new CustomTransformType());
myBundle.Include("~/path/to/file");
bundles.Add(myBundle);

Bundle and truly dynamic response

As we noted earlier, we can set BundleContext.UseServerCache to false in order to process all bundle request and generate dynamic response. Let try to simulate this by small walkthrough and see it works or we need to take care any additional parameter.

public void Process(BundleContext context, BundleResponse response)

{
    context.UseServerCache = false;
    response.Content = DateTime.Now.ToString();
}


We are returning current date time with UseServerCache set to false. Now try to hit bundle url multiple times by pressing F5. Oops… it seems it has processed bundle response only first time. Let dig more into this, open another browser and hit same url… ahmm it seems it has processed bundle response one more time… again press F5 multiple times…bad luck

As we can see, it seems (read again it seems) it is processing bundle response only first time for separate client (is it really? nop). Nop this is not the case. In fact this is how client deals with it due to HTTP cache control header. Confused? See response header of bundle url to get more information.

As we noted earlier default value of BundleResponse.Cacheability is Public. So even if we have set BundleContext.UseServerCache to false then also due to Expires response header and Public Cache-Control header client is not sending request back to server. So in this case we need to also set BundleResponse.Cacheability to NoCache. We can also set it to Private but in some client we need to press Ctrl + F5 to refresh bundle response.

public void Process(BundleContext context, BundleResponse response)
{
    context.UseServerCache = false;
    response.Cacheability = HttpCacheability.NoCache;
    response.Content = DateTime.Now.ToString();
}

After setting BundleResponse.Cacheability to NoCache try to refresh bundle url again now it is re generating bundle response on each request.



European ASP.NET MVC 4 Hosting - Amsterdam :: Using MySql 5 as Membership Backend for ASP.NET 4.5 MVC 4 Application

clock May 1, 2013 09:18 by author Scott

Oracle provide MySql ASP.Net web providers through NuGet – search for MySql.Web. Using the MySql providers you can easily use MySql as your membership/profile/role backend for an ASP.Net application.

I am going to demonstrate using it as the membership provider for an MVC 4 application using Razor but the steps are almost identical for the ASPX views.

Web.config for MySql Membership Provider

Use the following configuration in your web.config file:

1              <membership defaultProvider="MySqlMembershipProvider">
2              <providers>
3              <clear />
4              <add name="MySqlMembershipProvider" type="MySql.Web.Security.MySQLMembershipProvider, MySql.Web, Version=6.5.4.0, PublicKeyToken=c5687fc88969c44d"
5              autogenerateschema="true"
6              connectionStringName="*NAME_OF_YOUR_CONN_STRING*"
7              enablePasswordRetrieval="false"
8              enablePasswordReset="true"
9              requiresQuestionAndAnswer="false"
10           requiresUniqueEmail="false"
11           passwordFormat="Hashed"
12           maxInvalidPasswordAttempts="5"
13           minRequiredPasswordLength="6"
14           minRequiredNonalphanumericCharacters="0"
15           passwordAttemptWindow="10"
16           passwordStrengthRegularExpression=""
17           applicationName="/" />
18           </providers>
19           </membership>

Obviously you also need to configure a valid MySql connection string, create a MySql schema, change any other security settings you want and put the name of your connection string into the provider configuration but your on your own doing that.

Create Tables

Once you have the initial setup done open the ASP.Net configuration website (VS2012: Project menu -> ASP.NET Configuration – at the bottom of the menu) and create a user in the security tab. Doing this will create the database structure and a new user providing you have set the configuration up correctly.

Unbreak the MVC 4 AccountController

This is a simple fix for getting MySql up and running. Basically we just rollback the AccountController to use the old style MembershipProvider which is supported by the MySql MembershipProvider.

  1. Delete the MVC 4 AccountController, AccountModels, Account view folder and _LoginPartial shared view
  2. Create a new MVC 3 web application
  3. Copy the MVC 3 AccountController, AccountModels, Account view folder and _LogOnPartial shared view into your MVC 4 application
  4. Replace @Html.Partial(“_LoginPartial”) in the shared _Layout view with @Html.Partial(“_LogOnPartial”)

This won’t support OAuth authentication but will get your MySql Membership provider up and running with ASP.Net 4.5 and MVC 4.

Raw SQL for MySql Membership Tables

If you want to directly create the membership data structure without using the ASP.NET configuration tools use the following SQL as a base and modify SCHEMA_NAME and collation to be what you require.

1              -- -----------------------------------------------------
2              -- Table `SCHEMA_NAME`.`my_aspnet_applications`
3              -- -----------------------------------------------------
4              CREATE  TABLE IF NOT EXISTS `SCHEMA_NAME`.`my_aspnet_applications` (
5                `id` INT(11) NOT NULL AUTO_INCREMENT ,
6                `name` VARCHAR(256) NULL DEFAULT NULL ,
7                `description` VARCHAR(256) NULL DEFAULT NULL ,
8                PRIMARY KEY (`id`) )
9              ENGINE = InnoDB
10           AUTO_INCREMENT = 2
11           DEFAULT CHARACTER SET = latin1
12           COLLATE = latin1_swedish_ci;
13           -- -----------------------------------------------------
14           -- Table `SCHEMA_NAME`.`my_aspnet_membership`
15           -- -----------------------------------------------------
16           CREATE  TABLE IF NOT EXISTS `SCHEMA_NAME`.`my_aspnet_membership` (
17             `userId` INT(11) NOT NULL DEFAULT '0' ,
18             `Email` VARCHAR(128) NULL DEFAULT NULL ,
19             `Comment` VARCHAR(255) NULL DEFAULT NULL ,
20             `Password` VARCHAR(128) NOT NULL ,
21             `PasswordKey` CHAR(32) NULL DEFAULT NULL ,
22             `PasswordFormat` TINYINT(4) NULL DEFAULT NULL ,
23             `PasswordQuestion` VARCHAR(255) NULL DEFAULT NULL ,
24             `PasswordAnswer` VARCHAR(255) NULL DEFAULT NULL ,
25             `IsApproved` TINYINT(1) NULL DEFAULT NULL ,
26             `LastActivityDate` DATETIME NULL DEFAULT NULL ,
27             `LastLoginDate` DATETIME NULL DEFAULT NULL ,
28             `LastPasswordChangedDate` DATETIME NULL DEFAULT NULL ,
29             `CreationDate` DATETIME NULL DEFAULT NULL ,
30             `IsLockedOut` TINYINT(1) NULL DEFAULT NULL ,
31             `LastLockedOutDate` DATETIME NULL DEFAULT NULL ,
32             `FailedPasswordAttemptCount` INT(10) UNSIGNED NULL DEFAULT NULL ,
33             `FailedPasswordAttemptWindowStart` DATETIME NULL DEFAULT NULL ,
34             `FailedPasswordAnswerAttemptCount` INT(10) UNSIGNED NULL DEFAULT NULL ,
35             `FailedPasswordAnswerAttemptWindowStart` DATETIME NULL DEFAULT NULL ,
36             PRIMARY KEY (`userId`) )
37           ENGINE = InnoDB
38           DEFAULT CHARACTER SET = latin1
39           COLLATE = latin1_swedish_ci
40           COMMENT = '2';
41           -- -----------------------------------------------------
42           -- Table `SCHEMA_NAME`.`my_aspnet_profiles`
43           -- -----------------------------------------------------
44           CREATE  TABLE IF NOT EXISTS `SCHEMA_NAME`.`my_aspnet_profiles` (
45             `userId` INT(11) NOT NULL ,
46             `valueindex` LONGTEXT NULL DEFAULT NULL ,
47             `stringdata` LONGTEXT NULL DEFAULT NULL ,
48             `binarydata` LONGBLOB NULL DEFAULT NULL ,
49             `lastUpdatedDate` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ,
50             PRIMARY KEY (`userId`) )
51           ENGINE = InnoDB
52           DEFAULT CHARACTER SET = latin1
53           COLLATE = latin1_swedish_ci;
54           -- -----------------------------------------------------
55           -- Table `SCHEMA_NAME`.`my_aspnet_roles`
56           -- -----------------------------------------------------
57           CREATE  TABLE IF NOT EXISTS `SCHEMA_NAME`.`my_aspnet_roles` (
58             `id` INT(11) NOT NULL AUTO_INCREMENT ,
59             `applicationId` INT(11) NOT NULL ,
60            `name` VARCHAR(255) NOT NULL ,
61             PRIMARY KEY (`id`) )
62           ENGINE = InnoDB
63           DEFAULT CHARACTER SET = latin1
64           COLLATE = latin1_swedish_ci
65           ROW_FORMAT = DYNAMIC;
66           -- -----------------------------------------------------
67           -- Table `SCHEMA_NAME`.`my_aspnet_schemaversion`
68           -- -----------------------------------------------------
69           CREATE  TABLE IF NOT EXISTS `SCHEMA_NAME`.`my_aspnet_schemaversion` (
70             `version` INT(11) NULL DEFAULT NULL )
71           ENGINE = InnoDB
72           DEFAULT CHARACTER SET = latin1
73           COLLATE = latin1_swedish_ci;
74           -- -----------------------------------------------------
75           -- Table `SCHEMA_NAME`.`my_aspnet_sessioncleanup`
76           -- -----------------------------------------------------
77           CREATE  TABLE IF NOT EXISTS `SCHEMA_NAME`.`my_aspnet_sessioncleanup` (
78             `LastRun` DATETIME NOT NULL ,
79             `IntervalMinutes` INT(11) NOT NULL )
80           ENGINE = InnoDB
81           DEFAULT CHARACTER SET = latin1
82           COLLATE = latin1_swedish_ci;
83           -- -----------------------------------------------------
84           -- Table `SCHEMA_NAME`.`my_aspnet_sessions`
85           -- -----------------------------------------------------
86           CREATE  TABLE IF NOT EXISTS `SCHEMA_NAME`.`my_aspnet_sessions` (
87             `SessionId` VARCHAR(255) NOT NULL ,
88             `ApplicationId` INT(11) NOT NULL ,
89             `Created` DATETIME NOT NULL ,
90             `Expires` DATETIME NOT NULL ,
91            `LockDate` DATETIME NOT NULL ,
92             `LockId` INT(11) NOT NULL ,
93             `Timeout` INT(11) NOT NULL ,
94             `Locked` TINYINT(1) NOT NULL ,
95             `SessionItems` LONGBLOB NULL DEFAULT NULL ,
96             `Flags` INT(11) NOT NULL ,
97             PRIMARY KEY (`SessionId`, `ApplicationId`) )
98           ENGINE = InnoDB
99           DEFAULT CHARACTER SET = latin1
100         COLLATE = latin1_swedish_ci;
101         -- -----------------------------------------------------
102         -- Table `SCHEMA_NAME`.`my_aspnet_users`
103         -- -----------------------------------------------------
104         CREATE  TABLE IF NOT EXISTS `SCHEMA_NAME`.`my_aspnet_users` (
105           `id` INT(11) NOT NULL AUTO_INCREMENT ,
106           `applicationId` INT(11) NOT NULL ,
107          `name` VARCHAR(256) NOT NULL ,
108           `isAnonymous` TINYINT(1) NOT NULL DEFAULT '1' ,
109           `lastActivityDate` DATETIME NULL DEFAULT NULL ,
110           PRIMARY KEY (`id`) )
111         ENGINE = InnoDB
112         AUTO_INCREMENT = 2
113         DEFAULT CHARACTER SET = latin1
114         COLLATE = latin1_swedish_ci;
115         -- -----------------------------------------------------
116         -- Table `SCHEMA_NAME`.`my_aspnet_usersinroles`
117         -- -----------------------------------------------------
118         CREATE  TABLE IF NOT EXISTS `SCHEMA_NAME`.`my_aspnet_usersinroles` (
119           `userId` INT(11) NOT NULL DEFAULT '0' ,
120           `roleId` INT(11) NOT NULL DEFAULT '0' ,
121           PRIMARY KEY (`userId`, `roleId`) )
122         ENGINE = InnoDB
123         DEFAULT CHARACTER SET = latin1
124         COLLATE = latin1_swedish_ci
125         ROW_FORMAT = DYNAMIC;

 



European ASP.NET MVC 4 Hosting - Amsterdam :: Using Dependency Injection with AutoFac in the ASP.NET Web API

clock March 26, 2013 11:07 by author Scott

This post is going to tell you exactly how to use the same in DI container in your MVC Controllers and your Web Api controllers, so you can share the same set of services. Of course after you have seen this, it will be immediately clear how to use different containers in both, if you like to do so. The example will be implemented using the Repository pattern, AutoFac, Entity Framework 5 and the EF powertools.

Setting things up

Fire up Visual Studio 2012 RC and start a new MVC 4 empty project:

Call it anything you like. After Visual Studio is done creating your project layout, we’re going to implement the Repository pattern. In a production application you’ll probably want to split your solution into multiple projects, but for now we’re going to do everything in one. First, make sure you have installed the Entity Framework powertools using the Visual Studio extension manager:

After this, use NuGet to add EF 5.0 support to your MVC project:

If you don’t see the PreRelease version, make sure to set the combobox in the top of the screen to “Include Prerelease”. There is one last thing left to do to complete the setup and that’s adding a DI container to our project. You can of course use anything you like, but I’m going with AutoFac. If you want to find out why you should use AutoFac too you can read this. In short, AutoFac combines a full feature set with great performance, is easy to configure and has great support. You can use NuGet to add AutoFac to your project:

Make sure you get the “MVC 4 RC Integration” package. This will provide you with easy integration and will also install the basic AutoFac DLL’s. That’s it, now we’ve got everything we need (assuming you already have a database).

Creating the repository

Create the following interface:

01           using System;
02           using System.Collections.Generic;
03           using System.Linq;
04           using System.Text;
05           using System.Threading.Tasks;
06          
07           namespace Adventureworks.DAL.Repository
08           {
09               public interface IRepository<in TKey,TEntity>    {
10                   void Add(TEntity entity);
11                   void Delete(TEntity entity);
12                   void Update(TEntity entity);
13                   IEnumerable<TEntity> GetAll();
14                   TEntity GetById(TKey id);
15               }
16           }

Now let’s implement it using EF 5.0 and the powertools. I really like the Code only feature of the new Entity Framework release, totally removing the .edmx file. But until recently you couldn’t reverse engineer code only from an existing database. Luckily the EF powertools fix this for us. Right click your Web Project and go the “Entity Framework” menu and select “Reverse engineer Code first”:

Select the database of your choosing and let the tooling do it’s magical stuff. After all is said and done, you will have Entity classes, a DBContext and a file containing the code for configuring the DbContext. Create a class which implements the IRepository interface like this:

1              using System;
2              using System.Collections.Generic;
3              using System.Data.Entity.Infrastructure;
4              using System.Linq;
5              using System.Text;
6              using System.Threading.Tasks;
7              using Adventureworks.Domain;
8             
9              namespace Adventureworks.DAL.Repository.EntityFramework
10           {
11               public class EntityFrameworkProductRepository : IRepository<int,Product>
12               {
13          
14                   public void Add(Product entity)
15                   {
16                       PerformAction((context) =>
17                           {
18                               context.Product.Add(entity);
19                               context.SaveChanges();
20                           });
21          
22                   }
23          
24                   public void Delete(Product entity)
25                   {
26                       PerformAction((context) =>
27                           {
28                               context.Product.Attach(entity);
29                               context.Product.Remove(entity);
30                               context.SaveChanges();
31                           });
32                   }
33          
34                   public void Update(Product entity)
35                   {
36                       PerformAction((context) =>
37                           {
38                              context.Product.Attach(entity);
39                              context.Entry(entity).State = System.Data.EntityState.Modified;
40                              context.SaveChanges();
41                           });
42                   }
43          
44                   public IEnumerable<Product> GetAll()
45                   {
46                       return Read((context) =>
47                           {
48                               return context.Product.AsNoTracking().ToArray();
49                           });
50          
51                   }
52          
53                   public Product GetById(int id)
54                   {
55                       return Read((context) =>
56                           {
57                               Product p = context.Product.AsNoTracking().SingleOrDefault((pr) => pr.ProductID ==
id);
58                               if (p == null)
59                               {
60                                   throw new ArgumentException("Invalid id: " + id);
61                               }
62                               return p;
63                           });
64                   }
65          
66                   private void PerformAction(Action<AdventureWorks2012Entities> toPerform)
67                   {
68                       using (AdventureWorks2012Entities ents = new AdventureWorks2012Entities())
69                       {
70                           ConfigureDbContext(ents);
71                           toPerform(ents);
72                       }
73                   }
74          
75                   private T Read<T>(Func<AdventureWorks2012Entities, T> toPerform)
76                   {
77                       using (AdventureWorks2012Entities ents = new AdventureWorks2012Entities())
78                       {
79                           ConfigureDbContext(ents);
80                           return toPerform(ents);
81                       }
82                   }
83          
84                   private void ConfigureDbContext(AdventureWorks2012Entities ents)
85                   {
86                       ents.Configuration.AutoDetectChangesEnabled = false;
87                       ents.Configuration.LazyLoadingEnabled = false;
88                       ents.Configuration.ProxyCreationEnabled = false;
89                       ents.Configuration.ValidateOnSaveEnabled = true;
90          
91                   }
92          
93               }
94           }

There are a couple of things going on here. Starting on line 66 I’ve created three helper methods which set up the DbContext correctly and dispose it. These methods are used by calling them and supplying a Lambda which uses the DbContext. Let’s take a look at the GetAll method on line 44. You can see that I don’t use change tracking. Change tracking is something you get as a bonus when using the EF, I like to abstract this away with my Repository implementation. It’s also completely useless in a web application since all state is gone after each request and it has a lot of overhead. “But how do you update if you don’t have any change tracking?” you ask?, well take a look at the Update method on line 34. Just set the whole entity as “Modified” and the EF will perform an update for you.

Creating a Web API Controller

Now let’s create a Web API controller to perform some CRUD functionality:

Implement it like this:

1              using System;
2              using System.Collections.Generic;
3              using System.Linq;
4              using System.Net;
5              using System.Net.Http;
6              using System.Web.Http;
7              using Adventureworks.DAL.Repository;
8              using Adventureworks.Domain;
9             
10           namespace Adventureworks.Web.Controllers
11           {
12               public class ProductController : ApiController
13               {
14          
15                   private IRepository<int, Product> _productRepository;
16          
17                   public ProductController(IRepository<int,Product> repository)
18                   {
19                       _productRepository = repository;
20                   }
21          
22                   public IEnumerable<Product> Get()
23                   {
24                       return _productRepository.GetAll();
25                   }
26          
27                   public Product Get(int id)
28                   {
29                       try
30                       {
31                           return _productRepository.GetById(id);
32                       }
33                       catch (ArgumentException ex)
34                       {
35                           throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound){ Content = new StringContent(ex.Message)});
36                       }
37                   }
38          
39                   // POST api/product
40                   public HttpResponseMessage Post(Product product)
41                   {
42                      ValidateProduct();
43                      _productRepository.Add(product);
44                      return new HttpResponseMessage(HttpStatusCode.Created) { Content = new StringContent(Url.Route("DefaultApi",
45                          new{controller="Product",id=product.ProductID}))};
46                   }
47          
48                   // PUT api/product/5
49                   public HttpResponseMessage Put(Product product)
50                   {
51                       ValidateProduct();
52                       _productRepository.Update(product);
53                       return new HttpResponseMessage(HttpStatusCode.NoContent);
54                   }
55          
56                   // DELETE api/product/5
57                   public HttpResponseMessage Delete(Product product)
58                   {
59                       _productRepository.Delete(product);
60                       return new HttpResponseMessage(HttpStatusCode.NoContent);
61                   }
62          
63                   private void ValidateProduct()
64                   {
65                       if (!ModelState.IsValid)
66                       {
67                           throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest));
68                       }
69                   }
70               }
71           }

Let’s go to line 65 first. This is a helper method which uses the built in Model Binding feature to validate the incoming product. This means that you can just decorate your Product class with attributes or implement IValidatable object to implement data validation. Keeping up with the spirit of rest, this method will generate a BadRequest statuscode when the incoming product is invalid. Now jump up to the constructor. The controller only works with an IRepository interface to perform the crud functionality, it never knows anything about the Entity Framework. This is the key advantage of DI, as we can now mock the repository and unittest our controller. Now jump to line 42; The Post method. A post in REST means an insert. It’s also in the spirit of REST that you use the HTTP statuscodes to signal what’s going on. When you create new content, you should provide the caller with an url to the new content. Similar to the Post method, you can see that the other methods also use statuscodes to indicate if everything went well or not.

Wiring everything up

Last thing left to do is to configure our container and integrate it with MVC. Here’s my Global.asax:

1              using System;
2              using System.Collections.Generic;
3              using System.Linq;
4              using System.Web;
5              using System.Web.Http;
6              using System.Web.Mvc;
7              using System.Web.Routing;
8              using Adventureworks.DAL.Repository.EntityFramework;
9              using Adventureworks.Web.Services;
10           using Autofac;
11           using Autofac.Integration.Mvc;
12           using Autofac.Integration.WebApi;
13          
14           namespace Adventureworks.Web
15           {
16               // Note: For instructions on enabling IIS6 or IIS7 classic mode,
17               // visit http://go.microsoft.com/?LinkId=9394801
18               public class MvcApplication : System.Web.HttpApplication
19               {
20                   protected void Application_Start()
21                   {
22                       AreaRegistration.RegisterAllAreas();
23          
24                       FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
25                       RouteConfig.RegisterRoutes(RouteTable.Routes);
26          
27                       var builder = new ContainerBuilder();
28                       builder.RegisterControllers(typeof(MvcApplication).Assembly);
29                       builder.RegisterApiControllers(typeof(MvcApplication).Assembly);
30                       builder.RegisterType<EntityFrameworkProductRepository>().AsImplementedInterfaces().InstancePerApiRequest().InstancePerHttpRequest();
31                       var container = builder.Build();
32          
33                       DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
34                       GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
35                   }
36               }
37           }

First up are lines 28-32. This is the configuring of the AutoFac container. You register all the controllers for MVC and the Web API with two lines of code. This is done on lines 29 and 30. On line 31 I am registering the EntityFrameworkProductRepository in a per request scope, for MVC controllers and Web API controllers. On line 32 the container is built. On line 35 the container is registered for MVC controllers. On line 36 it’s registered for API controllers. This is what bites people the most. To use DI with MVC, you need a class which implements IDependencyResolver. To use DI with the ASP.NET Web API, you also need a class which implements IDependencyResolver. But these interfaces aren’t the same and they live in different namespaces. The dependency resolvers are also registered differently as you can see on lines 35 and 36. Luckily, AutoFac’s MVC integration package which we installed earlier, contains dependency resolvers for use to use, otherwise we had to implement these ourselves. That’s all! Now go out and test your REST service with your favorite tool.



European ASP.NET MVC 4 Hosting - Amsterdam :: Simple Wizard Form in ASP.NET MVC 4

clock February 21, 2013 05:53 by author Scott

For small MVC sample application I’m fiddling with on my spare time, I wanted to be able to split my form up in smaller parts, much like the ASP.NET Wizard Control that is available to you when you are using Web Forms.

Basically I wanted a pretty simple Wizard, where I break up the input fields in a form in two or more steps, and display a summary at the end. I wanted the users to be able to step through the wizard without filling in required fields (just so they can get a grasp of the amount of info they would need to fill in), but of course they should be stopped when trying to submit it if anything is missing. I also wanted to avoid going to the server to retrieve a partial view for the summary.

The model I will use is pretty straight forward. It contains some fields for the user to fill inn, that I will split up in “Personal Details”, “Address” and “Contact Details”:

public class SimpleWizardFormModel : IValidatableObject
{
    [Required]
    [Display(Name = "First Name")]
    public string FirstName { get; set; }

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

    [Display(Name = "Street Address")]
    public string Address { get; set; }

    [Required]
    [Display(Name = "Postal Code")]
    public string PostalCode { get; set; }

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

    [Display(Name = "Home Phone")]
    public string Phone { get; set; }

    [Display(Name = "Mobile Phone")]
    public string Mobile { get; set; }

    [Display(Name = "I'm at least 18 years old?")]
    public bool HasTurned18 { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (!HasTurned18)
            yield return new ValidationResult("You must be 18 or older.", new[] { "HasTurned18" });
    }
}

The view isn’t very complicated either:

@model SimpleWizardFormModel
@section head
{
    <style type="text/css">
        .wizard-step { display: none; }
        .wizard-confirmation { display: none; }
        .wizard-nav {  }
        .wizard-nav input[type="button"] { width: 100px; }
    </style>
}
@section script
{
    <script type="text/javascript">
        //*SNIP*
    </script>
}
<h2>Simple Wizard Form</h2>
@using (Html.BeginForm())
{
    <fieldset>
        <legend></legend>
        <div class="wizard-step">
            <h4>Personal Details</h4>
            <ol>
                <li>
                    @Html.LabelFor(m => m.FirstName)
                    @Html.TextBoxFor(m => m.FirstName)
                    @Html.ValidationMessageFor(m => m.FirstName)
                </li>
                <li>
                    @Html.LabelFor(m => m.LastName)
                    @Html.TextBoxFor(m => m.LastName)
                    @Html.ValidationMessageFor(m => m.LastName)
                </li>
                <li>
                    @Html.LabelFor(m => m.HasTurned18)
                    @Html.CheckBoxFor(m => m.HasTurned18)
                    @Html.ValidationMessageFor(m => m.HasTurned18)
                </li>
            </ol>
        </div>
        <div class="wizard-step">
            @**SNIP**@
        </div>
        <div class="wizard-step wizard-confirmation">
            <h4>Confirm</h4>
            <div id="field-summary"></div>
            <div id="validation-summary">
                <span class="message-error">Please correct the following errors;</span>
                @Html.ValidationSummary(true)
            </div>
        </div>
        <div class="wizard-nav">
            <input type="button" id="wizard-prev" value="<< Previous" />
            <input type="button" id="wizard-next" value="Next >>" />
            <input type="button" id="wizard-submit" value="Submit" />
        </div>
    </fieldset>
}

I’ve cut out the javascript as I will get back to that later, as well as a couple of the wizard steps since they are look just like step 1 (just with other input fields). Inside my Layout.cshtml-file I’m importing jquery, jquery.validate, jquery.validate.unobtrusive, and rendering the “head”-section (in the head-tag) and “script”-section (just before body-close-tag) seen above.

The most important “feature” of the view are the divs which have been given the “wizard-step”-class. These contains the various input fields and will become the (as the class name suggests) steps in the wizard that is presented to the user. Initially all these divs are hidden from the user (note the display –> none in the css styles), and the javascript will take care of showing the div that represents the current wizard step to the user.

And now the stuff which actually performs some work, the javascript:

function DisplayStep() {
    var selectedStep = null;
    var firstInputError = $("input.input-validation-error:first"); // check for any invalid input fields
    if (firstInputError.length) {
        selectedStep = $(".wizard-confirmation");
        if (selectedStep && selectedStep.length) { // the confirmation step should be initialized and selected if it exists present
            UpdateConfirmation();
        }
        else {
            selectedStep = firstInputError.closest(".wizard-step"); // the first step with invalid fields should be displayed
        }
    }
    if (!selectedStep || !selectedStep.length) {
        selectedStep = $(".wizard-step:first"); // display first step if no step has invalid fields
    }

    $(".wizard-step:visible").hide(); // hide the step that currently is visible
    selectedStep.fadeIn(); // fade in the step that should become visible

    // enable/disable the prev/next/submit buttons
    if (selectedStep.prev().hasClass("wizard-step")) {
        $("#wizard-prev").show();
    }
    else {
        $("#wizard-prev").hide();
    }
    if (selectedStep.next().hasClass("wizard-step")) {
        $("#wizard-submit").hide();
        $("#wizard-next").show();
    }
    else {
        $("#wizard-next").hide();
        $("#wizard-submit").show();
    }
}

The first method in my javascript, called “DisplayStep”, takes care of displaying the correct wizard step (typically this means the first step) when the view is loaded. if the view is loaded after submitting it to the server and server validation errors are found however, it will show the confirmation step if there is one, and if not it will show the first step which contains erroneous input. Once the correct step to show is found, it will decide where this step is located in relation to the other steps and show or hide the “previous”, “next” and “submit” buttons.

function PrevStep() {
    var currentStep = $(".wizard-step:visible"); // get current step

    if (currentStep.prev().hasClass("wizard-step")) { // is there a previous
step?


        currentStep.hide().prev().fadeIn();  // hide current step and display previous step

        $("#wizard-submit").hide(); // disable wizard-submit button
        $("#wizard-next").show(); // enable wizard-next button

        if (!currentStep.prev().prev().hasClass("wizard-step")) { // disable wizard-prev button?
            $("#wizard-prev").hide();
        }
    }
}

The “PrevStep” method is pretty straight forward. It just finds the current step, hides it, shows the previous one, and shows/hides the buttons. No validation is performed before navigation to the previous step, but if desired, this could be done just like in the “NextStep” shown below.

function NextStep() {
    var currentStep = $(".wizard-step:visible"); // get current step

    var validator = $("form").validate(); // get validator
    var valid = true;
    currentStep.find("input:not(:blank)").each(function () { // ignore empty fields, i.e. allow the user to step through without filling in required fields
        if (!validator.element(this)) { // validate every input element inside this step
            valid = false;
        }
    });
    if (!valid)
        return; // exit if invalid

    if (currentStep.next().hasClass("wizard-step")) { // is there a next step?

        if (currentStep.next().hasClass("wizard-confirmation")) { // is the next step the confirmation?
            UpdateConfirmation();
        }

        currentStep.hide().next().fadeIn();  // hide current step and display next step

        $("#wizard-prev").show(); // enable wizard-prev button
        if (!currentStep.next().next().hasClass("wizard-step")) { // disable wizard-next button and enable wizard-submit?
            $("#wizard-next").hide();
            $("#wizard-submit").show();
        }
    }
}

The “NextStep” is a little more complicated. In addition to performing pretty much the same tasks as the “PrevStep” (only the opposite), it validates all input fields in the current step, and if there are any errors, you won’t be allowed to go to the next step. It only validates none empty fields however, i.e. the required rule if applicable for a given field isn’t evaluated. This is done because I wanted the user to be able to step through the entire form to see how much needs to be filled in (you can easily change this by changing the part of the script where the input fields are found). If the next step has been given the “wizard-confirmation”-class a call is also made to setup/update the confirmation (the specifics of this function will be explained further down).

function Submit() {
    if ($("form").valid()) { // validate all fields, including blank required
fields

        $("form").submit();
    }
    else {
        DisplayStep(); // validation failed, redisplay correct step
    }
}

The last function related to navigation is “Submit”. This function validates the entire form (including required fields), and submits the form if all is good, or calls “DisplayStep” to show the confirmation step (if there is one), or the first step with errors on it (in cases where there are no confirmation step).

function UpdateConfirmation() {
    UpdateValidationSummary();
    var fieldList = $("<ol/>");
    $(".wizard-step:not(.wizard-confirmation)").find("input").each(function () {
        var input = this;
        var value;
        switch (input.type) {
        case "hidden":
            return;
        case "checkbox":
            value = input.checked;
            break;
        default:
            value = input.value;
        }
        var name = $('label[for="' + input.name + '"]').text();
        fieldList.append("<li><label>" + name + "</label><span>" + value + "&nbsp;</span></li>");
    });
    $("#field-summary").children().remove();
    $("#field-summary").append(fieldList);
}

function UpdateValidationSummary() {
    var validationSummary = $("#validation-summary");
    if (!validationSummary.find(".validation-summary-errors").length) { // check if validation errors container already exists, and if not create it
        $('<div class="validation-summary-errors"><ul></ul></div>').appendTo(validationSummary);
    }
    var errorList = $(".validation-summary-errors ul");
    errorList.find("li.field-error").remove(); // remove any field errors that might have been added earlier, leaving any server errors intact
    $('.field-validation-error').each(function () {
        var element = this;
        $('<li class="field-error">' + element.innerText + '</li>').appendTo(errorList); // add the current field errors
    });
    if (errorList.find("li").length) {
        $("#validation-summary span").show();
    }
    else {
        $("#validation-summary span").hide();
    }
}

The “UpdateConfirmation” function (and the “UpdateValidationSummary”-function called by this function) takes care of setting up / displaying the confirmation step. The “UpdateValidationSummary” function finds all input errors (if any) and adds them to the server validation error list (creating this list if it doesn’t already exist). The “UpdateConfirmation” function, in addition to calling “UpdateValidationSummary”, finds all input fields and associated labels and created a list with them that is displayed to the user.

$(function () {
    // attach click handlers to the nav buttons
    $("#wizard-prev").click(function () { PrevStep(); });
    $("#wizard-next").click(function () { NextStep(); });
    $("#wizard-submit").click(function () { Submit(); });

    // display the first step (or the confirmation if returned from server with errors)
    DisplayStep();
});

Last part of the javascript is where we hook up handlers for the navigation buttons and calls the function to display the first (or correct) step when the view is first loaded.

That was all the code needed, not to bad if I say so myself.

A couple of screens to show how it looks in action (first picture shows one of the steps, while the second picture shows the confirmation step):


As I said in the beginning, this wizard is pretty basic, but it works pretty good.

 



European ASP.NET MVC 4 Hosting - Amsterdam :: Optimization Performance MVC 4 with Bundling and Minification

clock February 12, 2013 04:37 by author Scott

MVC4 and .Net Framework 4.5 offer bundling and minification techniques that reduce the number of request to the server and size of requested CSS and JavaScript library, which improve page loading time.

What is Bundle?

A bundle is a logical group of files that is loaded with a single HTTP request. You can create style and script bundle for css and javascripts respectively by calling BundleCollection class Add() method with in BundleConfig.cs file.

Creating Style Bundle

bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.min.css",
"~/Content/mystyle.min.css"));

Creating Script Bundle

bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
 "~/Scripts/jquery-1.7.1.min.js",
 "~/Scripts/jquery.validate.min.js",
 "~/Scripts/jquery.validate.unobtrusive.min.js"));

Above both the bundles are defined with in BundleConfig class as shown below:

public class BundleConfig
{
 public static void RegisterBundles(BundleCollection bundles)
 {
 bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.min.css",
 "~/Content/mystyle.min.css"));

bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
 "~/Scripts/jquery-1.7.1.min.js",
 "~/Scripts/jquery.validate.min.js",
 "~/Scripts/jquery.validate.unobtrusive.min.js"));
 }
}

Creating Bundle using the "*" Wildcard Character

"*" wildcard character is used to combines the files that are in the same directory and have same prefix or suffix with its name. Suppose you want to add all the scripts files that exist with in "~/Script" directory and have "jquery" as prefix then you can create bundle like below:

bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include("~/Scripts/jquery*.js"));

You can also add all the css that exist with in "~/Content" directory and have ".css" extension(as suffix) like below:

bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/*.css"));

Registering Bundle

All bundles are registered with in Application_Start event of Global.asax file of you web application.

protected void Application_Start()
{
 BundleConfig.RegisterBundles(BundleTable.Bundles);
 // Other Code is removed for clarity
}

Minification

Minification is technique for removing unnecessary characters (like white space, newline, tab) and comments from the JavaScript and CSS files to reduce the size which cause improved load times of a webpage. There are so many tools for minifying the js and css files. JSMin and YUI Compressor are two most popular tools for minifying the js and css files.

You can also add WebEssentials2012.vsix extension to your VS2012 for minifying the js and css files. This is a great extension for VS2012 for playing with js and css.

Minification with VS2012 and WebEssentials 2012 extension

I would like to share how can you make minify version of you css file using WebEssentials extension and VS2012. This minify version will updated automatically if you will make change in original css file.

Performance Optimization with Bundling and Minification

I have done a performance test on a MVC4 application with & without bundling and minification. I have noticed the below result.

Without Bundling and Minification

I have the below css and js files on the layout page and run the application in chrome browser and test no of request and loding time using chrome developer tools as shown below.

<link href="~/Content/Site.css" rel="stylesheet"/>
<link href="~/Content/MyStyle.css" rel="stylesheet"/>
<script src="~/Scripts/jquery-1.7.1.js"></script>
<script src="~/Scripts/jquery-ui-1.8.20.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>

In this test, I have seen, There are 7 request, total data size is 3.96KB and loading time is approximate 296ms.

With Bundling and Minification

I have run the above application with Bundling and Minification of css and js files and test no of request and loding time using chrome developer tools as shown below.

@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/jquery")

In this test, I have seen, There are only 3 request, total data size is 2.67KB and loading time is approximate 80ms. In this way by using bundling and minification you have reduced the total no of request, size and loading time.

Enabling Bundling and Minification in debug mode

Bundling and minification doesn't work in debug mode. So to enable this featues you need to add below line of code with in Application_Start event of Global.asax.

protected void Application_Start()
{
 BundleConfig.RegisterBundles(BundleTable.Bundles);
 //Enabling Bundling and Minification
 BundleTable.EnableOptimizations = true;
 // Other Code is removed for clarity
}

Busting Browser's Cache by Bundling

As you know browsers cache resources based on URLs. When a web page requests a resource, the browser first checks its cache to see if there is a resource with the matched URL. If yes, then it simply uses the cached copy instead of fetching a new one from server. Hence whenever you change the content of css and js files will not reflect on the browser. For this you need to force the browser for refreshing/reloading.

But bundles automatically takes care of this problem by adding a hashcode to each bundle as a query parameter to the URL as shown below. Whenever you change the content of css and js files then a new has code will be generated and rendered to the page automatically. In this way, the browser will see a different url and will fetch the new copy of css and js.

I hope you will enjoy the tips while performance optimization of your MVC4 application.

 



European ASP.NET MVC 4 Hosting - Amsterdam :: jQuery UI Datepicker in MVC 4 Issue

clock January 29, 2013 08:02 by author Scott

I believe some of you will find this issue. If you create a MVC 4 application using "Internet" template, you will find the "BundleConfig.cs" file in the "App_Start" folder; open it.

You will notice there is a total of 6 bundles (jQuery and CSS) being processed. Now, open the "_Layout.cshtml" file and look at this image:

You will notice only three bundles are added by default. We have to add 2 more to enable the use of Datepicker.

Note to use the same ordering.

Now, on the view page use as follows:

Now if you run the application you will see your Datepicker working.

Hope this helps. Thanks.

 



European ASP.NET MVC 4 Hosting - Amsterdam :: Seed Users and Roles with MVC 4, SimpleMembershipProvider, SimpleRoleProvider, EntityFramework 5 CodeFirst, and Custom User Properties

clock January 21, 2013 06:43 by author Scott

Today post, I will show you how to integrate EF5 CodeFirst nicely with SimpleMembership and at the same time, seeding some of your users, roles and associating users to roles while supporting custom fields/properties during registration.

I think this is a nice to have, especially during PoC development where you could be developing features that depend on authentication and authorization while making schema changes with EF CodeFirst. The last thing you want to do is run update-database for migrations and have to manually re-insert/re-seed all your users, roles and associating the two every time you ran migrations (e.g. update-database -force from the Package Manager Console).

First, create an “Internet Application” ASP.NET MVC4 Project, because this is the only out of the box MVC template that has the new SimpleMembershipProvider wired up out of the box. One of the features I like the most about the SimpleMembershipProvider is it gives you total control of the highly requested “User” table/entity. Meaning you integrate SimpleMembershipProvider with your own user table, as long as it has a UserId and UserName fields in your table.

Explicitly wire up the providers even though this is implied, so that when do run the “update-database” command from the Package Manager Console for migrations we can use the native “Roles” Api.

In the “System.Web” Section add:

01    <roleManager enabled="true" defaultProvider="SimpleRoleProvider">
02      <providers>
03        <clear/>
04        <add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData"/>
05      </providers>
06    </roleManager>
07    <membership defaultProvider="SimpleMembershipProvider">
08      <providers>
09        <clear/>
10        <add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
11      </providers>
12    </membership>

Let’s add a custom field to the User table by adding a Mobile property to the UserProfile entity (MVC4SimpleMembershipCodeFirstSeedingEF5/Models/AccountModel.cs).

1     [Table("UserProfile")]
2     public class UserProfile
3     {
4         [Key]
5         [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
6         public int UserId { get; set; }
7         public string UserName { get; set; }
8         public string Mobile { get; set; }
9     }

Enable EF5 CodeFirst Migrations

Seed your Roles and any Users you want to provision, also note the WebSecurity.InitializeDatabaseConnection method we are invoking. This method is what tells SimpleMembership which table to use when working with Users and which columns are for the UserId and UserName. I’m also going to demonstrate how you can hydrate additional custom columns such as requiring a User’s mobile number when registering on the site.

01    #region
02   
03    using System.Data.Entity.Migrations;
04    using System.Linq;
05    using System.Web.Security;
06    using MVC4SimpleMembershipCodeFirstSeedingEF5.Models;
07    using WebMatrix.WebData;
08   
09    #endregion
10   
11    namespace MVC4SimpleMembershipCodeFirstSeedingEF5.Migrations
12    {
13        internal sealed class Configuration : DbMigrationsConfiguration<UsersContext>
14        {
15            public Configuration()
16            {
17                AutomaticMigrationsEnabled = true;
18            }
19   
20            protected override void Seed(UsersContext context)
21            {
22                WebSecurity.InitializeDatabaseConnection(
23                    "DefaultConnection",
24                    "UserProfile",
25                    "UserId",
26                    "UserName", autoCreateTables: true);
27   
28                if (!Roles.RoleExists("Administrator"))
29                    Roles.CreateRole("Administrator");
30   
31                if (!WebSecurity.UserExists("lelong37"))
32                    WebSecurity.CreateUserAndAccount(
33                        "lelong37",
34                        "password",
35                        new {Mobile = "+19725000000"});
36   
37                if (!Roles.GetRolesForUser("lelong37").Contains("Administrator"))
38                    Roles.AddUsersToRoles(new[] {"lelong37"}, new[] {"Administrator"});
39            }
40        }
41    }

Now, run the update-database -verbose command from Package Manager Console, we are using the -verbose switch so that we can get better visibility on what’s getting executed on SQL. Notice the Mobile field is being created.

Let’s go ahead and do a sanity check and make sure all of our Users and Roles were provisioned correctly from the Seed method in our migration configuration, by executing a few queries.

01           SELECT TOP 1000 [UserId]
02                 ,[UserName]
03                 ,[Mobile]
04             FROM [aspnet-MVC4SimpleMembershipCodeFirstSeedingEF5].[dbo].[UserProfile]
05             
06             SELECT TOP 1000 [RoleId]
07                 ,[RoleName]
08             FROM [aspnet-MVC4SimpleMembershipCodeFirstSeedingEF5].[dbo].[webpages_Roles]
09             
10             SELECT TOP 1000 [UserId]
11                 ,[RoleId]
12             FROM [aspnet-MVC4SimpleMembershipCodeFirstSeedingEF5].[dbo].[webpages_UsersInRoles]

Results



- Users were inserted
- Roles were provisioned
- The user “LeLong37″ was added and associated to the Administrator role

Finally for a sanity check, let’s go ahead and run the app and sign-in with the provisioned user from our Seed method.

One last thing, let’s go ahead and modify our Register view, Register model and AccountController to gather the user’s mobile number during registration.

Register View (Register.cshtml)

01           @model MVC4SimpleMembershipCodeFirstSeedingEF5.Models.RegisterModel
02           @{
03               ViewBag.Title = "Register";
04           }
05          
06           <hgroup class="title">
07               <h1>@ViewBag.Title.</h1>
08               <h2>Create a new account.</h2>
09           </hgroup>
10          
11           @using (Html.BeginForm()) {
12               @Html.AntiForgeryToken()
13               @Html.ValidationSummary()
14          
15               <fieldset>
16                   <legend>Registration Form</legend>
17                   <ol>
18                       <li>
19                           @Html.LabelFor(m => m.UserName)
20                           @Html.TextBoxFor(m => m.UserName)
21                       </li>
22                       <li>
23                           @Html.LabelFor(m => m.Password)
24                           @Html.PasswordFor(m => m.Password)
25                       </li>
26                       <li>
27                           @Html.LabelFor(m => m.ConfirmPassword)
28                           @Html.PasswordFor(m => m.ConfirmPassword)
29                       </li>
30                       <li>
31                           @Html.LabelFor(m => m.Mobile)
32                           @Html.TextBoxFor(m => m.Mobile)
33                       </li>
34                   </ol>
35                   <input type="submit" value="Register" />
36               </fieldset>
37           }
38          
39           @section Scripts {
40               @Scripts.Render("~/bundles/jqueryval")
41           }

Register model (AccountModel.cs)

01           public class RegisterModel
02           {
03               [Required]
04               [Display(Name = "User name")]
05               public string UserName { get; set; }
06          
07               [Required]
08               [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
09               [DataType(DataType.Password)]
10              [Display(Name = "Password")]
11               public string Password { get; set; }
12          
13               [DataType(DataType.Password)]
14               [Display(Name = "Confirm password")]
15               [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
16               public string ConfirmPassword { get; set; }
17          
18               [Required]
19               [DataType(DataType.PhoneNumber)]
20               [Display(Name = "Mobile")]
21               public string Mobile { get; set; }
22           }

Register Action (AccountController.cs)

01           [HttpPost]
02           [AllowAnonymous]
03           [ValidateAntiForgeryToken]
04           public ActionResult Register(RegisterModel model)
05           {
06               if (ModelState.IsValid)
07               {
08                   // Attempt to register the user
09                   try
10                   {
11                       WebSecurity.CreateUserAndAccount(
12                           model.UserName,
13                           model.Password,
14                           new { Mobile = model.Mobile },
15                           false);
16          
17                       WebSecurity.Login(model.UserName, model.Password);
18                       return RedirectToAction("Index", "Home");
19                   }
20                   catch (MembershipCreateUserException e)
21                   {
22                       ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
23                   }
24               }
25          
26               // If we got this far, something failed, redisplay form
27               return View(model);
28           }

Finally, let’s register.

Let’s go ahead and run our SQL queries again and make sure the mobile number was actually saved to our UserProfile table during the registration.

Sweet! Registration successful, with mobile number saved to the UserProfile table.

Happy Coding…!

 



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