Saturday, 17 March 2012

Asp.net mvc using AutoMapper simplified.

Most of the time in the real world applications it is not possible to map the database model to your presentation view directly because of the fact you may need some additional fields in your view. Using view Data or Viewbag is not always the good idea as it may make things harder or less elegant which are much easier to do.

We are creating the User create view as an example here in which confirm password field is additional field in the view and it has nothing to do with the database model. So in this case you would create one model for the database fields as usual and one extra model for the view. The problem is that in the controller you have to map each property from your model for the database to the model for the view manually which shouldn't be done because it is not a good practice as there is a tool for that. The third party tool the Automapper solves this problem by automatically mapping your view model which you get from the view in the controller to the database model.


User Table

UserName varchar(50)
password varchar(50)

User Model or database model
    public class User
    {
        public string UserName
        {
            get;
            set;
        }

        public string Password
        {
            get;
            set;
        }
    }
UserView Model for the presentation view
    public class UserView
    {
        [Required(ErrorMessage = "UserName Required")]
        public string UserName
        {
            get;
            set;
        }

        [Required(ErrorMessage = "Password Required")]
        public string Password
        {
            get;
            set;
        }

        [Compare("Password")]
        public string ConfirmPassword
        {
            get;
            set;
        }
    }
The generated view in which the model specified is the Userview not the User.

@model MvcApplication22.Models.UserView
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <title>Creates</title>
</head>
<body>
    <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
    @using (Html.BeginForm()) {
        @Html.ValidationSummary(true)
        <fieldset>
           
    
            <div class="editor-label">
                @Html.LabelFor(model => model.UserName)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.UserName)
                @Html.ValidationMessageFor(model => model.UserName)
            </div>
    
            <div class="editor-label">
                @Html.LabelFor(model => model.Password)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.Password)
                @Html.ValidationMessageFor(model => model.Password)
            </div>
    
            <div class="editor-label">
                @Html.LabelFor(model => model.ConfirmPassword)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.ConfirmPassword)
                @Html.ValidationMessageFor(model => model.ConfirmPassword)
            </div>
    
            <p>
                <input type="submit" value="Create" />
            </p>
        </fieldset>
    }
    
    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>
</body>
</html>


Below is the code without Automapper which is not a good practise.Two fields are not the problem but imagine having 15 fields to map which will be quite a task, the number of line will increase also the possibility of an error.

    public ActionResult Creates()
    {
         UserView UserViewModel = new UserView();
         return View("Creates",UserViewModel);
    }

    [HttpPost]
    public ActionResult Creates(UserView UserView)
    {
        // Valdations

        if (ModelState.IsValid)
        {
          User User = new User();
          User.UserName = UserView.UserName;
          User.Password = UserView.Password;
                          
          // Create User code            
        }
        return View();
    }
Now finally automapper in action below.

In global.asax you have to create a map before using it in the controller.

global.asax.

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        Mapper.CreateMap<UserView, User>();
        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }


Controller.

    public ActionResult Creates()
    {
        UserView UserViewModel = new UserView();
        return View("Creates",UserViewModel);
    }

    [HttpPost]
    public ActionResult Creates(UserView UserView)
    {
        // Valdations
        if (ModelState.IsValid)
        {
           User User = new User();
           //  User.UserName = UserView.UserName;
           //  User.Password = UserView.Password;
           AutoMapper.Mapper.Map(UserView, User);
                          
           // Create User code            
         }
         return View();
     }    

No comments:

Post a Comment