Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/asp.net-mvc-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Dynamic Razor中的动态匿名类型导致RuntimeBinderException_Dynamic_Asp.net Mvc 3_Razor_Anonymous Types - Fatal编程技术网

Dynamic Razor中的动态匿名类型导致RuntimeBinderException

Dynamic Razor中的动态匿名类型导致RuntimeBinderException,dynamic,asp.net-mvc-3,razor,anonymous-types,Dynamic,Asp.net Mvc 3,Razor,Anonymous Types,我得到以下错误: “对象”不包含“分级名称”的定义 当您查看匿名动态类型时,它显然有RatingName 我意识到我可以用一个元组来实现这一点,但我想知道为什么会出现错误消息。我在一个对话框中找到了答案。答案在David Ebbo的博客文章 原因是 在中传递的匿名类型 控制器在内部,因此它只能 可以从程序集中访问 在其中声明。自视图 单独编译时,动态 宾德抱怨说,它不能过去 这是集会的边界 但是如果你仔细想想,这个 动态活页夹的限制是 其实很做作,因为如果 你使用私人反射,没有什么是真实的 阻

我得到以下错误:

“对象”不包含“分级名称”的定义

当您查看匿名动态类型时,它显然有RatingName

我意识到我可以用一个元组来实现这一点,但我想知道为什么会出现错误消息。

我在一个对话框中找到了答案。答案在David Ebbo的博客文章

原因是 在中传递的匿名类型 控制器在内部,因此它只能 可以从程序集中访问 在其中声明。自视图 单独编译时,动态 宾德抱怨说,它不能过去 这是集会的边界

但是如果你仔细想想,这个 动态活页夹的限制是 其实很做作,因为如果 你使用私人反射,没有什么是真实的 阻止你访问这些 内部成员(是的,它甚至在 中等信任度)。所以默认的动态 活页夹正在不遗余力地 执行C#编译规则(其中 您无法访问内部成员), 而不是让你做CLR 运行时允许

您可以使用该框架在接口中包装匿名类型


您只需返回一个
IEnumerable
,并在Linq结束时使用
.AllActLike()之所以这样做,是因为它使用具有声明匿名类型的程序集上下文的DLR调用匿名属性。

在我看来,具有内部属性的匿名类型是一个糟糕的.NET framework设计决策

这里有一个快速而漂亮的扩展来解决这个问题,即立即将匿名对象转换为ExpandooObject

public static ExpandoObject ToExpando(this object anonymousObject)
{
    IDictionary<string, object> anonymousDictionary =  new RouteValueDictionary(anonymousObject);
    IDictionary<string, object> expando = new ExpandoObject();
    foreach (var item in anonymousDictionary)
        expando.Add(item);
    return (ExpandoObject)expando;
}
当然,在你看来:

@foreach (var item in Model) {
     <div>x = @item.x, y = @item.y</div>
}
@foreach(模型中的变量项){
x=@item.x,y=@item.y
}

编写了一个控制台应用程序,并添加Mono.Cecil作为参考(您现在可以从中添加它),然后编写代码:

static void Main(string[] args)
{
    var asmFile = args[0];
    Console.WriteLine("Making anonymous types public for '{0}'.", asmFile);

    var asmDef = AssemblyDefinition.ReadAssembly(asmFile, new ReaderParameters
    {
        ReadSymbols = true
    });

    var anonymousTypes = asmDef.Modules
        .SelectMany(m => m.Types)
        .Where(t => t.Name.Contains("<>f__AnonymousType"));

    foreach (var type in anonymousTypes)
    {
        type.IsPublic = true;
    }

    asmDef.Write(asmFile, new WriterParameters
    {
        WriteSymbols = true
    });
}
static void Main(字符串[]args)
{
var asmFile=args[0];
WriteLine(“为{0}公开匿名类型”,asmFile);
var asmDef=AssemblyDefinition.ReadAssembly(asmFile,新的ReaderParameters
{
ReadSymbols=true
});
var anonymousTypes=asmDef.Modules
.SelectMany(m=>m.Types)
其中(t=>t.Name.Contains(“f_u匿名类型”);
foreach(匿名类型中的变量类型)
{
type.IsPublic=true;
}
asmDef.Write(asmFile,新WriterParameters
{
WriteSymbols=true
});
}
上面的代码将从输入参数获取程序集文件,并使用Mono.Cecil将可访问性从内部更改为公共,这将解决问题


我们可以在网站的后期构建事件中运行该程序。我写过,但我相信您可以阅读代码和快照。:)

