Можно ли изменить переменную строки запроса в пути ASP.NET MVC, прежде чем она попадет в контроллер? - PullRequest
4 голосов
/ 30 декабря 2010

У меня есть метод контроллера в 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, чтобы получить изображения, отфильтрованные по идентификатору альбома:

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

Однако я бы хотел изменить параметр querystring на album вместо albumid:

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

Это будет означать, что метод контроллера должен быть изменен на:

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

Однако это не идеально, потому что теперь метод имеет параметр с именем album, который можно спутать с Album объект вместо ID из Album.

Мой вопрос: есть ли способ настроить ASP.NET MVC так, чтобы в маршрутизации он получалпараметр строки запроса с именем album, но затем передать его контроллеру как параметр albumId?

PS Я знаю, что могу сделать это в таблице маршрутизации:

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

Но из-за унаследованных проблем, я должен заставить его работать для строки запроса менятакже.

Ответы [ 4 ]

9 голосов
/ 30 декабря 2010

Вы можете создать атрибут фильтра настраиваемого действия для обработки этого сценария.Я не тестировал эту конкретную реализацию, но общая идея состоит в том, чтобы сделать что-то вроде этого:

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);
}
0 голосов
/ 30 декабря 2010

Рассмотрите возможность перехвата вашего запроса и используйте HttpContext.RewritePath, чтобы изменить строку запроса, прежде чем она будет обработана механизмом маршрутизации.Здесь есть хорошая диаграмма, показывающая, как перезапись Url выполняется задолго до маршрутизации :)

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

0 голосов
/ 30 декабря 2010

Вы можете использовать пользовательскую модель Binder, и она будет работать как с альбомом, так и с альбомом Это может быть реализовано следующим образом:

Пользовательская модель 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;
    }
}

Реализация действия:

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 );
}
0 голосов
/ 30 декабря 2010

Вы можете перехватить запрос, прежде чем он попадет в контроллер в Application_BeginRequest в вашем global.asax. У вас не будет доступа к контекстам MVC, но вы можете использовать

Server.Transfer(...);

или

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