7

I've encountered a strange anomaly while learning/tinkering with 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

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

a RuntimeBinderExceptionis with the message

'object' does not contain a definition for '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:

enter image description here

So what happened here?

4

3 回答 3

9

这个问题的答案可以在这里找到:http ://www.heartysoft.com/ashic/blog/2010/5/anonymous-types-c-sharp-4-dynamic

从优秀的博客文章中提取:

Anonymous Types are Internal

调用Model.Action失败的原因是 的类型信息Model在运行时不可用。它不可用的原因是因为匿名类型不是公共的。当该方法返回该匿名类型的实例时,它返回一个引用匿名类型实例的 System.Object - 主程序无法获得信息的类型。动态运行时试图找到Action在对象上调用的属性,但无法从它拥有的类型信息中解析它。因此,它会引发异常。

于 2015-11-27T16:38:43.637 回答
3

那么这里发生了什么?

您的部分视图是弱类型的。你没有@model它的定义。所以默认情况下它object显然没有Action属性。

解决这个问题的正确方法是定义一个视图模型:

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

您的部分视图将被强输入:

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

并将由主视图传递:

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

另一种可能性(我个人不喜欢,因为它依赖于运行时绑定)是在局部视图中使用动态模型:

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

然后您将能够在调用它时传递一个匿名对象:

@Html.Partial("_PartialView", new { Action = "Foo" })
于 2013-11-13T08:53:20.327 回答
1

以下是一些使用反射的选项。在大多数情况下,性能应该可以忽略不计。

实用类

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

视图.cshtml

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

paritial.cshtml 文件

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

在 view.cshtml 中使用更紧凑的部分调用

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

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

调整变量以在 paritial.cshtml 文件中获取推断名称

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

创建一个简单的视图模型类并不难,但我不喜欢只使用一次来传递数据的类,所以这对我有用。

您还可以扩展默认视图基础

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

在 /Views/web.config 中注册基类

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

像这样在局部视图中获取数据

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

或者使用我建议的扩展方法。

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

这个选项真的不会给您带来任何好处,因为我们是从以前的实用程序方法中找到模型的。电话会变成。

@{
    var id = Model.Data("Id");
}
于 2014-05-03T02:24:41.813 回答