我可以将匿名类型传递给我的ASP.NET MVC视图吗?

时间:2008-10-21 22:11:41

标签: asp.net-mvc

我刚刚开始使用ASP.NET MVC,因为它处于测试阶段。在我的代码中,我正在运行一个简单的LINQ to SQL查询来获取结果列表并将其传递给我的视图。这种事情:

var ords = from o in db.Orders
           where o.OrderDate == DateTime.Today
           select o;

return View(ords);

但是,在我的视图中,我意识到我需要访问每个订单的客户名称。我开始使用o.Customer.Name,但我很确定这是为每个订单执行一个单独的查询(因为LINQ的延迟加载)。

减少查询数量的合理方法是同时选择客户名称。类似的东西:

var ords = from o in db.Orders
           from c in db.Customers
           where o.OrderDate == DateTime.Today
               and o.CustomerID == c.CustomerID
           select new { o.OrderID, /* ... */, c.CustomerName };

return View(ords);

现在我的“ords”变量是一个匿名类型的IEnumerable。

是否可以以这样的方式声明ASP.NET MVC视图:它接受IEnumerable作为其视图数据,其中T由从控制器传递的内容定义,或者我是否必须定义填充的具体类型从我的查询?

11 个答案:

答案 0 :(得分:22)

你能把它传递给视图吗?是的,但您的视图不会被强类型化。但帮手会工作。例如:

public ActionResult Foo() {
  return View(new {Something="Hey, it worked!"});
}

//Using a normal ViewPage

<%= Html.TextBox("Something") %>

该文本框应呈现“嘿,它有效!”作为价值。

那么你可以定义一个视图,其中T是由从控制器传递给它的内容定义的吗?是的,但显然不是在编译时。

考虑一下。当您为视图声明模型类型时,您将获得视图的智能感知。这意味着必须在编译时确定类型。但问题是,我们可以在运行时从给定的东西中确定类型。当然,但没有强大的打字保留。

你怎么会得到一个你还不知道的智能感知器?控制器最终可以在运行时将任何类型传递给视图。我们甚至无法分析代码和猜测,因为动作过滤器可以为我们所知道的所有人改变传递给视图的对象。

我希望能够澄清答案而不会使其更加模糊。 :)

答案 1 :(得分:11)

可以将匿名类型传递给视图,只需记住将模型转换为动态模型。

你可以这样做:

return View(new { 
    MyItem = "Hello", 
    SomethingElse = 42, 
    Third = new MyClass(42, "Yes") })

在视图的顶部,您可以执行此操作(在此使用剃刀)

@{
    string myItem = (dynamic)Model.MyItem;
    int somethingElse = (dynamic)Model.SomethingElse;
    MyClass third = (dynamic)Model.Third;
}

或者您可以像这样从ViewData中投射它们:

@{
    var myItem = ViewData.Eval("MyItem") as string
    var somethingElse = ViewData.Eval("SomethingElse") as int?
    var third = ViewData.Eval("Third") as MyClass 
}

答案 2 :(得分:7)

在.NET 4.0上,匿名类型可以很容易地转换为ExpandoObjects,因此所有问题都可以通过转换本身的开销来解决。 查看here

答案 3 :(得分:4)

为了它的价值,今晚我发现了DataLoadOptions类及其LoadWith方法。每当检索到Orders行时,我能够告诉我的LINQ to SQL DataContext始终加载Customers行,因此原始查询现在可以在一次点击中获得我需要的所有内容。

答案 4 :(得分:3)

Here是一篇文章,解释了如何将匿名类型传递给视图并绑定数据。

由于

答案 5 :(得分:1)

这个post显示了如何从方法中返回匿名类型,但它不符合您的要求。

另一个选择可能是将匿名类型转换为JSON(JavaScriptSerializer会这样做),然后将该JSON返回到视图,然后你需要一些jQuery等来做你喜欢的事情。

我一直在使用Linq将我的数据“塑造”成JSON格式,我的观点非常成功。

答案 6 :(得分:1)

您可以编写一个具有匿名类型相同属性的类,并且可以将您的匿名类型转换为手写类型。缺点是在linq查询中进行投影更改时必须更新类。

答案 7 :(得分:0)

您可以传递一个Object并使用反射来获得所需的结果。看一下ObjectDumper.cs(包含在csharpexamples.zip中)的一个例子。

答案 8 :(得分:0)

如果我没弄错的话,匿名类型会在编译时转换为强类型对象。强类型对象是否对视图数据有效是另一个问题。

答案 9 :(得分:0)

我遇到了同样的问题......经过一番思考后,我得出的结论是最正确,最具扩展性的解决方案,它是在发送到View之前序列化这个匿名类型。因此,您可以使用相同的方法使用后面的View代码填充页面并使用JSON填充页面

答案 10 :(得分:0)

请记住: anonymous类型是内部的,这意味着它们的属性无法在其定义的程序集之外看到。

通过将dynamic类型转换为anonymous,您可以更好地将View个对象(而不是anonymous个)传递给dynamic扩展方法。

public class AwesomeController : Controller
{
    // Other actions omitted...
    public ActionResult SlotCreationSucceeded(string email, string roles)
    {
        return View("SlotCreationSucceeded", new { email, roles }.ToDynamic());
    }
}

扩展方法如下所示:

public static class DynamicExtensions
{
    public static dynamic ToDynamic(this object value)
    {
        IDictionary<string, object> expando = new ExpandoObject();

        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType()))
            expando.Add(property.Name, property.GetValue(value));

        return (ExpandoObject) expando;
    }
}

尽管如此,仍然可以传递anonymous个对象,但您必须将其转换为dynamic一个。

public class AwesomeController : Controller
{
    // Other actions omitted...
    public ActionResult SlotCreationSucceeded(string email, string roles)
    {
        return View("SlotCreationSucceeded", new { email, roles });
    }
}

查看:

@{
    var anonymousModel = DynamicUtil.ToAnonymous(Model, new { email = default(string), roles = default(string) });
}

<h1>@anonymousModel.email</h1>
<h2>@anonymousModel.roles</h2>

辅助方法如下所示:

public class DynamicUtil
{
    public static T ToAnonymous<T>(ExpandoObject source, T sample)
        where T : class
    {
        var dict = (IDictionary<string, object>) source;

        var ctor = sample.GetType().GetConstructors().Single();

        var parameters = ctor.GetParameters();

        var parameterValues = parameters.Select(p => dict[p.Name]).ToArray();

        return (T) ctor.Invoke(parameterValues);
    }
}