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 :: Error Handling and Logging in MVC4

clock April 2, 2013 10:19 by author Scott

Error handing is the main concern in any application, whether it is web application or desktop application. Usually, we catch the exception and log its details to database or text,xml file and also display a user friendly message to end user in-place of error.

Asp.Net MVC has some bulit-in exception filters. HandleError is the default bulit-in exception filter. Let's see how to use this filter with in your application.

HandleError Attribute

The HandleErrorAttribute filter works only when custom errors are enabled in the Web.config file of your application. You can enable custom errors by adding a customErrors attribute inside the <system.web> node, as shown below:

</system.web>
...
<customErrors mode="On" defaultRedirect="Error.htm"/>
</system.web>

HandleError Attribute can be used to handle error at Action Method level, Controller level and Global level.

HandleError Attribute at Action Method Level

Simply put this attribute to the action method to tell MVC how to react when an exception occurs.

[HandleError(ExceptionType = typeof(System.Data.DataException), View = "DatabaseError")]
public ActionResult Index(int id)
{
 var db = new MyDataContext();
 return View("Index", db.Categories.Single(x => x.Id == id));
}

In the above example when a database exception (System.Data.DataException) occurs during the execution of the Index action, MVC will display the DatabaseError view.

HandleError Attribute at Controller Level

Simply put this attribute to the controller to tell MVC how to react when an exception occurs with in the action methods of this controller.

[HandleError(ExceptionType = typeof(System.Data.DataException), View = "DatabaseError")]
public class HomeController : Controller
{
 /* Controller Actions with HandleError applied to them */
}

In the above example when a database exception (System.Data.DataException) occurs during the execution of the controler's any action methos, MVC will display the DatabaseError view.

HandleError Attribute at Global Level

You can also apply the HandleError Attribute for the entire application by registering it as a global error handler. For registering a global error handler, open the FilterConfig.cs file with in App_Start folder to find the RegisterGlobalFilters method.

By default, ASP.NET MVC template has already registered a global HandleErrorAttribute to the GlobalFilterCollection for your application. Here you can also add your own custom filter to the global filter collection as well.

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
 filters.Add(new HandleErrorAttribute
 {
 ExceptionType = typeof(System.Data.DataException),
 View = "DatabaseError"
 }); 

 filters.Add(new HandleErrorAttribute()); //by default added
}

Note

Always remember, by default, global filters are executed in their registered order. so register error filters for specific exception types before any other.

You can also set the order of execution of these filter by giving number values to each. The above registered filters can be re-written as:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
 filters.Add(new HandleErrorAttribute(),2); //by default added
 filters.Add(new HandleErrorAttribute
 {
 ExceptionType = typeof(System.Data.DataException),
 View = "DatabaseError"
 },1);
}

Now, all the filters will be executed in the number sequence.

Limitation of HandleError Attribute

1. It has no support to log the exceptions since it suppressed the error once it is handled.
2. It only catch 500 Http error and doesn't catch other HTTP errors like 404,401 etc.
3. It doesn't catch the errors that occur outside the controllers like errors occurs in model.
4. It returns error view even if error occurred in AJAX calls that is not useful in the client-side. It would be great to return a piece of JSON in AJAX exceptions .

Extending HandleError Filter for logging and handling more errors

You can also make your custom error filter by extending HandleError filter. Let's see how to extend this filter to log the exceptions and return a JSON object for AJAX calls.

public class CustomHandleErrorAttribute : HandleErrorAttribute
{
 public override void OnException(ExceptionContext filterContext)
 {
 if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
 {
 return;
 }

 if (new HttpException(null, filterContext.Exception).GetHttpCode() != 500)
 {
 return;
 }

 if (!ExceptionType.IsInstanceOfType(filterContext.Exception))
 {
 return;
 }

 // if the request is AJAX return JSON else view.
 if (filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
 {
 filterContext.Result = new JsonResult
 {
 JsonRequestBehavior = JsonRequestBehavior.AllowGet,
 Data = new
 {
 error = true,
 message = filterContext.Exception.Message
 }
 };
 }
 else
 {
 var controllerName = (string)filterContext.RouteData.Values["controller"];
 var actionName = (string)filterContext.RouteData.Values["action"];
 var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);

 filterContext.Result = new ViewResult
 {
 ViewName = View,
 MasterName = Master,
 ViewData = new ViewDataDictionary(model),
 TempData = filterContext.Controller.TempData
 };
 }

 // log the error by using your own method
 LogError(filterContext.Exception.Message, filterContext.Exception);

 filterContext.ExceptionHandled = true;
 filterContext.HttpContext.Response.Clear();
 filterContext.HttpContext.Response.StatusCode = 500;

 filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
 }
}

 



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 :: How to Integrate Facebook Login button in ASP.NET MVC 4 application

