views:

72

answers:

1

I'm using ASP.NET MVC 2 & VS 2008 Pro.

I am building a web site where users must go from page A to page B to page C. In other words, the order is very important. I want to guard against a user on page A simply entering a url for page C. If the user attempted to do such a thing I'd like to redirect them back to the page they were on before they entered the url.

It seems like I would make an action filter for this, but I'm honestly not sure what kind I would need. I would need access to the url the user was on and the url they are going to, and would have to validate them.

Thoughts?

EDIT 1

This is ugly, but it looks like I can get the full Uri's for the referring & destination urls inside of the OnActionExecuting method. I'd wager that this could be done from any kind of action filter. I'm currently testing all of this inside of the OnActionExecuting event of a custom action filter initially designed to check session state for expiration.

LogUtil.Write("OnActionExecuting", String.Format("Referring Url: {0} \n Destination Url: {1} ",
                filterContext.RequestContext.HttpContext.Request.UrlReferrer.AbsoluteUri.ToString(),
                filterContext.RequestContext.HttpContext.Request.Url.AbsoluteUri.ToString() ));     

LogUtil is just a custom class I wrote that writes out to a log file.

So far it isn't pretty, but it works. Anyone have a more elegant solution?

EDIT 2

Another take that makes comparing the url's a bit easier is below. I haven't tried this using routes that actually contain parameters. In that situation, this might get thrown off.

String[] referrerSegments = filterContext.RequestContext.HttpContext.Request.UrlReferrer.Segments;

String[] destinationSegments = filterContext.RequestContext.HttpContext.Request.Url.Segments;

Perform action lookup logic to ensure destinationSegments[destinationSegments.length-1] comes after referrerSegments[referrerSegments-1]. This will likely be done with a static string List that contains the names of all the actions in the application in order. The index values of these shouldn't be more than 1 apart (i.e. destination action should have an index of plus or minus 1 of the value of referring action index).

Thoughts?

EDIT 3

Sigh. Apparently the referrer information is lost when a user is on a page and manually types in the url into the address bar. This seems odd to me, but it means I can only get the url for the current page the person is on.

Anyone have any suggestions here aside from session? I really, really want to avoid storing something like this in session if possible.

+1  A: 

An Action filter is exactly what you need, with a redirect when they are being naughty. Keep track of their progress in the time honoured fashion, using the Session State.

This keeps the main part of your application relatively stateless (compared to classic ASP.NET) and keeps this logic in the action filter.

Another consideration: If your input is potentially a long-lived process you could save the user's progress to a database or into a Windows Workflow object. Just a thought. This would enable them to start the process on one machine and pick it up elsewhere. This might not apply to your scenario, but it is worth considering in some situations.

Daniel Dyson
Thanks for responding Daniel. Okay, so I could store where the user came from in session, but how would I know where they are going? filterContext.Result maybe? I'll check that and see. I would really prefer to find some way to figure out where the user is coming from via the ActionExecutingContext (or whatever context parameter is being used) if it's possible as opposed to the session.
Jason
filterContext.Result is asigned an ActionResult to change the response. You could assign a RedirectAction, but only after you have established that they have made a request ahead of themselves. You should maintain a status of which stage they are at, setting it when each response has been validated. If they have completed stage 1 and a request comes in to view the form for stage 3, they should be redirected to the form for stage 2, until that form has been validated and their status updated to stage 2. I am writing this in general terms. It is up to you to find the right implementation.
Daniel Dyson
I appreciate your input Daniel, but I'm here to poll input on what exactly the correct implementation is. I already know the gist of what I need to do, it's the 'how to do it correctly' part that I'm here for. I'm posting another take on how to do this in code and it will likely be the direction I go with unless I get some input from the community stating I probably don't want to do it that way.
Jason
No worries. The problem I can see with the UrlReferrer approach is that you lose the ability to direct the user to a particular stage that they had already completed. In many cases in a wizard style interface you would want the user to be able to go back to any stage, either through a back button or an explicit link. You should think carefully before deciding to throw away this ability. Then again, this might fit your requirement perfectly and you could put in logic to be able to go back to any previous stage.
Daniel Dyson
Jason
Email me some code if you like and I will take a look at it. It is v difficult to provide this kind of help in a forum
Daniel Dyson