Introduction
This is the quick start to the MVC project. Login form is the first part of every project. There are several ways to create login functionality. I will demonstrate one of them and build basic MVC3 project structure so you can enhanced based on your project requirement.
Answer
Let's look at the project structure. I have create
MVC3
empty project. I have database name Student
in
App_Data
folder. I have created ADO.NET entity
data model
name Student_db.edmx
as my Model
in Model folder of MVC
.
Add controller
Home
and create action
name index. Create index View
. Index is the startup page of our
website. Open Global.asax
contain RegisterRoutes
method as fellow.
public static void RegisterRoutes(RouteCollection routes)<br /> {<br /> routes.IgnoreRoute("{resource}.axd/{*pathInfo}");<br /> routes.MapRoute(<br /> "Default",
RegisterRoutes
is static method which get called in Application_Start
event. RegisterRoutes
accept RouteCollection
object as parameter and call MapRoute
method of RouteCollection
class. MapRoute
method has overload that accept route name, url with parameters and default parameter to url. Controller
Home and action
Index is specified as the default parameter to url this set our startup page.
I have designed indexpage as fellow.
LogIn is anchor tag which navigate to the Login page.
I have designed login page as fellow.
Here is trick, on click of the LogIn link instead of navigating to the login page we will display login page as popup as fellow.
Let's look at the IndexView closely.
I have use ajax
helper method to create LogIn action link. On click on LogIn link it call to the
controller action asynchronously and render the return view into the
updateTargetControllId
.
I have set updateTargetControllId
to the id of div tag hence
the return partial view get render inside the div. I have use JQuery plugin name
bpopup to display div as popup.
Ajax
Helper method to use Ajax
helper method you need to add following Jquery into you page. I have chosen min
version due to its lightweight nature.
<script src="@Url.Content("../../Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script><br /><script src="@Url.Content("../../Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
You can use ajax
helper method by using @Ajax.
syntax. I have perform Ajax
call using LogIn action link.
<li class="nav"><br /> @Ajax.ActionLink("Login", "Login", new { area="" }, new AjaxOptions() { UpdateTargetId = "loginView" }, new { id = "lnkLogin", @class="nav" })<br /></li> <br /> <h2>Home Page</h2><br /> <h2>Some site description!!!!</h2><br /><br /><br /><div id="loginView" class="white_content"><br /></div>
I have added css class nav
to provide menu item look to the
action link. Action link LogIn call to the Home controller Login action and
render the return partial view into the div with id loginView.
<div id="loginView" class="white_content"><br /></div>
Login View Login View consist of form contain the label
and textbox for username
and password
with button to submit the form . I have
created Login as the partial view
as it is get render into the Index View
. Login is a partial strongly type View
of type ViewModel
class. For each strongly type View
I have created ViewModel
class. A ViewModel represents data that you want to displayed on your view/page
.
@model LoginScreenDemo.ViewModel.LoginVM
<div id="pnl_Login">
@using (Ajax.BeginForm("Login", "Home", new { area = "" }
, new AjaxOptions { UpdateTargetId = "error_message", OnSuccess = "RedirectToUrl", OnFailure = "OnFailuar", OnBegin = "validateForm" }, new { method = FormMethod.Post }))
{
<table border="0">
<tr>
<td>
@Html.LabelFor(Model => Model.LoginName)
</td>
<td>
@Html.TextBoxFor(Model => Model.LoginName)
</td>
<td>
@Html.ValidationMessageFor(Model => Model.LoginName, "*")
</td>
</tr>
<tr>
<td>
@Html.LabelFor(Model => Model.Password)
</td>
<td>
@Html.PasswordFor(Model => Model.Password)
</td>
<td>
@Html.ValidationMessageFor(Model => Model.Password, "*")<br />
</td>
</tr>
<tr>
<td>
</td>
<td>
<input type="submit" value="Login" />
<input type="button" value="Cancle" class="loginClose" />
</td>
<td>
</td>
</tr>
</table>
<div id="error_message">
@Html.ValidationSummary(true)
</div>
}
</div>
Javascript to handle AjaxForm
OnSuccess
and OnFailuar
methods.
<script>
function RedirectToUrl(Result) {
if (Result == 1)
window.open("/Home/SiteMap", "_self");
else
$("#loginView").html(Result);
}
function OnFailuar(exMessage) {
$("#error_message").html(exMessage);
}
function validateForm() {
}
</script>
Object of ViewModel
get filled into the controller
action
method
and pass to the View
. Controller
action
method
perform call to its
Manager class (Business class)
to fill the ViewModel
object.
Each strongly type View
is of type ViewModel
class and have a Action
Method
. Action
Method
transfer ViewModel
object to the View
. Action
method
call
method of it's Manager
class
method to fill ViewModel
object. Manager
Class
interact with the
database i.e. with the entity model and provide mapping between one or more
entity object to the ViewModel
Object.
LoginManager class [Manager Class
] contain the logic to interact with database and return the result.
public class LoginManager:BaseManager
{
public string RollName {get;set;}
public bool ValidateLogin(LoginVM loginContext)
{
var result= (from login in studentContext.tblLogins
where login.LoginName == loginContext.LoginName && login.Password == loginContext.Password
select new { login.Role, login.LoginName}).FirstOrDefault();
if (result.LoginName == null)
{
return false;
}
RollName = result.Role;
return true;
}
public string GetRole(string userName)
{
return (from login in studentContext.tblLogins
where login.LoginName ==userName
select login.Role).FirstOrDefault();
}
}
In general Manager class
contain the function to fetch data, insert data and update data.
Fetch data function will fetch the data from database and fill the ViewModel
object and return to the action method. Where insert and update perform the insert and update on the database in our case using entity framework
.
LoginVM class [ViewModel class
] each View
is directly map with the ViewModel
or with IEnumerable<ViewModel>
to provide collection of ViewModel
in View
. Each strongly type View
is of type ViewModel
or IEnumerable<ViewModel>
. ViewModel
contain property that are related to one or more entities form the entity set. Like LoginName
might be present in entity class tblNameMaster
where Password
might be present in entity class tblRecordMaster
. Where tblNameMaster
and tblRecordMaster
are directly map with database table object schema.
Note :- In code first approach you can create entity and form the entity you will generate database schema.
public class LoginVM:BaseVM
{
[Required(ErrorMessage="Please enter valid user name.")]
public string LoginName { get; set; }
[Required(ErrorMessage="Please enter valid password.")]
public string Password { get; set; }
}
LoginVM class
use using
System.ComponentModel.DataAnnotations
namespace
to provide validation for
the property LoginName
and Password
for time being I have use the data annotation Required()
attribute to indicate that LoginName
and Password
can not be kept null.
If you look at the Login view you will notice the following code.
@Html.ValidationMessageFor(Model =>Model.LoginName, "*")
@Html.ValidationMessageFor(Model=> Model.Password, "*")
@Html.ValidationSummary(true)
@Html.VlaidationMessageFor
helper classes help us to provide
the inline validation message for.
@ValidationSummary
method displays a list of all validation
messages on the page.
When the View
is rendered, the validation messages and
validation summary
are displayed based on the Errors property of the ModelState
object.
Following are the JavaScript
that help us to provide client
side validation message.
<script src="@Url.Content("../../Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("../../Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
Jquery.validate.min.js
contain the validation logic where
the jquery.validate.unobtrusive.js
remove inline jquery code and provide some
nice attribute to call it. If you notice the web.config of the project you will notice
following keys that help to enable client side validation
.
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
Please read following codeproject articulate to get more knowledge about
the validation in MVC.
http://www.codeproject.com/Articles/249452/ASP-NET-MVC3-Validation-Basic
User
put credential into the login popup. Valid user will be redirect to the Sitemap
page
. If user is invalid appropriate message get display. Once user login let’s
identify role of the user. Based on the role provided to user, user will grant permission to access page. If user do not have permission to access page he will get redirect to the login page. I have use custom role base form authentication.
I
have added following code to web.config
to enable form authentication.
<authentication mode="Forms">
<forms loginUrl="/Home/Index" timeout="2880" />
</authentication>
Login
URL indicate URL where user will redirect if he is not authenticated.
I
have also overridden the method FormsAuthentication_OnAuthenticate
in the Global.asax
file.
protected void FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string roles = string.Empty;
LoginScreenDemo.Business.LoginManager loginManager = new Business.LoginManager();
roles = loginManager.GetRole(username);
e.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal
.GenericIdentity(username, "Forms"), roles.Split(';'));
}
catch (Exception)
{
}
}
}
I have created GenericPrincipal
object
and set our user specific details (Username and Role) into it. Please go through
the following article on how to create custom form authentication in MVC. http://www.codeproject.com/Articles/578374/AplusBeginner-27splusTutorialplusonplusCustomplusF
I have created two areas [organizer and monitor] that
indicate the student role in the project. You can create area by selecting
project name, right click -> Add -> Area
, and assign a name to the new
area, when the area creation ends, we see a new folder called Areas, and within
this folder you can see a folder with the name of your area. Area content same
file structure as you project has you can visualize area as the child project
within you parent MVC
project.
Lot time we face situation where we
want to navigate to different section from one parent section. For better user
experience let’s create parent section as the View
and all the related section
as the Partial View
and render them into parent section based on the
requirement.
@{
Layout = "~/Views/Shared/_Layout1.cshtml";
ViewBag.Title = "Monitor";
}
<h2>
Moniter Task.</h2>
<div class="nav">
<ul class="nav">
<li class="nav">
@Html.ActionLink("Site Map", "SiteMap", "Home", new { area = "" }, new { @class = "nav" })
</li>
<li class="nav">
@Ajax.ActionLink("Task1", "Task1", "Home", new { Area = "Moniter" }, new AjaxOptions { UpdateTargetId = "body_content" }, new { @class = "nav" })
</li>
<li class="nav">
@Ajax.ActionLink("Task2", "Task2", "Home", new { Area = "Moniter" }, new AjaxOptions { UpdateTargetId = "body_content" }, new { @class = "nav" })
</li>
</ul>
</div>
<div id="body_content">
</div>
Notice the area
Monitor it contain parent view as the Index View
. Index view contain navigation bar to the page related to the Monitor task. For better UI experience instead of navigating to the related pages I have created Partial View
and PartialViewResult
. where navigation link is the @ajax.actionlink
that render the Partial View
into the same page.
On the click of the task1 link, ajax
actionlink call to the Partial View
action
task1 and get Partial View
as return. It render Partial View
inside the element having id specified as the update target control id.
Using the same logic I have created other area
controller
action
. When you are developing actual project you will have complex logic instead of this simple "Task One Begin.." message inside you Partial View
.
Please look into the attached code for more clearity. Hope this will kick start your application development.