Compartir a través de


Dominios de aplicación

Nota:

Este artículo es específico de .NET Framework. No se aplica a implementaciones más recientes de .NET, incluidas .NET 6 y versiones posteriores.

Los sistemas operativos y los entornos en tiempo de ejecución suelen proporcionar alguna forma de aislamiento entre aplicaciones. Por ejemplo, Windows usa procesos para aislar aplicaciones. Este aislamiento es necesario para asegurarse de que el código que se ejecuta en una aplicación no puede afectar negativamente a otras aplicaciones no relacionadas.

Los dominios de aplicación proporcionan un límite de aislamiento para la seguridad, la confiabilidad, el control de versiones y la descarga de ensamblados. Normalmente, los hosts en tiempo de ejecución crean dominios de aplicación, que son responsables del arranque de Common Language Runtime antes de que se ejecute una aplicación.

Las ventajas de aislar aplicaciones

Históricamente, los límites de proceso se han usado para aislar las aplicaciones que se ejecutan en el mismo equipo. Cada aplicación se carga en un proceso independiente, que aísla la aplicación de otras aplicaciones que se ejecutan en el mismo equipo.

Las aplicaciones están aisladas porque las direcciones de memoria son relativas al proceso; Un puntero de memoria pasado de un proceso a otro no se puede usar de ninguna manera significativa en el proceso de destino. Además, no puede realizar llamadas directas entre dos procesos. En su lugar, debe usar servidores proxy, que proporcionan un nivel de direccionamiento indirecto.

El código administrado debe pasarse a través de un proceso de comprobación para poder ejecutarse (a menos que el administrador haya concedido permiso para omitir la comprobación). El proceso de comprobación determina si el código puede intentar acceder a direcciones de memoria no válidas o realizar alguna otra acción que podría provocar que el proceso en el que se ejecuta no funcione correctamente. Cuando el código pasa la prueba de comprobación, se dice que tiene seguridad de tipos. La capacidad de verificar el código como seguro de tipos permite que el Common Language Runtime proporcione un nivel de aislamiento tan grande como el límite del proceso, pero con un costo de rendimiento mucho menor.

Los dominios de aplicación proporcionan una unidad de procesamiento más segura y versátil que Common Language Runtime puede usar para proporcionar aislamiento entre aplicaciones. Puede ejecutar varios dominios de aplicación en un único proceso con el mismo nivel de aislamiento que existiría en procesos independientes, pero sin incurrir en la sobrecarga adicional de realizar llamadas entre procesos o cambiar entre procesos. La capacidad de ejecutar varias aplicaciones dentro de un único proceso aumenta considerablemente la escalabilidad del servidor.

El aislamiento de las aplicaciones también es importante para la seguridad de las aplicaciones. Por ejemplo, puede ejecutar controles desde varias aplicaciones web en un único proceso del explorador de tal manera que los controles no puedan acceder a los datos y los recursos de los demás.

El aislamiento proporcionado por dominios de aplicación tiene las siguientes ventajas:

  • Los errores de una aplicación no pueden afectar a otras aplicaciones. Dado que el código seguro de tipos no puede provocar errores de memoria, el uso de dominios de aplicación garantiza que el código que se ejecuta dentro de un dominio no pueda afectar a otras aplicaciones del proceso.

  • Las aplicaciones individuales se pueden detener sin detener todo el proceso. El uso de dominios de aplicación permite descargar el código que se ejecuta en una sola aplicación.

    Nota:

    No se pueden desmontar ensamblajes o tipos individuales. Solo se puede descargar un dominio completo.

  • El código que se ejecuta en una aplicación no puede acceder directamente al código ni a los recursos de otra aplicación. Common Language Runtime aplica este aislamiento evitando llamadas directas entre objetos en dominios de aplicación diferentes. Los objetos que pasan entre dominios se copian o se acceden mediante un proxy. Si se copia el objeto, la llamada al objeto es local. Es decir, tanto el autor de la llamada como el objeto al que se hace referencia se encuentran en el mismo dominio de aplicación. Si se accede al objeto a través de un proxy, la llamada al objeto es remota. En este caso, el autor de la llamada y el objeto al que se hace referencia se encuentran en dominios de aplicación diferentes. Las llamadas entre dominios usan la misma infraestructura de llamadas remotas que las llamadas entre dos procesos o entre dos máquinas. Por lo tanto, los metadatos del objeto al que se hace referencia deben estar disponibles para ambos dominios de aplicación para permitir que la llamada al método se compile correctamente. Si el dominio que realiza la llamada no tiene acceso a los metadatos del objeto al que se llama, es posible que se produzca un error en la compilación con una excepción de tipo FileNotFoundException. Para obtener más información, vea Objetos remotos. El mecanismo para determinar cómo se puede acceder a los objetos entre dominios viene determinado por el objeto . Para obtener más información, consulte System.MarshalByRefObject.

  • El comportamiento del código está en el ámbito de la aplicación en la que se ejecuta. En otras palabras, el dominio de aplicación proporciona opciones de configuración como directivas de versión de aplicación, la ubicación de los ensamblados remotos a los que accede e información sobre dónde localizar los ensamblados que se cargan en el dominio.

  • Los permisos concedidos al código se pueden controlar mediante el dominio de aplicación en el que se ejecuta el código.

