我正在从 ASP.NET MVC 迁移到 ASP.NET Core,同时研究此页面上的 Microsoft 文档 https://learn.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/验证?view=aspnetcore-2.2
我读过这行关于
DataTypeAttribute
:
DataType 属性可以使 ASP.NET Core 框架选择正确的字段模板来呈现数据。 DisplayFormat 如果单独使用,则使用字符串模板。
这对我来说听起来不清楚,我所知道的
DataTypeAttribute
就是上面一行(在同一页上)中提到的内容:
浏览器可以启用 HTML5 功能(例如显示日历控件、适合区域设置的货币符号、电子邮件链接等)
所以这意味着第一个引用确实谈论了与第二个不同的东西。我正在寻求一些更清晰的解释来解释它的含义(在第一个引用中)以及(如果可能的话)一些有趣的代码片段来证明这一点。
更准确地说,我在这里想要什么,实际上是两个引号之间的差异,如以下快照所示:
我理解第一句话(在快照中),但实际上第二句话让我感到困惑,这就是我要求更清晰的解释。这样一个列表中的 2 个点不可能相同,可以吗?
DataType 属性可以使 ASP.NET Core 框架选择正确的字段模板来呈现数据。 DisplayFormat 如果单独使用,则使用字符串模板。
DataType
只不过是描述与数据字段相关的数据类型的
enum
,例如,Date
、DateTime
、Currency
、Url
、CreditCard
和很快。
[DataTypeAttribute]
只是一个指示符,指示如何生成标签。
考虑以下模型:
[Display(Name = "Release Date"), DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public DateTime ReleaseDate2 { get; set;
ReleaseDate
和 ReleaseDate2
都具有 与 DateTime
相同的声明类型。但两个字段渲染的html类型不同:
<input class="form-control" type="date" data-val="true" data-val-required="The Release Date field is required." id="ReleaseDate" name="ReleaseDate" value="">
<input class="form-control" type="datetime-local" data-val="true" data-val-required="The ReleaseDate2 field is required." id="ReleaseDate2" name="ReleaseDate2" value="">
请注意,第一个字段是
type="date"
,而第二个字段是 type="datetime-local"
。这是由 TagHelper
自动为您完成的。
此外,如果字段有值,则
TagHelper
在构造[DateTypeAttribute]
时会知道ModelExpression
,并在处理此标签时获取此类型的相关格式:
string format;
if (string.Equals("month", inputType, StringComparison.OrdinalIgnoreCase))
{
// "month" is a new HTML5 input type that only will be rendered in Rfc3339 mode
format = "{0:yyyy-MM}";
}
else if (string.Equals("decimal", inputTypeHint, StringComparison.OrdinalIgnoreCase) &&
string.Equals("text", inputType, StringComparison.Ordinal) &&
string.IsNullOrEmpty(modelExplorer.Metadata.EditFormatString))
{
// ...
}
else if ...
更多详情请参见 GetFormat(modelExplorer, inputTypeHint, inputType)
处理
datetime
& date
& time
时,相关格式由以下方式生成:
private static readonly Dictionary<string, string> _rfc3339Formats =
new Dictionary<string, string>(StringComparer.Ordinal)
{
{ "date", "{0:yyyy-MM-dd}" },
{ "datetime", @"{0:yyyy-MM-ddTHH\:mm\:ss.fffK}" },
{ "datetime-local", @"{0:yyyy-MM-ddTHH\:mm\:ss.fff}" },
{ "time", @"{0:HH\:mm\:ss.fff}" },
};
结果,渲染的视图是:
这就是
DateTypeAttribute
影响显示格式的方式。
最后,你可能想知道
data-
属性是如何生成的,你可以看一下
DataTypeAttributeAdapter
的源代码:
MergeAttribute(context.Attributes, "data-val", "true");
MergeAttribute(context.Attributes, RuleName, GetErrorMessage(context));
还有:ValidationAttributeAdapterProvider:
...
else if (type == typeof(CreditCardAttribute))
{
adapter = new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "data-val-creditcard", stringLocalizer);
}
...
else if (type == typeof(EmailAddressAttribute))
{
adapter = new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "data-val-email", stringLocalizer);
}
else if (type == typeof(PhoneAttribute))
{
adapter = new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "data-val-phone", stringLocalizer);
}
else if (type == typeof(UrlAttribute))
{
adapter = new DataTypeAttributeAdapter((DataTypeAttribute)attribute, "data-val-url", stringLocalizer);
}
...
这意味着在处理
Email
、Phone
等时,ASP.NET Core 还将重用 DataTypeAttribute
并为您生成不同的验证元信息(但 DateTypeAttribute
不会验证这些字段)。
[更新]:
也许使用
DataType=Currency
如@Hooman Bahreini评论是一个更好的例子。
但是这里渲染的
type
的input
不会是number
,而是一个普通的text
。 text
不是 HTML5 功能。另外,我现在将使用 DisplayFor()
作为示例。
考虑以下字段:
[Column(TypeName = "decimal(10, 4)")]
public decimal PlainPriceField { get; set; }
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(10, 4)")]
public decimal PriceWithDateType { get; set; }
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(10, 4)")]
[DisplayFormat(DataFormatString = "₿ {0:F3}BTC", ApplyFormatInEditMode = false)]
public decimal PriceWithDateTypeAndDisplayFormat { get; set; }
默认情况下,数据库将以 2 的比例存储
decimal
。为了清楚地说明这个问题,我添加了 [Column]
注释将它们声明为 decimal(10,4)
。
然后,我设置了所有价格字段
=1.2345
。请注意,所有这些字段在内存中的值均为 1.2345
。
但是,当呈现给最终用户时,
@Html.DisplayFor(item=>item.XyzPriceField)
的结果将是:
PlainPriceField
:1.23
PriceWithDataType
:$1.23
(而不是1.2345
或€1.2345
或其他任何东西)PriceWithDataTypeAndDisplayFormat
:₿ 1.235BTC
PriceWithDataType
以前缀 $
呈现,这是由当前区域设置确定的美元符号。
请注意,在这种情况下,HTML5 根本不支持货币(它将呈现为文本)。而且我们没有为此货币字段设置字符串模板。
通过检查
[DataType(DataType.Currency)]
注释,ASP.NET Core
框架知道这是一个 currency
数字,并且应该以某种特定格式显示。尽管不支持 HTML5 货币,但最终用户将获得 $1.23
。 上面已经介绍了 ASP.NET Core 如何为某些 DataType
选择内置格式的方式。
最后,如果您同时提供
[DisplayFormat]
,ASP.NET Core 将更喜欢 DataFormatString
中定义的格式。