ASP.NET Core Mercury App Deployment to IIS Guidance?

Elements Version 11.0.0.2753
VS2022

I have a very basic ASP.NET Core Razor Pages Mercury App that is running fine in the debugger in both VS2022 and Water, and is also running fine from the IDE without debugging. Now I would like to deploy it to IIS. So far, I have been unsuccessful in doing this - while IIS is serving static pages fine, I get a 404 for my Razor pages.

One thing I have noticed so far is that building my ASP.NET Core Mercury application does not generate an EXE. A regular C# ASP.NET Core application that I create DOES generate an EXE (which Iā€™ve been able to successfully deploy to IIS). It is also a bit surprising that the Mercury ASP.NET Core application does not, because its .elements file contains this section:

 <PropertyGroup>
    <Mode>Echoes</Mode>
    <OutputType>Exe</OutputType>
    <TargetFramework>.NETCore</TargetFramework>

Maybe the EXE isnā€™t needed (Iā€™m definitely still learning ASP.NET core and Mercury), but I do wonder if that might be part of the problem. Thoughts on this and suggestions for next steps to troubleshoot this would be welcome.

Thanks!

ā€“Avonelle

This is bit complicatedā€¦ In its infinite wisdom, Microsoft decided that on .NET Core, executables, just like libraries, should be named ā€œ.dllā€, not .exe. Because why not.

If you build a ConsoleApp1 project with OutputType=Exe(cutable) for classic .NET, you get ā€œConsoleApp1.exeā€, if you build it for Core, you get ā€œConsoleApp.dllā€.

In addition, on Core, you also get a native stub (essentially a copy of dotnet.exe hardcoded to just just the one ā€œdllā€, on this one computer). On Windows that stub is, of course, named ConsoleApp1.exe, and you can run your ap either as ā€œdotnet ConsoleApp1.dllā€ or as ā€œConsoleApp1.exeā€.

This stub is called the App Host.

I donā€™t know. right now I limit creating this stub to

      if Setting["NETCoreRuntime"].Value.ToLower not in ["microsoft.netcore.app", "microsoft.windowsdesktop.app"] then
        exit;

which is why itā€™s not generated for ASP.NET. If you like, I could drop this check and send you a build, to see if this helps?

Oh dear. My head hurts already! Ugh.

Yes, if you donā€™t mind, thatā€™s worth a try. I did find this Microsoft documentation describing the ASP.NET Core directory structure for applications, and the EXE is mentioned in both application types (Framework-dependent Executables and Self-Contained deployment), which is why I thought that might be part of what is expected.

ā€“Avonelle

Done, will put it to Personal Downloads when it has finished building (1-2h)

Great, thanks! I donā€™t know if I will get back to this today, but hopefully by tomorrow I can give you an update.

ā€“Avonelle

1 Like

