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.
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.
Which to choose? Here's a decision tree:
Let's rush through each of these:
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:
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.
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>
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With