是否有可能在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
对象而不是Album
的ID
。
我的问题是,有没有办法配置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();