Sorry, someone else broke the build, so no build for you today :(. hopefully tomorrow morning.

No worries - weā€™ve all been there. Iā€™ll keep an eye out for it tomorrow. Thanks for letting me know!

ā€“Avonelle

Got a build for you; up now. :raised_hands:t3:

Thanks! I will dig into it today and get back to you.

ā€“Avonelle

1 Like

I was able to create a simple test project that basically used the ASP.NET core Empty Web Application project template for Mercury, so it didnā€™t have much of anything besides an index and privacy page, and get that deployed successfully within IIS. There are still some open questions, but hereā€™s what Iā€™ve learned so far which might help the next guy trying to figure this out:

.NET Core Hosting Bundle Needed (of course)
This is probably obvious, but Iā€™m including it here for completeness.

Application Pool .NET CLR Version
This needs to be set to No Managed Code.

The EXE is not needed
Having the EXE did not solve my issue. However, having the EXE was nice because I could use it to run the app from the folder I published to and verify that it ran successfully (so thus the issue was specific to IIS and not a missing asset or something.) So I think it might be a good idea for ASP.NET Core applications to generate it. But not critical.

web.config is needed
I did seem to need a basic web.config with an aspNetcore handler. Hereā€™s an example of mine (obviously change the DLL name as needed.) I enabled logging which helped solve the remaining issues, then that could probably be disabled.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <location path="." inheritInChildApplications="false">
    <system.webServer>
      <handlers>
        <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
      </handlers>
      <aspNetCore processPath="dotnet"
                  arguments=".\TestIISInstall.dll"
                  stdoutLogEnabled="true"
                  stdoutLogFile=".\logs\stdout"
                  hostingModel="inprocess" />
    </system.webServer>
  </location>
</configuration>

Generated .deps.json needed changes
Part of how I got things working was to compare a simple C# ASP.NET Core application that I got working to my Mercury ASP.NET core app. In the logging files I started seeing errors like this:

Error:
  An assembly specified in the application dependencies manifest (TestIISInstall.deps.json) was not found:
    package: 'Microsoft.Win32.Registry', version: '5.0.0'
    path: 'runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll'

Also sometimes there were similar errors in the Windows Application Event log. So I edited the above mentioned json file so that it more closely matched the one in the C# file (but still included the Mercury, Elements, and Echoes references.) That seemed to do the trick.

Since this appears to be a file generated during build, and those references do seem to be part of the project template (and hence my project), I havenā€™t quite figured out yet if the template should be changed or if I will need to get those references working as soon as I try to do anything non-trivial.

Iā€™ve attached a zip of the original JSON file that was generated and also the one that is actually working for me.
TestIISInstall.deps.zip (1.5 KB)

I may have to step away from this for a few days unfortunately, but eventually I hope to get back to it and figure out if those references that I removed from the *.deps.json file are needed or if I can get rid of them in the project as well (which I assume will remove them from the generated *.deps.json).

ā€“Avonelle

Hmm, so you had to remote references to the Microsoft.* and System.* packages/dlls from the .json? That seems odd, Iā€™m pretty sure other stuff will break if I do thatā€¦

Curiosuly, while youā€™re building for .NETCoreApp,Version=v6.0, those are all 5.0, is that expected/correct?

FWIW, a fresh project from template doesnt have them, so I presume you added them? You should only need them if you use types from these packages (e.g. Microsoft.Win32.Registry if you need ao access the registry, etc). That said, I believe Elements.dll on Core/Standard depends on Microsoft.Win32.Registry.

Reference ā€˜Elementsā€™ added dependency NuGet Reference ā€˜Microsoft.Win32.Registry:5.0.0ā€™ for target ā€˜Echoesā€™.

yup. so you canā€™t get rid of that one. Not without dropping Elements.dll and Mercury.dll.

It would, yeah.

Okay, Iā€™ll leave it because it does no harm. But note that even without the exe you can call ā€œdotnet YourProject.dllā€.

Are these things that need changing in the project, or in IIS?

Tis too, is this something the project/template should contain/create, or just sometime that should be documented as needed for IIS?

(iā€™d like to, once this all works and with your help add a Deployment for ASP.NET Core topic to the Deployment docs area)

It does seem to me that the items I had to remove references to in .deps.json were things that had a 5.0 reference, although I havenā€™t yet gone through it in detail to confirm that. And is that expected or correct? I donā€™t know. I wouldnā€™t think so, but Iā€™m still learning.

Hmmmmm, no I did not add themā€¦Hereā€™s what I can tell you. Using this template in Water, I just created a new project:
image

I do NOT see those references in the Water IDE:
image

But they do appear if I load the same project in VS2022:
image

And if I build the project in Water, making no other changes, I see the additional references within the .deps.json file.

But I donā€™t see them in the .Elements project file itself, so maybe there is something off about my environment?

Interesting, good to know!

Nope - these are IIS related, not project related.

Probably not, as I donā€™t see one in the sample C# project I created in VS2022. It seems like that is an IIS only thing, so yes just documenting it would be useful.

Absolutely! One of the challenges here for me is trying to figure out if the issues I run into are Elements related or my ignorance about ASP.NET Core. So I think capturing this for others who might be running into the same basic issues would be great. Maybe most people using this would switch away from IIS to Apache or something, but for me it makes sense to stick with IIS because it is one less thing to learn.

ā€“Avonelle

Ah, that might be a quick fo VS showing indirect package references too, as Registry is not in the project, but dopes get pulled in via Elements.dll, as discussed above.

D:                      Package Microsoft.Win32.Registry:5.0.0 found in repository https://api.nuget.org/v3/index.json.
                        Adding dependency System.Security.AccessControl:5.0.0] from Microsoft.Win32.Registry:5.0.0.
...
D:                      Package System.Security.AccessControl:5.0.0 found in repository https://api.nuget.org/v3/index.json.
                        Adding dependency Microsoft.NETCore.Platforms:5.0.0] from System.Security.AccessControl:5.0.0.

it seems that both of these get added indirectly, via Microsoft.Win32.Registry, so that mystery is solved.

VS probably shows one level of indirect refs in the tree, but not 2 or more. (*buit Iā€™ll check with the VS team. @viktoriad?)

That said, I do believe even indirect references need to be in the .deps.json. I can try removing them, but Iā€™m like 99% sure that (some other) stuff will fail if I do.

As for the 5.0, Elements.deps.json has the Registry reference as ā€œMicrosoft.Win32.Registry/5.0.0ā€, so I assume thats why this one gets pulled in as 5.0, despite being on 6 (or, in my case, 7). the other core refs such as Microsoft.NETCore.App.Ref do get pulled in as 7.0 for me.

