Cannot debug a project with nested dependencies in Git submodules - c#

I have a solution with a sample .NET Core microservice that has dependencies on two projects (one of which is dependent on another and dependencies are set up using Git submodules). It builds fine, but when I try to debug the microservice, I get the error:
An unhandled exception of type 'System.IO.FileNotFoundException'
occurred in Unknown Module. Could not load file or assembly
'CommonLibrary, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null'. The system cannot find the file specified.
I checked the bin\Debug\net6.0 folder and the CommonLibrary.dll file is there along with all other dependencies.
I made a copy of the solution, included both dependency projects without using Git submodules, and it worked fine. I compared the Debug\net6.0 folders in both solutions and they contain the same files (only the timestamps of the assemblies from the three projects are different). Any idea what could be going on here?
Here are some details (with project names redacted for clarity). The three .NET 6 projects include:
CommonLibrary (has no dependencies on other projects)
CommonControllerLibrary (depends on CommonLibrary)
SampleMicroservice (depends on both CommonLibrary and CommonControllerLibrary)
I created 3 repos in GitLab and linked project dependencies via the Git submodules. On the file system, the directory structure for the SampleMicroservice project looks like this:
…
└── sample-microservice
│
├── common-library
│ └── CommonLibrary
│ ├── CommonLibrary.csproj
│ …
├── common-controller-library
│ ├── common-library
│ │ └── CommonLibrary
│ │ ├── CommonLibrary.csproj
│ │ …
│ └── CommonControllerLibrary
│ ├── CommonControllerLibrary.csproj
│ …
├── SampleMicroservice.sln
│
├── SampleMicroservice
│ ├── SampleMicroservice.csproj
│ ├── Bin
│ │ └── Debug
│ │ └── net6.0
… …
The CommonLibrary project is referenced twice in the solution, so in the Solution Explorer, it looks like this (I use solution folders to isolate the dependencies in the submodules from the main project):
Solution 'SampleMicroservice' (4 of 4 projects)
│
├── Submodules (folder)
│ ├── CommonLibrary (folder)
│ │ └── CommonLibrary (project)
│ │
│ └── CommonControllerLibrary (folder)
│ ├── CommonLibrary (project)
│ └── CommonControllerLibrary (project)
│
└── SampleMicroservice (project)
The SampleMicroservice project is dependent on the CommonLibrary project in the CommonLibrary solution folder and the CommonControllerLibrary in the CommonControllerLibrary solution folder.
I'm not sure if I messed up the projects when I set up the submodules, but I can't think of any other way to configure it. The main goal is to reuse projects across GitLab repos considering that some of the shared projects have nested dependencies (shared project B depends on shared project A, and project C depends on both A and B). TIA

Related

Use MediatR with Class Library

i'm trying to use MediatR in my ASP.NET 6 application, but i need to write builder.Services.AddMediatR(typeof(ExampleCommandHandler).Assembly); for every handler. I was looking for a way to add just in single line like builder.Services.AddMediatR(typeof(Startup).Assembly);. But all the examples i saw throw the exception with message Register your handlers with the container.
I think this problem is because my Commands and my Command Handlers are in different class library, example of my folder structure:
.
└── MyApp/
└── src/
├── MyApp.API/
│ ├── Startup.cs
│ └── ...
├── MyApp.ClassLibrary1/
│ ├── Handlers/
│ │ └── ExampleCommandHandler.cs
│ └── ...
└── MyApp.ClassLibrary2/
├── Commands/
│ └── ExampleCommand.cs
└── ...
Can someone help me?
try builder.Services.AddMediatR(AppDomain.CurrentDomain.GetAssemblies());

Importing Dependent DLLs in a PowerShell Script

