简体   繁体   English

在视图中访问动态匿名类型时的RuntimeBinderException

[英]RuntimeBinderException when accessing dynamic anonymous type in view

I've encountered a strange anomaly while learning/tinkering with asp.net. 我在学习/修补asp.net时遇到了一个奇怪的异常现象。

I'm trying to show a partial view like this: 我试图显示这样的局部视图:

@Html.Partial("_PartialView", new { Action = "Foo" })

When I'm trying to access Action with 当我尝试访问Action时

// Throws Microsoft.Csharp.RuntimeBinder.RuntimeBinderException
string throwsException = Model.Action; 

a RuntimeBinderExceptionis with the message 带有消息的RuntimeBinderExceptionis

'object' does not contain a definition for 'Action' 'object'不包含'Action'的定义

is thrown. 被扔了。
The strange thing is that this line works fine: 奇怪的是这条线很好用:

// This line works fine
string works = ((Type)Model.GetType()).GetProperty("Action").GetValue(Model);

This behavior puzzles me quite a bit and I'd rather avoid using this workaround. 这种行为让我很困惑,我宁愿避免使用这种解决方法。 Also I don't think the problem is anonymous types being internal because the MVC template for ASP.NET Project in VS2013 does this successfully: 此外,我不认为问题是匿名类型是内部的,因为VS2013中的ASP.NET项目的MVC模板成功完成了此操作:

在此输入图像描述

So what happened here? 那么这里发生了什么?

The answer to this question can be found here: http://www.heartysoft.com/ashic/blog/2010/5/anonymous-types-c-sharp-4-dynamic 这个问题的答案可以在这里找到: http//www.heartysoft.com/ashic/blog/2010/5/anonymous-types-c-sharp-4-dynamic

Pulling from the excellent blog post: 从优秀的博客文章中拉出来:

Anonymous Types are Internal

The reason the call to Model.Action fails is that the type information of Model is not available at runtime. 调用Model.Action失败的原因是Model的类型信息在运行时不可用。 The reason it's not available is because anonymous types are not public. 它不可用的原因是因为匿名类型不公开。 When the method is returning an instance of that anonymous type, it's returning a System.Object which references an instance of an anonymous type - a type who's info isn't available to the main program. 当该方法返回该匿名类型的实例时,它返回一个System.Object,它引用一个匿名类型的实例 - 一个类型的信息不可用于主程序。 The dynamic runtime tries to find a property called Action on the object, but can't resolve it from the type information it has. 动态运行时尝试在对象上查找名为Action的属性,但无法从其拥有的类型信息中解析它。 As such, it throws an exception. 因此,它会引发异常。

So what happened here? 那么这里发生了什么?

Your partial view is weakly typed. 你的部分视图是弱类型的。 You do not have a @model definition for it. 您没有@model定义。 So by default it is object which obviously doesn't have an Action property. 所以默认情况下它是object ,这显然不具有Action特性。

The correct way to solve this is to define a view model: 解决此问题的正确方法是定义视图模型:

public class MyViewModel
{
    public string Action { get; set; }
}

that your partial view will be strongly typed to: 您的部分视图将被强类型化为:

@model MyViewModel
@{
    string throwsException = Model.Action; 
}

and which will be passed by the main view: 哪个将通过主视图传递:

@Html.Partial("_PartialView", new MyViewModel { Action = "Foo" })