Dominios de aplicación y ensamblados

En esta sección se describe la relación entre los dominios de aplicación y los ensamblados. Debe cargar un ensamblado en un dominio de aplicación para poder ejecutar el código que contiene. La ejecución de una aplicación típica hace que varios ensamblados se carguen en un dominio de aplicación.

La forma en que se carga un ensamblado determina si varios dominios de aplicación pueden compartir su código compilado Just-In-Time (JIT) en el proceso y si el ensamblado se puede descargar del proceso.

  • Si se carga un ensamblado neutro para el dominio, todos los dominios de aplicación que comparten el mismo conjunto de permisos de seguridad pueden compartir el mismo código compilado JIT, lo que reduce la memoria requerida por la aplicación. Sin embargo, el ensamblado nunca se puede descargar del proceso.

  • Si un ensamblado no se carga con dominio neutro, debe utilizarse la compilación JIT de ese ensamblado en los dominios de aplicación en que se carga. Sin embargo, el ensamblado se puede descargar del proceso; para ello, tendrán que descargarse todos los dominios de aplicación en que está cargado el ensamblado.

El host en tiempo de ejecución determina si los ensamblados se cargan con dominio neutro cuando se carga el motor en tiempo de ejecución en un proceso. En el caso de las aplicaciones administradas, aplique el LoaderOptimizationAttribute atributo al método de punto de entrada para el proceso y especifique un valor de la enumeración asociada LoaderOptimization . Para las aplicaciones no administradas que hospedan Common Language Runtime, especifique la marca adecuada al llamar al método CorBindToRuntimeEx Function .

Hay tres opciones para cargar ensamblados neutrales de dominio:

  • LoaderOptimization.SingleDomain no carga ensamblados con dominio neutro, a excepción de Mscorlib que siempre se carga con dominio neutro. Esta configuración se denomina dominio único porque se usa normalmente cuando el host ejecuta solo una sola aplicación en el proceso.

  • LoaderOptimization.MultiDomain carga todos los ensamblados con dominio neutro. Use esta configuración cuando haya varios dominios de aplicación en el proceso, todos los cuales ejecutan el mismo código.

  • LoaderOptimization.MultiDomainHost carga con dominio neutro los ensamblados que tienen un nombre seguro si se han instalado junto con todas sus dependencias en la caché global de ensamblados. La carga y la compilación JIT de los demás ensamblados se realiza de forma independiente en cada dominio de aplicación y, por tanto, estos ensamblados pueden descargarse del proceso. Use esta configuración al ejecutar más de una aplicación en el mismo proceso o si tiene una combinación de ensamblados compartidos por muchos dominios de aplicación y ensamblados que deben descargarse del proceso.

El código compilado JIT no se puede compartir en los ensamblados que se cargan en la carga de ensamblado por contexto especificado por el usuario utilizando el método LoadFrom de la clase Assembly, o que se cargan a partir de imágenes que utilizan las sobrecargas del método Load que especifican matrices de bytes.

