Pregunta

He visto muchas preguntas sobre esto, pero nunca obtuve la respuesta que necesito.

Estoy convirtiendo una aplicación web bastante grande de Web Forms a MVC y después de un tiempo encontré un problema al pasar datos a la vista.En la Acción ejecuto el código:

//This is just an example ViewData["QProducts"] = from p in db.Products select new{Name = p.Name, Date = p.ToShortDateString() } ViewData["QUsers"] = from u in db.Users select u;

Utilizo un bucle foreach para iterar sobre los objetos en html, así:

foreach(var q in (IEnumerable)ViewData["QEvents"])
{ 
    /*Print the data here*/
}

Antes de usar MVC solo usaba un asp:Repeater, pero como se trata de MVC, no puedo usar controles ASP.NET.

¿Cómo se supone que debo pasar estos datos a la Vista?Realmente no tengo la opción de no usar tipos anónimos aquí. <%#ViewData.Eval()%> obviamente no funcionará.

¿Algunas ideas?

¿Fue útil?

Solución

En lugar de un tipo anónimo, cree un tipo que contenga el nombre y la fecha:

public class NameDate
{
  public string Name { get; set; }
  public DateTime Date { get; set; }
}

Luego úselo en su consulta de Linq:

from p in db.Products select new NameDate { Name = p.Name, Date = p.Date }

Escriba fuertemente su vista para ser MyView<IEnumerable<NameDate>> y luego simplemente haz un foreach ( var nameDate in ViewData.Model )...

Otros consejos

Si te sientes un poco vago, puedes usar este código aquí ... Es un poco largo, pero básicamente es un envoltorio para Reflection ...

var something = { Name = "Jim", Age = 25 };
AnonymousType type = AnonymousType.Create(something);

//then used...
string name = type.Get<string>("Name");
int age = type.Get<int>("Age", -1 /* optional default value */);