Another possibility (which personally I don't like as it relies on runtime binding) is to use a dynamic model in the partial view: 另一种可能性(我个人不喜欢,因为它依赖于运行时绑定)是在局部视图中使用动态模型:

@model dynamic
@{
    string throwsException = Model.Action; 
}

and then you will be able to pass an anonymous object when calling it: 然后你可以在调用它时传递一个匿名对象:

@Html.Partial("_PartialView", new { Action = "Foo" })

Here are some options using reflection. 以下是使用反射的一些选项。 The performance should be negligible in most scenarios. 在大多数情况下,性能应该可以忽略不计。

Utility Class 实用类

public static class ModelHelper
{
    public static T Data<T>( String key)  
    {
        var html = ((System.Web.Mvc.WebViewPage)WebPageContext.Current.Page).Html;
        var model = html.ViewData.Model;
        return (T)model.GetType().GetProperty(key).GetValue(model) ;
    }
}

view.cshtml view.cshtml

@(Html.Partial("partial",new { Id="InstructorId"}))

paritial.cshtml file paritial.cshtml文件

@model dynamic 
@{ 
    var id = ModelHelper.Data<String>("Id");
}

With a more compact parital call in view.cshtml 在view.cshtml中使用更紧凑的parital调用

@{
  var instructorId = "InstructorId";
  var windowTitle = "Window Title";
  var editorPageUrl = "~/View/Editors/Instructors.chstml";
}

@(Html.Partial("partial",new { instructorId, windowTitle, editorPageUrl }))

With variables adjusted to get inferred names in paritial.cshtml file 将变量调整为在paritial.cshtml文件中获取推断的名称

@model dynamic 
@{ 
    var id = ModelHelper.Data<String>("instructorId");
    var id = ModelHelper.Data<String>("windowTitle");
    var id = ModelHelper.Data<String>("editorPageUrl");
}

It is not hard to create a simple view-model class but I don't like classes that will only ever be used a single time for passing data, so this works for me. 创建一个简单的视图模型类并不难,但我不喜欢一次只能用于传递数据的类,所以这对我有用。

You could also extend the default view base 您还可以扩展默认视图库

namespace SafetyPlus.Shell.Code
{
    public abstract class ExtendedPageBaseClass<TModel> : WebViewPage<TModel> where TModel : class
    {
        public T Data<T>(String key) 
        {
            return (T)Model.GetType().GetProperty(key).GetValue(Model);
        }

        public Object Data(String key) 
        {
            return Data<Object>(key);
        }
    }
}

Register the base class in the /Views/web.config 在/Views/web.config中注册基类

<pages pageBaseType="SafetyPlus.Shell.Code.ExtendedPageBaseClass">
  ...
</pages>

Get the data in your partial view like this 像这样在部分视图中获取数据

@{ 
    var id = Data("Id");
    var idTyped = Data<String>("Id");
}

Or using an extension method which I suggested against. 或者使用我建议的扩展方法。

namespace NotYourDefaultNamespace
{
    public static class ModelExtensions
    {
        public static T Data<T>( this Object model, String key)  
        {
            return (T)model.GetType().GetProperty(key).GetValue(model) ;
        }
    }
} 

This options really doesn't buy you anything since we are finding the model from within the previous utility method. 这个选项真的不会给你带来什么,因为我们从之前的实用方法中找到了模型。 The call would become. 电话会变成。

@{
    var id = Model.Data("Id");
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 跨 dll 边界访问匿名/动态类型的属性会导致 RuntimeBinderException - Accessing properties of anonymous/dynamic types across dll boundaries gives RuntimeBinderException 尝试使用动态类型时RuntimeBinderException - RuntimeBinderException when trying to use dynamic type RuntimeBinderException 与 MVC 中的动态匿名对象 - RuntimeBinderException with dynamic anonymous objects in MVC 将JSON对象反序列化为动态类型,但获取RuntimeBinderException访问属性? - Deserialized JSON object to dynamic type but getting RuntimeBinderException accessing properties? 将int []传递给参数类型为动态的方法时发生RunTimeBinderException - RunTimeBinderException when passing int[] to method having parameter type dynamic 尝试实例化动态类型的数组时发生RuntimeBinderException(后期绑定) - RuntimeBinderException when trying to instantiate an array of a dynamic type (late-binding) 使用动态对象时的RuntimeBinderException - RuntimeBinderException when using dynamic object 访问动态属性会引发“Microsoft.CSharp.RuntimeBinder.RuntimeBinderException”类型的异常 - Accessing a dynamic's property threw an exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' 向动态类型添加值会导致RuntimeBinderException - Adding values to a dynamic type causes a RuntimeBinderException RuntimeBinderException 将泛型类型上的方法作为动态调用 - RuntimeBinderException invoking a method on a generic type as dynamic
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM