Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este documento se describen las nuevas características y mejoras introducidas en ASP.NET MVC 2.
Introducción
Actualización de un proyecto de ASP.NET MVC 1.0 a ASP.NET MVC 2
Nuevas características
Asistentes con plantilla
Áreas
Compatibilidad con controladores asincrónicos
Compatibilidad con DefaultValueAttribute en parámetros de método de acción
Compatibilidad con enlace de datos binarios con enlazadores de modelos
Clases ModelMetadata y ModelMetadataProvider
Compatibilidad con atributos DataAnnotations
Proveedores del validador de modelos
Validación del lado cliente
Fragmentos de código para Visual Studio 2010
Nuevo filtro de acción RequireHttpsAttribute
Invalidación del verbo del método HTTP
Nueva clase HiddenInputAttribute para asistentes con plantilla
El método auxiliar Html.ValidationSummary puede mostrar errores de nivel de modelo
las plantillas T4 en Visual Studio generan código específico de la versión de destino de las mejoras de la API de .NET Framework
Cambios importantes
Declinación de responsabilidades
Introducción
ASP.NET MVC 2 se basa en ASP.NET MVC 1.0 y presenta un gran conjunto de mejoras y características que se centran en aumentar la productividad. Esta versión es compatible con ASP.NET MVC 1.0, por lo que siguen aplicándose todos sus conocimientos, aptitudes, código y extensiones para ASP.NET MVC 1.0.
Para obtener más información acerca de ASP.NET MVC, consulte los siguientes recursos:
Actualización de un proyecto de ASP.NET MVC 1.0 a ASP.NET MVC 2
ASP.NET MVC 2 se puede instalar en paralelo con ASP.NET MVC 1.0 en el mismo servidor, lo que ofrece a los desarrolladores de aplicaciones flexibilidad al elegir cuándo actualizar una aplicación ASP.NET MVC 1.0 a ASP.NET MVC 2. Para obtener información sobre cómo actualizar, consulte el documento Actualizar una aplicación de ASP.NET MVC 1.0 a ASP.NET MVC 2.
Nuevas características
En esta sección se describen las características que se han introducido en la versión MVC 2.
Asistentes con plantilla
Los asistentes con plantilla permiten asociar automáticamente elementos HTML para editar y mostrar con tipos de datos. Por ejemplo, cuando se muestran datos de tipo System.DateTime en una vista, se puede representar automáticamente un elemento de interfaz de usuario de selector de fechas. Esto es similar al funcionamiento de las plantillas de campo en datos dinámicos de ASP.NET. Para obtener más información, consulte Usar asistentes con plantilla para mostrar datos en el sitio web de MSDN.
Áreas
Las áreas le permiten organizar un proyecto grande en varias secciones más pequeñas para administrar la complejidad de una aplicación web grande. Cada sección ("área") suele representar una sección independiente de un sitio web grande y se usa para agrupar conjuntos de controladores y vistas relacionados. Para obtener más información, consulte Tutorial: Organización de una aplicación de ASP.NET MVC por áreas en el sitio web de MSDN.
Para crear el área nueva, en el Explorador de soluciones, haga clic con el botón derecho en el proyecto, haga clic en Agregar y después haga clic en Área. Esto muestra un cuadro de diálogo que solicita el nombre del área. Después de escribir el nombre del área, Visual Studio agrega un área nueva al proyecto.
En la ilustración siguiente se muestra un diseño de ejemplo para un proyecto con dos áreas, Administración y Blogs.
Al crear un área, Visual Studio agrega una clase que deriva de AreaRegistration a cada área. Esta clase es necesaria para registrar el área y sus rutas, como se muestra en el ejemplo siguiente:
namespace MyApplication.Areas.Blog {
public class BlogAreaRegistration : AreaRegistration {
public override string AreaName {
get { return "blog"; }
}
public override void RegisterArea(AreaRegistrationContext context) {
context.MapRoute(
"blog_default",
"blog/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
context.MapRoute(
"blog_whatsnew",
"whats-new",
new { action = "WhatsNew", id = UrlParameter.Optional }
);
}
}
}
La plantilla de proyecto predeterminada para ASP.NET MVC 2 incluye una llamada al método RegisterAllAreas en el código del archivo Global.asax. Este método registra cada área del proyecto buscando todos los tipos que derivan de la clase AreaRegistration, creando instancias de una instancia del tipo y llamando al método RegisterArea en la instancia. En el ejemplo siguiente se muestra este proceso.
public class MyMvcApplication : HttpApplication {
void App_Start() {
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes) {
routes.MapRoute("default", "{controller}/{action}/{id}", ...);
}
}
Si no especifica el espacio de nombres en el método RegisterArea llamando al método context.Namespaces.Add, el espacio de nombres de la clase de registro se usa de forma predeterminada.
Compatibilidad con controladores asincrónicos
ASP.NET MVC 2 ahora permite a los controladores procesar solicitudes de forma asincrónica. Esto puede mejorar el rendimiento al permitir que los servidores que suelen llamar a operaciones de bloqueo (como las solicitudes de red) llamen a sus homólogos sin bloqueo. Para obtener más información, consulte el tema Usar un controlador asincrónico en ASP.NET MVC en MSDN.
Compatibilidad con DefaultValueAttribute en parámetros de método de acción
La clase System.ComponentModel.DefaultValueAttribute permite proporcionar un valor predeterminado para el parámetro de argumento a un método de acción. Por ejemplo, supongamos que se define la siguiente ruta predeterminada:
{controller}/{action}/{id}
Supongamos también que se define el siguiente controlador y método de acción:
public class ArticleController {
public ActionResult View(int id, [DefaultValue(1)]int page) {
}
}
Cualquiera de las siguientes direcciones URL de solicitud invocará el método de acción View que se define en el ejemplo anterior.
- /Article/View/123
- /Article/View/123?page=1 (Eficazmente igual que la solicitud anterior)
- /Article/View/123?page=2
Sin el atributo DefaultValueAttribute, la primera dirección URL de la lista anterior no funcionaría porque el argumento de página es un tipo de valor que no acepta valores NULL cuyo valor no se ha proporcionado.
Si el código está escrito en Visual Basic 2010 o Visual C# 2010, puede usar parámetros opcionales en lugar del atributo DefaultValueAttribute, como se muestra en el ejemplo siguiente:
Function View(ByVal id As Integer, Optional ByVal page As Integer = 1) _
As ActionResult
' ...
End Function
public ActionResult MyAction(int id, int page = 1) {
// ...
}
Posibilidad de vincular datos binarios con enlazadores de modelos
Hay dos nuevas sobrecargas del asistente Html.Hidden que codifican valores binarios como cadenas codificadas en base 64:
public static string Hidden(this HtmlHelper htmlHelper, string name, Binary value);
public static string Hidden(this HtmlHelper htmlHelper, string name, byte[] value);
Un uso típico es insertar una marca de tiempo para un objeto en la vista. Por ejemplo, la aplicación podría incluir el siguiente objeto Product:
public class Product {
//... other properties ...
public byte[] TimeStamp {
get;
set;
}
}
Un formulario de edición puede representar la propiedad TimeStamp en el formulario como se muestra en el ejemplo siguiente:
<%@ Page Inherits="ViewPage<Product>" %>
<%= Html.Hidden("TimeStamp", Model.TimeStamp) %>
Este marcado representa un elemento de entrada oculto con el valor de marca de tiempo como una cadena codificada en base 64 similar al ejemplo siguiente:
<input type="hidden" name="TimeStamp" value="QVNQLk5FVCBNVkMgaXMgZnVuIQ==" />
Este formulario puede publicarse en un método de acción que tenga un argumento de tipo Product, como se muestra en el ejemplo siguiente:
public ActionResult Edit(Product p) {
// p.TimeStamp is populated from the form
}
En el método de acción, la propiedad TimeStamp se rellena correctamente porque la cadena codificada en base 64 publicada se convierte en una matriz de bytes.
Clases ModelMetadata y ModelMetadataProvider
La clase ModelMetadataProvider proporciona una abstracción para obtener metadatos para el modelo dentro de una vista. MVC 2 incluye un proveedor predeterminado que pone a disposición los metadatos expuestos por los atributos del espacio de nombres System.ComponentModel.DataAnnotations. Es posible crear proveedores de metadatos que proporcionen metadatos de otros almacenes de datos, como bases de datos o archivos XML.
La clase ViewDataDictionary expone un objeto ModelMetadata que contiene los metadatos extraídos del modelo por la clase ModelMetadataProvider. Esto permite a los asistentes con plantilla consumir estos metadatos y ajustar su salida en consecuencia.
Para obtener más información, consulte la documentación de las clases ModelMetadata y ModelMetadataProvider.
Compatibilidad con atributos DataAnnotations
ASP.NET MVC 2 admite el uso de los atributos de validación RangeAttribute, RequiredAttribute, StringLengthAttribute y RegexAttribute (definidos en el espacio de nombres System.ComponentModel.DataAnnotations) cuando se enlaza a un modelo para proporcionar validación de entrada.
Para obtener más información, consulte Cómo: Validar los datos del modelo mediante los atributos de DataAnnotations en el sitio web de MSDN. Se puede descargar un proyecto de ejemplo que muestra el uso de estos atributos en https://go.microsoft.com/fwlink/?LinkId=157753.
Proveedores del validador de modelos
La clase de proveedor de validación de modelos representa una abstracción que proporciona lógica de validación para el modelo. ASP.NET MVC incluye un proveedor predeterminado basado en atributos de validación que se incluyen en el espacio de nombres System.ComponentModel.DataAnnotations. También puede crear sus propios proveedores de validación que definan reglas de validación personalizadas y asignaciones personalizadas de reglas de validación al modelo. Para obtener más información, consulte la documentación de la clase ModelValidatorProvider.
Validación del lado cliente
La clase de proveedor de validador de modelos expone los metadatos de validación al explorador en forma de datos serializados por JSON que puede consumir una biblioteca de validación del lado cliente. ASP.NET MVC 2 incluye una biblioteca de validación de cliente y un adaptador que admite los atributos de validación del espacio de nombres DataAnnotations anotados anteriormente. La clase de proveedor también permite usar otras bibliotecas de validación de cliente escribiendo un adaptador que procesa los datos JSON y llama a la biblioteca alternativa.
Nuevos fragmentos de código para Visual Studio 2010
Se instala un conjunto de fragmentos de código HTML para ASP.NET MVC 2 con Visual Studio 2010. Para ver una lista de estos fragmentos de código, en el menú Herramientas, seleccione Administrador de fragmentos de código. Para el lenguaje, seleccione HTML y, para la ubicación, seleccione ASP.NET MVC 2. Para obtener más información sobre cómo usar fragmentos de código, consulte la documentación de Visual Studio.
Nuevo filtro de acción RequireHttpsAttribute
ASP.NET MVC 2 incluye una nueva clase RequireHttpsAttribute que se puede aplicar a los métodos y controladores de acción. De forma predeterminada, el filtro redirige una solicitud no SSL (HTTP) al equivalente habilitado para SSL (HTTPS).
Invalidación del verbo del método HTTP
Al compilar un sitio web mediante el estilo de arquitectura REST, se usan verbos HTTP para determinar qué acción realizar para un recurso. REST requiere que las aplicaciones admitan la gama completa de verbos HTTP comunes, incluidos GET, PUT, POST y DELETE.
ASP.NET MVC 2 incluye nuevos atributos que se pueden aplicar a métodos de acción y que presentan una sintaxis compacta. Estos atributos permiten que ASP.NET MVC seleccione un método de acción basado en el verbo HTTP. En el ejemplo siguiente, una solicitud POST llamará al primer método de acción y una solicitud PUT llamará al segundo método de acción.
[HttpPost]
public ActionResult Edit(int id)
[HttpPut]
public ActionResult Edit(int id, Tag tag)
En versiones anteriores de ASP.NET MVC, estos métodos de acción requerían una sintaxis más detallada, como se muestra en el ejemplo siguiente:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id)
[AcceptVerbs(HttpVerbs.Put)]
public ActionResult Edit(int id, Tag tag)
Dado que los exploradores solo admiten los verbos HTTP GET y POST, no es posible publicar en una acción que requiera un verbo diferente. Por lo tanto, no es posible admitir de forma nativa todas las solicitudes RESTful.
Sin embargo, para admitir solicitudes RESTful durante las operaciones POST, ASP.NET MVC 2 presenta un nuevo método auxiliar HTML HttpMethodOverride. Este método representa un elemento de entrada oculto que hace que el formulario emule eficazmente cualquier método HTTP. Por ejemplo, mediante el método auxiliar HTML HttpMethodOverride, puede hacer que un envío de formulario aparezca como una solicitud PUT o DELETE. El comportamiento de HttpMethodOverride afecta a los atributos siguientes:
- HttpPostAttribute
- HttpPutAttribute
- HttpGetAttribute
- HttpDeleteAttribute
- AcceptVerbsAttribute
El elemento de entrada oculto tiene como nombre X-HTTP-Method-Override y como valor el verbo HTTP que se va a emular. El valor de invalidación también se puede especificar en un encabezado HTTP o en un valor de cadena de consulta como un par nombre/valor.
La invalidación solo se puede usar cuando la solicitud real es una solicitud POST. El valor de invalidación se omitirá para las solicitudes que usan cualquier otro verbo HTTP.
Nueva clase HiddenInputAttribute para asistentes con plantilla
Puede aplicar el nuevo atributo HiddenInputAttribute a una propiedad de modelo para indicar si se debe representar un elemento de entrada oculto al mostrar el modelo en una plantilla de editor. (El atributo establece un valor UIHint implícito de HiddenInput). La propiedad DisplayValue del atributo permite especificar si el valor se muestra en los modos de editor y visualización. Cuando DisplayValue se establece en false, no se muestra nada, ni siquiera el marcado HTML que normalmente rodea un campo. El valor predeterminado de DisplayValue es true.
Puede usar el atributo HiddenInputAttribute en los escenarios siguientes:
- Cuando una vista permite a los usuarios editar el identificador de un objeto y es necesario mostrar el valor, así como proporcionar un elemento de entrada oculto que contenga el identificador antiguo para que se pueda devolver al controlador.
- Cuando una vista permite a los usuarios editar una propiedad binaria que nunca se debe mostrar, como una propiedad de marca de tiempo. En ese caso, no se muestran el valor ni el marcado HTML circundante (como la etiqueta y el valor).
En el ejemplo siguiente se muestra cómo utilizar el atributo HiddenInputAttribute.
public class ProductViewModel {
[HiddenInput] // equivalent to [HiddenInput(DisplayValue=true)]
public int Id { get; set; }
public string Name { get; set; }
[HiddenInput(DisplayValue=false)]
public byte[] TimeStamp { get; set; }
}
Cuando el atributo se establece en true (o no se especifica ningún parámetro), se produce lo siguiente:
- En las plantillas de visualización, se representa una etiqueta y el valor se muestra al usuario.
- En las plantillas de editor, se representa una etiqueta y el valor se representa en un elemento de entrada oculto.
Cuando el atributo se establece en false, se produce lo siguiente:
- En las plantillas de visualización, no se representa nada para ese campo.
- En las plantillas de editor, no se representa ninguna etiqueta y el valor se representa en un elemento de entrada oculto.
El método auxiliar Html.ValidationSummary puede mostrar errores de nivel de modelo
En lugar de mostrar siempre todos los errores de validación, el método auxiliar Html.ValidationSummary tiene una nueva opción para mostrar solo los errores de nivel de modelo. Esto permite que los errores de nivel de modelo se muestren en el resumen de validación y que los errores específicos del campo se muestren junto a cada campo.
Las plantillas T4 en Visual Studio generan código que es específico de la versión de destino de .NET Framework
Los archivos T4 del host ASP.NET MVC T4 disponen de una nueva propiedad que especifica la versión de .NET Framework que utiliza la aplicación. Esto permite que las plantillas de T4 generen código y marcado específicos de una versión de .NET Framework. En Visual Studio 2008, el valor siempre es .NET 3.5. En Visual Studio 2010, el valor es .NET 3.5 o .NET 4.
Mejoras en la API
En esta sección se describen los cambios en los miembros y los tipos existentes de ASP.NET MVC.
- Se agregó un método CreateActionInvoker virtual protegido en la clase Controller. La propiedad ActionInvoker de Controller invoca este método y permite la creación de instancias diferida del invocador si no se ha establecido ningún invocador.
- Se ha agregado un método HandleUnauthorizedRequest virtual protegido en la clase AuthorizeAttribute. Esto permite que los filtros derivados de AuthorizeAttribute controlen el comportamiento cuando se produce un error en la autorización.
- Se ha agregado un método Add (clave de cadena, valor de objeto) en la clase ValueProviderDictionary. Esto le permite usar la sintaxis del inicializador de diccionario para ValueProviderDictionary, como en el ejemplo siguiente:
Controller c = new MyController();
c.ValueProvider = new ValueProviderDictionary(null) {
{ "example1", "example1Value" },
{ "example2", "example2Value" },
{ "example3", new int[] { 1, 2, 3 } }
};
- Se ha agregado un método get_object en la clase Sys.Mvc.AjaxContext. Se trata de un método de JavaScript similar al método get_data, pero si el tipo de contenido de la respuesta es application/json, get_object devuelve el objeto JSON.
- Se ha agregado una propiedad ActionDescriptor en la clase AuthorizationContext.
- Se ha agregado un token UrlParameter.Optional que se puede usar para solucionar problemas al enlazar con un modelo que contiene una propiedad ID cuando la propiedad está ausente en una publicación de formulario. Para obtener más información, consulte la entrada ASP.NET MVC 2 Optional URL Parameters en el blog de Phil Haack.
Últimos cambios
Los siguientes cambios pueden provocar errores en las aplicaciones existentes de ASP.NET MVC 1.0.
Cambio en el comportamiento de validación de propiedades para las clases que implementan IDataErrorInfo
Para los objetos de modelo que usan IDataErrorInfo para realizar la validación, se valida cada propiedad, independientemente de si se estableció un nuevo valor. En ASP.NET MVC 1.0, solo se validaron las propiedades que tenían nuevos valores establecidos. En ASP.NET MVC 2, la propiedad Error de IDataErrorInfo solo se llama si todos los validadores de propiedades son correctos.
El script de asignación de scripts de IIS ya no está disponible en el instalador
El script de asignación de scripts de IIS es un script de línea de comandos que se usa para configurar asignaciones de scripts para IIS 6 y para IIS 7 en modo clásico. El script de asignación de scripts no es necesario si usa el Servidor de desarrollo de Visual Studio o si usa IIS 7 en modo integrado. Los scripts están disponibles como descarga independiente no compatible en ASP.NET WebStack.
El método auxiliar Html.Substitute en MVC Futures ya no está disponible
Debido a los cambios en el comportamiento de representación de los motores de visualización MVC, el método auxiliar Html.Substitute no funciona y se ha eliminado.
La interfaz IValueProvider reemplaza todos los usos de IDictionary
Cada argumento de propiedad o método que aceptó IDictionary en MVC 1.0 ahora acepta IValueProvider. Este cambio afecta solo a las aplicaciones que incluyen proveedores de valores personalizados o enlazadores de modelos personalizados. Entre los ejemplos de propiedades y métodos afectados por este cambio se incluyen los siguientes:
- La propiedad ValueProvider de las clases ControllerBase y ModelBindingContext.
- Los métodos TryUpdateModel de la clase Controller.
Se agregaron nuevas clases CSS en el archivo Site.css
El archivo Site.css de las plantillas de proyecto de ASP.NET MVC se ha actualizado para incluir nuevos estilos usados por la funcionalidad de validación y por los asistentes con plantilla.
Ahora, los asistentes devuelven un objeto MvcHtmlString
Para aprovechar la nueva sintaxis de expresión de codificación HTML en ASP.NET 4, el tipo de valor devuelto para los asistentes HTML ahora es MvcHtmlString en lugar de una cadena. Si usa ASP.NET MVC 2 y los nuevos asistentes en ASP.NET 3.5, no podrá aprovechar la sintaxis de codificación HTML; la nueva sintaxis solo está disponible cuando se ejecuta ASP.NET MVC 2 en ASP.NET 4.
JsonResult ahora solo responde a las solicitudes HTTP POST
Para mitigar los ataques de secuestro de JSON que tienen potencial de divulgación de información, de forma predeterminada, la clase JsonResult ahora solo responde a las solicitudes HTTP POST. Las llamadas GET de Ajax a los métodos de acción que devuelven un objeto JsonResult deben cambiarse para usar POST en su lugar. Si es necesario, puede invalidar este comportamiento estableciendo la nueva propiedad JsonRequestBehavior de JsonResult. Para obtener más información sobre la posible vulnerabilidad de seguridad, consulte la entrada de blog JSON Hijacking en el blog de Phil Haack.
Los establecedores de propiedades Model y ModelType en ModelBindingContext están obsoletos
Se ha agregado una nueva propiedad ModelMetadata a la clase ModelBindingContext. La nueva propiedad encapsula las propiedades Model y ModelType. Aunque las propiedades Model y ModelType están obsoletas, por motivos de compatibilidad con versiones anteriores, los captadores de propiedades siguen funcionando; delegan en la propiedad ModelMetadata para recuperar el valor.
Los cambios en la clase DefaultControllerFactory interrumpen los generadores de controladores personalizados que derivan de ella
La clase DefaultControllerFactory se ha corregido quitando la propiedad RequestContext. En lugar de esta propiedad, la instancia del contexto de solicitud se pasa a los métodos virtuales protegidos GetControllerInstance y GetControllerType. Este cambio afecta a los generadores de controladores personalizados que derivan de DefaultControllerFactory.
Los generadores de controladores personalizados se suelen usar para proporcionar inserción de dependencias a las aplicaciones ASP.NET MVC. Para actualizar los generadores de controladores personalizados para admitir ASP.NET MVC 2, cambie la firma o las firmas del método para que coincidan con las nuevas firmas y utilice el parámetro de contexto de solicitud en lugar de la propiedad.
"Área" es ahora una clave reservada de valor de ruta
La cadena "área" de los valores Route ahora tiene un significado especial en ASP.NET MVC, al igual que "controller" y "action". Una de las consecuencias es que si se proporciona a los asistentes HTML un diccionario de valores de ruta que contenga "área", los asistentes ya no anexarán "área" a la cadena de consulta.
Si usa la característica Áreas, asegúrese de no usar {area} como parte de la dirección URL de ruta.
Declinación de responsabilidades
Este documento es preliminar y puede cambiar considerablemente antes de la versión comercial final del software que se describe en él.
La información contenida en este documento representa la visión actual de Microsoft Corporation sobre los asuntos tratados a fecha de su publicación. Dado que Microsoft debe responder a condiciones de mercado variables, no debe interpretarse como un compromiso por parte de Microsoft, y Microsoft no puede garantizar la precisión de la información presentada tras la fecha de publicación.
Estas notas del producto solo tienen fines informativos. MICROSOFT NO OTORGA NINGUNA GARANTÍA, EXPRESA, IMPLÍCITA O ESTUTARIAS, EN LA INFORMACIÓN DE ESTE DOCUMENTO.
Es responsabilidad del usuario el cumplimiento de todas las leyes de propiedad intelectual aplicables. Sin perjuicio de los derechos que conforman la legislación de propiedad intelectual, ninguna parte de este documento se puede reproducir, almacenar o incorporar en un sistema de recuperación, ni se puede transmitir de forma alguna o por ningún medio (electrónico, mecánico, fotocopia, grabación o de otro modo) ni para ningún propósito, sin el expreso permiso por escrito de Microsoft Corporation.
Microsoft puede ser titular de patentes, solicitudes de patentes, marcas, derechos de autor y otros derechos de propiedad intelectual sobre los contenidos de este documento. El suministro de este documento no le otorga ninguna licencia sobre estas patentes, marcas, derechos de autor u otros derechos de propiedad intelectual, a menos que ello se prevea en un contrato por escrito de licencia de Microsoft.
A menos que se indique lo contrario, los nombres de ejemplos de compañías, organizaciones, productos, nombres de dominio, direcciones de correo electrónico, logotipos, personas, lugares y eventos aquí mencionados son ficticios, y no se pretende ni se debe deducir asociación alguna con compañías, organizaciones, productos, nombres de dominio, direcciones de correo electrónico, logotipos, personas, lugares o eventos reales.
© 2010 Microsoft Corporation. Todos los derechos reservados.
Microsoft y Windows son marcas registradas o marcas comerciales de Microsoft Corporation en Estados Unidos y en otros países.
Los nombres de las compañías y productos reales mencionados en el presente documento pueden ser marcas comerciales de sus respectivos propietarios.