Windows service + Plugins design - c#

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.

Related

Universal Apps with IoC: Dependency management/isolation

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.

C# Changing DLL app.config depending on consumer

I have a Class Library project containing some basic logic.
The DLL created by this project will be used in a few other projects.
I have a app.config file in the Class Library project with a couple of values the DLL uses.
When each consumer project will use the DLL, it has to change the values in the app.config
For example, if my DLL's app.config contains 3 settings: A, B, C, then:
The first consumer of the DLL will have A="a", B="aa", C="aaa" .
The second consumer of the DLL will have A="t", B="tt", C="ttt" .
and so on...
From design point of view, what is the most clean way to achieve this scenario?
(It seems to me that the app.config should reside at the project that uses the DLL)
Thanks for your attention! :)
EDIT:
Most of my code in the DLL is consuming ASMX web service which includes it's .config . Each application that will use the DLL, has it's own WS address (the contract is identical). How can I inject the address of the service from the application into the DLL?
EDIT #2:
Now I have 2 config files:
1. In the class library project - contains the WCF client config.
2. In the application that uses the DLL - contains the config with the values for the DLL.
How can I inject values from the application's config into the DLL's config (for example the address of the endpoint) ?
Only applications have a .config file, so having a .config file in your class library is useless.
That means that the values should come from somewhere else
The options I can think of are:
Use the .config file of the application - disadvantage: The person that write the application need to know about your config values and add them. Most of the time he/she will find out about these setting when they will get exceptions for missing values.
Save values to a DB (or some other web service) if all your applications use the same DB this can be a good idea. Works nicely when you have a very limited number of applications. I use this for different values for production/test environments
Make every class that needs these values to get them in a contractor. advantage: no hints needed, the application programer will be aware to data. This is a clean interface. I would use this option if it's a customer specific project. disadvantage: lots of work for the applications programer

Referencing a 3rd party assembly which is not located in the root location

