Remote validation in MVC3 : simple way to pass the form value from custom view model to controller via Remote Attribute

There are so many article on web about the remote validation in MVC3. But I didn’t find the right article to get the perfect solution for my project. I just spend a week  to solve it by my own idea and it works like a charm. You are thinking what’s the problem as remote validation is so easy in MVC3. That’s right, but if you need to do remote validation against more then one parameter as well any type of value from form then, this article will help you a lot to make you job done perfectly.

This article covered the following topics:

  • What I want to do?
  • What I did and save my hair loss?
  • Is there any alternates?

What I want to do?

What want to do?

As per above picture, I want to send the bo_account_id, bo_account_no and hidden value of FormType to controller to check that bo_account_no is exist or not. This doesBoExist method will work for both create and edit view. That’s way I use hidden value as ‘create’ at create view and ‘edit’ at edit view. In case of bo_account_id, at create view it will send null value and edit view it will send bo account no of which data want to edit.

What I did and save my hair loss?

BO Model

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

namespace StockPortfolio.Models
{
    [MetadataType(typeof(BO_Validation))]
    [Bind(Include = "vBONo,vBrokerID,vInvestorID,nCommision")]
    public partial class BO
    {
        public string FormType { get; set; }

        public BO()
        {
        }
    }
    public class BO_Validation
    {
        [Key]
        [HiddenInput(DisplayValue = false)]
        public string vBOID { get; set; }

        [Required]
        [Display(Name = "BO Account NO")]
        [Remote("doesBoExist", "BO", AdditionalFields = "FormType,vBOID", HttpMethod = "POST", ErrorMessage = "BO account no already exists. Please enter a different BO account no.")]
        public string vBONo { get; set; }

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

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

        [Required]
        [Range(0.01,1)]
        [Display(Name = "Commision")]
        public decimal nCommision { get; set; }

    }

}

BOCreate Model

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

namespace StockPortfolio.Models
{
    [Bind(Exclude = "SelectedStockExchange")]
    public class BOCreate
    {
        stock_sadequeEntities db = new stock_sadequeEntities();

        public BO bo { get; set; }
        public IEnumerable<SelectListItem> StockExchange { get; set; }
        public IEnumerable<SelectListItem> BrokerSelect { get; set; }
        public IEnumerable<SelectListItem> InvestorSelect { get; set; }

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

        public BOCreate()
        {
        }

        public BOCreate(BO boes)
        {
            this.bo = boes;

            var queryA = db.StockExchanges.Select(c => new SelectListItem
            {
                Value = c.vStockExchangeID,
                Text = c.vStockExchangeName,
            });
            StockExchange = queryA.AsEnumerable();

            var queryB = db.Brokers.Select(c => new SelectListItem
            {
                Value = c.vBrokerID,
                Text = c.vBrokerName,
            }).Where(u => u.Value == bo.vBrokerID);
            BrokerSelect = queryB.AsEnumerable();

            var queryC = db.Investors.Select(c => new SelectListItem
            {
                Value = c.vInvestorID,
                Text = c.vInvestorName,
            });
            InvestorSelect = queryC.AsEnumerable();

        }
    }
}

BOController (Due to some security issue of my project I didn’t post all the code of this controller, but below code is enough to understand the concept)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using StockPortfolio.Models;
using StockPortfolio.Models.BOFolder;
using System.Web.Script.Serialization;
using MvcPaging;

namespace StockPortfolio.Controllers
{
    public class BOController : Controller
    {
        IBORepository BORepository;

        [HttpPost]
        public JsonResult doesBoExist(FormCollection parm)
        {
            BO bo = BORepository.GetBOByName(parm["bo.vBONo"], parm["bo.FormType"], parm["bo.vBOID"]);
            return Json(bo == null);
        }
    }
}

Create view (Due to some security issue of my project I didn’t post all the code of this view, but below code is enough to understand the concept)

@model StockPortfolio.Models.BOCreate

@{
    ViewBag.Title = "Create New BO Account";
}

<div class="row">
    <div class = "span8 offset2">
        <h1>Create New BO Account</h1>
        <hr />

        @if (!Html.ViewData.ModelState.IsValid)
        {
        <div class="alert alert-error">
          <a class="close" data-dismiss="alert">×</a>
          Incomplete data found. Please correct the errors and try again.
        </div>
        }

        @using (Html.BeginForm("Create", "BO", FormMethod.Post, new { @class = "form-horizontal", id = "BOform" })) 
        {
            <fieldset>
                @Html.HiddenFor(model => model.bo.FormType)

                <div class="control-group">
                    <label class="control-label" for="focusedInput">@Html.LabelFor(model => model.bo.vBONo)</label> 
                    <div class="controls">
                        @Html.TextBoxFor(model => model.bo.vBONo)
                        <span class="help-inline">@Html.ValidationMessageFor(model => model.bo.vBONo)</span>
                    </div>
                </div>
                <div class="form-actions">
                    <input type="submit" class="btn btn-primary" value="Create" /> 
                </div>
            </fieldset>
        }
        <P>@Html.ActionLink("Back to List", "Index")</P>
    </div>
