WPF .NET CORE 3.0 packing with Costura.Fody - c#

When I migrate WPF Project to .NET CORE 3.0 and try to pack assemblies using Costura I am getting the following error:
The target process exited without raising a CoreCLR started event. Ensure that the target process is configured to use .NET Core. This may be expected if the target process did not run on .NET Core.
The program '[7980] CryptoBot.exe' has exited with code -2147450740 (0x8000808c).
The program '[7980] CryptoBot.exe: Program Trace' has exited with code 0 (0x0).
I found out that the reason for this behavior is that Costura.Fody doesn't properly handle *.deps.json file and that it should be 'removed or modified accordingly' by me.
There are two problems with this approach:
First: I am using database.sqlite file to store the data, removing *.deps.json will break references to e_sqlite3.dll and I don't know how to modify it properly (just add sqlite basic packages using nuget to an empty project if you want to check it out):
Second: Even if it did work it doesn't produce a single .exe file, but rather small .exe and big .dll containing the dependencies.
The desired result: I would like it to work exactly as it worked in .NET Framework, I want single .exe containing all the .dlls produced on DEBUG after pressing CTRL + SHIFT + B.
Alternatively, I also tried this:
dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true
but it didn't seem to pack anything at all, it just placed all the .dlls in the Release\netcoreapp3.0\win-x64 folder.
I PREFER that the app is packed into SINGLE .exe by using Costura and NOT anything else.

Related

MSBuild error MSB4018 cannot access project.assets.json in NET 5 build

