Tuesday, 8 May 2012

Entity Framework many to many relationship.

In this post I will be demonstrating how you can create many to many relationship between classes by using EF code first approach with DataAnnotation attributes. You can use the EF fluent API as well for many to many configuration which I have not covered here. I will be using the classes post and tag in my model which has many to many relationship between them i.e a single post can have many tags and a single tag can have many posts.

To get started with many to many configuration between the post and the tag you have to create the classes first. The EF will automatically create the third table when the application will execute, so you will not be creating the third table manually in the model. Let's get started with the code.
   public class Post
   {
     public long PostID { get; set; }

     [Required]
     [MaxLength(255)]
     public string Title { get; set; }

     [Required]
     [MaxLength(4000)]
     [DataType(DataType.MultilineText)]
     public string Question { get; set; }
      
     public virtual List<Tag> Tags { get; set; }
   }
  
   public class Tag
   {
     public long TagID { get; set; }

     [Required]
     [Display(Name = "Tag Name")]
     [MaxLength(30)]
     public string TagName { get; set; }

     public bool IsActive { get; set; }

     public virtual List<Post> Posts { get; set; }
   }
The Dbcontext class is below, without it there is no code first approach.
  
    public class ForumContext : DbContext
    {
      public DbSet<Post> Posts { get; set; }
      public DbSet<Tag> Tags { get; set; }
    }
   
Specify the connection string here in the web.comfig file otherwise the database will be created in the express edition of the sql server.
 <add name="ForumContext" connectionString="Data Source=localhost;Initial Catalog=test;Persist Security Info=True;User ID=sa;Password=xxxx"providerName="System.Data.SqlClient" /> 
  
After that Initialize the test data for the model.
public class foruminitializer : DropCreateDatabaseIfModelChanges<ForumContext>
   {
        protected override void Seed(ForumContext context)
        {
            var Posts = new List<Post>
            {
             new Post { Question = "abc" , Title = "abctitle" ,  Tags = new List<Tag>()},
             new Post { Question = "abc1", Title = "abctitle1",  Tags = new List<Tag>()},
             new Post { Question = "abc2", Title = "abctitle2",  Tags = new List<Tag>()}
             
            };
            Posts.ForEach(s => context.Posts.Add(s));
            var Tags = new List<Tag>
            {
                new Tag { TagName = "tag1",  IsActive=true,  Posts= new List<Post>()},
                new Tag { TagName = "tag2",  IsActive=true,  Posts= new List<Post>()},
                new Tag { TagName = "tag3",  IsActive=true,  Posts= new List<Post>()}
            };

              Tags.ForEach(s => context.Tags.Add(s));
              Posts[0].Tags.Add(Tags[0]);
              Posts[1].Tags.Add(Tags[0]);
              Posts[1].Tags.Add(Tags[1]);
              Posts[1].Tags.Add(Tags[2]);
              Posts[2].Tags.Add(Tags[0]);
              Posts[2].Tags.Add(Tags[1]);
              context.SaveChanges();
        }
    }
Next step is to inform EF to execute the above foruminitializer class to populate the data when the application runs. This will all be done in global.asax.
   
    protected void Application_Start()
    {
       AreaRegistration.RegisterAllAreas();          
       Database.SetInitializer<ForumContext>(new foruminitializer());
       RegisterGlobalFilters(GlobalFilters.Filters);
       RegisterRoutes(RouteTable.Routes);           
    }

Final step.

Finally after running the application the EF will recognize that it is many to many relationship and apart from creating the two tables post and tag it will create a third table tagpost by joing the name of the two parent tables and both table's primary key going there as the foreign key in the table.

Note If you want to create extra fields in the tagpost table then this approach is not for you and for that there is another approach which I will not be covering here.

Querying the database.

Now after creating the database and filling it with data the next natural step is to query it. I have covered here the most common scenarios. Lot of other scenarious can be derived from them. You have to reference System.Data.Entity so that you can specify lambda expression in Include.

1) Get all posts with their tags.
     
    var allposts = context.Posts
                   .Include(p => p.Tags)
                   .ToList();

    foreach (var acc in allposts)
    {
       long postid = acc.PostID;           
       foreach (var accchild in acc.Tags)
       {
          long tagid = accchild.TagID;                        
       }                        
    } 
  
2) Get all tags of postID = 1.
 
    var posts =context.Posts.Where(p => p.PostID==1)
               .Include(p => p.Tags)
               .FirstOrDefault();                            
            
    foreach (var acc in posts.Tags)
    {
       long tagid = acc.TagID;                       
    }

