从自定义属性中获取模型的属性值

发布于 2024-11-05 17:22:10 字数 2311 浏览 1 评论 0原文

我有一个名为 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,以生成包含来自 MyViewModelTargetId 中的值的链接。因此,如果 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

椒妓 2024-11-12 17:22:10

阅读这篇文章后,描述了自定义 DataAnnotationsModelMetadataProvider 中 modelAccessor 的用途:

MVC 中的“FuncmodelAccessor”参数是什么? DataAnnotationsModelMetadataProvider?

我能够将在自定义提供程序中实现的这个(非常黑客的)解决方案拼凑在一起:

    // retrieve the values to generate a file link
    var fileLinkAttributes = attributes.OfType<FileLinkAttribute>();
    if (fileLinkAttributes.Any())
    {
        var fileLinkAttribute = fileLinkAttributes.First();

        // modelAccessor contains a pointer the container, but the type is not correct but contains the name of the correct type
        if (modelAccessor.Target.GetType().ToString().Contains("System.Web.Mvc.AssociatedMetadataProvider"))
        {
            // get the container model for this metadata
            FieldInfo containerInfo = modelAccessor.Target.GetType().GetField("container");
            var containerObject = containerInfo.GetValue(modelAccessor.Target);

            // get the value of the requested property
            PropertyInfo pi = containerObject.GetType().GetProperty(fileLinkAttribute.IdPropertyName);
            string idPropertyValue = pi.GetValue(containerObject, null).ToString();
            fileLinkAttribute.IdPropertyValue = idPropertyValue;
        }

        metadata.AdditionalValues["FileLinkAttribute"] = fileLinkAttribute;
        metadata.TemplateHint = "FileLink";
    }

我不确定如何取消引用 Func 来获取它的实际目标,并且类型名称在此都被奇怪地显示出来例如,例如

“System.Web.Mvc.AssociatedMetadataProvider+<>c__DisplayClassb”

因此我转换为字符串以检查它是否包含“System.Web.Mvc.AssociatedMetadataProvider”。可能不是最好的事情,但这是我让它发挥作用的唯一方法。

哦,我还向属性添加了第四个属性来包含值:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
公共密封类 FileLinkAttribute :属性
{
公共字符串 ActionName { 获取;放; }
公共字符串控制器名称{获取;放; }
公共字符串 IdPropertyName { 获取;放; }
公共字符串 IdPropertyValue { 获取;放; 做

public FileLinkAttribute(string actionName, string controllerName, string idPropertyName)
{
    ActionName = actionName;
    ControllerName = controllerName;
    IdPropertyName = idPropertyName;
}

在 DisplayTemplate 中我这样

var modelId = fileLinkAttribute.IdPropertyValue;

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:

    // retrieve the values to generate a file link
    var fileLinkAttributes = attributes.OfType<FileLinkAttribute>();
    if (fileLinkAttributes.Any())
    {
        var fileLinkAttribute = fileLinkAttributes.First();

        // modelAccessor contains a pointer the container, but the type is not correct but contains the name of the correct type
        if (modelAccessor.Target.GetType().ToString().Contains("System.Web.Mvc.AssociatedMetadataProvider"))
        {
            // get the container model for this metadata
            FieldInfo containerInfo = modelAccessor.Target.GetType().GetField("container");
            var containerObject = containerInfo.GetValue(modelAccessor.Target);

            // get the value of the requested property
            PropertyInfo pi = containerObject.GetType().GetProperty(fileLinkAttribute.IdPropertyName);
            string idPropertyValue = pi.GetValue(containerObject, null).ToString();
            fileLinkAttribute.IdPropertyValue = idPropertyValue;
        }

        metadata.AdditionalValues["FileLinkAttribute"] = fileLinkAttribute;
        metadata.TemplateHint = "FileLink";
    }

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

"System.Web.Mvc.AssociatedMetadataProvider+<>c__DisplayClassb"

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; }

public FileLinkAttribute(string actionName, string controllerName, string idPropertyName)
{
    ActionName = actionName;
    ControllerName = controllerName;
    IdPropertyName = idPropertyName;
}

}

and in the DisplayTemplate I do:

var modelId = fileLinkAttribute.IdPropertyValue;
看海 2024-11-12 17:22:10

这应该是 strsing 或 object 的编辑器模板,因为这就是您要应用属性的对象。所以在 ~/Views/Shared/EditorTemplates/string.cshtml:

@model string

@{
    var fileLinkAttribute = (FileLinkAttribute)ViewData.ModelMetadata.AdditionalValues["FileLinkAttribute"];
    var targetId = fileLinkAttribute.IdPropertyName;
}

@Html.ActionLink(Model, fileLinkAttribute.ActionName, fileLinkAttribute.ControllerName, new { Id = targetId}, null)

和主视图中:

@Html.EditorFor(x => x.Name)

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:

@model string

@{
    var fileLinkAttribute = (FileLinkAttribute)ViewData.ModelMetadata.AdditionalValues["FileLinkAttribute"];
    var targetId = fileLinkAttribute.IdPropertyName;
}

@Html.ActionLink(Model, fileLinkAttribute.ActionName, fileLinkAttribute.ControllerName, new { Id = targetId}, null)

and in your main view:

@Html.EditorFor(x => x.Name)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文