Can implicit or session values be automatically added to the RouteValues in Url.Action() in ASP.NET MVC2?
We've got a ton of code already written where a URL is written using code like this:
Url.Action("Index", "MyController", new {page=1})
Our application is a multi-tenant application where our user's log in to their database. This means that the log-in process allows the user to select the database they want to use for the session. We did not build this in the beginning so the database name is part of the URL. That was just kept as part of the session.
Now we would like to put the database name in all of our URLs, that way a user can still create bookmarks with the browser URL, and access that specific page correctly without having to select the right matching database during login. Essentially, it would be nice if in ASP.NET MVC there was a way to make the above call do something like this:
Url.Action("Index", "MyController", new {page=1, clientName=Identity.ClientName})
withou开发者_Python百科t having to go everywhere and do it mannually. We're talking several thousand places to do this..
Is this doable?
Ok, I assume this just can't be done right now, and we need to write our own implementations of Url.Action, Html.ActionLink, and Controller.Redirect and just do a global search and replace to use our versions. Too bad.
I had to solve a very similar problem to this today. When I was searching for a solution I found your question. I've now found a solution, which although it's probably no longer relevant for your project, might be helpful for anyone else who stumbles upon it.
We can solve this problem by adding a custom implementation of the Route
class to your routes collection instead of the vanilla MVC Route class. So something like this:
public class ClientNameRoute : Route
{
public ClientNameRoute(string url, IRouteHandler routeHandler) : base (url, routeHandler) {}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
values["clientName"] = Identity.ClientName;
return base.GetVirtualPath(requestContext, values);
}
}
You will then want to make a couple of extension methods to make registering these routes easier. For example:
public static RegionRoute MapClientNameRoute(this AreaRegistrationContext context, string name, string url, object defaults)
{
if (context.Routes == null)
throw new ArgumentNullException("context.Routes");
if (url == null)
throw new ArgumentNullException("url");
if (context.Namespaces != null)
context.Namespaces.ToArray();
var route = new ClientNameRoute(url, new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(defaults),
DataTokens = new RouteValueDictionary(),
};
route.DataTokens["area"] = context.AreaName;
var useNamespaceFallback = context.Namespaces == null || context.Namespaces.Count == 0;
route.DataTokens["UseNamespaceFallback"] = useNamespaceFallback;
if (!useNamespaceFallback)
route.DataTokens["Namespaces"] = context.Namespaces.ToArray();
context.Routes.Add(name, route);
return route;
}
public static RegionRoute MapClientNameRoute(this RouteCollection routes, string name, string url, object defaults, string[] namespaces)
{
if (routes == null)
throw new ArgumentNullException("routes");
if (url == null)
throw new ArgumentNullException("url");
var route = new ClientNameRoute(url, new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(defaults),
DataTokens = new RouteValueDictionary()
};
if (namespaces != null && namespaces.Length > 0)
{
route.DataTokens["Namespaces"] = namespaces;
}
routes.Add(name, route);
return route;
}
精彩评论