3) Get all posts of tagID = 1.
   

    var tags =context.Tags.Where(p => p.TagID==2)
              .Include(p => p.Posts)
              .FirstOrDefault();                            
                  
    foreach (var acc in tags.Posts)
    {
       long postid = acc.PostID;                       
    }

4) Check to see if that tag exists in that particular post.
     
    var postsexists = from s in context.Posts 
                      from c in s.Tags
                      where s.PostID == 1 && c.TagName == "tag1"
                      select s;

    if (postsexists!=null)
    {

    }

Tuesday, 3 April 2012

Asp.net mvc 3 DataAnnotation using IValidatableObject for multiple properties.

If you have a scenario in which you want to base a validation on multiple business logics on multiple properties then you should consider using IValidatableObject. One of the advantages is that you can use the properties attributes directly which open door to a lot of validation possibilities. It will only be called when there are no individual properties error. It doesn't support clientside validation. Below is the simple code that will give you insight of how this all works.

    public class User : IValidatableObject
    {
        [Key]
        public string UserId { get; set; }
        [Required]
        public string UserName { get; set; }
        [Required]
        public string Password { get; set; }
        [Compare("Password")]
        public string ConfirmPassword { get; set; }

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            List<ValidationResult> err = new List<ValidationResult>();
            if(UserName.Equals(Password))
            {
                yield return new ValidationResult("UserName and password cannot be equal", new[] { "UserName" });
            }
        }
    }

Monday, 2 April 2012

Asp.net mvc entity framework code first appoach.

Entity Framework comes with three approaches for development.

1) Database First: In this approach you already have your database and the entity framework will generate the model for you.

2) Model First: You don't have the database in this approach and you manually create the domain model using the entity framework designer. After creating the model the designer will generate the ddl statement which will be used to create the database.

3) Code First which I am covering in this post was introduced in EF 4.1. Code first allows you to create the domain model in the code without using the designer. After that EF will be generating the database for you. This approach is used only if you don't have the database the first time. If the database exists use the first approach. So here how the things goes.
public class User
{
    [Key]
    public int UserID { get; set; }
    [Required]
    public string UserName { get; set; }
    [Required]
    public string Password { get; set; }
    [MaxLength(30)]
    public string EmailAddress { get; set; }
  
}


The above class has no value on it's own . In order to take part in the database generation you have to create the context class.

public class UserContext: DbContext
{
     public DbSet<User> Users { get; set; }
}


Then the controller class.

public ViewResult Index()
{
    return View(db.Users.ToList());
}

Running the application the first time.

Now the thing is that you have to run the application for the first time i.e query the database as done in the Index ActionMethod to generate the database. There are two possibilities here if it finds the connection string with the name UserContext in the web.config it will generate the database there.

<add name="UserContext" connectionString="Data Source=localhost;Initial Catalog=testing2;Persist Security Info=True;User ID=sa;Password=123456" providerName="System.Data.SqlClient"/>

If not then it will generate the database in the sqlexpress installed i.e go with convention.

Running the application the second time.

After generating the database in the first try, if the model changes and you run it the second time it will generate an error. So to fix it you have to specify the strategy for EF that whenever it sees the database with the model changed then drop and recreate the database.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    Database.SetInitializer(new DropCreateDatabaseIfModelChanges<UserContext>());
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
}

Wednesday, 28 March 2012

Asp.net mvc DataAnnotation ValidateAttribute two properties comparison.

Using Datannotion is great but there are scenarious in which the current attributes compare, range etc becomes inadequate especially for the comparisions. So we create here our own custom validation using ValidationAttribute class which is the base class for all the annotation attributes. So by deriving from it and overriding the Isvalid method we can create our custom attribute for the model.

So here is the scenario in which I will be validating the Username against the password which should not be equal. Compare attribute cannot be used in this scenario so I have created a custom attribute for that. Here is the model with the attribute.

User View Model
    [CompareUserPass("UserName", "Password", ErrorMessage = "UserName and password cannot be equal")]
    public class UserView
    {
        [Required(ErrorMessage = "UserName Required")]
        public string UserName
        {
            get;
            set;
        }
        [Required(ErrorMessage = "Password Required")]
        public string Password
        {
            get;
            set;
        }
         
        public string ConfirmPassword
        {
            get;
            set;
        }
     }

