Question

We are building a site using asp.net mvc. We want to allow the user to easily register and create an account. There is though a very special piece of information, that will be registered in his profile, that we want to show to him *after registration is finished, and he is logging in for the first time.

The logic is whatever the URL that was hit, if the user is authenticated and does not have a valid profile, redirect him to the "Create Profile" page.

The whole ui will depend on those profile choices. What approach should we use within the MVC framework, to force this workflow on the visitor? The ideas I can come up with require tons of code duplication in controllers etc, so its clearly a bad idea.

We are using Membership for users, but profile is our own implementation (no profile provider) that will connect profile data to a userId.

Was it helpful?

Solution

I think the easiest way to do this is either create a custom AuthorizeAttribute, extending the existing one or create a separate FilterAttribute. Either one of these would get applied to all of your controllers and ensure that an authenticated user has a profile. In the case where no profile exists, the filter would redirect the user to the page where the profile is created. This would be done by setting the result property on the context to a RedirectResult to the profile creation action. Only if the profile exists and is complete would the filter allow the user to proceed to the desired action.

Alternatively, you could create a base controller that overrides OnActionExecuting and performs the same task. I prefer the attribute mechanism as it is more flexible, i.e., you could have some public actions that are available without the profile (including the profile setting action).

OTHER TIPS

Answering my own question: In the end I created a custom actionFilter. In the beginning, I took the path of subclassing [authorize] into [AuthorizeCheckProfile]. But then I realized that the use case was wrong: I did not want the logged-in only parts of my site to redirect to the create-profile page, if no user profile existed. I wanted any page of my site to redirect to that page, if its a logged-in user with no profile. The only place I don't want to check that is in the actual profile-create. Here's the code:

public class AssertProfileAttribute : ActionFilterAttribute {
    public AssertProfileAttribute() {
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext) {
        if (filterContext.HttpContext.Request.IsAuthenticated == false)
            return;
        //we have a user, but does he have a profile?
        if (filterContext.HttpContext.Session["UserProfile"] == null) { //not in the session
            IUnityContainer container = filterContext.HttpContext.Application["container"] as IUnityContainer;
            Profile hasProfile = container.Resolve<IProfileRepository>().GetUserProfile(Membership.GetUser());
            if (hasProfile == null) {
                //we have to redirect to the create profile 
                string returnURL = filterContext.HttpContext.Request.AppRelativeCurrentExecutionFilePath;
                filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Profile", action = "Create", returnTo = returnURL }));
            } else {
                //he has a profile but we haven't put it in session yet
                filterContext.HttpContext.Session["UserProfile"] = hasProfile;
            }
        }
    }
}

It has the side-effect that it will store the profile in a Session key. This way it can be easily be fetched so that further role checks can happen in every request with other custom filters. The implementation uses Unity and repositories for db access.

A big thanks to the community.

Try consider ActionFilter and FilterAttribute if not most pages need to do so, or else, you may actually put this redirection logic to global.asax (in those Begin Request or similar events)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top