Universal Apps with IoC: Dependency management/isolation - c#

I'm a huge fan of using Unity for .NET applications to keep code module and dependencies "manageable" in large code-bases. I've used it for years with .NET by dropping assemblies into the main program's program directory and re-configuring an IoC configuration file (usually the .exe.config file), injecting new behaviour into a program without needing to re-compile the main program.
However, I have started my foray into writing universal apps for Windows Store and more importantly, Windows IoT - however because these apps are "packaged up" during compilation, I'm finding it difficult to understand how best to continue doing this.
One possible option would be to compile the "modules" (PCL/Universal class libraries) and include them (and their dependencies) as "Content" files within the Universal app, then use reflection to load types from these assemblies during the start-up of the program via reflection.
Another option would be to include all modules and their dependencies into the main program's project references before compilation but using "poor man's dependency injection to hard code the registrations and resolutions", but this feels really wrong to me - I'd ideally like to keep the separation of dependencies if at all possible?
Any ideas...?
PS. I'm not tied to Unity in any way, if there is another IoC library that does it better on this platform then fine - but Unity is what I already know and love!

I do this using Castle Windsor. You can probably use the same approach with Unity:
Limit references only to when an assembly needs a type defined in
another assembly
Define a class (or classes depending on how you want to organize) for IoC configuration in each assembly by implementing IWindsorInstaller and configure DI using the fluent API inside the implemented Install method.
Define a container instance inside your app root
At application start, use reflection to find all types implementing
IWindsorInstaller in the bin folder and run their Install method,
passing in the container instance
This way you can keep your dependencies separate, and you don't have to worry about adding extra references or adding .dlls as content files.

Related

Is there an elegant way to separate Plugin Interface and Implementation in C#?

I am developing a C# desktop application that should try to find and consume a plugin hosted in a totally different C# project so that the application does not know anything of the plugin host project and its types.
If the plugin DLL is found in my application EXE folder, I should be able to create an instance of the plugin interface. But to do so in the application, I would need to make the plugin assembly known to the application solution at compilation time, which is not permissible due to the project management issues.
The only way to do it, as far as I can see, is to have two assemblies: the one with the interface only, which can be added to the application solution, and the other one with the plugin implementation.
But is there a possibly more elegant solution?
The only way to do it, as far as I can see, is to have two assemblies: the one with the interface only, which can be added to the application solution, and the other one with the plugin implementation
This is the solution I have used for plugins. The interface project is hosted in the main application solution, with the interface dll either manually copied to the plugin solution, or referenced thru nuget. I'm not aware of any solution that is more elegant.
Changes to the interface will be slightly cumbersome, but this is not necessarily a bad thing since frequent changes to public APIs can be difficult for the user of the API. It is a good idea to have some plan for how different API versions should be handled by the plugin implementation. For example by exposing a version property in the interface that can be used to determine what methods are safe to call or not.

How to resolve NuGet dependency hell

