是否可以在 ASP.NET MVC 路径中的查询字符串变量到达控制器之前更改它?

发布于 2024-10-09 12:33:05 字数 1251 浏览 0 评论 0原文

我在 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

但是,我想更改将查询字符串参数设置为 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" });

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

I have a controller method in ASP.NET MVC that looks like this:

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

The routing for this method looks like this:

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

The user will use the following URL to get the pictures, filtered by the album ID:

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

However, I'd like to change the querystring parameter to just album instead of albumid:

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

This would mean that the controller method needs to be modified to:

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

However, this is not ideal because now the method has a parameter named album, which can be confused as an Album object instead of the ID of the Album.

My question is, is there any way of configuring ASP.NET MVC so that in the routing, it will receive a querystring parameter called album, but then pass it off to the controller as the albumId parameter?

P.S. I know that I can do this in the routing table:

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

But due to legacy issues, I have to make it work for the querystring method as well.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

渔村楼浪 2024-10-16 12:33:05

您可以创建自定义操作过滤器属性来处理这种情况。我还没有测试这个具体的实现,但总体思路是做这样的事情:

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

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);
}
孤凫 2024-10-16 12:33:05

您可以使用自定义模型绑定器,它将与 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 );
}

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 );
}
无远思近则忧 2024-10-16 12:33:05

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

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

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/

眸中客 2024-10-16 12:33:05

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

Server.Transfer(...);

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

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文