Chame UrlHelper em modelos no ASP.NET MVC

159

Preciso gerar alguns URLs em um modelo no ASP.NET MVC. Gostaria de chamar algo como UrlHelper.Action (), que usa as rotas para gerar a URL. Não me importo de preencher os espaços em branco habituais, como nome do host, esquema e assim por diante.

Existe algum método que eu possa chamar para isso? Existe uma maneira de construir um UrlHelper?

pupeno
fonte
1
Eu estava pensando nisso, mas saiba que o Url.Action irá gerar um URL relativo. Certifique-se de que é isso que você deseja.
Vivian River

Respostas:

277

Dica útil: em qualquer aplicativo ASP.NET, você pode obter uma referência do HttpContext atual

HttpContext.Current

que é derivado de System.Web. Portanto, o seguinte funcionará em qualquer lugar de um aplicativo ASP.NET MVC:

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

Exemplo:

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

Chamar a Linkpropriedade em um objeto MyModel criado retornará o URL válido para exibir o Modelo com base no roteamento em Global.asax

Omar
fonte
Tem certeza de que há um HttpContext.Current.Request.RequestContext? HttpContext.Current.Request parece não ter um RequestContext.
pupeno
1
Isso é estranho. Acabei de testar esta solução e ela funciona perfeitamente. Estou executando o ASP.NET MVC 2 Preview 2, mas acho que isso funciona em todas as versões. Não sei por que não está funcionando para você. Você está criando a classe fora de um projeto MVC? Verifique também se existem usingpara ambos System.WebeSystem.Web.Mvc
Omar
Estou em um projeto do ASP.NET MVC 1, pensei em perder os usos, mas tenho os dois.
pupeno
Não sei ao certo por que não está aparecendo. Se alguém mais pudesse confirmar isso não existe no ASP.NET MVC 1, isso seria ótimo. Eu só tenho uma máquina com o VS2010 e o MVC 2 instalados. Se você estiver interessado, o MVC RC 2 haacked.com/archive/2009/12/16/aspnetmvc-2-rc.aspx
Omar
6
Observe que Request.RequestContex é suportado no .NET4 +
h - n
64

Gosto da resposta de Omar, mas isso não está funcionando para mim. Apenas para constar, esta é a solução que estou usando agora:

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
fonte
Ele contém o URL do meu site. Lá, eu o removi.
pupeno
4
Considerando que a classe UrlHelper depende do contexto da solicitação (e do contexto HTTP), a construção manual desses objetos de contexto pode gerar resultados inesperados. Se HttpContext.Current for nulo e você usar essa abordagem, eu continuaria com cuidado.
Sean
4
Cuidado com essa resposta - o RequestContext resulta em um UrlHelper que sempre retorna uma string vazia.
Gknicker # 30/16
47

Um UrlHelper pode ser construído a partir de uma ação do Controller com o seguinte:

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

Fora de um controlador, um UrlHelper pode ser criado criando um RequestContext a partir de RouteTable.Routes RouteData.

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

(Com base na resposta de Brian, com uma pequena correção de código adicionada.)

Nathan Taylor
fonte
2
Mas eu não tenho um controlador no modelo.
pupeno
Ok, peço desculpas, não sabia exatamente onde o código estava sendo executado. Deixe-me dar uma olhada ...
Nathan Taylor
2
Não há necessidade de criar um novo contexto de solicitação:var urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
bradlis7
Bom @ bradlis7. Isso é MVC 5?
23415 Nathan Taylor
1
Não funciona, porque this.ControllerContext.RequestContexté a HttpRequestContext, e construtor de UrlHelperespera a RequestContext. Ambas as classes não são relacionadas.
Florian Winter
8

Sim, você pode instanciar. Você pode fazer algo como:

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

RouteTable.Routesé uma propriedade estática, então você deve estar bem lá; para obter uma HttpContextBasereferência, HttpContextWrapperleva uma referência HttpContexte HttpContextentrega isso.

Brian Mains
fonte
Isso não vai funcionar, embora seja muito próximo. Veja minha resposta abaixo.
Nathan Taylor
3

Depois de tentar todas as outras respostas, acabei com

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

Aborrecedores odeiam ¯ \ _ (ツ) _ / ¯

Florian Winter
fonte
0

Eu estava tentando fazer algo semelhante dentro de uma página (fora de um controlador).

O UrlHelper não me permitiu construí-lo tão facilmente quanto a resposta do Pablos, mas lembrei-me de um velho truque para efetivamente fazer a mesma coisa:

string ResolveUrl(string pathWithTilde)
vGHazard
fonte
-30

Eu acho que o que você está procurando é o seguinte:

Url.Action("ActionName", "ControllerName");
user246874
fonte