I develop a library with some functional named CompanyName.SDK which must be integrated in company project CompanyName.SomeSolution
CompanyName.SDK.dll must be deployed via NuGet package.
And CompanyName.SDK package has a dependency on 3rd party NuGet packages. For good example, let's take Unity. Current dependency is on v3.5.1405-prerelease of Unity.
CompanyName.SomeSolution.Project1 depends on Unity v2.1.505.2.
CompanyName.SomeSolution.Project2 depends on Unity v3.0.1304.1.
Integrating CompanyName.SDK into this solution adds dependency on Unity v3.5.1405-prerelease.
Let's take that CompanyName.SomeSolution has one runnable output project CompanyName.SomeSolution.Application that depends on two above and on CompanyName.SDK
And here problems begin. All Unity assemblies has equal names in all packages without version specifier. And in the target folder it will be only one version of Unity assemblies: v3.5.1405-prerelease via bindingRedirect in app.config.
How can code in Project1, Project2 and SDK use exactly needed versions of dependent packages they were coded, compiled and tested with?
NOTE1: Unity is just an example, real situation is 10 times worse with 3rdparty modules dependent on another 3rdparty modules which in turn has 3-4 versions simultaneously.
NOTE2: I cannot upgrade all packages to their latest versions because there are packages that have dependency not-on-latest-version of another packages.
NOTE3: Suppose dependent packages has breaking changes between versions. It is the real problem why I'm asking this question.
NOTE4: I know about question about conflicts between different versions of the same dependent assembly but answers there does not solve the root of a problem - they just hide it.
NOTE5: Where the hell is that promised "DLL Hell" problem solution? It is just reappearing from another position.
NOTE6: If you think that using GAC is somehow an option then write step-by-step guide please or give me some link.
Unity package isn't a good example because you should use it only in one place called Composition Root. And Composition Root should be as close as it can be to application entry point. In your example it is CompanyName.SomeSolution.Application
Apart from that, where I work now, exactly the same problem appears. And what I see, the problem is often introduced by cross-cutting concerns like logging. The solution you can apply is to convert your third-party dependencies to first-party dependencies. You can do that by introducing abstractions for that concepts. Actually, doing this have other benefits like:
more maintainable code
better testability
get rid of unwanted dependency (every client of CompanyName.SDK really needs the Unity dependency?)
So, let's take for an example imaginary .NET Logging library:
CompanyName.SDK.dll depends on .NET Logging 3.0
CompanyName.SomeSolution.Project1 depends on .NET Logging 2.0
CompanyName.SomeSolution.Project2 depends on .NET Logging 1.0
There are breaking changes between versions of .NET Logging.
You can create your own first-party dependency by introducing ILogger interface:
public interface ILogger
{
void LogWarning();
void LogError();
void LogInfo();
}
CompanyName.SomeSolution.Project1 and CompanyName.SomeSolution.Project2 should use ILogger interface. They are dependent on ILogger interface first-party dependency. Now you keep that .NET Logging library behind one place and it's easy to perform update because you have to do it in one place. Also breaking changes between versions are no longer a problem, because one version of .NET Logging library is used.
The actual implementation of ILogger interface should be in different assembly and it should be only place where you reference .NET Logging library.
In CompanyName.SomeSolution.Application in place where you compose your application you should now map ILogger abstraction to concrete implementation.
We are using that approach and we are also using NuGet for distribute our abstractions and our implementations. Unfortunately, issues with versions can appear with your own packages. To avoid that issues apply Semantic Versioning in packages you deploy via NuGet for your company. If something change in in your code base that is distributed via NuGet you should change in all of the packages that are distributed via NuGet. For example we have in our local NuGet server :
DomainModel
Services.Implementation.SomeFancyMessagingLibrary (that references DomainModel and SomeFancyMessagingLibrary)
and more...
Version between this packages are synchronized, if version is changed in DomainModel, the same version is in Services.Implementation.SomeFancyMessagingLibrary. If our applications needs update of our internal packages all dependencies are updated to the same version.
You can work at post-compilation assembly level to solve this issue with...
Option 1
You could try merging the assemblies with ILMerge
ilmerge /target:winexe /out:SelfContainedProgram.exe Program.exe ClassLibrary1.dll ClassLibrary2.dll
The result will be an assembly that is the sum of your project and its required dependencies. This comes with some drawbacks, like sacrificing mono support and losing assembly identities (name, version, culture etc.), so this is best when all the assemblies to merge are built by you.
So here comes...
Option 2
You can instead embed the dependencies as resources within your projects as described in this article. Here is the relevant part:
At run-time, the CLR won’t be able to find the dependent DLL
assemblies, which is a problem. To fix this, when your application
initializes, register a callback method with the AppDomain’s
ResolveAssembly event. The code should look something like this:
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
String resourceName = "AssemblyLoadingAndReflection." +
new AssemblyName(args.Name).Name + ".dll";
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) {
Byte[] assemblyData = new Byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
Now, the first time a thread calls a method that references a type in
a dependent DLL file, the AssemblyResolve event will be raised and the
callback code shown above will find the embedded DLL resource desired
and load it by calling an overload of Assembly’s Load method that
takes a Byte[] as an argument.
I think this is the option i would use if I were in your shoes, sacrificing some initial startup time.
Update
Have a look here. You could also try using those <probing> tags in each project's app.config to define a custom sub-folder to look in when the CLR searches for assemblies.

Windows service + Plugins design

I have a windows service. The idea is to execute as many different tasks as possible. Lets say we have this IServicePart interface with Start() and Stop() methods. When the service starts it will search all assemblies in some directory and find all classes which implements IServicePart. Done, no problem.
The problem:
Assembly1.dll is a good candidate for IServicePart. But it needs a configuration. For example Assembly1.dll.config. Now I can copy/paste/rename the dll to task2.dll and task2.dll.config and create a second task for the service. Each of those plugins comes with 10-20 dll dependencies
1) The most obvious problem is how to load the configuration, because the service host's appDomain is different than assembly1 and task2.
2) I expect issues when I try to load the two IServiceParts when they depend on the same 3rd party assemblies
Solution 1 is to make a custom configuration and not use the app.config.
Solution 2 is to run each plugin in its own appDomain.
What are your suggestions.
Hope I explained this correctly
===================
reference: similar question here: Plugin to use its own app.config
The way I've done this, involves having each plugin in its own app domain. However, the codebase property of those appdomains continue to point to the root directory where my service exe is located. This achieves two things:
The many tertiary dependencies that the plugins have now don't need to be duplicated. For example, I can put my logger assembly in the root folder (with the service exe) and all the plugins can see it. This is great, because I neither wish to put my logger assembly into each plugin subdirectory, nor do I wish to use the GAC.
All plugins now share the same app config (the same one used by the service exe). This is a good or bad thing, depending on your needs. But don't forget the configSource attribute, which can allow you to put specific config sections into seperate config files within your plugin subdirectories.
Incidentally, I've been using MAF for my plugins.

[EntLib 5]: Logging between assemblies

I've got a project that I'm working Enterprise Library logging into, and that application is made up of multiple assemblies. The UI assembly, the domain assembly and some others. Is there a way to have the logging all go to the same location (in the case of rolling flat file)?
Edit> Now that I look at it further, can you even use EntLib loggin in a class library? None of the setup that I've used thus far is available because of a lack of an app.config for a class library.
Yes, multiple assemblies can log to the same file provided that they are all running in the same app domain.
For configuration you can use the FileConfigurationSource and use the factory method LogWriterFactory(IConfigurationSource) to create a LogWriter. See External configuration files in Enterprise Library for more information.
An alternative approach would be to forgo file based configuration and use programmatic configuration.

Dependency Injection while dynamic assembly loading

i have a winforms applicatoin that has a lot of implementations of IOrderDataLoader. Other teams are starting to build their own new implementations of IOrderDataLoader. So we switched our app to look in a directories of Dlls and load all classes that implement IOrderDataLoader using reflection. This way other groups can deploy their dlls on their own and the main app loads them on demand.
The problem is one of the implementations that we have as an internal project that we are trying to move out into its own deployment has a number of dependencies. How i do i break this out and load it up with all the dependencies? All the other data loader have empty constructors so i simply just loop . .
Try looking at the Managed Extensibility Framework. It is a framework for doing what you've already done, and supports dependency injection in the style you request.

Categories