Let me review that code if maybe i set the version requirement there too stringent, and should allow Microsoft.Win32.Registry:* to be pulled (which would then get 7.0 I expect)ā€¦

Naa, thatā€™s not it. 5.0 is just the latest version of that oneā€¦

D:                      Package Microsoft.Win32.Registry found in repository https://api.nuget.org/v3/index.json
D:                      Available Versions of 'Microsoft.Win32.Registry': 5.0.0, 4.7.0, 4.6.0, 4.5.0, 4.5.0-rc1, 4.5.0-preview2-26406-04, 4.5.0-preview1-26216-02, 4.5.0-preview1-25914-04, 4.4.0, 4.4.0-preview2-25405-01, 4.4.0-preview1-25305-02, 4.3.0, 4.3.0-preview1-24530-04, 4.0.0, 4.0.0-rc2-24027, 4.0.0-beta-23516, 4.0.0-beta-23409, 4.0.0-beta-23225, 4.0.0-beta-23123, 4.0.0-beta-23109, 4.0.0-beta-23019, 4.0.0-beta-22816, 4.0.0-beta-22605, 4.0.0-beta-22416, 4.0.0-beta-22231.

Okay, so it seems like the *.deps.json file is likely correct (or mostly so), and that the reason why I am getting an error when I use the *.deps.json file as generated is that it canā€™t find the reference to Microsoft.Win32.Registry.

So I need to figure out why it isnā€™t finding the reference to Microsoft.Win32.Registry.dll when deploying in IIS. The error indicates the path it is looking in is:

path: 'runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll'

Which makes me think it is looking here:
C:\Program Files\dotnet\sdk\6.0.302\runtimes\win\lib\netstandard2.0

If that is true, then yes, it is definitely not in there on my computer.

It seems like during build (at least in VS2022), it ultimately finds the reference in AppData:

               Ignoring duplicate reference to 'Microsoft.Win32.Registry.dll' from Microsoft.Win32.Registry:*.
               > New path 'C:\Users\alovhaug\AppData\Local\RemObjects Software\EBuild\Packages\NuGet\microsoft.win32.registry\5.0.0\ref\netstandard2.0\Microsoft.Win32.Registry.dll'.
               > Old path 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\6.0.7\ref\net6.0\Microsoft.Win32.Registry.dll'.
               | Added by package 'Microsoft.Win32.Registry:*'.
               | Existing reference was added by package 'Microsoft.NETCore.App.Ref:[3.0,6.0.7]'.

What isnā€™t clear to me yet is if it SHOULD be in the path it is looking for it in (meaning there is a problem with my system), or if there is something wrong with the path included in the *.deps.json.

FYI: Iā€™ll be out most of today, so I wonā€™t be very responsive here.

ā€“Avonelle

Hmm, This should be set to CopyLocal, and copied to Bin? But I can confirm itā€™s not. thatā€™s weird.

Hm, yeah, it seems that ,NET Core 6 (and 7, here for me) has its own copy of Microsoft.Win32.Registry.dll, meaning that maybe the separate package is obsolete? But how is the toolchain supposed to know that!? :woman_shrugging:t3:

God, Core is such a #%&^@# mess.

AH, ofc no itā€™s not. It/s using the one from Microsoft.NETCore.App.Ref which, being the system, will not be copy-localed. itā€™s ignoring the one from the actual Microsoft.Win32.Registry package, and as such also ignores the copy local flag for that.

So yeah, the problem is the fact that the (not actually used) Microsoft.Win32.Registry dependency ends up in the deps.json and cant be found (even though the actual dll it needs is in the system), because Core is really strict with what it needs in the .deps.json.

The question is, how can this be fixed? All EBuild knows is that the .NET Standard Elements.dll requires Microsoft.Win32.Registry, it can;t know that that reference is essentially ignored on Coreā€¦

Maybe creating a separate .NET Core version of Elements.dll would solve this (but isnā€™t the point of .NET Standard to have one version that works for all variants of .NET? But Iā€™ll try that.

I say again, what a f**ing mess.

Iā€™m able to build Elemenmts.dll for .NET Core 6.0 and later, without needing Microsoft.Win32.Registry.

Oddly, it wonā€™t build for 5.0 without the package reference even though .NET Core 5, too, has Microsoft.Win32.Registry.dll as part of the system DLLs. Strange.

Ah well. vNext should have a dedicated Elements.dll for use by Core 6.0 and later and that should hopefully address this issue. Iā€™ll upload a new build for you once I have one.

It is nice to know that it isnā€™t just me that finds some of this confusing.

Thatā€™s great! Thank you for helping me work my way through all of this!

ā€“Avonelle

:upside_down_face:

Thank you for bearing with me and reporting these, itā€™s a great help in getting this stuff closer to solid/usable :pray:t3:.