C# IoC Container that scans the bin folder - c#

I am looking for an IoC container that scans all types in all assemblies within the bin folder AND is compatible with mono.
I used to use LightCore, which took a little configuration to declare the implementation of a specific interface, and then automagically resolves it, but it doesn't seem to be compatible with mono...
I have tried TinyIoC too, but that one only scans types within referenced assemblies, and my problem is that the assembly that contains the implementation cannot be referenced by my other project that needs to resolve it (circular reference issue).
Thanks!

Related

.Net Core 3.1 Application throws FileNotFoundException with indirect Package reference?

I have an odd behavior in one of our .Net Core 3.1 projects, namely the application throws a FileNotFoundException for one of the 3rd party NuGet packages even though the file the exception referring to be missing is physically in the same directory.
Basically the Asp.net Core 3.1 Web Api .exe knows nothing about concrete implementations, only interfaces. (.Net Core 3.1 Class) Libaries then implement those interfaces and some of them pull in NuGet packages. It all comes together at runtime when the libraries register themselves to the .exe's IServiceCollection on startup. There's no direct project/nuget reference between the Web Api and these libraries, rather the Web Api .exe scans on startup the assemblies and calls an (interface declared) method to allow the libraries to register themselves to the host's DI container / service collection. This all works fine. However, whenever a method is now called in one of these libraries' classes that has a using statement to one NuGet package reference, the .exe throws said FileNotFoundException stating that, i.e. "System.IO.FileNotFoundException: 'Could not load file or assembly 'Hangfire.Core, Version=1.7.22.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.'". That file (and all its dependencies) are in the .exe's base directory though.
Now, comes the confusing part: when adding a project reference to that class library (that references Hangfire) and doing nothing else, it works - no FileNotFoundException anymore. The assemblies in the base directory are the same BUT the only main difference is, that the .exe.deps.json file of the Web API project is with this direct project reference vastly bigger and also lists Hangfire.Core and its sub-dependencies. I can also take the .exe.deps.json file and place it in the build output of the non-project-referenced compilation state (which throws the FileNotFoundException) and then it works.
So the only difference is the .exe.deps.json file with and without these (in)direct references and I am wondering, is there any way to get out of this mess?
I'd really like to keep things loosely coupled in our application for a good reason and I would not want to pull in package references if I didn't have to.
Problem is, I don't even know where to begin to solve / work on that deps.json generation and I don't know if I even want to go there. In the old days build output was enough to run an application, having a .json file make or break an application is somewhat.. odd to me.

Ref folder within .NET 5.0 bin folder

