2012-02-25 13 views
5

En mi aplicación, el parámetro de cadena de consulta key se puede usar para otorgar acceso a ciertas acciones/vistas.
Ahora quiero que todos los ActionLinks y Formularios incluyan automáticamente este parámetro si está presente en la cadena de consulta actual.ASP.NET MVC: la forma correcta de propagar el parámetro de consulta a través de todos los enlaces de acción

¿Cuál es la forma correcta de hacerlo?

Pregunto por el camino correcto porque vi varias soluciones que proponían cambiar las vistas de una forma u otra (métodos de extensión/ayudantes alternativos, paso de parámetros manual). Esta no es una solución que estoy buscando.

ACTUALIZACIÓN:
solución final (basado en anwer de MikeSW): https://gist.github.com/1918893.

+0

Esto también parece relevante: http: // stackoverflow.com/questions/5060346/howto-automatically-add-a-specific-value-from-current-route-to-all-generated-lin – DenNukem

Respuesta

9

Puedes hacerlo con rutas pero necesitas un poco más de infraestrcutura. Algo como esto

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

Por supuesto que necesita para recuperar la clave de los parametros de petición y manejar el caso donde la clave es el segundo parámetro de la consulta, pero esto apporach añadirá automáticamente la clave de todos los utel construido a través de la normal como.net mvc helpers

Simplemente uso una ruta personalizada para una aplicación, para un propósito diferente pero he probado con el código anterior y agrega el parámetro, por lo que al menos en mi proyecto parece funcionar correctamente.

+0

Esta es una buena idea que es realmente relevante para la pregunta, gracias. Desafortunadamente, se rompe cuando se usa en ActionLink con sus propios parámetros. Produce url con '? Key = mykey? Other = myother' ya que' ActionLink' no espera '?' En 'VirtualPath'. –

+0

He actualizado el ejemplo para manejar ese caso – MikeSW

+0

¡Hurra, esto realmente funciona! Muchas gracias. Sin embargo, he encontrado una forma aún más fácil: agregar clave/valor a los 'valores' antes de llamar a' base.GetVirtualPath'. ¿Puedes actualizar tu respuesta con eso (ya que es bueno tener la mejor solución en la respuesta aceptada)? –

0

Hola, para la situación que describes, puedes usar cookies fácilmente. Cree una cookie con la clave de nombre y valide lo mismo que el valor para su parámetro de URL clave. Ahora puede dar o rechazar el acceso a sus usuarios utilizando la presencia o ausencia de cookies válidas, en lugar de la presencia o ausencia del parámetro clave.

Puede acceder a las cookies usando Response.Cookies

Si aún desea cambiar toda la forma y ayudantes ActionLink, entonces usted puede crear sus propios ayudantes, que internamente llama a los ayudantes de MVC, con el parámetro clave adicional, y usa los ayudantes personalizados en todas partes. Mire here para escribir ayudantes personalizados

+0

Considere "compartir", donde desea mostrar una cierta galería de fotos a cierta personas que no están registradas en el sitio. Puedes enviarles un enlace por correo. También puede establecer una cookie la primera vez que la visita, pero hace que la validación de seguridad sea más compleja (ahora revisamos la cadena de consulta o la cookie) y crea problemas si realmente desean compartir algún subvínculo específico con otra persona. Además, no todos han habilitado las cookies. –

+0

Este no es exactamente mi caso de uso actual, pero también tengo motivos para el actual, por lo que preferiría implementarlo exactamente como se me pidió. –

+0

Tenga en cuenta que mencioné que no se consideran ayudantes personalizadas (métodos de extensión alternativos en la pregunta), requiere cambios en la vista. Pregunta actualizada para que quede más claro. –

-1

Tener un parámetro querystring que controla la autorización es una mala idea en mi humilde opinión. ¿Qué me impide agregar este parámetro a mi URL que no contenía?

La forma preferida de implementar la autorización es usar roles (http://msdn.microsoft.com/en-us/library/system.web.security.roleprovider.aspx).

+2

Soy consciente de esto, sin embargo, no todos los casos de uso y no todas las aplicaciones requieren ese nivel de seguridad. Por ejemplo, puede otorgar a alguien acceso a su documento de Google mediante la url con una clave específica. –

+0

@JakubKonecki eche un vistazo a la seguridad basada en capacidades y Waterken http://higherlogics.blogspot.com/2012/01/clavis-web-security-microframework.html –

1

¿Qué le parece agregar la clave a los valores de ruta.

{controlador}/{acción}/{clave}

Cada vez que un URL contiene una cadena de consulta con la tecla = somevalue, la URL se verá como

Inicio/Índice/somevalue,

Ahora todos los enlaces de acción y las URL relativas también incluirán esto por defecto.

+0

La clave debe estar en la cadena de consulta (y opcional), puede Lo hago con valores de ruta? Quiero decir que la URL esperada es 'Home/Index? Key = somevalue'. –

+0

no, esto no se puede hacer por valores de ruta. Pero aún en el enfoque mencionado anteriormente, puede definir la clave como Opcional. Si desea tenerla en la cadena de consulta, puede definir una extensión para ActionLink menthod, que anexará los valores clave de la cadena de consulta (si están disponibles) al crear un enlace. – Manas

-1

Lo más sencillo es poner el parámetro "clave" en todo el Url.Action y Html.ActionLink de esta manera:

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

si Request["key"] está vacío se omitirá el parámetro de cadena de consulta.

+0

Mencioné que esta no es la respuesta que estoy buscando en esta pregunta. Tener un marco que específicamente haga que las preocupaciones transversales sean más fáciles en la mayoría de los casos ('ActionFilter', etc.), aún no estoy listo para renunciar aquí. –

0

Para hacer esto, escribí una extensión a HtmlHelper llamada "ActionLinkBack". Los métodos componen enlaces de acción para una acción del mismo controlador y fusionan los valores de ruta existentes con los nuevos que se especifiquen.

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

En mi reutilizable "navegador de páginas" vista utilizo las extensiones para componer la anterior, siguiente y enlaces de páginas individuales:

@Html.ActionLinkBack("Next", new { page = (int)ViewData["Page"] + 1 }, new { @class = "navigationLink" }) 
Cuestiones relacionadas