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 Hosting - HostForLIFE.eu :: Custom Model Binders in ASP.NET MVC

clock December 22, 2016 06:31 by author Scott

In ASP.NET MVC, our system is built such that the interactions with the user are handled through Actions on our Controllers. We select our actions based on the route the user is using, which is a fancy way of saying that we base it on a pattern found in the URL they’re using. If we were on a page editing an object and we clicked the save button we would be sending the data to a URL somewhat like this one.

Notice that in our route that we have specified the name of the object that we’re trying to save. There is a default Model Binder for this in MVC that will take the form data that we’re sending and bind it to a CLR objects for us to use in our action. The standard Edit action on a controller looks like this.

[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
    try
    {
        // TODO: Add update logic here
 
        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

If we were to flesh some of this out the way it’s set up here, we would have code that looked a bit like this.

[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
    try
    {
        Profile profile = _profileRepository.GetProfileById(id);

        profile.FavoriteColor = collection["favorite_color"];
        profile.FavoriteBoardGame = collection["FavoriteBoardGame"];

        _profileRepository.Add(profile);

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

What is bad about this is that we are accessing the FormCollection object which is messy and brittle. Once we start testing this code it means that we are going to be repeating code similar to this elsewhere. In our tests we will need to create objects using these magic strings. What this means is that we are now making our code brittle. If we change the string that is required for this we will have to go through our code correcting them. We will also have to find them in our tests or our tests will fail. This is bad. What we should do instead is have these only appear on one place, our model binder. Then all the code we test is using CLR objects that get compile-time checking. To create our Custom Model Binder this is all we need to do is write some code like this.

public class ProfileModelBinder : IModelBinder
{
    ProfileRepository _profileRepository = new ProfileRepository();

    public object BindModel(ControllerContext controllerContext,
        ModelBindingContext bindingContext)
    {
        int id = (int)controllerContext.RouteData.Values["Id"];
        Profile profile = _profileRepository.GetProfileById(id);

        profile.FavoriteColor = bindingContext
            .ValueProvider
            .GetValue("favorite_color")
            .ToString();


        profile.FavoriteBoardGame = bindingContext
            .ValueProvider
            .GetValue("FavoriteBoardGame")
            .ToString();

        return profile;
    }
}

Notice that we are using the form collection here, but it is limited to this one location. When we test we will just have to pass in the Profile object to our action, which means that we don’t have to worry about these magic strings as much, and we’re also not getting into the situation where our code becomes so brittle that our tests inhibit change. The last thing we need to do is tell MVC that when it is supposed to create a Profile object that it is supposed to use this model binder. To do this, we just need to Add our binder to the collection of binders in the Application_Start method of our GLobal.ascx.cs file. It’s done like this. We say that this binder is for objects of type Profile and give it a binder to use.

ModelBinders.Binders.Add(typeof (Profile), new ProfileModelBinder());

Now we have a model binder that should let us keep the messy code out of our controllers. Now our controller action looks like this.

[HttpPost]
public ActionResult Edit(Profile profile)
{
    try
    {
        _profileRepository.Add(profile);

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

That looks a lot cleaner to me, and if there were other things I needed to do during that action, I could do them without all of the ugly binding logic.

 



European ASP.NET MVC Hosting - UK :: Tips Using BindAttribute in ASP.NET MVC

clock March 3, 2015 06:21 by author Scott

The Bind attribute is used to protect against over-posting. Represents an attribute that is used to provide details about how model binding to a parameter should occur.

Let’s take an example of Employee Controller which creates the records for employee basic information.

This code adds the Employee entity created by the ASP.NET MVC model binder to the Employees entity set and then saves the changes to the database.

The ValidateAntiForgeryToken attribute helps prevent cross-site request forgery attacks.

EmployeeController.cs –> Create

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(
   [Bind(Include = "FirstName, LastName, JoiningDate")]
   Employee employee)
{
   try
   {
      if (ModelState.IsValid)
      {
         db.Employees.Add(employee);
         db.SaveChanges();
         return RedirectToAction("Index");
      }
   }
   catch (DataException ex)
   {
      //Log the error
      ModelState.AddModelError("", "Unable to save. Try again.");
   }
   return View(employee);
}

Employee.cs

public class Employee
   {
      public int ID { get; set; }
      public string LastName { get; set; }
      public string FirstName { get; set; }
      public DateTime JoiningDate { get; set; }
      public string City { get; set; }

    }

For example, suppose the Employee entity includes a City property that you don’t want this web page to update. Even if you don’t have a City field on the web page, a hacker could use a tool such as fiddler, or write some JavaScript, to post a City form value. Without the Bind attribute limiting the fields that the model binder uses when it creates an Employee instance, the model binder would pick up that City form value and use it to update the Employee entity instance. Then whatever value the hacker specified for the City form field would be updated in your database.

It’s a security best practice to use the Include parameter with the Bind attribute to whitelist fields. It’s also possible to use the Exclude parameter to blacklist fields you want to exclude. The reason Include is more secure is that when you add a new property to the entity, the new field is not automatically protected by an Exclude list.

Another alternative approach, and one preferred by many, is to use only view models with model binding. The view model contains only the properties you want to bind. Once the MVC model binder has finished, you copy the view model properties to the entity instance.



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