Note in the model above I had covered two properties comparision here so the attribute is at the top of the class and to validate one property you specify the attribute with that property which I have not covered here.

Custom Validation attribute class
     [AttributeUsage(AttributeTargets.Class)]
     public class CompareUserPassAttribute : ValidationAttribute
     {
        private string Property1 { get; set; }
        private string Property2 { get; set; }

        public CompareUserPassAttribute(string PropertyName1, string PropertyName2)
        {
             Property1 = PropertyName1;
             Property2 = PropertyName2;
        }

        public override Boolean IsValid(Object value)
        {
            if (Property1 == null && Property2 == null)
                return true;
            else
            {
                PropertyDescriptorCollection propertiess = TypeDescriptor.GetProperties(value);
                object originalValue1 = propertiess.Find(Property1, true).GetValue(value);
                object originalValue2 = propertiess.Find(Property2, true).GetValue(value);
                if (!originalValue1.Equals(originalValue2))
                    return true;
                else
                    return false;
            }
        }
     }


View

@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>
            <legend>UserView</legend>
    
            <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>

Thursday, 22 March 2012

Asp.net mvc model binding security.

One of the thing that makes asp.net.mvc so interesting is default model binding. Model binding in simple words allows you to take the posted form data from the view and bind it to the action method's parameter in the controller without any fuss. But there is a security flaw in model binding which everyone using asp.net mvc should know .The problem is, in asp.net mvc controller you cannot be sure what you got as the posted value from the view because it is absolutely possible that an extra property, or an overwritten property which you don't want get passed to the controller which could spell disaster. And in the controller if the property matches the orginal property then the things could get out of hand.

Here's a simple scenario to understand more what I have defined. A person filling a create user form to become the member of the website requiring some payment in the process passed an Isenabled=true property (which we all have) and unfortunately there is a match in the model at the controller and you haven't defined any whitelist properties (which are included at the controller) or any black listed properties which (which we excluded at the controller) then the user will automatically become active. The cycle which was to be followed was that the moderator after viewing if everything was right and the payment is successfully accepted was going to enable him. So there is a voilation of that cycle.


Tools

You can create the scenario by using firebug.

Solution

By using Include or Exclude in the Bind Attribute class we can lock the properties that are allowed in the model.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateUser([Bind(Include="UserName, Password,ConfirmPassword EmailAddress")] UserView User)
If there are large quantity of fields you have the option to use exclude to restrict the properties.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateUser([Bind(Exclude="IsEnabled")] UserView User)
Other option
   [Bind(Exclude="GroupID")]
    public class Group
    { 
        [Key]
        public int GroupID { get; set; }

        [Required]
        [Display(Name = "Group Name")]
        [StringLength(50)]
        public string GroupName { get; set; }
        [ScaffoldColumn(false)]
        public DateTime? CreatedDate { get; set; }
        [ScaffoldColumn(false)]
        public DateTime? ModifiedDate { get; set; }
    }

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();
     }    

Tuesday, 28 February 2012

Asp.net mvc using JsonResult

Json has become one of the most popular form of data interchange method and being tightly integrated in the mvc framework makes it very easy to use. I will be demonstratating a very usefull technique of passing a response in an Ajax style using JsonResult (It is a class that is used in mvc framework to pass a json formatted content to the response).

Model
    public class Users
    {
       public int UserId { get; set; }
       public string UserName { get; set; }
    }

Controller
    public ActionResult Index()
    {    
       return View();
    }

    public JsonResult GetUsers()
    {
       List<Users> users = new List<Users>()
                           {
                           new Users
                           {
                           UserId =1, UserName ="kaunain"
                           }};
       return this.Json(users,JsonRequestBehavior.AllowGet);
    }

View
<script type="text/javascript" language="javascript">
    $(document).ready(function () {
        $.getJSON("/Home/GetUsers", null, function (data) {
            $.each(data, function (index, users) {
                    $("p").text(users.UserName);
            });
        });
    });
</script>


Updated view for multiple users
<script type="text/javascript" language="javascript">   
   
       $(document).ready(function () {
        $.getJSON("/Home/GetUsers", function (data) {
            var items = [];

            $.each(data, function (key, users) {
                items.push('<li id="' + users.UserId + '">' + users.UserName + '</li>');
            });

                    $('<ul/>', {
                        'class': 'Users-list',
                        html: items.join('')
                    }).appendTo('p');
               });
       });
    
 
</script>

Lastly specify Home/GetUsers route in global.asax.