Llame a UrlHelper en modelos en ASP.NET MVC

159

Necesito generar algunas URL en un modelo en ASP.NET MVC. Me gustaría llamar a algo como UrlHelper.Action () que usa las rutas para generar la URL. No me importa llenar los espacios en blanco habituales, como el nombre de host, el esquema, etc.

¿Hay algún método que pueda llamar para eso? ¿Hay alguna manera de construir un UrlHelper?

pupeno
fuente
1
Estaba pensando en esto yo mismo, pero tenga en cuenta que Url.Action generará una URL relativa. Asegúrate de que eso es lo que quieres.
Vivian River

Respuestas:

277

Consejo útil, en cualquier aplicación ASP.NET, puede obtener una referencia del HttpContext actual

HttpContext.Current

que se deriva de System.Web. Por lo tanto, lo siguiente funcionará en cualquier lugar de una aplicación ASP.NET MVC:

UrlHelper url = new UrlHelper(HttpContext.Current.Request.RequestContext);
url.Action("ContactUs"); // Will output the proper link according to routing info

Ejemplo:

public class MyModel
{
    public int ID { get; private set; }
    public string Link
    {
        get
        {
            UrlHelper url = new UrlHelper(HttpContext.Current.Request.RequestContext);
            return url.Action("ViewAction", "MyModelController", new { id = this.ID });
        }
    }

    public MyModel(int id)
    {
        this.ID = id;
    }
}

Llamar a la Linkpropiedad en un objeto MyModel creado devolverá la URL válida para ver el Modelo basado en el enrutamiento en Global.asax

Omar
fuente
¿Estás seguro de que hay un HttpContext.Current.Request.RequestContext? HttpContext.Current.Request parece no tener un RequestContext.
pupeno
1
Eso es extraño. Acabo de probar esta solución y funciona perfectamente. Estoy ejecutando ASP.NET MVC 2 Preview 2, pero creo que esto funciona en todas las versiones. No estoy seguro de por qué no funciona para ti. ¿Estás creando la clase fuera de un proyecto MVC? También asegúrese de que haya usingpara ambos System.WebySystem.Web.Mvc
Omar
Estoy en un proyecto ASP.NET MVC 1, pensé en los usos perdidos, pero tengo ambos.
pupeno
No estoy seguro de por qué no se muestra. Si alguien más pudiera confirmar que esto no existe en ASP.NET MVC 1, sería genial. Solo tengo una máquina con VS2010 y MVC 2 instalados. Si está interesado, MVC RC 2 haacked.com/archive/2009/12/16/aspnetmvc-2-rc.aspx
Omar el
66
Tenga en cuenta que Request.RequestContex es compatible con .NET4 +
h - n
64

Me gusta la respuesta de Omar, pero eso no me funciona. Solo para el registro, esta es la solución que estoy usando ahora:

var httpContext = HttpContext.Current;

if (httpContext == null) {
  var request = new HttpRequest("/", "http://example.com", "");
  var response = new HttpResponse(new StringWriter());
  httpContext = new HttpContext(request, response);
}

var httpContextBase = new HttpContextWrapper(httpContext);
var routeData = new RouteData();
var requestContext = new RequestContext(httpContextBase, routeData);

return new UrlHelper(requestContext);
pupeno
fuente
Contiene la URL de mi sitio. Ahí lo quité.
pupeno
44
Teniendo en cuenta que la clase UrlHelper se basa en el contexto de solicitud (y el contexto HTTP), construir esos objetos de contexto manualmente podría producir resultados inesperados. Si HttpContext.Current es nulo y utiliza este enfoque, procedería con precaución.
Sean
44
Tenga cuidado con esta respuesta: el RequestContext ficticio da como resultado un UrlHelper que siempre devuelve una cadena vacía.
gknicker
47

Un UrlHelper se puede construir desde una acción de Controlador con lo siguiente:

 var url = new UrlHelper(this.ControllerContext.RequestContext);
 url.Action(...);

Fuera de un controlador, se puede construir un UrlHelper creando un RequestContext desde RouteTable.Routes RouteData.

HttpContextWrapper httpContextWrapper = new HttpContextWrapper(System.Web.HttpContext.Current);
UrlHelper urlHelper = new UrlHelper(new RequestContext(httpContextWrapper, RouteTable.Routes.GetRouteData(httpContextWrapper)));

(Según la respuesta de Brian, con una corrección de código menor agregada).

Nathan Taylor
fuente
2
Pero no tengo un controlador en el modelo.
pupeno
Bien, me disculpo, no estaba seguro exactamente dónde se estaba ejecutando el código. Déjame echar un vistazo ...
Nathan Taylor
2
No es necesario crear un nuevo contexto de solicitud:var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
bradlis7
Niza @ bradlis7. ¿Eso es MVC 5?
Nathan Taylor
1
No funciona, porque this.ControllerContext.RequestContextes a HttpRequestContext, y el constructor de UrlHelperespera a RequestContext. Ambas clases no están relacionadas.
Florian Winter
8

Sí, puedes instanciarlo. Puedes hacer algo como:

var ctx = new HttpContextWrapper(HttpContext.Current);
UrlHelper helper = new UrlHelper(
   new RequestContext(ctx,
   RouteTable.Routes.GetRouteData(ctx));

RouteTable.Routeses una propiedad estática, por lo que debería estar bien allí; para obtener una HttpContextBasereferencia, HttpContextWrappertoma una referencia HttpContexty la HttpContextentrega.

Brian Mains
fuente
Esto no funcionará, aunque está muy cerca. Vea mi respuesta a continuación.
Nathan Taylor el
3

Después de probar todas las otras respuestas, terminé con

$"/api/Things/Action/{id}"

Los que odian odiarán ¯ \ _ (ツ) _ / ¯

Florian Winter
fuente
0

Estaba tratando de hacer algo similar desde una página (fuera de un controlador).

UrlHelper no me permitió construirlo tan fácilmente como Pablos responde, pero luego recordé un viejo truco para hacer lo mismo:

string ResolveUrl(string pathWithTilde)
vGHazard
fuente
-30

Creo que lo que estás buscando es esto:

Url.Action("ActionName", "ControllerName");
usuario246874
fuente