</div>

I post all the required code. Now I will point the important code from above.

  1. FormType is created at BO model. (See BO Model [Line – 14])
  2. Use a remote validation attribute with required data. It contains AddtionalFields as FormType and vBOID (see BO Model [Line – 28])
  3. create a custom model with the object of BO and three SelectListItem StockExchange, BrokerSelect and InvestorSelect. This model is used for view. (see BOCreate Model [Line – 15 to 18])
  4. create a doesBoExist method with FormCollection parameter and pickup the individual data from parameter as parm["bo.vBONo"], parm["bo.FormType"], parm["bo.vBOID"] and that’s the main trick. (see BOController [Line – 20])

and that’s all.

Is there any alternates?

If you know any alternatives, please let us know.

This article is selected by ASP.NET and marked as Article of the Day.

RenderBody, RenderPage and RenderSection methods in MVC 3

In this article we will learn about the three methods of MVC 3 and those are RenderBody, RenderPage and RenderSection.  We will learn by the following topics:

  • RenderBody
    • What is RenderBody?
    • How RenderBodyworks?
    • RenderBody Example
  • RenderPage
    • What is RenderPage?
    • How RenderPageworks?
    • RenderPage Example
  • RenderSection
    • What is RenderPage?
    • How RenderPageworks?
    • RenderPage Example

Now go to in detail…

RenderBody

What is RenderBody?

In layout pages, renders the portion of a content page that is not within a named section. [MSDN]

How RenderBody Works (graphical presentation)?

RenderBody

RenderBody Example

It’s simple. Just create a ASP.NET MVC 3 web application by visual studio 2010. After creating this application, you will see that some files and folders are created by default. After that open the _layout.cshtml file from views/Shared folder.  Basically this file will be used as a standard layout for all the page in project. Keep in mind that you can create more then one layout page in a application and to use layout page in other page is optional. _layout.cshtml file consist the following code.

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
</head>
<body>
    <div class="page">
        <div id="header">
            <div id="title">
                <h1>My MVC Application</h1>
            </div>
            <div id="logindisplay">
                @Html.Partial("_LogOnPartial")
            </div>
            <div id="menucontainer">
                <ul id="menu">
                    <li>@Html.ActionLink("Home", "Index", "Home")</li>
                    <li>@Html.ActionLink("About", "About", "Home")</li>
                </ul>
            </div>
        </div>
        <div id="main">
            @RenderBody()
        </div>
        <div id="footer">
        </div>
    </div>
</body>
</html>

Now open another file called index.cshtml from views/home. This file consist the following code.

@{
    ViewBag.Title = "Home Page";
}

<h2>@ViewBag.Message</h2>
<p>
    To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>

Main thing is that by the above code you couldn’t find which layout page is being used by this index page. But there is little tricks done at MVC3. You will get a file called _ViewStart.cshtml at views folder. This file consist of  following code.

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

This code means that by default all the content pages will follow the _Layout.cshtml layout page.  Now if we consolidate the _layout.cshtml and index.cshtml page both, we will get the following code.

<!DOCTYPE html>
<html>
<head>
<title>Home Page</title>
<link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
</head>
<body>
<div class="page">
<div id="header">
<div id="title">
<h1>My MVC Application</h1>
</div>
<div id="logindisplay">
@Html.Partial("_LogOnPartial")
</div>
<div id="menucontainer">
<ul id="menu">
<li>@Html.ActionLink("Home", "Index", "Home")</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
</ul>
</div>
</div>
<div id="main"><h2>@ViewBag.Message</h2>
<p>
To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>
</div>
<div id="footer">
</div>
</div>
</body>
</html>

It’s nothing complicated, it’s just replacing the code of RenderBody() of layout page by the code of content page.

if you want to use different layout for different content pages, then create a layout page as like _Layout.cshtml and just copy below code to your desired content page.

@{
Layout = "another layout page";
}

RenderPage

What is RenderPage?

Renders the content of one page within another page. [MSDN] The page where you will place the content could be layout or normal page.

How RenderPage Works (graphical presentation)?

RenderPage

RenderPage Example

Create a page called _StaticRenderPage at Views/Shared folder. Open it and paste the below code.

<p>
This messge from render page.
</p>

Open the Index.cshtml file from Views/Home folder and paste the below code.

@RenderPage("~/Views/Shared/_StaticRenderPage.cshtml")

Now If you merge the code of _StaticRenderPage to Index.cshtml, then you will get the below code.

@{
    ViewBag.Title = "Home Page";
}

<h2>@ViewBag.Message</h2>
<p>
    To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>
<p>
This messge from render page.
</p>

If you want to pass the data by using RenderPage, then you have to use the data parameter at RenderPage. I will give another example for this. To do this, at first create a class file called AvailableUser at Models/AccountModels. Create the class with the below code.