而不是从匿名类型创建模型,然后尝试将匿名对象转换为
ExpandoObject
像这样

var model = new 
{
    Profile = profile,
    Foo = foo
};

return View(model.ToExpando());  // not a framework method (see other answers)
您可以直接创建
ExpandoObject

dynamic model = new ExpandoObject();
model.Profile = profile;
model.Foo = foo;

return View(model);
然后在视图中将模型类型设置为动态
@model dynamic
,您可以直接访问属性:

@Model.Profile.Name
@Model.Foo

我通常会为大多数视图推荐强类型视图模型,但有时这种灵活性很方便。

使用扩展方法是最好的解决方案

以下是不需要System.Web程序集的版本:

public static ExpandoObject ToExpando(this object anonymousObject)
{
    IDictionary<string, object> expando = new ExpandoObject();
    foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(anonymousObject))
    {
        var obj = propertyDescriptor.GetValue(anonymousObject);
        expando.Add(propertyDescriptor.Name, obj);
    }

    return (ExpandoObject)expando;
}
publicstaticexpandooobjecttoexpando(此对象为匿名对象)
{
IDictionary expando=新的ExpandoObject();
foreach(TypeDescriptor.GetProperties(匿名对象)中的PropertyDescriptor PropertyDescriptor)
{
var obj=propertyDescriptor.GetValue(匿名对象);
expando.Add(propertyDescriptor.Name,obj);
}
返回(ExpandoObject)expando;
}

根据已接受的答案,我已在控制器中重写,使其在一般情况下和幕后工作

代码如下:

protected override void OnResultExecuting(ResultExecutingContext filterContext)
{
    base.OnResultExecuting(filterContext);

    //This is needed to allow the anonymous type as they are intenal to the assembly, while razor compiles .cshtml files into a seperate assembly
    if (ViewData != null && ViewData.Model != null && ViewData.Model.GetType().IsNotPublic)
    {
       try
       {
          IDictionary<string, object> expando = new ExpandoObject();
          (new RouteValueDictionary(ViewData.Model)).ToList().ForEach(item => expando.Add(item));
          ViewData.Model = expando;
       }
       catch
       {
           throw new Exception("The model provided is not 'public' and therefore not avaialable to the view, and there was no way of handing it over");
       }
    }
}
在ResultExecuting(ResultExecutingContext filterContext)上受保护的覆盖无效
{
base.OnResultExecuting(filterContext);
//当razor将.cshtml文件编译到一个单独的程序集中时,这是允许匿名类型的必要条件,因为它们是程序集的专用类型
if(ViewData!=null&&ViewData.Model!=null&&ViewData.Model.GetType().IsNotPublic)
{
尝试
{
IDictionary expando=新的ExpandoObject();
(新的RouteValueDictionary(ViewData.Model)).ToList().ForEach(item=>expando.Add(item));
ViewData.Model=expando;
}
抓住
{
抛出新的异常(“提供的模型不是‘公共’的,因此视图不可用,并且无法将其移交”);
}
}
}

现在,您只需传递一个匿名对象作为模型,它将按预期工作。

我将从

如果安装软件包,则可以执行以下操作:

return View(Build<ExpandoObject>.NewObject(RatingName: name, Comment: comment));
返回视图(Build.NewObject(RatingName:name,Comment:Comment));

农民们也很高兴。

RuntimeBinderException引发的原因,我认为在其他帖子中有很好的答案。我只是想解释一下我是如何做到这一点的

请参考答案@DotNetWise和

首先,创建一个用于扩展的静态类

public static class impFunctions
{
    //converting the anonymous object into an ExpandoObject
    public static ExpandoObject ToExpando(this object anonymousObject)
    {
        //IDictionary<string, object> anonymousDictionary = new RouteValueDictionary(anonymousObject);
        IDictionary<string, object> anonymousDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(anonymousObject);
        IDictionary<string, object> expando = new ExpandoObject();
        foreach (var item in anonymousDictionary)
            expando.Add(item);
        return (ExpandoObject)expando;
    }
}
鉴于@model IEnumerable(动态,而不是模型类),这一点非常重要,因为我们将绑定匿名类型对象

@model IEnumerable<dynamic>

