gpt4 book ai didi

c# - ModelMetadata TemplateHint 始终为空

转载 作者:行者123 更新时间:2023-11-30 16:18:34 29 4
gpt4 key购买 nike

我正在尝试创建自定义 ModelMetadataProvider为 JQuery UI 自动完成小部件提供不显眼的属性。

我有一个看起来像这样的自定义属性:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class AutocompleteAttribute : Attribute, IMetadataAware
{
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.TemplateHint = "Autocomplete";
}
}

和一个看起来像这样的编辑器模板:

@{
var attributes = new RouteValueDictionary
{
{"class", "text-box single-line"},
{"autocomplete", "off"},
{"data-autocomplete-url", "UrlPlaceholder" },
};
}

@Html.TextBox("", ViewContext.ViewData.TemplateInfo.FormattedModelValue, attributes)

我有一个 viewModel,其属性类型为 string其中包括 AutocompleteAttribute像这样:

public class MyViewModel
{
[Autocomplete]
public string MyProperty { get; set; }
}

当我在我的 View 中使用此 viewModel 时,我检查生成的 html,我得到一个 <input>具有如下属性的标签:data-autocomplete-url="UrlPlaceholder" .

我接下来要做的是能够在我的 View 中指定使用我的 viewModel 的 URL,如下所示:

@model MyViewModel

@{ ViewBag.Title = "Create item"; }

@Html.AutoCompleteUrlFor(p => p.MyProperty, UrlHelper.GenerateUrl(null, "Autocomplete", "Home", null, Html.RouteCollection, Html.ViewContext.RequestContext, true))

// Other stuff here...

<div>
@Html.ActionLink("Back to List", "Index")
</div>

我的 AutoCompleteForUrl helper 只是将生成的 URL 保存在字典中,使用属性名称作为键。

接下来我创建了一个自定义 ModelMetadataProvider并使用这行代码在 global.asax 中注册它 ModelMetadataProviders.Current = new CustomModelMetadataProvider(); .

我想做的是将 JQuery UI 自动完成小部件要使用的 URL 插入到 metadata.AdditionalValues 中。自动完成编辑器模板使用的字典。

我的习惯ModelMetadataProvider看起来像这样:

public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(IEnumerable<System.Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);

if (metadata.TemplateHint == "Autocomplete")
{
string url;
if(htmlHelpers.AutocompleteUrls.TryGetValue(metadata.propertyName, out url)
{
metadata.AdditionalValues["AutocompleteUrl"] = url;
}
}

return metadata;
}
}

我更新后的编辑器模板如下所示:

@{
object url;

if (!ViewContext.ViewData.ModelMetadata.TryGetValue("AutocompleteUrl", out url))
{
url = "";
}

var attributes = new RouteValueDictionary
{
{"class", "text-box single-line"},
{"autocomplete", "off"},
{"data-autocomplete-url", (string)url },
};
}

@Html.TextBox("", ViewContext.ViewData.TemplateInfo.FormattedModelValue, attributes)

问题是,TemplateHint在我的自定义模型元数据提供程序中,属性从不等于“自动完成”,因此我生成 URL 的逻辑永远不会被调用。我本以为此时 TemplateHint属性将被设置为我调用 CreateMetadata 的基本实现的 DataAnnotationsModelMetadataProvider .

这是我可以确认的:

  • CustomModelMetadataProvider已正确注册,因为它包含正在调用的其他代码。
  • 由于生成的 Html 包含名为 "data-autocomplete-url" 的属性,因此选择了正确的编辑器模板.
  • 如果我在自动完成模板中放置断点,Visual Studio 会转到调试器。

那么有人可以帮我解释一下吗?我对 ModelMetadataProvider 有什么误解?系统?

最佳答案

在查看 ASP.NET MVC 3 源代码后,我发现这是因为 CreateMetadata 方法在 OnMetadataCreated 方法之前被调用IMetadataAware 应用于模型的属性。

我找到了一个替代解决方案,可以让我做我想做的事。

首先我更新了我的 AutocompleteAttribute:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class AutocompleteAttribute : Attribute, IMetadataAware
{
public const string Key = "autocomplete-url";
internal static IDictionary<string, string> Urls { get; private set; }

static AutocompleteAttribute()
{
Urls = new Dictionary<string, string>();
}

public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.TemplateHint = "Autocomplete";

string url;

if (Urls.TryGetValue(metadata.PropertyName, out url))
{
metadata.AdditionalValues[Key] = url;
Urls.Remove(metadata.PropertyName);
}
}
}

在我的 View 中设置 url 的 Html 辅助方法如下所示:

public static IHtmlString AutocompleteUrlFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, string url)
{
if (string.IsNullOrEmpty(url))
throw new ArgumentException("url");

var property = ModelMetadata.FromLambdaExpression(expression, html.ViewData).PropertyName;
AutocompleteAttribute.Urls[property] = url;

return MvcHtmlString.Empty;
}

然后我在编辑器模板中要做的就是:

@{
object url;
ViewData.ModelMetadata.AdditionalValues.TryGetValue(AutocompleteAttribute.Key, out url);

var attributes = new RouteValueDictionary
{
{"class", "text-box single-line"},
{"autocomplete", "off"},
{ "data-autocomplete-url", url },
};
}

@Html.TextBox("", ViewContext.ViewData.TemplateInfo.FormattedModelValue, attributes)

关于c# - ModelMetadata TemplateHint 始终为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16058272/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com