clock March 15, 2013 07:06 by author Scott

This article demonstrates how to integrate login button on the web page in order to obtain access token that we'll need for further tutorials.

Visual Studio project setup

Firstly, let's get started by opening visual studio and creating new ASP.NET Mvc 4 Web Application. Name it FacebookLoginButton and make sure .NET Framework 4 is selected. Click on OK. Another window should now pop up asking for a type of tempalte you'd like to install in your app. Select An Empty ASP.NET MVC Project.

Once you've got your project created, right click on Controllers folder and Add Controller. Make sure controller name is set to HomeController.

What we need now is a view associated with home controller index method. To add a view, open newly created HomeController and look for a line where it returns View() ActionResult. View() should be highligted in red. Right click on it and select Add View.

Make sure you compile your project before editing anything. There is some problem with VS 2010 and MVC 4 Razor engine. When you try to edit .cshtml file without rebuilding your solution first, VisualStudio will crash.

Import and configure facebook javascript framework

Time for a little bit of javascript-ing. Buuu. Right click on Scripts and create new Javascript file. Name it Facebook.js. Paste in following content:

function InitialiseFacebook(appId) { 

    window.fbAsyncInit = function () {
        FB.init({
            appId: appId,
            status: true,
            cookie: true,
            xfbml: true
        }); 

        FB.Event.subscribe('auth.login', function (response) {
            var credentials = { uid: response.authResponse.userID, accessToken: response.authResponse.accessToken };
            SubmitLogin(credentials);
        }); 

        FB.getLoginStatus(function (response) {
            if (response.status === 'connected') {
                alert("user is logged into fb");
            }
            else if (response.status === 'not_authorized') { alert("user is not authorised"); }
            else { alert("user is not conntected to facebook");  } 

        }); 

        function SubmitLogin(credentials) {
            $.ajax({
                url: "/account/facebooklogin",
                type: "POST",
                data: credentials,
                error: function () {
                    alert("error logging in to your facebook account.");
                },
                success: function () {
                    window.location.reload();
                }
            });
        } 

    }; 

    (function (d) {
        var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
        if (d.getElementById(id)) {
            return;
        }
        js = d.createElement('script');
        js.id = id;
        js.async = true;
        js.src = "//connect.facebook.net/en_US/all.js";
        ref.parentNode.insertBefore(js, ref);
    } (document)); 

}

This javascript will ensure that we're subscribed to login event on which we'll submit fb access token to our controller and save it in session. Also, on each window load, we'll check for fb login status and alert user accordingly.

Sign up for an app

Now, go to developers.facebook.com and create a new app. Make sure all app's urls point to the actual address of the app. If you're running the app from Visual Studio, its address will be http://localhost:[PORT NUMBER].

Login model and controller

Next, we need to add account controller that will save facebook response in session. Before we add it, let's create a model for an object that we'll pass to account controller. Right click on Models folder and add FacebookLoginModel.cs (Class).

namespace FacebookLoginButton.Models
{
    public class FacebookLoginModel
    {
        public string uid { get; set; }
        public string accessToken { get; set; }
    }
}

Once we've got our model, we can add AccountController.cs.

using System.Web.Mvc;
using FacebookLoginButton.Models; 

namespace FacebookLoginButton.Controllers
{
    public class AccountController : Controller
    {
        [HttpPost]
        public JsonResult FacebookLogin(FacebookLoginModel model)
        {
            Session["uid"] = model.uid;
            Session["accessToken"] = model.accessToken; 

            return Json(new {success = true});
        } 

    }
}

Login button configuration

To enable facebook framework, make sure you've got following lines added to your Views -> Shared -> Layout.cshtml file. Following lines should be added just before body closing tag.

<div id="fb-root"></div>
    <script src="@Url.Content("~/Scripts/jquery-1.6.2.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/Facebook.js")"
type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            InitialiseFacebook(@System.Configuration.ConfigurationManager.AppSettings["FacebookAppId"]);
        });
    </script>

