Можно ли передать анонимный тип моему представлению 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);

Тем не менее, в моем View я понял, что мне нужно будет получить доступ к имени клиента для каждого заказа. Я начал использовать 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 View таким образом, чтобы он принимал IEnumerable в качестве данных своего представления, где T определяется тем, что передается из контроллера, или мне нужно будет определить конкретный тип для заполнения из моего запроса?

11 ответов

Решение

Можете ли вы передать его на вид? Да, но ваше мнение не будет строго напечатано. Но помощники будут работать. Например:

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

//Using a normal ViewPage

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

Это текстовое поле должно отображать "Эй, это сработало!" в качестве значения.

Итак, вы можете определить представление, где T определяется тем, что передается ему от контроллера? Ну да, но не во время компиляции, очевидно.

Задумайтесь об этом на мгновение. Когда вы объявляете тип модели для представления, это значит, что вы получаете intellisense для представления. Это означает, что тип должен быть определен во время компиляции. Но возникает вопрос, можем ли мы определить тип из чего-то, данного ему во время выполнения. Конечно, но не с сильной типизацией сохранились.

Как бы вы получили Intellisense для типа, который вы еще даже не знаете? Контроллер может в конечном итоге передать любой тип в представление во время выполнения. Мы даже не можем анализировать код и догадываться, потому что фильтры действий могут изменить объект, переданный в представление, для всех, что мы знаем.

Я надеюсь, что это проясняет ответ, не запутывая его больше.:)

Вы можете передавать анонимные типы в представление, просто не забудьте привести модель к динамическому виду.

Вы можете сделать так:

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 
}

В.NET 4.0 анонимные типы могут быть легко преобразованы в ExpandoObjects, и, таким образом, все проблемы устраняются с помощью издержек самого преобразования. Проверьте здесь

Во что бы то ни стало, сегодня вечером я обнаружил класс DataLoadOptions и его метод LoadWith. Я смог указать свой LINQ to SQL DataContext, чтобы он всегда загружал строку "Клиенты" всякий раз, когда извлекается строка "Заказы", ​​так что исходный запрос теперь получает все, что мне нужно, за одно обращение.

Вот статья, объясняющая передачу анонимного типа в Views и привязку данных.

Спасибо

Помните: 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);
    }
}

В этом посте показано, как вы можете вернуть анонимный тип из метода, но он не будет соответствовать вашим требованиям.

Другой вариант может заключаться в том, чтобы вместо этого преобразовать анонимный тип в JSON (JavaScriptSerializer сделает это), а затем вернуть этот JSON в представление, тогда вам потребуется jQuery и т. Д., Чтобы сделать то, что вам нравится с ним.

Я использовал Linq для "преобразования" моих данных в формат JSON, который необходим моему представлению с большим успехом.

Вы можете написать класс с теми же свойствами, что и у вашего анонимного типа, и вы можете привести свой анонимный тип к вашему рукописному типу. Недостатком является необходимость обновления класса при внесении изменений в проекцию в запросе linq.

Если я не ошибаюсь, анонимные типы преобразуются в строго типизированные объекты во время компиляции. Вопрос о том, является ли строго типизированный объект действительным для данных представления, - другой вопрос.

Вы можете пройти Объект и использовать отражение, чтобы получить желаемые результаты. Посмотрите на ObjectDumper.cs (включенный в csharpexamples.zip) для примера этого.

У меня та же проблема... подумав немного, я пришел к выводу, что самое правильное и наиболее масштабируемое решение - это сериализация этого анонимного типа перед отправкой в ​​View. Таким образом, вы можете использовать тот же метод, чтобы заполнить страницу с помощью кода View и заполнить вашу страницу с помощью JSON

Другие вопросы по тегам