Problem Statement:
Optimal way of importing dependent DLLs in PowerShell script.
Explanation:
I have a DLL, namely a.dll which has almost 10 dependencies on b.dll, c.dll,.... When I import the a.dll from the Nuget Package A in a PowerShell script then as the Dependent DLLs are not present in the same Directory it throws an error. I only have the DLLs in Nuget packages. The packages as usual will be in the
├── Nuget-A
│ ├── 1.0
| | |── a.dll
│
├── Nuget-B
│ ├── 2.0
| | |── b.dll
In the PoweShell script I will import the a.dll,
Import-Module "Nuget-A/1.0/a.dll"
This throws me an error so I do the following
Import-Module "Nuget-B/2.0/b.dll"
Import-Module "Nuget-A/1.0/a.dll"
In the same way I have to do for the 10 DLLs.
What is the optimal way of handling the scenario? I am open to any other approaches too
I'm not terribly experienced with PowerShell, but I expect that if all the assemblies were in the same directory, then when you import a.dll, it will automatically find the references, such as b.dll. That's how the .NET runtime loads assemblies, more or less, regardless of PowerShell, a console app, web app, and so on.
Therefore, instead of creating a package A that contains only a.dll and a dependency on package B, have package A not have any dependencies, and contain all 10 dlls in it.
There are a few ways to achieve that. One is to re-use csproj's PackAsTool. It publishes the project (using the equivalent of dotnet publish), and then packs everything in the publish folder. Since it's designed to pack console apps so that they can later be installed via dotnet tool install, you might have to do some hackery to get it to work. Another way is to run dotnet publish, then get nuget.exe from nuget.org/downloads, and cd to the publish directory run nuget.exe spec to create a template .nuspec file, edit that nuspec with all the metadata you want, then run nuget.exe pack. It will pack all the files in the directory into a nupkg. There are other ways too, for example try nugetizer, a community created tool, but this question is about how to solve referenced assembly loading, not how to pack, so I'll leave it at that. My point is that when you have a package that contains a PowerShell cmdlet, you shouldn't need to worry about loading all the dependencies in the powershell script/environvment using the package, so make sure the package is "self contained". It shifts the burden from consuming time to packing time, but at packing time all the dependencies are known, so it's an easier problem to solve.

Why and when you should create a new project in a visual studio solution?

Why and When you should create a new project in a visual studio solution?
To be more specific, when you should separate the main project in multiple projects?
We all know that Database files should be separated by main project, that Entity Framework models should be separated, but what about "components"?
Let's assume i have a WebAPI project, with some Apis and some features, including Entity Framework and Database files.
Atm these features are included in the main project and my solution structure is:
- App.Api [Main project, With Feature1, Feature2, Feature3, FeatureX, Reference projects App.Models]
|- ApiControllers
|- Helpers
|- Managers
|- Assets
|- Web.config
- App.Models [Models Project]
|- Entity Framework Auto Generated Models
- App.Database [Database Project]
|- Sql Files
What if i split my features in multiple projects and include them in the main project, using the main project as "HEAD" of the other projects?
Something like:
- App.Api [Main project, reference Projects App.Feature.Feature1, App.Feature.Feature2, App.Feature.Feature3, App.Feature.FeatureX, App.Models]
|- ApiControllers
|- Web.config
- App.Feature.Feature1 [Library Project - Feature 1, splitted from main project]
|- Managers
|- Helpers
|- Other files *.cs
- App.Feature.Feature2 [Library Project - Feature 2, splitted from main project]
|- Managers
|- Helpers
|- Other files *.cs
- App.Feature.Feature3 [Library Project - Feature 3, splitted from main project]
|- Managers
|- Helpers
|- Other files *.cs
- App.Feature.FeatureX [Library Project - Feature X, splitted from main project]
|- Managers
|- Helpers
|- Other files *.cs
- App.Models [Models Project]
|- Entity Framework Auto Generated Models
- App.Database [Database Project]
|- Sql Files
After that i could but some unit testing attached to each project:
- App.Api [Main project]
- App.Feature.Feature1 [Feature 1, splitted from main project]
- App.Feature.Feature1.Tests
- App.Feature.Feature2 [Feature 2, splitted from main project]
- App.Feature.Feature2.Tests
- App.Feature.Feature3 [Feature 3, splitted from main project]
- App.Feature.Feature3.Tests
So, this is the question. Why, why not and when create multiple projects?
I find more clean this approach instead of first

NuGet direct project references as versioned dependencies