MSBuild error MSB4018 cannot access project.assets.json in NET 5 build operation
MSBuild error MSB4018
I am building 70 C# NET 5 projects in parallel groups and sometimes get the following error on random projects within the build
error MSB4018: The "GenerateDepsFile" task failed unexpectedly.
[c:\dev\highspeed\HsCore\hscore\HsCore.csproj]
C:..\sdk\6.0.202\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.targets(172,5): error MSB4018: System.IO.IOException: The process cannot access the
file
'c:\dev\highspeed\HsCore\hscore\bin\Debug\net5.0-windows7.0\win-x64\HsCore.deps.json'
because it is being used by another process.
[c:\dev\highspeed\HsCore\hscore\HsCore.csproj]
The Microsoft doc says: This error is emitted when a task fails with an unhandled exception. This is generally a sign of a bug in the task. Error MSB4018 may be caused when running a task in an environment that it was not prepared for, for instance when a task has an x86 dependency but is running in a 64-bit MSBuild environment. This can manifest as a System.DllNotFoundException.
In my case, I am totally in a windows x64 environment, building and using AnyCPU libraries (and publishing to win-x64, but that doesn’t matter before the build runs).
I invoke the build on xxx.sln files with the following arguments:
Exit Code 1: /t:Clean;Restore;Publish /p:Platform="Any CPU"
/p:Configuration=Debug /p:TargetFramework=net5.0-windows7.0
/p:RuntimeIdentifier=win-x64 "c:\path\MySolution.sln"
The code normally builds and runs fine, except for when this kind of an error occurs. Often, when I run the build a second time, the build succeeds.
I do not understand why the MSBuild process (or one of its processes) cannot access the project.assets.json file, because MSBuild is the only one who ever accesses that file in that project. None of my tools ever reference that file; Visual Studio does not have the file or project open; No other projects in the parallel build group would ever access the projects.assets.json file anyway; so MSBuild is the only one working with the entire project tree.
The best I can think of is that maybe the Restore target in the Clean;Restore;Publish chain might be locking the file and not releasing it fast enough for the Publish(Build included) operation. But wouldn’t MSBuild be smart enough to manage that kind of thing?
Does anyone have any idea what might be going on? What other process could possibly be looking at (and locking) that file? Thank you
After days of debugging and investigating, I am convinced the problem is caused by using MSBuild multi-core operation (-m:) when building my solution (.sln) files.
If I remove the -m MSBuild command line argument, all the weird "file being used by another process" errors go away instantly. If I enable the -m:2 argument (or higher, or unbounded -m), the errors come back, instantly.
My .sln files that fail typically have three .csproj projects - a library DLL project, a LibraryXxxTests project, and a thin console program interface to the library. The Tests and console projects typically use a project reference to the library project.
Maybe (but I can't imagine why) the project references that point to the library project open the gate for MSBuild parallelism errors. (But MSBuild -m should be smart enough to see the project references and build the library project first before the console and Tests projects that reference the library DLL, yes?)
The other kind of project that sometimes fails has only two projects (lib and tests project).
My solution file and project files do nothing special or tricky - as far as I know, they are typical C# projects with 20 - 50 C# files. The errors occur on the main DLL file (Library.DLL) produced by the build, when some process is trying to write to that .DLL file and can't do it because of a lock. I don't know why.
But I do know that if I remove the MSBuild -m command line argument, the errors go away. Back to serial builds at the solution level for me ...
UPDATE: I wanted to believe MSBuild could figure out the build order among projects in a solution file, so I did more searching on the net. I found this information in the MSBuild documentation on how it calculates builds.
Graph option
If you specify the graph build switch (-graphBuild or -graph), the
ProjectReference becomes a first-class concept used by MSBuild.
MSBuild will parse all the projects and construct the build order
graph, an actual dependency graph of projects, which is then traversed
to determine the build order. As with targets in individual projects,
MSBuild ensures that referenced projects are built after the projects
they depend on.
Using the -graph option with the -m option seemed to work for solution-level builds (passing .sln files to MSBuild). The graph option tells it to calculate a build order graph among projects within each solution file. The -m -graph combination seems to let me use multiple cores to do the builds in a shorter time without MSBuild getting access errors among projects within a solution.
Keep in mind that this method requires that you use ProjectReferences in your project XML files. If you use direct assembly references to the project.DLLs stored in some other location, the -graph option cannot calculate a proper build order within the solution.
UPDATE 2:
The information about using -graph above seemed to help but did not solve all the problems. I was lucky enough to find the following information on GitHub:
I'm tempted to call this a duplicate of #9585, which is itself not the
first time the problem has been found but I can't find the original.
Problems arise whenever you explicitly pass a --framework (CLI) or
/p:TargetFramework= (direct MSBuild) to the build of a solution. The
issue is that global properties (such as that TF setting) are
inherited in most cases, but not all. Here, the ClassLibrary1 project
is built once with an explicit TF (inherited from the solution build)
and once with no TF (since it only has one, the ProjectReference from
WebApplication1 does not pass its TF down).
The best way out of this is to only pass --framework to builds of
individual projects, not solutions. Project-to-project references are
careful not to get into this situation.
Removing the /p:TargetFramework=win-x64 from the msbuild command line when building .SLN files seems to be working for me so far.

How can I use SmartAssembly 8 with .NET 3.1+ Single-File Executable (.EXE) publish and not end up with bundled, unobfuscated dependencies?

SmartAssembly has an official method of using single-file executables* (EXE) (introduced in .NET Core 3) in order to publish with their obfuscation tool.
We followed this method. The short of it is they use a clever, I won't say 'hack', but rather, 'method' of injecting the obfuscated assembly into the MSBuild / publish process (via the $(ProjectDir)\obj directory). This seems to work in that in generates a single .EXE file which executes as expected.
The issue we are running into is when we examine the resulting single file executable at a binary level, we are finding that it seems to contain copies of dependencies the main assembly references (which were supposed to be merged and obfuscated via SmartAssembly) in unobfuscated form! This outcome defeats the purpose of using an obfuscator.
Has anybody used SmartAssembly in this manner successfully?
UPDATE: There is a sample project here which illustrates this issue (this sample project is built to .netcoreapp3.1, so this is not a .net5.0-specific issue). This sample is a console application with a dependency on a class library. The obfuscation project is set to obfuscate and merge the class library into the console application.
This image shows a portion of a hex dump of the single EXE file which contains a string that's supposed to be obfuscated. In fact, the EXE contains the entire class library verbatim.
Finally, if you build and run the sample, it tries to print the name of an obfuscated type, and an obfuscated string, which comes out as its obfuscated type. Our conclusion at this point is this issue is likely caused by the publish process re-adding the unobfuscated dependencies back to the .EXE file.

dotnet core::Unable to run your project. Ensure you have a runnable project type and ensure 'dotnet run' supports this project

I have been running into an error lately trying to run some code with dotnetcore. When I try to run the project in the console (dotnet run), I get this error.
Unable to run your project.
Ensure you have a runnable project type and ensure 'dotnet run' supports this project.
A runnable project should target a runnable TFM (for instance, netcoreapp2.0) and have OutputType 'Exe'.
The current OutputType is 'Exe'.
FYI, here are entries in the .csproj file
Also, I have the following skds and runtimes installed. Yet, whatever TargetFramework I set in the .csproj, I get the same error.
I found a solution to my issue.
The problem was that I had created the project using Visual studio. Hence, the .csproj project file was not in a suitable format for dotnet core.
To solve the issue, I created an empty project with dotnet core:
mkdir myNewApp
cd myNewApp
dotnet new console
Then, I added to the project all the source files I had created with visual studio by simply copying and pasting them in the app folder. I grouped them in the single directory 'src'. At build, dotnet core automatically finds these files and builds the project with them.
Mine is an Azure Durable function. I got the following error when I try to run it with dotnet cli using the command dotnet run.
Unable to run your project.
Ensure you have a runnable project type and ensure 'dotnet run' supports this project.
A runnable project should target a runnable TFM (for instance, net5.0) and have OutputType 'Exe'.
The current OutputType is 'Library'.
The solution is simple. You cannot use dotnet cli for this. Instead You need to run using the command func start as explained here.
And of course you need to install the azure function tools.
Most probably it is do something with the version you are trying, in my case, I was using .nerstandard 2.0 which was wrong and I changed it to net5.0 and I was able to run successfully.
It looks like this now -
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
I have experienced the same problem that the project refuses to create an EXE file. It was showing to compile a DLL, yet required an EXE to run.
I was using dotnet core and VS-Code and didnt suspect anything until I tried to rename the project folder to start another with the same name. What I got was greyed out folder/file names for some time about 10 sec with no name change.
Only then I realized: though I deleted "bin" folder, there was an instance of the project somehow running alive but hidden (should have prevented me deleting folder otherwise) and prevents any new EXE to be written.
Solution you might ask, simple: just close/restart IDE completely. Any program spawned with it will be terminated. trying to close/terminate terminals do not work.
Open CMD.EXE and run the following commands:
dotnet new console -o myApp
cd myApp
dotnet run
It works for me.
https://dotnet.microsoft.com/learn/dotnet/hello-world-tutorial/run

Compile C# console without dll needed

When I compile my C# Console it comes with an dll, if I remove the dll the application doesn't work, and I need it to work with only an .exe and no .dll files.
https://prnt.sc/t1gu4m
Right Click your Project
Select Publish
Deployment Mode: Self-Contained
Check the Produce single file option
Et voila, you got a single exe with the required dependencies
In addition to Maurice Legoland's answer. If you're using dotnet cli, run:
dotnet publish -p:PublishSingleFile=true --no-self-contained # Other arguments.
Only use the --no-self-contained flag if you want your executable to be dependent on .NET i.e, it cannot run without the user having .NET's CoreCLR. Otherwise simply set PublishSingleFile to true. You can also use a manifest/configuration file. See this for more information.

.net core adding a .net standard dll as a reference

create a .net standard dll , name it as Paas dll, and change the output path
..\Output\
add a class logger like below-
public class Logger
{
public void LogMessage()
{
Console.Write("test");
}
}
Now create another .net core console project in solution and add dll as a refrence ( not project refrence) for pass.dll and make copy local to false.
Also change output directory of console app to ..\Output\
add below code in console app -
var logger = new Logger();
logger.LogMessage();
Console.Read();
Build and run .net core app, but now application goes in break mode with below error
Could not load file or assembly 'Paas, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null'. The system cannot find the file
specified.
But if you perform same steps with .net framework 4.6.1 projects it works, why this different behavior with .net core exists and how to fix it?
github link for project showcasing this issue -
https://github.com/ankgupta067/DependencyInjection.git
The issue is setting copy local to false. On .NET Core, in order to know which assemblies should get loaded, it uses what is called a .deps.json file that gets generated next to your output .dll. In order to generate this .deps.json file, the .NET Core SDK inspects information about the assemblies you reference. One of the pieces of information it uses is whether the Reference is CopyLocal or not. See the code here. If you inspect your console app's .deps.json file, you'll see there is no entry for Paas.dll in it.
So in order to make this work, the .deps.json file will need to be written correctly. Using the current tools, that means you will have to stop setting copy local to false. If you want to open an issue for this scenario please log it here. That way it can be fixed in a future release.
OLD ANSWER:
A difference between SDK-based (".NET Core style") .csproj projects and traditional .csproj projects is that by default SDK-based projects will append the target framework to the <OutputPath> property.
So when you say
Also change output directory of console app to ..\Output\
What is really happening is that the output of the SDK-based netstandard library is going to ..\Output\netstandard2.0\Paas.dll and the output of the SDK-based console project is going to ..\Output\netcoreapp2.0\. These are 2 different directories, so the runtime can't find the library.
To stop this behavior, edit both .csproj files and add:
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
inside a <PropertyGroup> element.
This will cause both projects to output directly to the specified ..\Output\ folder.

Categories