I have a Visual Studio 2010 C# project which creates an .exe and this project is using some 3rd party class library.
My project is located in: /MyFramWork/tests/test1
3rd party library is located at: /MyFrameWork/bin/utils/
I am adding the reference to the library by using References->Add Reference->Browse. I can see that in the project file all is fine:
....\bin\utils\log4net.dll
False
I would like to reference the 3rd party library without using the option "Copy Local". However if I don't use the option, the library is not found and I get an exception.
My question is: Is there a way to specify that the 3rd party library should be found at ....\bin\utils. It seems that when the .exe gets build the information from the .csproj gets lost.
By default, .NET apps look for their dependencies in only two places: the EXE directory, and the GAC (Global Assembly Cache).
You have three choices:
You can make sure the dependency gets copied into the same directory as your EXE (this is what Copy Local does). This is the best choice most of the time, which is why it's the default when you reference an assembly that's not already in the GAC.
You can install your dependency into the GAC using gacutil. This might be a good choice if your dependency isn't going to change, is going to be in a different location on every development machine (i.e. if relative paths won't work well), and if you want to use it from many different projects. But it's a major pain if the dependency is still under active development and changing frequently. You'll also need to make sure to put the DLL into the GAC on every computer you deploy your app to.
You can customize the dependency-loading behavior so it looks in other places, as Hans noted in his comment. This is an advanced option and comes with a whole new set of headaches.
Normally, you would just use Copy Local; it's a very sensible default. You should need a fairly compelling reason to do anything different.
Use the <probing> element to specify where the CLR should search for your assemblies. The only restriction is that the assemblies must be located in subdirectories of your application's base directory.
For example, if your application base directory is C:\MyFramework, then you could have your assemblies in C:\MyFramework\bin.
Have a look at this article to learn how the CLR searches for assemblies.
If you need to load assemblies from custom locations, you could try the Assembly.LoadFile Method.
The following links may be useful:
C# - Correct Way to Load Assembly, Find Class and Call Run() Method
http://www.csharp-examples.net/reflection-examples/
It's me Potzon. I am still investigating this incredibly silly problem.
I have been hoping for some elegant solution. I am about to build fairly large framework with lots of assemblies which would be placed inside /Framework/bin/. However I wanted to have some directory structure inside the the directory, for example /bin/utils, /bin/test, /bin/devices/ and so on.
One possible solution that I have found is to define environmental variable DEVPATH (see here http://msdn.microsoft.com/en-us/library/cskzh7h6.aspx) but it turns out that .net4 is not using this variable when an assembly is run independently (outside the visual studio), or at least this is the case for me - I can't make it work.
It seems that the solution to put all the assemblies inside the /bin directory without using sub-directories is the best. I think I will give up and just do it this way.

[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.

In .NET, is there a need to register the DLL?

Is it necessary to register a compiled DLL (written in C# .NET) on a target machine.
The target machine will have .NET installed, is it enough to simply drop the DLL onto the target machine?
I think you're confusing things a little. Registering a dll has never been needed in order to use it.
Using a dll requires only to load it (given a known location or if the library is in the system path) and get the address of the function you wanted to use.
Registering the dll was used when distributing COM or ActiveX objects which need to add certain entries to the windows registry. In order to use a COM service (for example) you need to reference a GUID — that is, a unique identifier — which allows you to get a handle to the dll that implements the service (or provide access to it). Sometimes you can make reference to a fully-qualified name and get the same results.
In order for all that to work the dll needed to be registered. This "registration" process just creates several entries in the registry, but mainly these two: one associating a GUID with the location of the dll (so that you can reference it through the GUID without knowing where is it exactly located) and a second one associating the full name with the GUID. But again, this is just for COM or ActiveX objects.
When you develop an application in .NET, the libraries referenced on your project are automatically loaded when they're needed without you having to worry about locating or loading them. In order to to that, the framework checks two locations for the referenced libraries.
The first location is the application path.
The second location is the GAC.
The GAC (Global Assembly Cache) allows you to effectively register a dll to be used throughout the system and works as an evolution of the old registering mechanism.
So basically you just need to put the dll in the same folder of the application.
You need to "drop" it into a directory where the application needing it will find it.
If there are multiple applications, or you want to "drop" the file somewhere other than the application directory, you generally need to either adjust the PATH variable, or register the assembly in the Global Assembly Cache (GAC).
It is usually enough to drop the dll into the folder of your app on the target machine.
If the dll must be available to other applications then you may want to consider the GAC.
If you wish to access the assembly via com+. An example would be using a type defined in a .NET assembly from a non .NET application, such as a VB6 winforms app.
If you plan on accessing the assembly from another .NET application, you don't have to do anything. If your assembly has a strong name, it probably is a good idea to drop it in the GAC. Otherwise, just drop it in the directory of the application that will be referencing it.
One of the great selling points of .NET for the Windows platform when it came onto the scene is that by default, .NET assembly DLLs don't have to be registered and can be consumed privately by an application by merely putting them in the same folder as the EXE file. That was a great stride forward because it enabled developers to avoid the fray of DLL/COM hell.
Shared DLL/COM modules proved to be one of the greatest design mistakes of Windows as it lead to instability of applications that users installed. Installing a new app could well screw up an app that had been working just fine - because the new app introduced newer versions of shared DLL/COM modules. (It proved in practice to be too much of a burden for developers to properly manage fine-grained version dependencies.)
It's one thing to manage versions of modules with a build repository system like Maven. Maven works extremely well doing what it does.
It's an entirely different matter, though, to deal with that problem in an end-user runtime environment spread across a population of millions of users.
The .NET GAC is by no means a sufficient solution to this age-old Windows problem.
Privately consumed DLL assemblies continue to be infinitely preferable. It's a no-brainer way to go as diskspace is extremely cheap these days (~$100 can by a terabyte drive at Fry's these days). There is nothing to be gained with sharing assemblies with other products - and yet company reputation to loose when things go south for the poor user.
Actually there is NO need to register a dll in .NET on the target machine.
If you reference a .dll in your application, click on the referenced .dll under references in your project, look at the properties and set Isolated to TRUE.
This will now automatically include this .dll in your project and your application will use the copy of the .dll included in your project without any need to register it on the target system.
To see a working Example of this look here:
http://code.msdn.microsoft.com/SEHE
The .dll in question will need to be registered on the system where you build your application for this to work properly. However once you build your project, there will not be any need to register the .dll in question on any system you deploy your application or program.
An additional benefit of using this method, is that even if in the future, another .dll is registered with the same name on the target system in question, your project will continue to use the .dll you deployed with. This is very handy where a .dll has many versions and you wish to maintain some stability, like using the one you tested with, yet all other applications will use the registered .dll unless they use the isolated = true method as well.
The example above is one of those cases, there are many versions of Skype4COM which is a Skype API .dll and can change often.
This method allows the above example to use the API .dll that the project was tested with, each time a user installs a new version of Skype, it is possible that a modified version of this .dll is installed.
Also, there are some Skype clients that do not install this .dll, the business version of the Skype client for example, is smaller, and does not include this .dll, so in this case, the project does not fail on that .dll missing and not being registered because it is included in the project as isolated = true.
An application can use a .NET dll by simply having it present in the same folder with the application.
However if you want other third-party applications to find the DLL and use it they would also have to include it in their distribution. This may not be desirable.
An alternative is to have the DLL registered in the GAC (Global Assembly Cache).

Categories