public class AvailableUser
    {
        public string UserName { get; set; }
        public string UserPassword { get; set; }

        public static List<AvailableUser> AllUsers()
        {
            List<AvailableUser> userList = new List<AvailableUser>();

            AvailableUser user1 = new AvailableUser
            {
                UserName = "Anupam Das",
                UserPassword = "lifeisbeautiful",
            };

            AvailableUser user2 = new AvailableUser
            {
                UserName = "Chinmoy Das",
                UserPassword = "GoodTime",
            };

            userList.Add(user1);
            userList.Add(user2);

            return userList;
        }
    }

Now go to AccountController and write down the below code

public ActionResult AvailableUserList()
{
return View(MvcApplication1.Models.AvailableUser.AllUsers());
}

Create a view page called AvailableUserList.cshtml at Views/Account with the below code.

@model IEnumerable<MvcApplication1.Models.AvailableUser>

@{
ViewBag.Title = "AvailableUserList";
Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>AvailableUserList</h2>

@RenderPage("~/Views/Shared/_DisplayAllUsers.cshtml", new { AvailableUser = Model })

At last create another view page called _DisplayAllUsers at Views/Shared with the below code.

@foreach (var usr in Page.AvailableUser)
{
<text>
@usr.UserName   @usr.UserPassword <br />
</text>
}

Now run the project (Account/AvailableUserList) and see the user list which comes from AvailableUser class.

RenderSection

What is RenderSection?

In layout pages, renders the content of a named section. [MSDN]

How RenderSection Works (graphical presentation)?

RenderSection

RenderSection Example

It’s simple, just add the below code at _layout page.

@RenderSection("Bottom",false)

and add the below code at Index page.

@section Bottom{
This message form bottom.
}

That’s All. But keep in mind that if you don’t want to use the Bottom section in all page then must use the false as second parameter at RenderSection method. If you will mention it as false then it will be mandatory to put Botton section at every content page.

Download the project

Now run the project and see how it works !!!

I will be happy, if you found anything wrong or know more please share it via comments.

This article is also available at :

The Code Project

The Code Project

This article is also selected by ASP.NET and marked as Article of the Day.

Deploy MVC2 Application at IIS 5.1 (windows XP)

If you try to deploy the MVC2 application at IIS 5.1 then normally it will not work properly. It could show you the following errors.

Deploy MVC2 Application at IIS 5.1 (windows XP) Deploy MVC2 Application at IIS 5.1 (windows XP)

So what could be the ultimate solution to for this? Just Follow the below instructions and check that it works or not.

At first create a virtual directory and publish the project successfully. Then go to Internet Information Services and right click on virtual directory. Select Properties from the menu. A window will appear. Click on Configuration button.

Deploy MVC2 Application at IIS 5.1 (windows XP)

After clicking on Configuration button a Application Configuration window will appear. Now select first Application Mapping and click on Edit button. A Add/Edit Application Extension Mapping window will appear. Copy the executable location from text box. Paste it into notepad. Click on cancel button.

Deploy MVC2 Application at IIS 5.1 (windows XP)

Now click on Add button and once again Add/Edit Application Extension Mapping window will appear. Paste the executable location from notepad to executable text box. and write .* as extension. Also uncheck the Check that file exists. Now click on OK button.

Deploy MVC2 Application at IIS 5.1 (windows XP)

At last just change the ASP.NET version to 4.0 from virtual directory properties.

Now try to run the site once again. It should work.

Code encryption at MVC2

It’s been on my mind that, to encrypt all the major code of MVC project. Last night I did it. Now its time to share it with you. Lets start.

Step 01. Create a new asp.net mvc2 project and named it TestProject.

Step 02. Now you need to create a class library project. For that, select File > Add > New Project. Add New Project window will appear. Select Class Library as project type and named the project as Test.EncryptCode. Solution Explorer window will be like as below picture.

Code encryption at MVC2

Delete the Class1.cs file from Test.EncryptCode project.

Step 03. Now add all the references to Test.EncryptCode project, those references are exist in TestProject project.

Step 04. Select the AccountModels.cs file from TestProject > Models. Drag that file to Test.EncryptCode project. Delete the AccountModels.cs file from TestProject project. Now Solution Explorer window will be like as below picture.

Code encryption at MVC2

Step 04. Now change the AccountsModels namespace as Test.EncryptCode. It will look like below picture.

Code encryption at MVC2

Now build the Test.EncryptCode project. Add the Test.EncryptCode project as reference into TestProject project. We can add it by using project > add reference menu. A Reference window will appear and select the Test.EncryptCode from project tab

Code encryption at MVC2

Open AccountController.cs file and change the TestProject.Models namespace to Test.EncryptCode.

Now open the ChangePassword.aspx, LogOn.aspx and Register.aspx file. just change the TestProject.Models to Test.EncryptCode in inherits property. The code will be like as below.

ChangePassword.aspx

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Test.EncryptCode.ChangePasswordModel>" %>

Register.aspx

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Test.EncryptCode.RegisterModel>" %>

LogOn.aspx

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Test.EncryptCode.LogOnModel>" %>

 

Now run the project and see it works!

Download Code

This article is also available at :

The Code Project

The Code Project