ASP.NET MVC: The right way to propagate query parameter through all ActionLinks

前端 未结 6 2286
礼貌的吻别
礼貌的吻别 2020-12-15 13:27

In my application, key query string parameter can be used to grant access to certain actions/views.
Now I want all ActionLinks and Forms to automatically in

相关标签:
6条回答
  • 2020-12-15 14:06

    Having a querystring parameter that controls authorization is a bad idea IMHO. What's stopping me from adding this parameter to my url that didn't contain?

    The preferred way to implement authorization is to use roles (http://msdn.microsoft.com/en-us/library/system.web.security.roleprovider.aspx).

    0 讨论(0)
  • 2020-12-15 14:08

    The simplest thing is to put the "key" parameter in all the Url.Action and Html.ActionLink in this way:

    @Url.Action("MyAction", "MyController", new { key = Request["key"] })
    

    if Request["key"] is empty the querystring parameter will be skipped.

    0 讨论(0)
  • 2020-12-15 14:13

    Hi for the situation you describe, you can easily use cookies. Create a cookie with name key and value the same as value for your key URL parameter. Now you can give or reject access to your users using the presence or absence of valid cookie, instead of presence or absence of key parameter.

    You can access the cookies using Response.Cookies

    If you still want to change all the Form and ActionLink helpers, then you can create your own helpers, that internally call the MVC helpers, with the extra key parameter, and use the custom helpers everywhere. Look here for writing custom helpers

    0 讨论(0)
  • 2020-12-15 14:13

    To do this, I wrote an extension to HtmlHelper called "ActionLinkBack". The methods compose action links back to the same controller an action and merge the existing route values with any new ones that are specified.

    public static HtmlString ActionLinkBack(this System.Web.Mvc.HtmlHelper htmlHelper, string linkText, object routeValues)
    {
        return ActionLinkBack(htmlHelper, linkText, new RouteValueDictionary(routeValues), new RouteValueDictionary());
    }
    
    public static HtmlString ActionLinkBack(this System.Web.Mvc.HtmlHelper htmlHelper, string linkText, object routeValues, object htmlAttributes)
    {
        return ActionLinkBack(htmlHelper, linkText, new RouteValueDictionary(routeValues), new RouteValueDictionary(htmlAttributes));
    }
    
    public static HtmlString ActionLinkBack(this System.Web.Mvc.HtmlHelper htmlHelper, string linkText, RouteValueDictionary routeValues)
    {
        return ActionLinkBack(htmlHelper, linkText, routeValues, new RouteValueDictionary());
    }
    
    public static HtmlString ActionLinkBack(this System.Web.Mvc.HtmlHelper htmlHelper, string linkText, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
    {
        // Build a new dictionary of route values based on the previous set
        var newRouteValues = new RouteValueDictionary(htmlHelper.ViewContext.RouteData.Values);
    
        // Retain current querystring parameters
        var queryString = htmlHelper.ViewContext.HttpContext.Request.QueryString;
        if (queryString.Count > 0)
        {
            foreach (string key in queryString.Keys)
            {
                newRouteValues[key] = queryString[key];
            }
        }
    
        // Add and override entries from the list of new route values
        if (routeValues != null)
        {
            foreach (var routeValueItem in routeValues)
            {
                newRouteValues[routeValueItem.Key] = routeValueItem.Value;
            }
        }
    
        return new HtmlString(htmlHelper.ActionLink(linkText, null, newRouteValues, htmlAttributes).ToHtmlString());
    }
    

    In my reusable "page navigator" view I use the extensions to compose the previous, next, and individual page links:

    @Html.ActionLinkBack("Next", new { page = (int)ViewData["Page"] + 1 }, new { @class = "navigationLink" })
    
    0 讨论(0)
  • 2020-12-15 14:20

    You can do it with routes but you need a bit more infrastrcuture. Something like this

    public class RouteWithKey:Route
    {
      //stuff omitted
       public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
       {
         values.Add("key", requestContext.HttpContext.Request.QueryString["key"]);   
        var t = base.GetVirtualPath(requestContext, values);        
            return t;
        } 
    }
    

    Of course you'll need to retrieve the key from the request params and handle the case where key is the second parameter in the query, but this apporach will add automatically the key to every utel constructed via the normal as.net mvc helpers

    I just happen to use a custom route for an application, for a different purpose but I;ve tested with the code above and it adds the parameter, so at least in my project seems to work properly.

    0 讨论(0)
  • 2020-12-15 14:22

    How about adding the key to route values.

    {controller}/{action}/{key}

    Whenever a url contains a querystring with key=somevalue, the url will look like

    Home/Index/somevalue,

    Now all the action links and relative urls also will include this by default.

    0 讨论(0)
提交回复
热议问题