【问题标题】:Determining data input is a valid URL确定数据输入是一个有效的 URL
【发布时间】:2012-08-06 21:27:14
【问题描述】:

我在 MVC3 项目中有几个视图,允许用户在文本输入中输入 Url 并将其保存为实体上的数据。

我们需要验证输入是一个有效格式的 Url。

我首先使用http://dataannotationsextensions.org/ 中的[Url] 注释,但由于某些奇怪的原因,如果用户输入任何大写字符,客户端验证将失败。因此,为了缓解这种情况,我添加了一个 jQuery 事件,该事件在用户键入时强制输入为小写。事实证明这也不是最佳选择,因为用户可以粘贴已被 tinyUrl 等 Url 缩短服务缩短的 Url,而这些大写字符对于翻译是必需的。

所以我改用正则表达式:

[RegularExpression(@"^((ht|f)tp(s?)\:\/\/|~/|/)?([\w]+:\w+@)?([a-zA-Z]{1}([\w\-]+\.)+([\w]{2,5}))(:[\d]{1,5})?((/?\w+/)+|/?)(\w+\.[\w]{3,4})?((\?\w+=\w+)?(&\w+=\w+)*)?", ErrorMessage = "Please enter a valid Url")]

这适用于允许大写字符。但这并不完美。使用这个正则表达式,这些都被认为是有效的:

  1. www.asp
  2. asp.net
  3. http://asp.net
  4. http://www.asp.net
  5. http://www.asp

如您所见,其中一些并不是真正有效的。

这些 Url 的最大问题是在 Display View 中显示 Url 时。如果 Url 文本没有在 Url 前添加 http://,则在 View 中创建的链接最终看起来像这样:

http://www.mydomain.com/controller/action/www.asp 

http://www.mydomain.com/controller/action/asp.net

这两个显然都是无效的。

例如,如果 Url 没有 http:// 前缀,那么这部分 Razor 代码将创建一个类似上述两个的链接

....
<a href="@item.Link" target="blank">@item.LinkName</a>
...

但是如果输入的Url前面有http://,那么显示视图中生成的Url实际上是一个真实的Url比如

http://www.asp.net
http://asp.net
http://www.asp - this is actually an invalid address as well but it renders out correctly.

当然,显示一个保存到数据库中然后显示在视图上的 Url 并不像这样困难,并且还允许用户保存格式正确的 Url,但也可以将其缩写为:

asp.net
www.asp.net

不必包含前置协议。

更新

这是使用来自http://dataannotationsextensions.org/ 的注释在我的 ViewModel 中定义我的 Url 字段

[Required]
[StringLength(128)]
[Url(false)] // false denotes whether the protocol is required or not
public string URL { get; set; }

所以你不认为我疯了,这是一个使用大写且没有大写的屏幕截图。到目前为止在 IE8 和 Chrome 中测试,我得到了相同的结果

【问题讨论】:

  • 这 5 个例子中哪一个不是真正有效的?好的,它们可能不是全部 resolve,但如果你想测试你可以取消 Regex 并直接 ping 它们。
  • 1 和 5 完全无效,因为无法到达该地址,尽管 5 创建了一个 Url,但无法导航。 2、3 和 4 是有效的,但只有 3 和 4(带有前缀的 http:// 是可导航的,没有 http:// 的任何内容都会创建一个错误的可导航 URL,如上所示 http://www.mydomain.com/controller/action/www.asp

标签: asp.net-mvc-3 url razor


【解决方案1】:

[Url] from http://dataannotationsextensions.org/ 对我来说非常适合使用大写字母。但是如果由于某种原因你不想使用它,你可以抄袭它使用的正则表达式:

public class MyViewModel
{
    [RegularExpression(@"^(https?|ftp):\/\/(((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-fA-F]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$")]
    public string Url { get; set; }
}

【讨论】:

  • 你为什么将 false 传递给 Url 构造函数?这与您需要强制执行协议的要求相矛盾。
  • 那是在测试这两种情况。我不想强迫用户输入协议,除非我绝对必须这样做。我们的大多数用户将输入www.mybankname.commyschoolname.edu
  • 这个正则表达式在输入任何大写字符时也会失败... :-(
【解决方案2】:

已解决,我使用的来自 http://dataannotationsextensions.org/ 的 2 个 DLL DataAnnotationsExtensions.dll 和 DataAnnotationsExtensions.ClientValidation.dll 是 1.0 版,并且不允许在 [Url] 注释中使用大写。我将两者都更新到了 1.1 版,因为这是网站上演示的版本,问题现已修复。

现在使用[Url] 将允许我强制执行http://(如果我绝对必须)以及允许大写字符。

使用[Url(false)] 将允许用户不必输入http://,我可以在代码中添加它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-20
    • 1970-01-01
    • 2011-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多