Los ensamblados que han sido compilados a código nativo mediante el Generador de imágenes nativas (Ngen.exe), se pueden compartir entre dominios de aplicación, si se cargan de manera neutral al dominio la primera vez que se cargan en un proceso.

El código compilado jiT para el ensamblado que contiene el punto de entrada de la aplicación solo se comparte si se pueden compartir todas sus dependencias.

Un ensamblado con dominio neutro puede someterse a la compilación JIT varias veces. Por ejemplo, cuando los conjuntos de concesión de seguridad de dos dominios de aplicación son diferentes, no pueden compartir el mismo código compilado por JIT. Sin embargo, cada copia del ensamblado compilado por JIT se puede compartir con otros dominios de aplicación que tengan el mismo conjunto de concesión.

A la hora de determinar si va a cargar los ensamblados con dominio neutro, deberá decidir si prefiere reducir el consumo de memoria u otros factores relativos al rendimiento.

  • El acceso a los datos y métodos estáticos es más lento para los ensamblados de dominio-neutral debido a la necesidad de aislarlos. Cada dominio de aplicación que tenga acceso al ensamblado debe tener una copia independiente de los datos estáticos para evitar que las referencias a objetos de campos estáticos crucen los límites del dominio. Como resultado, el motor en tiempo de ejecución contiene lógica adicional para dirigir un llamador a la copia correspondiente del método o los datos estáticos. Esta lógica adicional ralentiza la llamada.

  • Todas las dependencias de un ensamblado deben ubicarse y cargarse cuando el ensamblado se carga como dominio neutro, ya que una dependencia que no se puede cargar como dominio neutro impide que el ensamblado se cargue como dominio neutro.

Dominios de aplicación y subprocesos

Un dominio de aplicación forma un límite de aislamiento para la seguridad, el control de versiones, la confiabilidad y la descarga de código administrado. Un hilo es la estructura del sistema operativo que utiliza el entorno de ejecución de lenguaje común para ejecutar código. En tiempo de ejecución, todo el código administrado se carga en un dominio de aplicación y lo ejecuta uno o varios subprocesos administrados.

No hay una correlación uno a uno entre los dominios de aplicación y los subprocesos. Varios subprocesos se pueden ejecutar en un solo dominio de aplicación en un momento dado y un subproceso determinado no se limita a un dominio de aplicación único. Es decir, los subprocesos son libres de cruzar los límites del dominio de la aplicación; No se crea un nuevo subproceso para cada dominio de aplicación.

En un momento dado, cada subproceso se ejecuta en un dominio de aplicación. Es posible que cero, uno o varios subprocesos se ejecuten en cualquier dominio de aplicación determinado. El tiempo de ejecución realiza un seguimiento de qué subprocesos están en ejecución dentro de cada dominio de aplicación. Puede localizar el dominio en el que se ejecuta un subproceso en cualquier momento llamando al Thread.GetDomain método .

Dominios de aplicación y referencias culturales

La cultura, que está representada por un CultureInfo objeto, está asociada a hilos. Puede obtener la referencia cultural asociada al subproceso que se está ejecutando actualmente mediante la CultureInfo.CurrentCulture propiedad y puede obtener o establecer la referencia cultural asociada al subproceso que se está ejecutando actualmente mediante la Thread.CurrentCulture propiedad . Si la referencia cultural asociada a un subproceso se ha establecido explícitamente mediante la Thread.CurrentCulture propiedad , sigue estando asociada a ese subproceso cuando el subproceso cruza los límites del dominio de la aplicación. De lo contrario, la referencia cultural asociada al subproceso en cualquier momento determinado viene determinada por el valor de la CultureInfo.DefaultThreadCurrentCulture propiedad en el dominio de aplicación en el que se ejecuta el subproceso:

  • Si el valor de la propiedad no es null, se asociará al subproceso la referencia cultural devuelta por la propiedad (y por consiguiente devuelta por las propiedades Thread.CurrentCulture y CultureInfo.CurrentCulture).

  • Si el valor de la propiedad es null, se asociará al subproceso la referencia cultural actual del sistema.

Programación con dominios de aplicación