@*@foreach (dynamic item in Model)*@
@foreach (var item in Model)
{
    <div>x=@item.nric, y=@item.count</div>
}
@model IEnumerable
@*@foreach(模型中的动态项)*@
@foreach(模型中的var项目)
{
x=@item.nric,y=@item.count
}
对于foreach中的类型,我使用var或dynamic都没有错误


顺便说一下,创建一个与新字段匹配的新ViewModel也是将结果传递给视图的方法。

现在是递归风格

public static ExpandoObject ToExpando(this object obj)
    {
        IDictionary<string, object> expandoObject = new ExpandoObject();
        new RouteValueDictionary(obj).ForEach(o => expandoObject.Add(o.Key, o.Value == null || new[]
        {
            typeof (Enum),
            typeof (String),
            typeof (Char),
            typeof (Guid),

            typeof (Boolean),
            typeof (Byte),
            typeof (Int16),
            typeof (Int32),
            typeof (Int64),
            typeof (Single),
            typeof (Double),
            typeof (Decimal),

            typeof (SByte),
            typeof (UInt16),
            typeof (UInt32),
            typeof (UInt64),

            typeof (DateTime),
            typeof (DateTimeOffset),
            typeof (TimeSpan),
        }.Any(oo => oo.IsInstanceOfType(o.Value))
            ? o.Value
            : o.Value.ToExpando()));

        return (ExpandoObject) expandoObject;
    }
publicstaticexpandooobjecttoexpando(此对象
@model IEnumerable<dynamic>

@*@foreach (dynamic item in Model)*@
@foreach (var item in Model)
{
    <div>x=@item.nric, y=@item.count</div>
}
public static ExpandoObject ToExpando(this object obj)
    {
        IDictionary<string, object> expandoObject = new ExpandoObject();
        new RouteValueDictionary(obj).ForEach(o => expandoObject.Add(o.Key, o.Value == null || new[]
        {
            typeof (Enum),
            typeof (String),
            typeof (Char),
            typeof (Guid),

            typeof (Boolean),
            typeof (Byte),
            typeof (Int16),
            typeof (Int32),
            typeof (Int64),
            typeof (Single),
            typeof (Double),
            typeof (Decimal),

            typeof (SByte),
            typeof (UInt16),
            typeof (UInt32),
            typeof (UInt64),

            typeof (DateTime),
            typeof (DateTimeOffset),
            typeof (TimeSpan),
        }.Any(oo => oo.IsInstanceOfType(o.Value))
            ? o.Value
            : o.Value.ToExpando()));

        return (ExpandoObject) expandoObject;
    }
var projectInfo = new {
 Id = proj.Id,
 UserName = user.Name
};

var workitem = WorkBL.Get(id);

return View(new
{
  Project = projectInfo,
  WorkItem = workitem
}.ToExpando());
public static class RazorDynamicExtension
{
    /// <summary>
    /// Dynamic object that we'll utilize to return anonymous type parameters in Views
    /// </summary>
    public class RazorDynamicObject : DynamicObject
    {
        internal object Model { get; set; }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            if (binder.Name.ToUpper() == "ANONVALUE")
            {
                result = Model;
                return true;
            }
            else
            {
                PropertyInfo propInfo = Model.GetType().GetProperty(binder.Name);

                if (propInfo == null)
                {
                    throw new InvalidOperationException(binder.Name);
                }

                object returnObject = propInfo.GetValue(Model, null);

                Type modelType = returnObject.GetType();
                if (modelType != null
                    && !modelType.IsPublic
                    && modelType.BaseType == typeof(Object)
                    && modelType.DeclaringType == null)
                {
                    result = new RazorDynamicObject() { Model = returnObject };
                }
                else
                {
                    result = returnObject;
                }

                return true;
            }
        }
    }

    public static RazorDynamicObject ToRazorDynamic(this object anonymousObject)
    {
        return new RazorDynamicObject() { Model = anonymousObject };
    }
}
var project = @(Html.Raw(JsonConvert.SerializeObject(Model.Project.AnonValue)));
var projectName = @Model.Project.Name;
var model = new { value = 1, child = new { value = 2 } };
return View(JObject.FromObject(model));
@using Newtonsoft.Json.Linq;
@model JObject

@{
    dynamic model = (dynamic)Model;
}
<span>Value of child is: @model.child.value</span>