Finally, modify Views -> Home -> Index.cshtml by pasting in following code:

@{
    ViewBag.Title = "Part 1 - Facebook Login Button";    Layout = "~/Views/Shared/_Layout.cshtml";


<h2>Part 1 - Facebook Login Button</h2> 

<fb:login-button autologoutlink="true" perms="read_friendlists, create_event, email, publish_stream"></fb:login-button> 

<p>Facebook Access Token: @Session["accessToken"]</p>
<p>Facebook User Id: @Session["uid"]</p> 

<p>If you're not getting javascript prompts on each window load, make sure facebook app id in web config is correct.</p>

That's it. Feel free to download comleted solution attached to this post.

Done. Great job

 



European ASP.NET MVC 4 Hosting - Amsterdam :: ASP.NET MVC 3 and MVC 4 Routing

clock March 11, 2013 05:59 by author Scott

Basically, Routing is a pattern matching system that monitor the incoming request and figure out what to do with that request. At runtime, Routing engine use the Route table for matching the incoming request's URL pattern against the URL patterns defined in the Route table. You can register one or more URL patterns to the Route table at Application_Start event.

How to defining route...

public static void RegisterRoutes(RouteCollection routes)
{
 routes.MapRoute(
 "Default", // Route name
 "{controller}/{action}/{id}", // Route Pattern
 new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Default values for above defined parameters
 );


protected void Application_Start()
{
 RegisterRoutes(RouteTable.Routes);
 //To:DO
}

When the routing engine finds a match in the route table for the incoming request's URL, it forwards the request to the appropriate controller and action. If there is no match in the route table for the incoming request's URL, it returns a 404 HTTP status code.

See the picture below:

In above example we have defined the Route Pattern {controller}/{action}/{id} and also provide the default values for controller,action and id parameters. Default values means if you will not provide the values for controller or action or id defined in the pattern then these values will be serve by the routing system.

Suppose your webapplication is running on www.example.com then the url pattren for you application will be www.example.com/{controller}/{action}/{id}. Hence you need to provide the controller name followed by action name and id if it is required. If you will not provide any of the value then default values of these parameters will be provided by the routing system.

What is the Difference between Routing and URL Rewriting

Many developers compares routing to URL rewritting that is wrong. Since both the approaches are very much different. Moreover, both the approaches can be used to make SEO friendly URLs. Below is the main difference between these two approaches.

1. URL rewriting is focused on mapping one URL (new url) to another URL (old url) while routing is focused on mapping a URL to a resource.

2. Actually, URL rewriting rewrites your old url to new one while routing never rewrite your old url to new one but it map to the original route.



European ASP.NET MVC 4 Hosting - Amsterdam :: Using NHibernate in an ASP.NET MVC 4 Application

clock March 6, 2013 05:58 by author Scott

ASP.NET MVC is a common framework for developing web applications. As we all know that M in MVC stands for model, and for a Line of business (LoB application ), the model is often the backbone. For defining a model that persists in a database, ASP.NET MVC supports Entity Framework (now Open Source) out of the box. Other possible options are:

ADO.NET hand coded data layer where you write all the queries explicitly.

- Use commercial O/R mappers like LLBLGen
- Use Open Source O/R mapper like NHibernate.

Today we will see how we can get started using Nhibernate

Getting Started with NHibernate

You can get additional information about the NHibernate from here.

Once you identify various models and relationship in your data model, you can now introduce NHibernate for mapping these models to a persistence store like (SQL Server, Oracle etc).
One of the most important part of using ORM is establishing mapping between Model objects and the Database tables. If we use NHibernate, then this mapping needs to be set explicitly using XML file.

In the following steps, we will be exploring use of NHibernate in ASP.NET MVC 4 application.

Step 1: Open VS 2012 and create MVC 4 application. On the project, right click and select  Manage NuGet Packages’. You will see the Manage Nuget Packages screen. In the search TextBox enter ‘NHibernate’ and you will get the following result:

Once you click the ‘Install’, you will get below references in then project:

- NHibernate
- Lesi.Collections

Step 2: Now it is a time to define the Model layer. As I wrote in the beginning that based upon the application requirement, you need to decide upon the Model objects and the relationship between them. So now let’s define an application that is used to maintain employee records (very simple, but you can extend the concept). Let’s add the new class in the Models folder as shown below:

public class EmployeeInfo
{
int _EmpNo;
public virtual int EmpNo
{
  get { return _EmpNo; }
  set { _EmpNo = value; }
}
string _EmpName;
public virtual string EmpName
{
  get { return _EmpName; }
  set { _EmpName = value; }
}
int _Salary;
public virtual int Salary
{
  get { return _Salary; }
  set { _Salary = value; }
}
string _DeptName;
public virtual string DeptName
{
  get { return _DeptName; }
  set { _DeptName = value; }
}
string _Designation;
public virtual string Designation
{
  get { return _Designation; }
  set { _Designation = value; }
}
}

The class EmployeeInfo contains properties. These properties will be used for mapping with the Table Columns. These properties are defined as virtual properties because of the lazy association which is used by NHibernate to set proxy entity on association property.

Step 3: Once the Model class for mapping is ready, now let’s think of the database to persist the data. For this simple application, we will use a database called Company in SQL Server. The name of the table is EmployeeInfo which can be created as shown below:

USE [Company]
GO
/****** Object:  Table [dbo].[EmployeeInfo]    Script Date: 1/17/2013 11:22:12 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[EmployeeInfo](
    [EmpNo] [int] IDENTITY(1,1) NOT NULL,
    [EmpName] [varchar](50) NOT NULL,
    [Salary] [decimal](18, 0) NOT NULL,
    [DeptName] [varchar](50) NOT NULL,
    [Designation] [varchar](50) NOT NULL,
CONSTRAINT [PK_EmployeeInfo] PRIMARY KEY CLUSTERED
(
    [EmpNo] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING
OFF
GO

Step 4: To set the mapping, we need to add an XML file in the project as ‘Embedded Resource’. For this sample, I’ll use two folders under the default Model folder - NHibernate\Configuration and NHibernate\Mappings.

The naming convention for the mapping files are by default <ModelName>.hbm.xml, so in our case it will be ‘EmployeeInfo.hbm.xml’. This file goes into the Mappings folder. This file maps the Model class with the database table columns with the constraints like primary key, data types etc. The file is as shown below:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping
xmlns="urn:nhibernate-mapping-2.2"
assembly="MVC4_Using_NHB"
namespace="MVC4_Using_NHB"
auto-import="true">
<class name="MVC4_Using_NHB.Models.EmployeeInfo,MVC4_Using_NHB">
  <id name="EmpNo" access="property" column="EmpNo" type="Int32">
   <generator class="native"></generator>
  </id>
  <property name="EmpName" access="property"
   column="EmpName" type="String"></property>
  <property name="Salary" access="property"
   column="Salary" type="Int32"></property>
  <property name="DeptName" access="property"
   column="DeptName" type="String"></property>
  <property name="Designation" access="property"
   column="Designation" type="String"></property>
  </class>
</hibernate-mapping>


The above xml file demonstrates the mapping between EmployeeInfo class and its properties with the columns. The mapping table is defined by the NHibernate APIs while establishing connection to database.

Note: One important thing is that by default no intellisense is available so to achieve this add nhibernate-configuration.xsd and nhibernate-mapping.xsd in below path

C:\Program Files (x86)\Microsoft Visual Studio 11.0\Xml\Schemas

Step 5: Once the mapping is defined, now let’s define the NHibernate configuration for the application. This provides information about the database provider, connection string and the mapping file used for the connectivity. So in the project, add a new XML file in the Models\Configuration folder created above; the name of the file will be ‘hibernate.cfg.xml’. Add the following configuration in it:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
  <property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider</property>
  <property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
  <property name="connection.driver_class">
NHibernate.Driver.SqlClientDriver</property>
  <property name="connection.connection_string">Data Source=.;Initial Catalog=Company;Integrated Security=SSPI</property>
  <property name="show_sql">false</property>
</session-factory>
</hibernate-configuration>


Step 6: Now it’s time to add some code to do CRUD operations against the database table using the mapping model. NHibernate provides various classes and interfaces for performing operations, some of them are used in this implementation and they are as below:

ISession: This is a main runtime interface between NHibernate and .NET and is used to manipulate entities.

ISessionFactory: A Session is created by this interface. The method ‘OpenSession()’ is provided to create session. One session factory is required per database. The implementation is thread safe and can live till the life time of the application.

As you can see in the code below, we have provided the absolute path of the configuration file to the configuration object and also provided it with the Directory Information where all the mapping files will be kept (in the OpenSession method).

IQuery: This is an object representation of NHibernate query. This is created using ‘CreateQuery()’ method of the ISession. This is the method where the table name is passed and based upon which column the mapping can take place.

ITransaction: Used to manage transactions. This is required during DML operations.
Add a new class in the Models folder and add the following code in it:

/// <summary>
/// class to perform the CRUD operations
/// </summary>
public class EmployeeInfoDAL
{
//Define the session factory, this is per database
ISessionFactory sessionFactory;
/// <summary>
/// Method to create session and manage entities
/// </summary>
/// <returns></returns>
ISession OpenSession()
{
  if (sessionFactory == null)
  {
   var cgf = new Configuration();
   var data = cgf.Configure(
         HttpContext.Current.Server.MapPath(
            @"Models\NHibernate\Configuration\hibernate.cfg.xml"));
   cgf.AddDirectory(new System.IO.DirectoryInfo(
         HttpContext.Current.Server.MapPath(@"Models\NHibernate\Mappings")));
   sessionFactory = data.BuildSessionFactory();
  }
  return sessionFactory.OpenSession();
}
public IList<EmployeeInfo> GetEmployees()
{
  IList<EmployeeInfo> Employees;
  using (ISession session = OpenSession())
  {
   //NHibernate query
   IQuery query = session.CreateQuery("from EmployeeInfo");
   Employees = query.List<EmployeeInfo>();
  }
  return Employees;
}
public EmployeeInfo GetEmployeeById(int Id)
{
  EmployeeInfo Emp = new EmployeeInfo();
  using (ISession session = OpenSession())
  {
   Emp = session.Get<EmployeeInfo>(Id);
  }
  return Emp;
}
public int CreateEmployee(EmployeeInfo Emp)
{
  int EmpNo = 0;
  using (ISession session = OpenSession())
  {
   //Perform transaction
   using (ITransaction tran = session.BeginTransaction())
   {
    session.Save(Emp);
    tran.Commit();
   }
  }
  return EmpNo;
}
public void UpdateEmployee(EmployeeInfo Emp)
{
  using (ISession session = OpenSession())
  {
   using (ITransaction tran = session.BeginTransaction())
   {
    session.Update(Emp);
    tran.Commit();
   }
  }
}
public void DeleteEmployee(EmployeeInfo Emp)
{
  using (ISession session = OpenSession())
  {
   using (ITransaction tran = session.BeginTransaction())
   {
    session.Delete(Emp);
    tran.Commit();
   }
  }
}
}

Build the project and make sure that it is error free.

Step 7: Add a new Controller in the Controllers folder, name it as ‘EmployeeInfoController’. Add the following action methods in the controller class:

using MVC4_Using_NHB.Models;
using System.Web.Mvc;
namespace MVC4_Using_NHB.Controllers
{
public class EmployeeInfoController : Controller
{
  EmployeeInfoDAL objDs;
  public EmployeeInfoController()
  {
   objDs = new EmployeeInfoDAL();
  }
  //
  // GET: /EmployeeInfo/
  public ActionResult Index()
  {
   var Employees = objDs.GetEmployees();
   return View(Employees);
  }
//
// GET: /EmployeeInfo/Details/5
public ActionResult Details(int id)
{
  return View();
}
//
// GET: /EmployeeInfo/Create
public ActionResult Create()
{
  var Emp = new EmployeeInfo();
  return View(Emp);
}
//
// POST: /EmployeeInfo/Create
[HttpPost]
public ActionResult Create(EmployeeInfo Emp)
{
  try
  {
   objDs.CreateEmployee(Emp);
   return RedirectToAction("Index");
  }
  catch
  {
   return View();
  }
}
//
// GET: /EmployeeInfo/Edit/5
public ActionResult Edit(int id)
{
  var Emp = objDs.GetEmployeeById(id);
  return View(Emp);
}
//
// POST: /EmployeeInfo/Edit/5
[HttpPost]
public ActionResult Edit(int id, EmployeeInfo Emp)
{
  try
  {
   objDs.UpdateEmployee(Emp);
   return RedirectToAction("Index");
  }
  catch
  {
   return View();
  }
}
//
// GET: /EmployeeInfo/Delete/5
public ActionResult Delete(int id)
{
  var Emp = objDs.GetEmployeeById(id);
  return View(Emp);
}
//
// POST: /EmployeeInfo/Delete/5
[HttpPost]
public ActionResult Delete(int id,FormCollection collection)
{
  try
  {
   var Emp = objDs.GetEmployeeById(id);
   objDs.DeleteEmployee(Emp);  
   return RedirectToAction("Index");
  }
  catch
  {
   return View();
  }
}
}


Each action method makes a call to the method defined in the EmployeeInfoDAL class. That’s it. Now add views for each action method and test them.

Conclusion

We saw how easy it is to make use of NHibernate in MVC application for building Line of Business (LOB) applications.

 



European ASP.NET MVC 4 Hosting - Amsterdam :: Seeding Membership &amp; Roles in ASP.NET MVC 4

clock March 5, 2013 06:44 by author Scott

Jon Galloway has an overview of the new membership features in ASP.NET MVC 4. The Internet project template moves away from the core membership providers of ASP.NET and into the world of SimpleMembershipProvider and OAuth.

There is quite a bit I could write about the new features and the code generated by the Internet project template, but for this post I just want to cover a scenario I've demonstrated in the past - seeding the roles and membership tables. If you are using Entity Framework code-first migrations it's relatively easy to add some code to the Seed method of the migrations configuration to populate the membership tables with some initial roles and users. Just remember every update-database command will call the Seed method, so you have to write the code to make sure you don't try to create duplicate data.

First, the new project template creates an MVC 4 Internet application without any provider configuration, but for the membership features to work properly during a migration, it appears you need at least some configuration. The following code makes sure the SimpleMembershipProvider and SimpleRolesProvider are in place.

<roleManager enabled="true" defaultProvider="simple">
 
<providers>
   
<clear/>
   
<add name="simple" type="WebMatrix.WebData.SimpleRoleProvider,
                             WebMatrix.WebData"/>
 
</providers>     
</roleManager>
<membership defaultProvider="simple">
 
<providers>
   
<clear/>
   
<add name="simple" type="WebMatrix.WebData.SimpleMembershipProvider,
                             WebMatrix.WebData"/>
 
</providers>
</membership>

Then inside the Seed method of the DbMigrationsConfiguration<T> derived class, you can have:

protected override void Seed(MovieDb context)
{           
    //context.Movies.AddOrUpdate(...);

    // ...

    SeedMembership();
}

private void SeedMembership()
{           
    WebSecurity.InitializeDatabaseConnection("DefaultConnection",
        "UserProfile", "UserId", "UserName", autoCreateTables: true);
 
    var roles = (SimpleRoleProvider) Roles.Provider;
    var membership = (SimpleMembershipProvider) Membership.Provider;
 
    if (!roles.RoleExists("Admin"))
    {
        roles.CreateRole("Admin");
    }
    if (membership.GetUser("sallen",false) == null)
    {
        membership.CreateUserAndAccount("sallen", "imalittleteapot");
    }
    if (!roles.GetRolesForUser("sallen").Contains("Admin"))
    {
        roles.AddUsersToRoles(new[] {"sallen"}, new[] {"admin"});
    }
}



European ASP.NET MVC 4 Hosting - Amsterdam :: How to upload a file in MVC4

clock February 27, 2013 05:38 by author Scott

Uploading a file in Asp.Net MVC application is very easy. The posted file is automatically available as a HttpPostedFileBase parameters in the action of the controler. For uploading a file on the server you required to have a file input control with in html form having encoding type set to multipart/form-data. The default encoding type of a form is application/x-www-form-urlencoded and this is no sufficient for posting a large amount of data to server.

1. Form for uploading the file

@using (Html.BeginForm("FileUpload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
 @Html.ValidationSummary();
 <ol>
 <li class="lifile">
 <input type="file" id="fileToUpload" name="file" />
 <span class="field-validation-error" id="spanfile"></span>
 </li>
 </ol>
 <input type="submit" id="btnSubmit" value="Upload" />
}

2. Validating the file on client side

<script type="text/jscript">
//get file size
function GetFileSize(fileid) {
 try
 {
 var fileSize = 0;
 //for IE
 if ($.browser.msie)
 {
 //before making an object of ActiveXObject,
 //please make sure ActiveX is enabled in your IE browser
 var objFSO = new ActiveXObject("Scripting.FileSystemObject"); var filePath = $("#" + fileid)[0].value;
 var objFile = objFSO.getFile(filePath);
 var fileSize = objFile.size; //size in kb
 fileSize = fileSize / 1048576; //size in mb
 }
 //for FF, Safari, Opeara and Others
 else
 {
 fileSize = $("#" + fileid)[0].files[0].size //size in kb
 fileSize = fileSize / 1048576; //size in mb
 }
 return fileSize;
 }
 catch (e)
 {
 alert("Error is :" + e);
 }
} 

//get file path from client system
function getNameFromPath(strFilepath)
{
 var objRE = new RegExp(/([^\/\\]+)$/);
 var strName = objRE.exec(strFilepath);

 if (strName == null)
 {
 return null;
 }
 else
 {
 return strName[0];
 }
} 

$("#btnSubmit").live("click", function ()
{
 if ($('#fileToUpload').val() == "")
 {
 $("#spanfile").html("Please upload file");
 return false;
 }
 else
 {
 return checkfile();
 }
}); 

function checkfile()
{
 var file = getNameFromPath($("#fileToUpload").val());
 if (file != null)
 {
 var extension = file.substr((file.lastIndexOf('.') + 1));
 // alert(extension);
 switch (extension) {
 case 'jpg':
 case 'png':
 case 'gif':
 case 'pdf':
 flag = true;
 break;
 default:
 flag = false;
 }
 }
 if (flag == false)
 {
 $("#spanfile").text("You can upload only jpg,png,gif,pdf extension file");
 return false;
 }
 else
 {
 var size = GetFileSize('fileToUpload');
 if (size > 3)
 {
 $("#spanfile").text("You can upload file up to 3 MB");
 return false;
 }
 else
 {
 $("#spanfile").text("");
 }
 }
} 

$(function ()
{
 $("#fileToUpload").change(function () {
 checkfile();});
});
</script>

3. Controller's action for receiving the posted file

[HttpPost]
public ActionResult FileUpload(HttpPostedFileBase file)
{
 if (ModelState.IsValid)
 {
 if (file == null)
 {
 ModelState.AddModelError("File", "Please Upload Your file");
 }
 else if (file.ContentLength > 0)
 {
 int MaxContentLength = 1024 * 1024 * 3; //3 MB
 string[] AllowedFileExtensions = new string[] { ".jpg", ".gif", ".png", ".pdf" };

 if (!AllowedFileExtensions.Contains(file.FileName.Substring(file.FileName.LastIndexOf('.'))))
 {
 ModelState.AddModelError("File", "Please file of type: " + string.Join(", ",
AllowedFileExtensions));
 }

 else if (file.ContentLength > MaxContentLength)
 {
 ModelState.AddModelError("File", "Your file is too large, maximum allowed size is: " + MaxContentLength + " MB");
 }
 else
 {
 //TO:DO
 var fileName = Path.GetFileName(file.FileName);
 var path = Path.Combine(Server.MapPath("~/Content/Upload"), fileName);
 file.SaveAs(path);
 ModelState.Clear();
 ViewBag.Message = "File uploaded successfully";
 }
 }
 }
 return View();
}

How it Works

 



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 :: Bundling and Minification of JavaScript and CSS ASP.NET MVC 4

clock February 8, 2013 05:32 by author Scott

ASP.NET MVC 4 beta has built in minification, which reduces the number of requests and general payload size, resulting in faster and better performing applications.

This feature allows you can create custom bundles where you specify the resource name and order of your stylesheets and JavaScript files.

Introducing ASP.NET MVC 4 BundleTables

Upon creating a new project in ASP.NET MVC 4, you'll notice that your default _Layout.cshtml file will reference System.Web.Optimization and BundleTable.Bundles in its head.

According to Microsoft, these references are for the beta and will be accessed via a helper in the RTM release, expected sometime next quarter.

<link href="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Content/css")" rel="stylesheet" type="text/css" />
<link href="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Content/themes/base/css")" rel="stylesheet"    type="text/css" />
<script src="@System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl("~/Scripts/js")"></script>

If you look at the actual source code in the browser, you will see these get rendered as:

<link href="/Content/css?v=x" rel="stylesheet" type="text/css" />
<link href="/Content/themes/base/css?v=y" rel="stylesheet" type="text/css" />
<script src="/Scripts/js?v=z"></script>

The CSS and JavaScript files in this project are minified and compressed and the querystring parameter, v, is a hash of the current files being served. This will change when you alter your .js and .css files.



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