从自定义属性中获取模型的属性值
我有一个名为 FileLink
的自定义属性,它使用 DisplayForModel()
为具有 ID 值的控制器生成 ActionLink
。
该属性看起来像这样:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class FileLinkAttribute : Attribute
{
public string ActionName { get; set; }
public string ControllerName { get; set; }
public string IdPropertyName { get; set; }
public FileLinkAttribute(string actionName, string controllerName, string idPropertyName)
{
ActionName = actionName;
ControllerName = controllerName;
IdPropertyName = idName;
}
}
它是否在视图模型中使用,如下所示:
public class MyViewModel
{
[HiddenInput(DisplayValue = false)]
public int? Id { get; set; }
[HiddenInput(DisplayValue = false)]
public int? TargetId { get; set; }
[FileLink("SomeAction", "SomeController", "TargetId")]
public string Name { get; set; }
}
我有一个派生自 DataAnnotationsModelMetadataProvider
的自定义 MetadataProvider
,它将属性值放入元数据AdditionalValues 中,如下所示:
// retrieve the values to generate a file link
var fileLinkAttributes = attributes.OfType<FileLinkAttribute>();
if (fileLinkAttributes.Any())
{
var fileLinkAttribute = fileLinkAttributes.First();
metadata.AdditionalValues["FileLinkAttribute"] = fileLinkAttribute;
metadata.TemplateHint = "FileLink";
}
目标是让 DisplayForModel
调用下面的 DisplayTemplate
,以生成包含来自 MyViewModel
的 TargetId
中的值的链接。因此,如果 TargetId
为 5,则链接将为“SomeController/SomeAction/5”。
// This DisplayTemplate for use with the "FileLinkAttribute"
//
// Usage: [FileLinkAttribute("ActionName","ControllerName","IdPropertyName")]
var fileLinkAttribute = (FileLinkAttribute)ViewData.ModelMetadata.AdditionalValues["FileLinkAttribute"];
var targetId = *<GET VALUE OF CONTAINER MODEL IdPropertyName>*;
@Html.ActionLink((string)ViewData.Model, fileLinkAttribute.ActionName, fileLinkAttribute.ControllerName, new { Id = targetId}, null)
完成所有这些后,我无法访问包含对象以从 TargetId 中提取属性值。我尝试在属性内、提供程序内和显示模板内执行此操作,但没有成功。
有没有办法或地方可以访问此值来实现我从包含该属性的视图模型对象读取属性值的意图?
I have a custom attribute called FileLink
that uses DisplayForModel()
to generate an ActionLink
to a controller with an ID value.
The attribute looks like this:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class FileLinkAttribute : Attribute
{
public string ActionName { get; set; }
public string ControllerName { get; set; }
public string IdPropertyName { get; set; }
public FileLinkAttribute(string actionName, string controllerName, string idPropertyName)
{
ActionName = actionName;
ControllerName = controllerName;
IdPropertyName = idName;
}
}
Is it used in a viewmodel, like so:
public class MyViewModel
{
[HiddenInput(DisplayValue = false)]
public int? Id { get; set; }
[HiddenInput(DisplayValue = false)]
public int? TargetId { get; set; }
[FileLink("SomeAction", "SomeController", "TargetId")]
public string Name { get; set; }
}
I have a custom MetadataProvider
derived from DataAnnotationsModelMetadataProvider
that puts the attribute values into the metadata AdditionalValues as so:
// retrieve the values to generate a file link
var fileLinkAttributes = attributes.OfType<FileLinkAttribute>();
if (fileLinkAttributes.Any())
{
var fileLinkAttribute = fileLinkAttributes.First();
metadata.AdditionalValues["FileLinkAttribute"] = fileLinkAttribute;
metadata.TemplateHint = "FileLink";
}
The goal is to have DisplayForModel
call the DisplayTemplate
below to generate a link with the value in TargetId
from MyViewModel
. So if TargetId
is 5, the link will be "SomeController/SomeAction/5"
// This DisplayTemplate for use with the "FileLinkAttribute"
//
// Usage: [FileLinkAttribute("ActionName","ControllerName","IdPropertyName")]
var fileLinkAttribute = (FileLinkAttribute)ViewData.ModelMetadata.AdditionalValues["FileLinkAttribute"];
var targetId = *<GET VALUE OF CONTAINER MODEL IdPropertyName>*;
@Html.ActionLink((string)ViewData.Model, fileLinkAttribute.ActionName, fileLinkAttribute.ControllerName, new { Id = targetId}, null)
With all this in place, I am unable to access the containing object to pull the property value from TargetId. I have tried to do this within the Attribute, within the Provider, and within the DisplayTemplate, with no luck.
Is there a way or place I can access this value to accomplish my intent to read a property value from the viewmodel object containing the attribute?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
阅读这篇文章后,描述了自定义 DataAnnotationsModelMetadataProvider 中
modelAccessor
的用途:MVC 中的“Func
我能够将在自定义提供程序中实现的这个(非常黑客的)解决方案拼凑在一起:
我不确定如何取消引用 Func 来获取它的实际目标,并且类型名称在此都被奇怪地显示出来例如,例如
因此我转换为字符串以检查它是否包含“System.Web.Mvc.AssociatedMetadataProvider”。可能不是最好的事情,但这是我让它发挥作用的唯一方法。
哦,我还向属性添加了第四个属性来包含值:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
公共密封类 FileLinkAttribute :属性
{
公共字符串 ActionName { 获取;放; }
公共字符串控制器名称{获取;放; }
公共字符串 IdPropertyName { 获取;放; }
公共字符串 IdPropertyValue { 获取;放; 做
:
在 DisplayTemplate 中我这样
After reading this post describing the purpose of
modelAccessor
in a custom DataAnnotationsModelMetadataProvider:What is the "Func<object> modelAccessor" parameter for in MVC's DataAnnotationsModelMetadataProvider?
I was able to piece together this (very hackish) solution implemented in the custom provider:
I am not sure how to derefence a Func to get it's actual target, and the type name comes out all munged wierdly in this example, such as
So I convert to a string to check if it contains "System.Web.Mvc.AssociatedMetadataProvider". Probably not the best thing but this is the only way I could get it to work.
Oh, I also added a 4th property to the attribute to contain the value:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class FileLinkAttribute : Attribute
{
public string ActionName { get; set; }
public string ControllerName { get; set; }
public string IdPropertyName { get; set; }
public string IdPropertyValue { get; set; }
}
and in the DisplayTemplate I do:
这应该是 strsing 或 object 的编辑器模板,因为这就是您要应用属性的对象。所以在
~/Views/Shared/EditorTemplates/string.cshtml
:和主视图中:
This should be an editor template for strsing or object as that'swhat you are applying the attribute on. So inside
~/Views/Shared/EditorTemplates/string.cshtml
:and in your main view: