Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to setup multiple apps with same port and domain but different paths in iisexpress vs2015

Im currently splitting a big asp.net core solution into multiple smaller solutions, each with a single app. In order to do this, the base app needs to point at

www.originalApp.com

and each of my smaller apps will be accessed using the path

www.originalApp.com/SplittedApp

I have managed to get this running using IIS with the following setup in the applicationHost.config

        <site name="OriginalApp" id="3" serverAutoStart="true">
            <application path="/" applicationPool="OriginalAppPool">
                <virtualDirectory path="/" physicalPath="OriginalAppPath/>
            </application>
            <application path="/SplittedApp" applicationPool="splittedApp">
                <virtualDirectory path="/" physicalPath="splittedAppPath />
            </application>
            <bindings>
                <binding protocol="http" bindingInformation="*:82:" />
                <binding protocol="http" bindingInformation="IpAddress:originalApp" />
            </bindings>
            <applicationDefaults applicationPool="Fire.Frontend" />
        </site>

I have tried multiple variations of this setup in the applicationHost.config files for IISExpress for these 2 apps with different problems coming up.

my app launchSettings.json in the splitted app looks like this

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:9345/splitted app",
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
}

and the original app

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:9345",
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
}

the current setup fails to load the second app because the same port is in use, however i need to use the same port so i can then append the path and effectively navidate the pages between the 2 applications.

I find it hard to believe that what im trying to achieve is not possible using IIS Express since it works fine with IIS.

Ive read a lot of post on SO and blogs over the web but i cant find anyone with the same issue and none of the solutions to issues that seemed similar worked for me, so if anyone can point me in the right direction it would be most appreciated.

Thanks.

PS im not sure about the tags i added in the question are correct so let me know if there are better tags to add.

like image 705
Joao Vasconcelos Avatar asked Nov 20 '22 03:11

Joao Vasconcelos


1 Answers

In our build process, we choose continue to "Package/Publish" to an IIS server, with .NET Core handler installed. Therefore, our options are somewhat restrictive in that there must be some means to provide symmetry between development and production deployment that is supported by the Web Publish tooling.

Here are some possible solutions:

  1. Deploy child content as a sub-application of parent application
  2. Deploy child content as additional static folder content during parent deploy
  3. Deploy child content as a build dependency of parent
  4. Deploy child content manually using virtual directories

Which to choose? Here's a decision tree:

  • Is the child path an application / assembly to deploy (e.g. WebAPI)? If so, choose option 1.
  • Is the child path a loosely coupled package, separately versioned or built by another team? If so, choose option 3.
  • Is the path best-maintained in a single unit at the server, during backup/restore, deployment, and security operations? If so, choose option 4.
  • Otherwise, choose option 2.

Let's rush through each of these:

1. Deploy child content as a sub-application of parent application

This is easy enough on the IIS Deployment target (e.g. public web server). A sub-application is created using the same old tools, or manually, on the publish target server. However, this is harder at the development workstation. In the following image, the top shows how a .NET Core application is configured, while the bottom shows how a .NET Framework application is presented in the Visual Studio UI: enter image description here

In both cases, it creates these in the .vs\config\applicationhost.config file; but the new ASP.NET Core tooling only creates root applications (not sub-applications) in that workstation .config file. We can edit this manually per-developer, but unfortunately we usually don't want to check these files in, because they have local machine paths. At any rate, if you try to use the old multi-project-startup property method, you'll end up with multiple sites attempting unsuccessfully to run at the same port. What you want instead is one site with multiple applications. Here's an example of such a (manually edited) working config:

<site name="MyNamespace.RootWeb" id="5">
  <application path="/" applicationPool="Clr4IntegratedAppPool">
    <virtualDirectory path="/" physicalPath="E:\Development\MySolution\MyProject" />
  </application>
  <application path="/assets" applicationPool="Clr4IntegratedAppPool">
    <virtualDirectory path="/" physicalPath="E:\Development\MySolution\MyProject.Assets" />
  </application>
  <bindings>
              <binding protocol="http" bindingInformation="*:55519:localhost" />
  </bindings>
</site>

Another approach might be to create a .target file to add the capability that Visual Studio has lost for ASP.NET Core projects, by scanning your projects launchsettings.json files, and merging all project URL Prefixes into a single intermediate XML <sites /> fragment file when any are newer than the fragment, and merging the fragment into the applicationhost.config (even performing change conflict via the intermediate file). I'll let you know if I do this.

Lastly, you could change the project web start application. Not to "project", because Kestrel can't host multiple applications on the same port either. However, WebListener can, can can accept all the command line parameters you need to accomplish this.

2. Deploy child content as additional static folder content during parent deploy.

We can run in a single application, if we don't actually have relevant assemblies we are building. On the development workstation, we can conditionally redirect a path for the child content, using if (env.IsDevelopment()) IApplicationBuilder.UseStaticFiles();. We'll still need to get the content running on the server. To that end we'll use the IncludePluginFilesForMsdeploy deployment directive, similar to this:

<PropertyGroup>
  <PipelineCopyAllFilesToOneFolderForMsdeployDependsOn>
    IncludePluginFilesForMsdeploy;
    $(PipelineCopyAllFilesToOneFolderForMsdeployDependsOn);
  </PipelineCopyAllFilesToOneFolderForMsdeployDependsOn>
</PropertyGroup>
<Target Name="IncludePluginFilesForMsdeploy">
  <ItemGroup>
    <FileWrites Include="$(MSBuildProjectDirectory)\bin\**\*" />
    <_CustomFiles Include="$(MSBuildProjectDirectory)\bin\**\*" />
    <FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
      <DestinationRelativePath>bin\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
    </FilesForPackagingFromProject>
  </ItemGroup>
</Target>

Although, note that previously IncludePluginFilesForMsdeploy was IncludePluginFilesForPackaging, and now in VS 2017 the same target is implemented with DotnetPublishFiles, as shown below:

<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Target Name="CustomCollectFiles" BeforeTargets="BeforePublish">
        <Message Text="Custom Collect Before Publish" Importance="high" />
        <ItemGroup>
            <_CustomFiles Include="$(MSBuildProjectDirectory)/../MyProject/compiled/**/*" />
            <DotnetPublishFiles Include="@(_CustomFiles)">
                <DestinationRelativePath>wwwroot/MyProject/compiled/%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
            </DotnetPublishFiles>
        </ItemGroup>
    </Target>
</Project>

3. Deploy child content as a build dependency of parent.

Again, for static content such as a browser application, we might consider building that application into a package, and requiring it into our root application in development, using NuGet, NPM, or similar. The fact that now there is a single application to deploy is both pro and con here. I'd leave this for very loosely coupled packages maintained by separate teams, or where versioning must be maintained separately for the dependencies.

4. Deploy child content manually using virtual directories.

On the server, if we don't need a sub-application, we might still wish to have an external folder hierarchy for this child content. We could reflect this content under the parent using a virtual directory and include the deployment flag <DeployAsIisApp>False</DeployAsIisApp>. Alternately, we might deploy directly to the server using NPM, FTP, or some other technology. On the development station, we can do the same UseStaticFiles() idea as above. Alternately, we could hack the .vs\config\applicationhost.config again (same downsides as above when working with a team) but to create an additional virtual directory rather than an additional application.

like image 58
shannon Avatar answered Nov 21 '22 19:11

shannon