What is the ref folder when compiling .NET 5.0 application?
I mean this one:
[project_path]\bin\Debug\net5.0\ref\
These are so called Reference Assemblies (assemblies that only contain the public interface of an assembly), these help speed up the build process, since projects that depend on this one will be able to see that there is no reason to recompile, even if the innards of the assembly have changed, because outwardly it's still the same.
These Reference Assemblies need to look the same as the real thing from the outside. Hence, they have the same filename, assembly name, assembly identity and everything. This allows the build system to use them as a substitute for the real thing. And since these assemblies don't have any of the implementation details, they only change when the interface of the contents changes. Due to these facts, they can't live in the same folder as the actual build output, and this is the reason for the extra ref folder. MsBuild will use these reference assemblies automatically to speed up the build process (at the expense of generating and comparing the reference assembly each time the compiled code results in a new project output and a few files in the output directory).
If your project isn't referenced by other projects, you don't get any benefits from these reference assemblies (if you don't hand them out to 3rd parties that is). And you can turn off this feature by adding this property to the project file:
<PropertyGroup>
<!--
Turns off reference assembly generation
See: https://learn.microsoft.com/en-us/dotnet/standard/assembly/reference-assemblies
-->
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
</PropertyGroup>
After changing the setting, make sure you clean your build outputs.
These reference assemblies can also be used to allow people to compile projects to work with your system, without having to install/redistribute the actual compiled assemblies that run on your server. This way people can develop extensions, plugins, or clients for your application without having to give them access to actual implementation. This can help protect your intellectual property, since .NET assemblies are easy to decompile.
See also:
https://stackoverflow.com/a/58911152/736079

Why does the assembly reference gets loaded successfully when using MEF?

Contrary to the usual issues of MEF users, I'm not trying to figure out why a dependency of an assembly I load with MEF is not resolved. I am solving the opposite problem - trying to find out why the dependency is loaded.
The situation is that I have an ASP.NET application which uses MEF to dynamically load extension assemblies residing outside the application directory. There may be several versions of the same extension assembly in different directories I probe with MEF, each with its own set of dependencies and these dependencies again may be multiple versions of a single assembly (i.e. extension A.dll, 1.0.0.0 has a dependency D.dll, 1.0.0.0 and an extension B.dll, 2.0.0.0 has a dependency D.dll, 2.0.0.0).
It works in a sense that all the extensions and all their dependencies are loaded correctly. And I don't know why. I have no special settings in my web.config file. Where in the official documentation on assembly resolving does it say that it should work? It doesn't say anything about looking at the same directory the requesting assembly is located at.
I was hoping the Fusion Log Viewer would tell me how the runtime locates the dependencies but even though it shows me the binding requests for all the different versions of a given dependency, when I click on it to see the full log, I only see failed bindings (and yes, I have it set to log all binding requests, not just the failed ones).
Can anyone point me to the part of an official documentation explaining why this scenario works?
The main resolution with MEF is determined by the ComposablePartCatalog used. For example, if you use DirectoryCatalog, all assemblies within the specified directory get probed and found.
By looking at the CompositionContainer, you should be able to find the catalogs that are in place, which in turn should provide some details as to why the parts are composing properly.
It is also possible that your dependencies are being found due to the rules defined in "Other Locations Probed":
If an assembly uses the LoadFrom method to reference another assembly, the calling assembly's location is considered to be a hint about where to find the referenced assembly. If a match is found, that assembly is loaded.
If you are using a DirectoryCatalog to find the assemblies within a directory, it internally loads every assembly within that folder. This will cause all of your dependencies to also be loaded into the process when the DirectoryCatalog is constructed.

Loading different version assemblies, what dependency assemblies will be loaded?

I am writing an app that will use different versions of assemblies and call their methods. Question is, what dependency assemblies will they use.
For example :
AbcV1.dll has dependency assembly General.dll, both files located
in \App\V1
AbcV2.dll has dependency assembly General.dll, both
files located in \App\V2
Application also has dependency assembly General.dll, located with executable.
Lets assume General.dll is also not same in all folders, its changed too.
Now, when application will load AbcV1.dll and AbcV2.dll by reflection. Will they use their own General.dll or they will use Application's General.dll ?

Copying indirectly referenced assembly to output directory - assembly is missing [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How does Copy-local work?
I have following situation:
there's a project named OLAF.Tools, and that project references Microsoft.Data.SqlXml in C:\Program Files\SQLXML 4.0\bin\Microsoft.Data.SqlXml.dll. Reference Copy Local property is set to True. When I build that project in bin directory I can see both OLAF.Tools.dll and Microsoft.Data.SqlXml.dll
there's a console application named OLAF.Generator, and that application references OLAF.Tools (I've added reference using Project tab). When I build that application in bin directory I can see only OLAF.Generator.exe and OLAF.Tools.dll - there's no Microsoft.Data.SqlXml.dll, what supprises me. Another wierd thing is that even though that dll is missing application is executing properly.
So my questions are:
why Microsoft.Data.SqlXml.dll is not copied to bin folder of OLAF.Generator console application?
how application resolves directory where Microsoft.Data.SqlXml.dll can be found?
Thanks,Pawel
EDIT 1: (after response from Marc Gravell)
#Marc Gravell: Your answer gave me food for thought, as I could swore that I could always see indirectly dependant assemblies in main application's bin directory. And IMHO I don't agree with you - with all due respect :)
Of course, references are not cascaded physically (we're are talking about strong relationship to classes, interfaces etc) - and it's exactly what I wanted to achieve when building OLAF.Tools library. That library provides a level of abstraction, it contains factories, and one factory accepts as a parameter string and returns interface. One particular implementation of that interface uses Microsoft.Data.SqlXml components. As a result,
OLAF.Generator uses interface that is located in OLAF.Tools, but doesn't know about components in Microsoft.Data.SqlXml.
Apart from that (I think we both know what I tried to explain in preceding paragraph), when building application, dependant assemblies should be copied (if Copy Local is set to TRUE). I just wrote sample application, Project B lib has reference to Project A lib, and Project C (console app) has reference to Project B. In Project C's bin directory I can see all: Project A.dll, Project B.dll & Project C.exe. So in discussed scenario, the reason why Microsoft.Data.SqlXml doesn't end up in OLAF.Generator bin folder has something to do with that assembly itself.
Does compiler/visual studio knows that Microsoft.Data.SqlXml is located in directory which is automatically probed (or it's in GAC) and this is the reason why that assembly is not copied?
EDIT 2: I've just checked GAC, and indeed, Microsoft.Data.SqlXml.dll is installed in GAC.
How does Copy-local work? log4net.dll is not being copied to MyProject output directory - this is answer to my question. When library is installed in GAC, it won't be copied even though COPY LOCAL setting is used.
References are not automatically cascaded, so adding a reference to OLAF.Tools does not also add a reference to SQLXML. If you want to deploy SQLXML with your exe, then the most convenient way to do that is to explicitly add a reference to SQLXML from your exe, and set it to copy local. Without this, it is not deployed. Basically, the onus is on the developer to decide which files are actually needed at runtime (which is often a subset of the references used, and depends on a number of deployment decisions which only you can know).
Re how it is resolved at runtime... the probing paths are a bit of a black art, mainly meaning "the app folder", but it depends on the config, and indeed the GAC may be consulted. You also get an opportunity to provide your own resolver, via AppDomain.Current.AssemblyResolve.

Categories