Como obter links para URLs em texto no ASP.NET MVC 4 com a syntax Razor?

Eu tenho um modelo com um campo de texto. O texto pode conter vários URLs. Não precisa conter URLs e não tem um formato específico.

Usando

@Html.DisplayFor(model => model.TextWithSomeUrls) 

o texto e as URLs são exibidos como texto normal, é claro. Gostaria de obter as URLs exibidas como links individuais de trabalho. Existe um método auxiliar para isso no ASP.NET / Razor?

Edit : Agora a saída é:

 http://www.google.com, foo: bar; http://www.yahoo.com 

Qual é exatamente o conteúdo do campo de texto.

Mas eu quero pegar as URLs e apenas os URLs renderizados como links como este:

 http://www.google.com, foo: bar; http://www.yahoo.com 

Minha solução :

 public static partial class HtmlExtensions { private const string urlRegEx = @"((http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?)"; public static MvcHtmlString DisplayWithLinksFor(this HtmlHelper htmlHelper, Expression<Func> expression) { string content = GetContent(htmlHelper, expression); string result = ReplaceUrlsWithLinks(content); return MvcHtmlString.Create(result); } private static string ReplaceUrlsWithLinks(string input) { Regex rx = new Regex(urlRegEx); string result = rx.Replace(input, delegate(Match match) { string url = match.ToString(); return String.Format("{0}", url); }); return result; } private static string GetContent(HtmlHelper htmlHelper, Expression<Func> expression) { Func func = expression.Compile(); return func(htmlHelper.ViewData.Model).ToString(); } } 

Esta extensão agora pode ser usada em visualizações:

 @Html.DisplayWithLinksFor(model => model.FooBar) 

Não existe um auxiliar como esse, mas você pode criar seu próprio auxiliar personalizado ou criar um modelo para o auxiliar DisplayFor , que conterá a lógica de que você precisa.

Eu tive alguns problemas com a solução:

  1. Não funcionou para nomes de host sem pontos, como localhost ou qualquer outro LAN-URL
  2. Não funcionou para URLs com espaços (edição menor)
  3. Não codificou todo o resto dos meus dados. Portanto, se houver “< ! -" no banco de dados, a página ficará truncada.
  4. O URI não é ignorado

Eu usei o código de cima, estendi um pouco e terminei com isso:

 private static readonly Regex urlRegEx = new Regex(@"(?< !="")((http|ftp|https|file):\/\/[\d\w\-_]+(\.[\w\-_]+)*([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?)"); private static readonly Regex quotedUrlRegEx = new Regex(@"(?(this HtmlHelper htmlHelper, Expression> expression, string templateName = null) { var encodedHTML = htmlHelper.DisplayFor(expression, templateName); return MvcHtmlString.Create(ReplaceUrlsWithLinks(encodedHTML.ToHtmlString())); } private static string ReplaceUrlsWithLinks(string input) { input = input.Replace(@"\\", @"file://").Replace('\\', '/'); var result = quotedUrlRegEx.Replace(input, delegate(Match match) { string url = match.Groups[2].Value; return String.Format("{1}", Uri.EscapeUriString(url), ShortenURL(url)); }); return urlRegEx.Replace(result, delegate(Match match) { string url = match.ToString(); return String.Format("{1}", Uri.EscapeUriString(url), ShortenURL(url)); }); } private static string ShortenURL(string url) { url = url.Substring(url.IndexOf("//", StringComparison.Ordinal) + 2); if (url.Length < 60) return url; var host = url.Substring(0, url.IndexOf("/", StringComparison.Ordinal)); return host + "/…"; } 

Obviamente, não 100% testado para todos os esquemas de URL, mas parece funcionar bem.

Exemplo de input:

 "\\02lanpc\abc\def\Bugs in the database.docx" http://localhost:81/applications/2/?releaseNumber=1.1&buildNumber=2 

Saída:

 02lanpc/abc/def/Bugs in the database.docx localhost:81/… 

Tente escrever seu próprio Html Helper, como o seguinte.

 public static string Urls(this HtmlHelper helper, string value) { var items = value.Split(';'); // use your delimiter var sb = new StringBuilder(); foreach(var i in items) { if(IsUrl(i)) // write a static method that checks if the value is a valid url sb.Append("" + i + ","); else sb.Append(i + ","); } return sb.ToString(); } 

E use assim

 @Html.Urls(myValue) 

Você pode usar @Html.Action(actionName) se o texto contiver mvc URL.