Y aquí está el código ...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Code {

    /// <summary>
    /// A convenient method of accessing the values of an 
    /// anonymous type without needing to define a separate class
    /// </summary>
    public class AnonymousType {

        #region Constants

        private const string EXCEPTION_MISSING_PARAMETER_INFORMATION = 
            "Unable to match the parameter '{0}' to a property in the AnonymousType. This could be due to a casting problem or a Property that does not exist.";
        private const string EXCEPTION_COULD_NOT_ACCESS_FIELD =
            "Unable to find a field named '{0}' (of type {1})";
        private const string EXCEPTION_COULD_NOT_ACCESS_FIELD_AT_INDEX =
            "Unable to find a field named '{0}' at the requested index (of type {1})";

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new AutoType for methods that return Anonymus types
        /// </summary>
        public AnonymousType(object type) {
            this._Init(type, false);
        }

        /// <summary>
        /// Creates a new AutoType for methods that return Anonymus types and
        /// detetrmins if exceptions should be thrown if a type is missing
        /// </summary>
        public AnonymousType(object type, bool supressErrors) {
            this._Init(type, supressErrors);
        }

        /// <summary>
        /// Initalizes the data for the is type
        /// </summary>
        private void _Init(object type, bool supressErrors) {
            this.SupressExceptions = supressErrors;
            this.m_Type = type.GetType();
            this.m_TypeData = type; 
        }

        #endregion

        #region Static Routines

        /// <summary>
        /// Creates a new Anonymous Type from the provided object data
        /// </summary>
        public static AnonymousType Create(object data) {
            return new AnonymousType(data);
        }

        /// <summary>
        /// Creates a new Anonymous Type from the provided object data
        /// </summary>
        public static AnonymousType Create(object data, bool supressErrors) {
            return new AnonymousType(data, supressErrors);
        }

        #endregion

        #region Private Members

        /// <summary>
        /// The type that will be accessed via reflection
        /// </summary>
        private Type m_Type;

        /// <summary>
        /// The actual typs that is being used
        /// </summary>
        private object m_TypeData;

        #endregion

        #region Properties

        /// <summary>
        /// Determines if errors should be thrown if any casting errors take place
        /// </summary>
        public bool SupressExceptions { get; set; }


        /// <summary>
        /// Accessess a property by name and returns an object
        /// </summary>
        public object this[string property] {
            get {
                return this.Get<object>(property);
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Checks if this Anonymous Type has the specified property
        /// </summary>
        public bool Has(string property) {
            return ((m_Type.GetProperty(property) as PropertyInfo) != null);
        }

        /// <summary>
        /// Returns if this Anonymous type has the specified property and that
        /// the value matches the type specified
        /// </summary>
        public bool Has(string property, Type isType) {

            //try and get the property
            PropertyInfo prop = m_Type.GetProperty(property) as PropertyInfo;

            //If this type doesn't exist at all, just return false
            if (prop == null) { return false; }

            //if it does exist, verify the type
            if (prop.PropertyType.Equals(isType)) { return true; }
            return false;

        }

        /// <summary>
        /// Returns a type value using the specified type
        /// </summary>
        public T Get<T>(string property) {

            //return this value if needed            
            PropertyInfo prop = m_Type.GetProperty(property) as PropertyInfo;
            try {
                return (T)prop.GetValue(this.m_TypeData, null);
            }
            catch (Exception ex) {
                if (this.SupressExceptions) { return default(T); }
                throw new Exception(
                    string.Format(EXCEPTION_COULD_NOT_ACCESS_FIELD, property, typeof(T).Name),
                    ex
                    );
            }
        }



        /// <summary>
        /// Returns a type value using the specified type
        /// </summary>
        public T Get<T>(string property, object[] index) {

            //return this value if needed
            PropertyInfo prop = m_Type.GetProperty(property) as PropertyInfo;
            try {
                return (T)prop.GetValue(this.m_TypeData, index);
            }
            catch (Exception ex) {
                if (this.SupressExceptions) { return default(T); }
                throw new Exception(
                    string.Format(EXCEPTION_COULD_NOT_ACCESS_FIELD_AT_INDEX, property, typeof(T).Name),
                    ex
                    );
            }
        }



        /// <summary>
        /// Returns a type value using the specified type but includes a default value
        /// if one it missing
        /// </summary>
        public T Get<T>(string property, T defaultValue) {
            //return this value if needed
            PropertyInfo prop = m_Type.GetProperty(property) as PropertyInfo;
            if (prop == null) { return defaultValue; }
            try {
                return (T)prop.GetValue(this.m_TypeData, null);
            }
            catch (Exception ex) {
                if (this.SupressExceptions) { return defaultValue; }
                throw new Exception(
                    string.Format(EXCEPTION_COULD_NOT_ACCESS_FIELD, prop, typeof(T).Name),
                    ex
                    );
            }

        }



        /// <summary>
        /// Accepts a delegate that will use the names of the passed in
        /// parameters as properties to map to. If the property does not
        /// exist, then the method will fail.
        /// </summary>
        public void Use<T1>(Action<T1> with) {

            //set a default for each of the params
            T1 param1 = default(T1);

            //get the parameters for this method
            var paramList = with.Method.GetParameters();

            //update each of the parameters            
            string paramName = string.Empty;
            try {
                for (int i = 0; i < paramList.Length; i++) {

                    //find the correct matching property for this parameter
                    paramName = paramList[i].Name;
                    switch (i + 1) {
                        case 1:
                            param1 = this.Get<T1>(paramName);
                            break;
                    }
                }

            }
            catch (Exception ex) {
                throw new ArgumentException(
                    string.Format(EXCEPTION_MISSING_PARAMETER_INFORMATION, paramName),
                    ex
                    );
            }

            //otherwise, execute the method provided
            with(param1);

        }



        /// <summary>
        /// Accepts a delegate that will use the names of the passed in
        /// parameters as properties to map to. If the property does not
        /// exist, then the method will fail.
        /// </summary>
        public void Use<T1, T2>(Action<T1, T2> with) {

            //set a default for each of the params
            T1 param1 = default(T1);
            T2 param2 = default(T2);

            //get the parameters for this method
            var paramList = with.Method.GetParameters();

            //update each of the parameters            
            string paramName = string.Empty;
            try {
                for (int i = 0; i < paramList.Length; i++) {

                    //find the correct matching property for this parameter
                    paramName = paramList[i].Name;
                    switch (i + 1) {
                        case 1:
                            param1 = this.Get<T1>(paramName);
                            break;

                        case 2:
                            param2 = this.Get<T2>(paramName);
                            break;
                    }
                }

            }
            catch (Exception ex) {
                throw new ArgumentException(
                    string.Format(EXCEPTION_MISSING_PARAMETER_INFORMATION, paramName),
                    ex
                    );
            }

            //otherwise, execute the method provided
            with(param1, param2);

        }



        /// <summary>
        /// Accepts a delegate that will use the names of the passed in
        /// parameters as properties to map to. If the property does not
        /// exist, then the method will fail.
        /// </summary>
        public void Use<T1, T2, T3>(Action<T1, T2, T3> with) {

            //set a default for each of the params
            T1 param1 = default(T1);
            T2 param2 = default(T2);
            T3 param3 = default(T3);

            //get the parameters for this method
            var paramList = with.Method.GetParameters();

            //update each of the parameters            
            string paramName = string.Empty;
            try {
                for (int i = 0; i < paramList.Length; i++) {

                    //find the correct matching property for this parameter
                    paramName = paramList[i].Name;
                    switch (i + 1) {
                        case 1:
                            param1 = this.Get<T1>(paramName);
                            break;

                        case 2:
                            param2 = this.Get<T2>(paramName);
                            break;

                        case 3:
                            param3 = this.Get<T3>(paramName);
                            break;
                    }
                }

            }
            catch (Exception ex) {
                throw new ArgumentException(
                    string.Format(EXCEPTION_MISSING_PARAMETER_INFORMATION, paramName),
                    ex
                    );
            }

            //otherwise, execute the method provided
            with(param1, param2, param3);

        }



        /// <summary>
        /// Accepts a delegate that will use the names of the passed in
        /// parameters as properties to map to. If the property does not
        /// exist, then the method will fail.
        /// </summary>
        public void Use<T1, T2, T3, T4>(Action<T1, T2, T3, T4> with) {

            //set a default for each of the params
            T1 param1 = default(T1);
            T2 param2 = default(T2);
            T3 param3 = default(T3);
            T4 param4 = default(T4);

            //get the parameters for this method
            var paramList = with.Method.GetParameters();

            //update each of the parameters            
            string paramName = string.Empty;
            try {
                for (int i = 0; i < paramList.Length; i++) {

                    //find the correct matching property for this parameter
                    paramName = paramList[i].Name;
                    switch (i + 1) {
                        case 1:
                            param1 = this.Get<T1>(paramName);
                            break;

                        case 2:
                            param2 = this.Get<T2>(paramName);
                            break;

                        case 3:
                            param3 = this.Get<T3>(paramName);
                            break;

                        case 4:
                            param4 = this.Get<T4>(paramName);
                            break;
                    }
                }

            }
            catch (Exception ex) {
                throw new ArgumentException(
                    string.Format(EXCEPTION_MISSING_PARAMETER_INFORMATION, paramName),
                    ex
                    );
            }

            //otherwise, execute the method provided
            with(param1, param2, param3, param4);

        }

        #endregion

        #region Working With Arrays

        /// <summary>
        /// Returns the specified property as an array of AnonymousTypes
        /// </summary>
        public AnonymousType[] AsArray(string property) {
            object[] values = this.Get<object[]>(property);
            return values.Select(o => {
                if (o is AnonymousType) { return (AnonymousType)o; }
                return new AnonymousType(o);
            }).ToArray();
        }

        /// <summary>
        /// Performs the specified action on each value in an array of AnonymousTypes
        /// </summary>
        public void WithEach(string property, Action<AnonymousType> action) {
            foreach (AnonymousType value in this.AsArray(property)) {
                action(value);
            }
        }

        #endregion

        #region Static Methods

        /// <summary>
        /// Returns the type of data for the provided object
        /// </summary>
        public static T Get<T>(object data, string property) {
            return new AnonymousType(data).Get<T>(property);
        }

        /// <summary>
        /// Returns the type of data for the provided object
        /// </summary>
        public static T Get<T>(object data, string property, T defaultValue) {
            return new AnonymousType(data).Get<T>(property, defaultValue);
        }

        /// <summary>
        /// Returns the type of data for the provided object
        /// </summary>
        public static AnonymousType[] AsArray(object data, string property) {
            return new AnonymousType(data).AsArray(property);
        }

        /// <summary>
        /// Performs the following action on each of the values in the specified
        /// property value for a user
        /// </summary>
        public static void WithEach(object data, string property, Action<AnonymousType> action) {
            new AnonymousType(data).WithEach(property, action);
        }

        #endregion

    }
}

Considere convertir explícitamente a una lista y enviar ViewData:

ViewData["QUsers"] = (from u in db.Users select u).ToList();

foreach(Users u in (List<Users>)ViewData["QUsers"]){ 

    /*Print the data here*/

}

Puede pasar datos de varias maneras, usando ViewData como se muestra arriba, o TempData para pasar entre Acciones. También puede usar ViewData.Model para contener un modelo fuertemente tipado. Tenga en cuenta que tendrá que cambiar la definición de la vista para que sea algo así como

ViewPage<User>

En cuanto a un buen reemplazo de repetidor, intente http://www.codeplex.com/MVCContrib . Tienen un Grid Html Helper que puede ayudar.

Si desea evitar crear una clase separada solo para mostrar su única proyección, también puede recurrir al uso de un diccionario, así:

from person in personList select new Dictionary<string, string>
{ 
    { "Name", person.Firstname + " " + person.Lastname },
    { "Id", person.Id.ToString() }
};

Luego puede escribir su página de vista en

ViewPage<IEnumerable<Dictionary<string, string>>>

Y finalmente iterar sobre la lista en la vista así:

<% foreach (Dictionary<string, string> p in (IEnumerable)ViewData.Model) 
{ %>
   <li> <%=p["Id"] %> - <%= p["Name"] %> </li>
<% } %>

No hace falta decir que el inconveniente es que su código ahora está bastante lleno de " cadenas mágicas " ;, lo que lo hace más propenso a errores debido a la ausencia de verificación del tiempo de compilación.

¿No puedes usar el RouteValueDictionary de MVC?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top