My question is more academic than a real problem: .NET Core has three different publish modes (see here). I'm interested in framework-dependent deployment (FDD) and framework-dependent executable (FDE).
As far as I understand, with framework-dependent deployment the publish folder will contain the project DLL, 3rd party DLLs and the runtimes. The app can only be started via dotnet run.
Using framework-dependent executable, the publish folder will contain the project DLL, the project EXE and 3rd party DLLs, but no runtimes. The app can be both launched via the EXE or dotnet run.
Now I'd like to host an ASP.NET Core Web API within IIS. The .NET Core runtime is installed system-wide. So I don't need the EXE and the included runtimes, but both FDE and FDD contain either one of them.
Now my question: is there any publish mode so that the publish folder contains a mixture of FDE and FDD, i. e. the DLL, 3rd party DLLs, no EXE and no runtime?
changing application .csproj file like below prevents exe to be written to publish path:
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<UseAppHost>false</UseAppHost>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Here <UseAppHost>false</UseAppHost> makes trick
Related
Let us imagine that we have two projects:
AspNetRunnerProject – an ASP.NET 6 project which is capable of loading DLLs of classlibs and serves as a driver/executor of such classlibs.
ClassLibraryProject – a .netstandard 2.1 classlib project which uses AspNetRunnerProject's nuget as its driver
What I've been able to do so far is to publish ClassLibraryProject as a self-contained app. This way all the DLLs that are needed (any kind of NuGet package or .NET 6 runtime DLLs) are bundled inside a common folder and the app can be executed with dotnet AspNetRunnerProject.dll. This way the driver project loads the classlibs it needs and runs it all.
Is it possible to publish the ClassLibraryProject (which has a NuGet reference towards the AspNetRunnerProject) as a framework dependent deployment instead of self contained app so that it can still be run with dotnet AspNetRunnerProject.dll?
If I try to execute something like the last command I get the info that "AspNetRunnerProject.deps.json" file does not exist, because the file that exists is actually "ClassLibraryProject.deps.json"?
Simple copying of this file to desired name does not solve the issue.
After researching for a few days I came to the following conclusions:
Find the ClassLibraryProject.runtimeconfig.json file in the published artifacts and rename it to AspNetRunnerProject.runtimeconfig.json
Execute the app with dotnet AspNetRunnerProject.dll
Alternatively it is possible to have a global appname.runtimeconfig.json file which could be used across multiple such projects.
For more info check https://learn.microsoft.com/en-us/dotnet/core/runtime-config/#runtimeconfigjson
I'm confused about the relationship between RuntimeIdentifier and PlatformTarget in .NET 5.
My .NET 5 C# project runs and publishes fine, but PlatformTarget is 'AnyCPU' and RuntimeIdentifier is 'win-x64'.
From Microsoft's documentation, RuntimeIdentifier is "used to identify target platforms where the application runs".
https://learn.microsoft.com/en-us/dotnet/core/rid-catalog
Isn't this what 'PlatformTarget' is supposed to do?
I tried using RuntimeIdentifers (plural) which I've seen before (perhaps .NET Core 3?), but the project doesn't compile with this:
<RuntimeIdentifiers>win-x64;win-x86</RuntimeIdentifiers>
From my current project file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0-windows</TargetFramework>
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>true</SelfContained>
<RuntimeIdentifier>win-x64</RuntimeIdentifier> -> RuntimeIdentifier is required since SelfContained is 'true'
...
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
...
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
...
</Project>
The term of "AnyCPU" means that it will have binaries that is compatible for both 32bit and 64bit. This means it is not meant to be specific for either 32bit and 64bit, and this "AnyCPU" is mostly used in older .NET Framework project, not commonly used in SDK project style that is mainly used in .NET Core projects.
These .NET Core projects include single targeted .NET Core project or multi targeted .NET Core projects, such as those that has with multiple target (usually known as TFM).
Since .NET 5.0, the TFM can be cross platform TFM such as net5.0 or .NET 5.0 target with specific OS, such as net5.0-windows or net5.0-ios. IF you want to specify .NET 5.0 class libraries that runs on Windows for 64bit, you have to specify both TFM and RuntimeIdentifier (usually called RID).
Therefore we should not use the older "AnyCPU" with combined Conditional "Release|AnyCPU". By default, any TFM without RID is always the same as having AnyCPU in these SDK project model.
For example, for targeting .NET 5.0 on Windows on both 64bit and 32bit:
<PropertyGroup>
<TargetFramework>net5.0-windows;</TargetFramework>
<RuntimeIdentifier>win-x64;win-x86</RuntimeIdentifier>
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>true</SelfContained>
</PropertyGroup>
The SDK projects has attribute Sdk="..." in the header, and this SDK will drive the reference resolutions for your project.
I recommend you to remove those PropertyGroup that has older "Release|AnyCPU" or "Debug|AnyCPU" combinations, because these combined MSBuild project syntax is not relevant for any .NET Core SDK project model.
One thing to be noted is when you have more than one RID like those in the sample above, you have to run publish for each RID you support.
Therefore, in order to have both 64bit and 32bit, you have to publish separately for each RID.
SO you have to run these:
dotnet publish yourproject.csproj -r win-x64
dotnet publish yourproject.csproj -r win-x86
See also the official doc on publishing single file executable:
https://learn.microsoft.com/en-us/dotnet/core/deploying/single-file
It's true that the pile of properties is difficult to understand (Platform, Platforms, PlatformTarget, TargetFramework (Moniker), and RuntimeIdentifier). Here is my current take on the properties - keep in mind that I have still have questions because of the results of my experiments).
Platform, Platforms, and PlatformTarget: These properties are kind of synonyms (Platforms plural is required to hold multiple platform specifiers) and refer to the bitness/CPU architectures such as AnyCPU, x86, x64, and Arm. I always think "hardware" for this property.
TargetFramework: This specifies a NET Framework API version that the app is intended to run on (net48, net5.0, wp (windows phone), netcore, netcoreapp2.1, etc). Some of these are cross-platform (cross-hardware?).
RuntimeIdentifier: The runtime specifier is the cross-platform glue part of the stack and sits here in the abstraction level stack: app->framework->runtime->platform. If your library was configured for both x86 and x64, msbuild publishes the variations to bin/debug/framework/win-x86/ and bin/debug/framework/win-x64/ (so that win-x86 and win-64 and other runtimes are siblings in the output folder tree).
You must publish/build your project once (with different property values) for each runtime that you use.
To the original question, you can see that AnyCPU is a platform specifier and RIDs are runtime identifiers. The RID monikers often include x86/x64 in their names for communication convenience, but those strings do not specify the platform. Only the Platform specifier can specifier the platform.
In operation, you can specify Platform AnyCPU for building the app (indicating the app binary is appropriate for x86, x64, arm, etc., and then use a specific runtime in the publication operation (which will assign the 32/64 bitness etc. to the published binary).
My NET 5 project files require the definition of both a Platform and a TargetFramework if no MSBuild override arguments are provided. MSBuild assumes win-x64 for the runtime on my projects that define Platform=AnyCPU and TargetFramework=net5.0-windows7.0.
It's worth saying that MSBuild can get its properties from three places: the MSBuild project file; the Visual Studio dialog sheets (probably override the project file values; and the MSBuild command line (override the project file values).
I have a .Net Core 3.1 console application that loads plugins. One of my plugins connects to Sqlite and so it has a Nuget dependency on Microsoft.Data.Sqlite. However, I'm getting a missing DLL exception from the console app when loading/running the plugin because the following path doesn't exist:
MyConsoleApp\bin\x86\Debug\netcoreapp3.1\runtimes\win-x86\native\e_sqlite3.dll
I also have an MsTest project which tests this Sqlite plugin project. It does not have the same problem. Apparently the runtimes folder and contents will automatically exist if a Visual Studio project (1) is some kind of executable and (2) has a pertinent Nuget or project reference.
Following those rules, two of my three Visual Studio projects do not have the runtimes folder:
The plugin has a Nuget dependency on Microsoft.Data.Sqlite, but does not have the runtimes folder because the plugin project is a DLL...not an executable.
The MsTest project which tests the Sqlite plugin does have the runtimes folder and contents because (1) it it is a type of executable and (2) it has a project reference to the plugin project (which in turn references the Nuget package).
The main console app is an executable, but (intentionally) doesn't have a project reference to the plugin. Thus it does not have the runtimes folder.
How do I solve this? As a hack I have simply copied the missing DLL into the output target directory for the console app.
Also, if I add a project reference from the console app to the plugin, this problem is solved. But, as stated, I don't want the console app to have project references to any plugins. Plugins should be discovered dynamically. I think fixing this may have something to do with creating a nuspec file. However, the documentation for nuspec files has no commentary about addressing this.
.Net Plugin Architecture Not Working with Nuget
Just as you said that, the lib plugins project which references Microsoft.Data.Sqlite does not have the runtime folder and when an exe project reference the lib plugins project, the runtimes folder will be copied into the the exe project's output folder.
Solution
1) Since you do not want to reference the lib plugins project for the console project, you can just do a copy task in msbuild from the MsTest project's runtimes folder.
Write this target in the xxx.csproj file of Net Core 3.1 console application:
<Target Name="Copy_Runtimes" AfterTargets="Build">
<ItemGroup>
<CopyItems Include="..\MsTest\bin\Debug\xxx\runtimes\**\*.*" />
</ItemGroup>
<Copy SourceFiles="#(CopyItems)" DestinationFolder="$(OutputPath)runtimes\%(RecursiveDir)%(Filename)%(Extension)')"></Copy>
</Target>
2) Besides, you can also install the nuget package called sqlite in the net core 3.1 console application, and this package only contains the runtimes folder and does not include other com dlls for using.
It is actually a pure service package for providing runtimes folder.
You can install this package in your console project directly and if you are not satisfied with this, you can only try solution 1 to solve the issue.
I created a .NET Core application (v1.1) in Visual Studio 2017. When I compile it, I get a DLL file produced instead of the expected EXE file for the built project. I did check the csproj file and confirmed the output type is set to exe, but no dice.
Why is Visual Studio 2017 is still producing a DLL file?
I'm sure it's a quick setting somewhere that I forgot...
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Core.EF.SqlServer\Core.EF.SqlServer.csproj" />
</ItemGroup>
</Project>
Update 2019:
.NET Core 3.0+ projects will now include an executable for the platform you build on by default. This is just a shim executable and your main logic is still inside a .dll file.
But .NET Core 3.0 also introduced single-file deployments so deploying with
dotnet publish -r win-x64 -p:PublishSingleFile=True --self-contained false
will create a single .exe file containing all your dependencies. You can change --self-contained to true to also include the .NET Core Runtime as well so .NET Core does not need to be installed globally on the target machine.
Original
.NET Core applications are supposed to be .dllfiles. OutputType set to Exe in this case means "executable" and does everything necessary to ensure that the output is runnable (entry point from Main() method, .runtimeconfig.json file). The resulting DLL file is meant to be run using:
dotnet yourapp.dll
This DLL file works across all platforms that are supported by the .NET Core runtime (Windows, Linux, and macOS). This is called a "portable" or "framework dependent" deployment.
If you want really a .exe file, consider self-contained deployments. This will create an output that contains its own copy of the .NET Core runtime and an yourapp.exe file - but it also increases the size of the published application and it needs to be updated when new versions of the runtime are released.
Also, the resulting application only works on the operating system published for.
Refer to .NET Core application deployment for more details on the deployment options and how to set them up.
In Visual Studio 2017:
Right click on your project and select Publish (In Visual Studio 2019, click on menu Build → Publish <projectName>)
Select 'Folder' and create a new profile
In tab 'Publish', click 'Configure...'
Select Deployment Mode: Self-contained, Target Runtime: win-x86 (or win-x64)
Save
Publish
In the folder <Your project>\bin\Debug\netcoreapp2.1\win-x86\ you will see the EXE file:
Starting with .NET Core 2.2 you can build framework-dependent executables
Although building a self-contained deployment can be a good solution, it has its own drawbacks. (See R.Titov and Martin Ullrichs' answers on SCD-s.)
Fortunately, .NET Core 2.2 supports the building of so called framework-dependent executable-s, that are essentially a wrapper binary (.exe on Windows) around the standard dll-s.
This way you have all the advantages (and disadvantages) of the standard framework-dependent deployment (again, see Martin's answer), but you have a convenient way to launch it, without having to call it through the dotnet CLI.
You can publish your app as a Framework-Dependent Executable using the following syntax:
dotnet publish -c Release -r <RID> --self-contained false
Where RID is the usual runtime identifier, e.g. win-x64 or whatever platform you wish to build for (see the catalog here).
That's how you do a self-contained publish with command-line in any OS:
dotnet publish C:\src\App\App.csproj -c release -r win-x64 -o output-win-x64
Besides, you might want to get the output decreased from typical ~60 MB for a simple Hello World app to ~30 MB by using ILLink.
Also, you might want to go further and get a single .exe file of a size at around 5 MB and use ILCompiler. See this reply.
The other answers are good, but what I find sometimes convenient is:
Not have it self-contained because the target machine is likely to have .NET Core of the correct version installed. This cuts on number of the DLL files I need to ship.
Not have to specify dotnet on the command line
For this, a bat file wrapper can be used, similar to these lines:
#ECHO OFF
REM see http://joshua.poehls.me/powershell-batch-file-wrapper/
SET SCRIPTNAME=%~d0%~p0%~n0.dll
SET ARGS=%*
dotnet "%SCRIPTNAME%" %ARGS%
EXIT /B %ERRORLEVEL%
If your application ends up in yourapp.dll, name the bat file yourapp.bat and place it along side the DLL file. Now instead of dotnet yourapp.dll params you can call yourapp params.
Note that the context of this answer is in-house tooling, so all the developers using the utility will have a pretty standard development machine setup. If this is to be distributed to an external customer who is running who knows what on their boxes, the self-contained option is far superior.
I published a small C# .Net Core 2.2 console application as executable using the following command from this post:
dotnet publish -c Release -r win10-x64
The generated files contain both the classic ConsoleApp.dll, but also the executable that I was expecting to be generated ConsoleApp.exe.
My question is why there was still the DLL generated, since all its code, I suppose, could have been compiled to the .exe, as in a .Net Framework application?
On the other hand, I tried to decompile the .exe file with ILSpy but the content from it does not seem to be managed code. In this case I also suppose that the .exe file is just calling the DLL using the dotnet command. Is this assumption right?
Below is the Console Application .csproj file content:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Management" Version="4.7.0-preview3.19551.4" />
</ItemGroup>
<ItemGroup>
<None Update="input.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
Very interesting question. I'll try to cover it as much as I possibly can.
With the introduction of .net core 3.0 came the Single file publish as described in the design documentation of .Net. So If you have a .net 3.0 application then you can use the /p:PublishSingleFile=true to bundle everything in a single executable.
Watch out for the /p:PublishTrimmed=true option, as treeshaking can and probably will cause problems with reflection code, as access to it is not covered by the tree shaking.
For previous versions of net core, you need to use one of the packagers like wrap or Costura.
As per the exe file, I'll mention somthing from the wrap documentation:
The final self-contained single binary application consists of two
parts: 1) runner and 2) the compressed target application executable
and dependencies.
The dll that is created by the standard publisher is multi platform and non specific to windows. So the executable file has all the code needed to create the process in windows and call the actual code that is in the dll that can be used on any platform. It's just a wrapper.
More information about the executable Microsoft .net core deploying docs
Self-contained deployment. Unlike FDD, a self-contained deployment
(SCD) doesn't rely on the presence of shared components on the target
system. All components, including both the .NET Core libraries and the
.NET Core runtime, are included with the application and are isolated
from other .NET Core applications. SCDs include an executable (such as
app.exe on Windows platforms for an application named app), which is a
renamed version of the platform-specific .NET Core host, and a .dll
file (such as app.dll), which is the actual application.
I am not sure about your assumption. But use the following command it will generate only two files, one is .exe and other is .pdb in the publish directory inside win10-x64 directory.
dotnet publish -r win10-x64 -c Release /p:PublishSingleFile=true /p:PublishTrimmed=true