是否有可能在ASP.NET MVC路径到达控制器之前更改它的querystring变量?

我在ASP.NET MVC中有一个控制器方法,如下所示:

public ActionResult GetAlbumPictures(int albumId) { var album = AlbumRepo.GetSingle(albumId); var pictures = album.Pictures; return View(pictures); } 

此方法的路由如下所示:

 routes.MapRoute(null, "pictures" new { controller = "Album", action = "GetAlbumPictures" }); 

用户将使用以下URL获取图片,按照相册ID进行过滤:

 GET http://server/pictures?albumid=10 

但是,我想将querystring参数更改为album而不是albumid

 GET http://server/pictures?album=10 

这意味着需要将控制器方法修改为:

 public ActionResult GetPictures(int album) { ... } 

但是,这并不理想,因为现在该方法有一个名为album的参数,可以将其混淆为Album 对象而不是AlbumID

我的问题是,有没有办法配置ASP.NET MVC,以便在路由中,它将收到一个名为album的查询字符串参数,但然后将其作为albumId参数传递给控制器​​?

PS我知道我可以在路由表中执行此操作:

 routes.MapRoute(null, "album/{albumId}/pictures", new { controller = "Album", action = "GetAlbumPictures" }); 

但由于遗留问题,我必须使其适用于查询字符串方法。

您可以创建自定义操作筛选器属性来处理此方案。 我没有测试过这个具体的实现,但一般的想法是做这样的事情:

 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); } } 

然后,使用[Album]属性修饰您的操作方法:

 [Album] public ActionResult GetAlbumPictures(int albumId) { var album = AlbumRepo.GetSingle(albumId); var pictures = album.Pictures; return View(pictures); } 

您可以使用自定义模型Binder,它将同时适用于album和albumId。 它可以实现如下:

自定义型号粘合剂:

 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; } } 

行动实施:

 public ActionResult GetAlbumPictures ([ModelBinder( typeof( AlbumModelBinder ) )] int albumId) { var album = AlbumRepo.GetSingle(albumId); var pictures = album.Pictures; return View(pictures); } 

Global.asax.cs实现:

 protected void Application_Start() { AreaRegistration.RegisterAllAreas(); ModelBinders.Binders.Add( typeof( int ), new AlbumModelBinder() ); RegisterRoutes( RouteTable.Routes ); } 

考虑拦截您的请求并使用HttpContext.RewritePath在路由引擎拾取之前更改查询字符串。 这里有一个很好的图表显示了如何在路由之前执行Url重写:)

http://learn.iis.net/page.aspx/496/iis-url-rewriting-and-aspnet-routing/

您可以在global.asax中的Application_BeginRequest中访问控制器之前拦截请求。 您将无法访问MVC上下文,但可以使用

 Server.Transfer(...); 

要么

 Response.Redirect(...); Response.End();