I have a controller method in ASP.NET MVC that looks like this:
public ActionResult GetAlbumPictures(int albumId)
{
var album = AlbumRepo.GetSingle(album
You can create a custom action filter attribute to handle this scenario. I haven't tested this specific implementation, but the general idea is to do something like this:
public class AlbumAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var albumId = filterContext.HttpContext.Request.QueryString["album"] as string;
filterContext.ActionParameters["albumId"] = albumId;
base.OnActionExecuting(filterContext);
}
}
Then, decorate your action method with the [Album] attribute:
[Album]
public ActionResult GetAlbumPictures(int albumId)
{
var album = AlbumRepo.GetSingle(albumId);
var pictures = album.Pictures;
return View(pictures);
}
You can intercept the request before it hits the controller in Application_BeginRequest in your global.asax. You won't have access to the MVC contexts though, but could use
Server.Transfer(...);
or
Response.Redirect(...);
Response.End();
You can use a Custom Model Binder and it will work with both album and albumId. It can be implemented as follows:
Custom Model Binder:
public class AlbumModelBinder : IModelBinder
{
public object BindModel
(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
int albumId;
var albumVar = bindingContext.ValueProvider.GetValue( "album" );
if (albumVar != null)
{
albumId = int.Parse( albumVar.AttemptedValue );
}
else
{
albumId = int.Parse( bindingContext.ValueProvider.GetValue( "albumId" ).AttemptedValue );
}
return albumId;
}
}
Action implementation:
public ActionResult GetAlbumPictures
([ModelBinder( typeof( AlbumModelBinder ) )] int albumId)
{
var album = AlbumRepo.GetSingle(albumId);
var pictures = album.Pictures;
return View(pictures);
}
Global.asax.cs implementation:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ModelBinders.Binders.Add( typeof( int ), new AlbumModelBinder() );
RegisterRoutes( RouteTable.Routes );
}
Consider intercepting your request and use HttpContext.RewritePath to alter the query string before its picked up by the Routing engine. There is a nice diagram here showing how Url Rewriting is executed ages before the routing :)
http://learn.iis.net/page.aspx/496/iis-url-rewriting-and-aspnet-routing/