Normalmente, los hosts en tiempo de ejecución crean y manipulan los dominios de aplicación. Sin embargo, a veces un programa de aplicación también puede querer trabajar con dominios de aplicación. Por ejemplo, un programa de aplicación podría cargar un componente de aplicación en un dominio para poder descargar el dominio (y el componente) sin tener que detener toda la aplicación.

AppDomain es la interfaz programática de los dominios de aplicación. Esta clase incluye métodos para crear y descargar dominios, para crear instancias de tipos en dominios y para registrarse para diversas notificaciones, como la descarga de dominios de aplicación. En la tabla siguiente se enumeran los métodos usados AppDomain habitualmente.

Método de AppDomain Descripción
CreateDomain Crea un nuevo dominio de aplicación. Se recomienda utilizar una sobrecarga de este método que especifique un objeto AppDomainSetup. Esta es la manera preferida de establecer las propiedades de un nuevo dominio, como la base de la aplicación o el directorio raíz de la aplicación; la ubicación del archivo de configuración del dominio; y la ruta de acceso de búsqueda que Common Language Runtime va a usar para cargar ensamblados en el dominio.
ExecuteAssembly y ExecuteAssemblyByName Ejecuta un ensamblado en el dominio de aplicación. Se trata de un método de instancia, por lo que se puede usar para ejecutar código en otro dominio de aplicación al que tiene una referencia.
CreateInstanceAndUnwrap Crea una instancia de un tipo especificado en el dominio de aplicación y devuelve un proxy. Utilice este método para evitar que se cargue el ensamblado que contiene el tipo creado en el ensamblado de llamada.
Unload Cierra el dominio correctamente. El dominio de aplicación no se descarga hasta que todos los subprocesos que se ejecutan en el dominio se han detenido o ya no están en el dominio.

Nota:

Common Language Runtime no admite la serialización de métodos globales, por lo que los delegados no se pueden usar para ejecutar métodos globales en otros dominios de aplicación.

Las interfaces no administradas descritas en la especificación de interfaces de hospedaje de Common Language Runtime también proporcionan acceso a los dominios de aplicación. Los hosts de motor en tiempo de ejecución pueden usar interfaces de código no administrado para crear y obtener acceso a los dominios de aplicación en un proceso.

La variable de entorno COMPLUS_LoaderOptimization

Variable de entorno que establece la directiva de optimización del cargador predeterminada de una aplicación ejecutable.

Sintaxis

COMPLUS_LoaderOptimization = 1

Observaciones

Una aplicación típica carga varios ensamblados en un dominio de aplicación antes de que se pueda ejecutar el código que contienen.

La forma en que se carga el ensamblado determina si varios dominios de aplicación pueden compartir su código compilado Just-In-Time (JIT) en el proceso.

  • Si un ensamblado se carga con dominio neutro, todos los dominios de aplicación que comparten el mismo conjunto de permisos de seguridad pueden compartir el mismo código compilado JIT. Esto reduce la memoria requerida por la aplicación.

  • Si un ensamblado no se carga de forma independiente del dominio, debe compilarse JIT en cada dominio de aplicación en el que se encuentre cargado, y el cargador no debe compartir recursos internos entre dominios de aplicación.

Cuando se establece en 1, la variable de entorno COMPLUS_LoaderOptimization obliga al anfitrión de ejecución a cargar todos los ensamblados de manera no neutral de dominio, conocida como SingleDomain. SingleDomain no carga ensamblados con dominio neutro, a excepción de Mscorlib, que siempre se carga con dominio neutro. Esta configuración se denomina dominio único porque se usa normalmente cuando el host ejecuta solo una sola aplicación en el proceso.

Precaución

La marca de entorno COMPLUS_LoaderOptimization se diseñó para usarse en escenarios de diagnóstico y prueba. Tener activada la bandera puede provocar una ralentización grave y un aumento significativo en el uso de memoria.

Ejemplo de código

Si anexa COMPLUS_LoaderOptimization=1 en el valor de cadena múltiple del entorno de la clave HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\IISADMIN, podrá conseguir que no todos los ensamblados se carguen como dominio neutro para el servicio IISADMIN.

Key = HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\IISADMIN
Name = Environment
Type = REG_MULTI_SZ
Value (to append) = COMPLUS_LoaderOptimization=1

Consulte también