Asociar un proyecto web con otro como directorio virtual en IIS Express

Desde hace algún tiempo suelo trabajar con IIS Express, ya que es la opción por defecto para Visual Studio 2012 (Scottgu nos cuenta algunas de sus virtudes). De hecho Windows Azure ahora se apoya sobre él cuando emula la creación de Web Roles (años atrás era necesario tener instalado Internet Information Services Hosteable Web Core y posteriormente apareció Full IIS y con ello el uso del IIS local) Sin embargo, hay momentos en los que necesitamos simular ciertos comportamientos tanto para soluciones on premise como cloud.

Por diversos motivos queremos tener dos proyectos web bien diferenciados con responsabilidades diferentes (por ejemplo, frontales web por un lado y APIs por otro) pero a la hora de alojarlo en un IIS queremos compartir el mismo sitio (Para cumplir por ejemplo con la política de Same Domain que veíamos en el post anterior :)). Este es el escenario que veremos hoy 🙂

Configuración para Windows Azure

Cuando queremos tener dos proyectos web pero queremos compartir el mismo sitio, y el mismo rol en la nube, necesitamos definir esta configuración a nivel de ServiceDefinition.csdef. En este caso, debemos tener el proyecto que consideremos como principal asociado a un rol de Windows Azure y, en la configuración, alterar la definición del sitio:

<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="MyWeb.Azure" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2012-10.1.8">
  <WebRole name="MyWeb" vmsize="Small">
    <Sites>
      <Site name="Web">
        <VirtualApplication name="Apis" physicalDirectory="C:projectsPoCsMyWebMyAPIs">
        </VirtualApplication>
        <Bindings>
          <Binding name="Endpoint1" endpointName="Endpoint1" />
        </Bindings>
      </Site>
    </Sites>
    <Endpoints>
      <InputEndpoint name="Endpoint1" protocol="http" port="80" />
    </Endpoints>
    <Imports>
      <Import moduleName="Diagnostics" />
    </Imports>
  </WebRole>
</ServiceDefinition>

En este ejemplo hemos creado un Virtual Application dentro del sitio principal del role asociado al proyecto MyWeb. Cuando ejecutamos la aplicación en local, IIS Express sólo nos mostrará un sitio y no tendremos información respecto al proyecto asociado, pero podremos acceder a él a través de http://127.0.0.1/Apis

IIS Express y Windows Azure

Configuración para On premise

En el caso de la configuración para On Premise no tenemos proyecto de Windows Azure que manipular :). He visto varios post donde tocan directamente el archivo de configuración de IIS Express, el cual está localizado en %userprofile%DocumentsIISExpressconfig, el llamado applicationhost. El problema en este modo de trabajar es que la configuración que hagamos es propia de nuestro IIS Express pero no queda ligado a nuestra solución, por lo que propongo la siguiente alternativa:

  1. Accedemos a las Propiedades del proyecto web principal en la sección Web y copiamos la Project Url:
    Project Url main project
  2. Accedemos al mismo apartado en el proyecto secundario y pegamos la Url del principal, añadiendo el nombre que queremos darle al directorio virtual y hacemos clic en Create Virtual Directory:
    Create Virtual Directory

Si ejecutamos la solución tendremos un único sitio alojado y un directorio virtual asociado:

IIS Expres On Premise

Lo cierto es que parece ser que desde la interfaz es todo lo que podemos hacer (y a veces es más que suficiente), ya que desde el archivo de configuración podemos además indicar cuál es el Application Pool que queremos asociarle a cada una de las aplicaciones. De hecho, la traducción de nuestras acciones se registran de la siguiente manera:

            <site name="MyAPIs" id="28">
                <application path="/" applicationPool="Clr4IntegratedAppPool">
                    <virtualDirectory path="/" physicalPath="C:projectsPoCsMyWebMyWeb" />
                </application>
                <application path="/apis" applicationPool="Clr4IntegratedAppPool">
                    <virtualDirectory path="/" physicalPath="C:projectsPoCsMyWebMyAPIs" />
                </application>
                <bindings>
                    <binding protocol="http" bindingInformation="*:62013:localhost" />
                </bindings>
            </site>

El nombre del sitio corresponde con el último proyecto sobre el cual hicimos la modificación relacionada con el IIS Express, cada una de las aplicaciones dentro del sitio tienen por defecto un Application Pool, pero existen otras opciones que desde la interfaz no podemos controlar:

    <applicationPools>
      <add name="Clr4IntegratedAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_USER_HOME%configaspnet.config" autoStart="true" />
      <add name="Clr4ClassicAppPool" managedRuntimeVersion="v4.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_USER_HOME%configaspnet.config" autoStart="true" />
      <add name="Clr2IntegratedAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Integrated" CLRConfigFile="%IIS_USER_HOME%configaspnet.config" autoStart="true" />
      <add name="Clr2ClassicAppPool" managedRuntimeVersion="v2.0" managedPipelineMode="Classic" CLRConfigFile="%IIS_USER_HOME%configaspnet.config" autoStart="true" />
      <add name="UnmanagedClassicAppPool" managedRuntimeVersion="" managedPipelineMode="Classic" autoStart="true" />
      <applicationPoolDefaults managedRuntimeLoader="v4.0">
        <processModel />
      </applicationPoolDefaults>
    </applicationPools>

Creo que es una buena alternativa para simular este tipo de escenarios sin la necesidad de un IIS local.
Espero que haya sido de utilidad 😀

¡Saludos!