I have 2 Projects Libraries in my Example Solution > Visual Studio.
I directly reference one of them in the other. When I now publish my nuget package, on the dependency overview I get that my directly referenced nuget is >= 1.0.0.0, when I do it via nuget the reference means no direct reference because same solution I get the right version number under >= dependency overview. I won't change the default dependency behavior lowest.
What I've tried is to update my nuspec file with dependencies / references / files elements none of them worked for me.
I would like to see the same version of the given nuget in the directly referenced nuget as dependency.
From the last sentence in you question and your emphasis on direct references makes me feel I know what you are after:
NuGet defines the -IncludeReferencedProjects option to instruct nuget.exe how it should treat referenced projects, either as dependencies or as part of the package:
If a referenced project has a corresponding .nuspec file that has the same name as the project, then that referenced project is added as an explicit NuGet dependency.
Otherwise, the referenced project is added as part of the package.
My guess is that you are after the former.
Let us simplify the problem to its most basic form: Let's say you have a solution where LibraryA references LibraryB directly as a project reference. When you build the solution, the assembly output from LibraryA is copied to LibraryB
~/
│ Solution.sln
├───LibraryA
│ │ ClassA.cs
│ │ LibraryA.csproj
│ │ LibraryA.nuspec
│ ├───bin
│ │ ├───Debug
│ │ │ LibraryA.dll
│ │ │ LibraryA.pdb
│ │ └───Release
│ └───Properties
│ AssemblyInfo.cs
└───LibraryB
│ ClassB.cs
│ LibraryB.csproj
│ LibraryB.nuspec
├───bin
│ ├───Debug
│ │ LibraryA.dll
│ │ LibraryA.pdb
│ │ LibraryB.dll
│ │ LibraryB.pdb
│ └───Release
└───Properties
AssemblyInfo.cs
Setup
For illustration purposes I will use the pattern [assembly: AssemblyVersion("1.0.*")] in my AssemblyInfo.cs files and will do a couple of separate builds on each project to ensure my assemblies get some different interesting versions.
Make sure that each project contains a .nuspec file with the same name as the project. This is specially important for project LibraryA, as it is the project being referenced by LibraryB. I'll do it for both as good practice. Let us use a basic template for now:
In the .nuspec below, the replacement tokens $id$ and $version$ will get their values inferred when you run nuget.exe against a .csproj file that has been built.
<?xml version="1.0"?>
<package >
<metadata>
<id>$id$</id>
<version>$version$</version>
<authors>The author... (**mandatory element**)</authors>
<description>Your description... (**mandatory element**)</description>
</metadata>
</package>
Use nuget pack -IncludeReferencedProjects
Now, I am going to run nuget.exe in the command line from the solution directory (~) on project LibraryB:
PS> nuget pack .\LibraryB\LibraryB.csproj -IncludeReferencedProjects -Verbosity detailed
Attempting to build package from 'LibraryB.csproj'.
Packing files from '~\LibraryB\bin\Debug'.
Using 'LibraryB.nuspec' for metadata.
Add file '~\LibraryB\bin\Debug\LibraryB.dll' to package as 'lib\net451\LibraryB.dll'
Id: LibraryB
Version: 1.0.5993.6096
Authors: The author... (**mandatory element**)
Description: Your description... (**mandatory element**)
Dependencies: LibraryA (= 1.0.5993.7310)
Added file 'lib\net451\LibraryB.dll'.
Successfully created package '~\LibraryB.1.0.5993.6096.nupkg'.
PS>
Generated packages
The above command will create a NuGet package LibraryB.1.0.5993.6096.nupkg with a explicit NuGet dependency to LibraryA.1.0.5993.7310.nupkg.
When you inspect the contents of LibraryB.1.0.5993.6096.nupkg, you will see that the .nuspec generated by nuget.exe will have replaced all the $version$ replacement tokens to that of the actual versions used.
One last thing, the command above will create the NuGet package only for LibraryB but obviously you can create the one for LibraryA just by running it again targeting LibraryA.csproj
I hope this is what you were after, or that at least sheds some light to what you can do.

How can i make my plugins load assemblies from their own path, instead of my .exe loading them

I have a small software application where i have some plugins in the form of .zip files i download to a folder called "plugins", this is my sample disc structure:
MyApplication.exe
|
|
|-Plugins (Folder)
|
|- Plugin1 (Folder)
| |
| |- MyPluginAssembly1.dll
|
|- Plugin2 (Folder)
|
|- MyPluginAssembly1.dll
|- Assembly1.dll
|- Assembly2.dll
My problem is that i have this plugin (Plugin2) which has some assemblies it need to load. Problem is that it will not work if the assemblies are located in the plugins folder the .exe which is loading the plugin cannot load the assemblies unless they are registered or resides "beside" the .exe file. Right now i copy the assemblies (Assembly1, Assembly2) to the folder which contains the .exe assembly. Is there any way i can keep the files inside the plugin folder where they belong?
You can attach to AssemblyResolve event and load your assemblies from any path you like.
AppDomain.CurrentDomain.AssemblyResolve += (sndr, resolveEventArgs) =>
{
return Assembly.LoadFile("......");
};
Try Assembly.GetExecutingAssembly().Location.
Note that this doesn't always work - it will likely only produce the intended behaviour when the library is a physical .dll on disk. There are other ways to load assemblies in .NET - but by the looks of it your application will work fine.
Do note that I haven't tried it, so test it thoroughly with various deployment scenarios before using it (obviously!)
edit #1: I'm now doubting whether I've understood your question correctly. GetExecutingAssembly will return the current assembly (fairly obviously) so if you want the path of the plugin library, you'd need to call this method in the plugin library. Is this what you wanted, or are you asking how to get the paths(s) of the plugin(s) from the application executable?
I suggest to use the codebase tag in the configuration file, like MSDN suggests here. Note you can only place libraries which are under you directory main application (like in your use case), unless you register them in the GAC. Here are some useful tips on CodeBase.

Categories