Custom AuthorizeAttribute: An example

August 31st, 2011

A great feature in MVC 3 is something called annotaions. Annotations is mainly used for authorization and validation. By annotating your controllers, actions and models you get a clear seperation of validation/authorization logic and your code. The code gets cleaner, we all like that right? :)

There are bunch of built in annotations in MVC 3 like:

  • [Authorize] – Forces a user to login
  • [Required] – Makes a model property required

You can also write your own annotations which I’m about to show you.
This custom annotaion is how you can force a user to only edit, for instance, his own profile.
All you need to do is to create a class that inherits of the AuthorizeAttribute class
and override the method AuthorizeCore(HttpContextBase httpContext).

public class AuthorizeUserProfileEdit : AuthorizeAttribute
{
    private string ParamName;

    public AuthorizeUserProfileEdit(string paramName)
    {
        ParamName = paramName;
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        string userNameParam = httpContext.Request[ParamName];
        if (userNameParam.Equals(
            httpContext.User.Identity.Name,
            StringComparison.InvariantCultureIgnoreCase))
        {
            return true;
        }

        return false;
    }
}

As you can see there is not much to the code that needs exmplaining.
The constructor takes one argument that sets what paramenter name to check against.
The AuthorizeCore(HttpContextBase httpContext) then checks the value of the parameter against the currently logged in user. If it is the same the method returns true and the user is allowed to edit the profile, else the user is prompted to log in.

You then annotate your edit methods in your controller like this:

[AuthorizeUserProfileEdit("userName")]
[HttpGet]
public ActionResult Edit(string userName)
{
    ...
}

And like this in your post method:

[AuthorizeUserProfileEdit("userName")]
[HttpPost]
public ActionResult Edit(string userName, FormCollection collection)
{
    ...
}

Just supply the argument name as parameter to the annotaion and you are ready to go!
Can’t be much simplier!

Development , , ,

ASP.NET MVC 3 book tip

August 29th, 2011

I would like to recommend a book, Professional ASP.NET MVC 3, recently published and written by Jon Galloway, Phil Haack, Brad Wilsson and K. Scott Allan.
The book is a classic programmers book and teaches you the way of ASP.NET MVC 3.
The book teaches you all about controllers, views, models, some advanced topics and much more.

It’s a great book if you want to start learning MVC. It has some useful tutorials and code examples and references the MVC Music Store throughout the book.

You can find links to the authors blogs in my blogroll.

Check it out!

Development , , ,

New to ASP.NET MVC 3?

August 28th, 2011

If you are new to MVC 3 you have to go visit this site http://www.asp.net/mvc
The site have som awsome tutorials and you should specially look at the videos from pluralsight where a gentlemen named Scott Allen takes you through the basics of MVC 3.

Be sure not to miss it! :D

Development , , ,

ViewModels and updating model in ASP.NET MVC 3

August 27th, 2011

I recently been diving in to ASP.NET MVC 3 latley and quite quickley I ran in to an issue when using a ViewModel to update model data. You usually use a view model when combining data from different model objects to be shown in a view. You could put data in the ViewBag but I prefere using a ViewModel as you get much cleaner code and the view gets strongly typed to your model objects.
The issue is when posting data back to your controller the model binder can not map your view model object to your “real” model objects. The solution to this was much simplier then I expected.

If your not using a ViewModel you may have a action method looking something like this:

[HttpGet]
public ActionResult Edit(int id)
{
   MyModel model = context.MyModels.FirstOrDefault(m => m.Id == id);
   return View(model);
}

Then you would have a post method looking something like this:

[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
    MyModel myModel = context.MyModels.FirstOrDefault(m => m.Id = id);

    if (TryUpdateModel(myModel))
    {
        context.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(myModel);
}

TryUpdateModel() will loop through the FormCollection values and map the posted data to the MyModel object.
If you look at the keys in the FormCollection you will see that they match your properties on the model. This is what makes the mapping possible.

But what now if you would like to use a ViewModel?
Here is an example view model that I have written.

public class UserProfileViewModel
{
    public UserProfile UserProfile { get; set; }
    public MembershipUser MembershipUser { get; set; }

    public UserProfileViewModel(string userName)
    {
        UserProfile = UserProfile.GetUserProfile(userName);
        MembershipUser = Membership.GetUser(userName);
    }
}

It’s a ViewModel containing a users profile and membership.
The UserProfile is a container of user information such as name, location, birthdate and so on.
The MembershipUser is a container for user name and email. The model is used in a view for displaying and edeting user information.

The edit get action would look something like this:

[HttpGet]
public ActionResult Edit(string userName)
{
    return View(new UserProfileViewModel(userName));
}

You would then have a post method looking something like this:

[HttpPost]
public ActionResult Edit(string userName, FormCollection collection)
{
    try
    {

        MembershipUser user = Membership.GetUser(userName);
        if (TryUpdateModel(user))
        {
            Membership.UpdateUser(user);
        }

        UserProfile profile = UserProfile.GetUserProfile(userName);
        if (TryUpdateModel(profile))
        {
            profile.Save();
        }

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

The problem now is that the FormCollection keys have the following values:
FormCollection key values

The model binder now has problem of mapping the FormCollection keys to the model object when calling TyrUpdateModel() as it can’t know what object to map with.
You can still user the TryUpdateModel() but use the overloaded method that takes a string prefix as an argument.
Here you can see how I have used the the method to update membership and userprofile opbjects:

if (TryUpdateModel(user, "MembershipUser"))

and

if (TryUpdateModel(profile, "UserProfile"))

This will enable the model minder to bind correctly.
It’s important to know that the string prefix should be the same as the ViewModels member name.
It will be clear to you when inspecting the content of the FormCollection keys in debug mode.

Development , , ,

SharePoint 2010 people picker and claims bug?

August 27th, 2011

In my current project I had to add claims to a sharepoint group to controll access to sites and pages. In this project we have built a custom claims provider and one of our own claims had to go in to this group.
Unfortunately I discovered a bug, in my opinion, in the people picker.
Our custom claim provider produces two claims with the same name(value) but with different claim types. When trying to add one of these claims to the group, I get an exception saying some something like:
No such user, group or duplicate found

What I had to do to solve this problem was to add a prefix to our claims in the claim provider.
This solution seems to work quite well.

Has some one else ran into this problem and have another solution?

Development , ,