.NET Application architecture allowing missing assembly - c#

I am searching for the correct assembly setup and abstraction to get this issue solved:
I got an app using an assembly to access an external system. Now this assembly is not available on every computer as it must be installed before my application (it comes with the complete external system setup).
When I now start my app on a computer where this external system is not installed I get: "FileNotFoundException" (I've got an Application.ThreadException handler)
I would like to only "lously" reference that assembly and be able to run without it (do offer configuration, advice, simulation).
I guess I have to implement a wrapper but I am not sure where to start. Will the wrapper reference the real assembly or use reflection to call it when available?

I think you have already kind of answered your question. The best way to go about it is by implementing a "wrapper" that can take objects from this assembly and utilize the concrete objects of this assembly, then implement a stub that will take over when this assembly is not found.
This wrapper could be a proxy object if you implement the Proxy Pattern and it should be able to have some intelligent logic to switch to a different concrete object(s) when the above-mentioned assembly is not found. Since you are using c#.net it should be as simple as checking whether the assembly exists in a specific location without trapping the check logic within a try/catch block.
Edit
By the way, the wrapper cannot reference the assembly because the assembly is not included in your project...you are manually loading the assembly which is different. Then, in order to instantiate objects of this assembly and call methods of these objects you need to use reflection.

You could handle the AppDomain.AssemblyResolve event. It's called when an assembly cannot be found, and it gives your code the opportunity to track down the specified assembly and return it back to the app domain.

Related

How to find a type that is not loaded yet in AppDomain?

I'm developing modular application using WPF and Prism.
All my UserControls have separate assemblies and implement IUserControl interface.
I would like to list all Types which implement IUserControl interface form a loaded module library in this way;
//ModuleA.cs
var interfaceType = typeof(IUserControl);
var userControlTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => interfaceType.IsAssignableFrom(p) && p.IsClass);
But I cannot see all UserControl types implementing IUserControl in userControlTypes list.
When I use the all classes that implements IUserControl in Bootstrapper.cs like in the following;
var userControlTypes = new List<Type>()
{
{typeof(HastaKayitControl)},
{typeof(ViziteUserControl)},
{typeof(DenemeUserControl)},
...
};
I can get all desired UserControls from the list just I wrote above(userControlTypes).
What is the reason behind this?
FYI:
All assemblies target the same .NET framework version.
My Prism version is 6.1.0
I will use userControlTypes to show all UserControl types inside the application to the end-user.
IUserControl interface contains nothing.
This behavior is by design. The .net CLR will not load in an assembly unless it is called/entered which forces it to be loaded. Imagine the startup cost of running an app if every .dll file in the directory were loaded into memory when the application started as opposed to when a type was referenced at run time for the first time, some apps with large libraries would have load times of minutes (maybe even more?). Also it would not be realistic because some types are resolved to libraries outside of the execution folder like assemblies that resolve to the GAC.
In your first example AppDomain.CurrentDomain.GetAssemblies will only return the loaded assemblies, not all the assemblies, in that application domain. To see this you could add a {typeof(ViziteUserControl)} (taken from your next code part) and place it right above it, this will force the type (and containing assembly) to be loaded by the CLR and now it (types containing assembly) too will be returned by AppDomain.CurrentDomain.GetAssemblies.
In your next code fragment your code is explicitly entering these assemblies and adding the types. I do not think this requires any explaining.
So if you want AppDomain.CurrentDomain.GetAssemblies to load all your types across your application you need to force the assembly to load into memory if it has not already done so. Depending on your structure you could do this a couple of ways.
Iterate through the .dll files on disk (using a reference location like Assembly.GetExecutingAssembly.Location) and call Assembly.LoadFrom. Use wild cards to ensure you are only loading your assemblies and not every .dll library you are encountering.
Reference interested types in a configuration file and load them from there. You can use Type t = Type.GetType(yourConfigType); when creating your list of types from your configuration string list.
Reference interested assemblies in a configuration file and load in the DLL in the same manner as option 1.
Just hard code the list as you did in your last example.
If you choose option 1 or 3 you will have to check to make sure you have not already loaded the assembly in memory before you call Assembly.LoadFrom. You can do this by again checking what is already loaded with AppDomain.CurrentDomain.GetAssemblies().Any(x =>your search query).
Also Note that once you load an assembly into your application domain you cannot unload it for the life of that application domain. If you do not want this but you still want to dynamically find all your types you will have to create a 2nd application domain to find all the types and return them as an array/list of fully qualified type name as a string. You can then unload this created application domain. Also, as correctly noted by #Peter below in the comments, use ReflectionOnlyLoadFrom if you go with this approach. This incurs much less overhead.
AppDomain.GetAssemblies() tells you the loaded assemblies, not the referenced ones. I can't speak to the Prism aspect of your question, and I agree with the comments that there is probably a better way to design this. But…
If you really want to enumerate all of the types that might get loaded in your AppDomain, you can approximate this by enumerating the types in the existing assemblies (i.e. as you've done here, with AppDomain.CurrentDomain.GetAssemblies(), but then for each assembly, call GetReferencedAssemblies()), which returns an array of AssemblyName values that you can use to load additional assemblies. For each of those, you can in turn inspect all of their types (to find the implementors of IUserControl) and to call GetReferencedAssemblies() to continue the recursive search.
Note that this still will not necessarily return all implementors of the IUserControl interface that your process might load. Assemblies can be loaded by means other than being referenced in your AppDomain's assemblies, such as by code searching a directory for candidates, or even the user explicitly naming an assembly to load. This is why using mechanisms directly supported by whatever API you're using is a much better approach, to make sure that you find exactly those assemblies that that API would find.

Can you use a class library if you don't reference all of it's dependencies?

Let me clarify:
I have built a class library to be used in several projects. As part of this DLL I want to add a few different custom providers for Owin Cookies by extending CookieAuthenticationProvider so I need to include a reference to Microsoft.Owin.Security.Cookies. This is safe because the newer projects that will use my library also use Microsoft.Owin.Security.Cookies.
However some of the projects are older and dont use Owin etc... Will they blow up if I include the library for other use? Or will they only blow up if I try to use the provider (which I wouldn't since they cant use it).
I want to put some commonly used things in my library without having to reference every one of it's dependent DLL's to every project that uses them. I'm pretty sure what I'm doing is ok but I was hoping somone could tell me before I waste many hours going forward with this. Also if there is a better way I'm all ears.
The rules:
All types which are visible to a given assembly must be declared in assemblies referenced by that assembly.As long as your class library does not actually expose in its public API the types found in the Microsoft.Owin.Security.Cookies assembly, then other assemblies can safely compile with your DLL without referencing that assembly.
A referenced assembly need not be present at runtime, except when code in that assembly is actually needed, i.e. some other code attempts to call that code.
In general, this means that as long as other assemblies which are referencing your assembly and which don't reference Microsoft.Owin.Security.Cookies also don't call any code in your assembly that would then in turn attempt to call code in Microsoft.Owin.Security.Cookies, that assembly need not be present at runtime.
The tricky part on that second point is that what constitutes "calling code in Microsoft.Owin.Security.Cookies" is not always clear. Typically, as long as you don't access the types in the assembly at all, .NET won't try to execute any code in that assembly. But it's not hard to accidently access the types even when they are not necessarily needed (e.g. in initializers, static or otherwise, code that checks for interface implementations, etc.).
If you really want your clients to be able to use your DLL, which references Microsoft.Owin.Security.Cookies, without necessarily needing that DLL to be present at runtime, you will need to be very careful to ensure you've fully supported that scenario. It is possible to do, but it's also not hard to make a mistake.
(I have to admit, I'm surprised that this useful question hasn't already been addressed on Stack Overflow. Seems like it would have come up before by now. But I was unable to find a duplicate, hence the answer above. If anyone is aware of a duplicate I've overlooked, I welcome any suitable notice of that.)

Dynamically loading assembly: why this code works?

In my situation there are three components: Consumer class, IExposedIface interface and Exposed class implementing IExposedIface. Both Consumer and Exposed are linked statically with IExposedIface, but Consumer bears no compile-time reference to Exposed.
I am trying to come up with a scheme which would allow Consumer loading different versions of Exposed at runtime (depending on input data - let's say each input document carries an information about which version of Exposed should be used to process it). To achieve this, I started studying AppDomains and now I have a basic version working.
So far it seems to me there are two options when it comes to providing IExposedIface assembly to Exposed assembly.
Having IExposedIface.dll only in Consumer's bin directory and handling AppDomain.AssemblyResolve event for the AppDomain in which I am creating an instance of Exposed
Having IExposedIface.dll both in Consumer's bin directory as well as aside each Exposed.dll.
Now consider that I build Exposed against this IExposedIface:
public interface IExposedIface
{
string SaySomething();
}
and I build Consumer against this IExposedIface:
public interface IExposedIface
{
string SaySomething();
string SaySomethingDifferent();
}
In the first case, the exception
Exception: Method 'SaySomethingDifferent' in type 'Exposed.Exposed' from
assembly 'Exposed, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
is thrown in the moment I call appDomain.CreateInstanceAndUnwrap(...) to create an instance of Exposed in the freshly created AppDomain.
That looks reasonable to me.
But in the second case, appDomain.CreateInstanceAndUnwrap(...) goes through just fine and I can without problems call 'SaySomething()' method on the retrieved object. An exception
The method 'SaySomethingDifferent' was not found on the interface/type 'IExposedIface.IExposedIface, IExposedIface, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null'.
is only thrown when I actually call SaySomethingDifferent() in Consumer.
I was quite surprised that in this second case CLR had let me go so far...Could someone explain why this is possible?
Case #1 means that Exposed.dll is binding against the wrong version of IExposedIface.dll - the metadata loader is able to detect this when loading the assemblies because it finds an unimplemented interface method.
Case #2 (probably) means that you have the correct version of each IExposedIface.dll besides each Exposed.dll so each assembly can load within its own AppDomain. However AppDomain A has a different interface than AppDomain B which is only a problem when the call actually crosses the AppDomain border.
I'd suggest not trying those binary compatibility games and rather do proper versioning (ie. create a new interface with the new methods, inheriting from the old interface, so the new version of IExposedIface.dll is really backwards compatible). Anything else is really hard to debug because you can accidently end up loading both versions of IExposedIface.dll if they are reachable for windows, and then you have two versions of a Type in the AppDomain causing no end of trouble ;)

Dynamic loading of DLL

I have a program which needs to use a large number of plugins.
Each plugin must support a very basic interface, this interface is defined in a DLL (IBaseComponent for simplicity of question sake).
Each plugin will be in a specific directory (AppDirectory\plugin\plugin-type).
Each plugin can have any name for the plugin's dll (AppDirectory\plugin\plugin-type\plugin-name.dll).
So I need to check through each plugin subdirectory, find each plugin that has a class which supports the IBaseComponent interface, instantiate the class and call some functions on the plug in.
ok, all fine and dandy, none of this is particularly hard. The problem though is that I seem to be running into some weird issues.
Every plugin needs to have the Base.dll file in the individual plugin folders (instead of just in the program that will be loading the plugin) and also it seems that I get many errors and warnings around dynamically loading a dll which have dll's that also need to be loaded.
I'm using:
pluginModule = System.Reflection.Assembly.ReflectionOnlyLoadFrom(PathToAssembly);
in order to grab the plugin dll and using:
types = moduleAssembly.GetTypes();
in order to grab the types contained within the dll.
I am iterating over the types and checking if the individual type is of the IBaseComponent interface (signifying this is a valid to load class) with:
if (type.GetInterface("FrameworkNameSpace.IBaseComponent") != null)
//it's of the IBaseComponent interface
Later, in order to actually create an instance of the class from the dll I use:
pluginModule = System.Reflection.Assembly.LoadFrom(PathToAssembly);
and then use:
types = component.GetTypes();
In order to get the types within the module then select and load the class which supports the interface same as above.
The problem seems to be on when I use:
types = component.GetTypes();
When actually trying to load the class, Instead of simply looking at it. (Hence my different usage of LoadFrom and ReflectionOnlyLoad)
The Exception I receive on the GetTypes call (on a second plug in, but never the first!) is:
{"Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information."}
With the LoaderExceptions property as:
{"The specified module could not be found. (Exception from HRESULT: 0x8007007E)":null}
I'm unsure why this occurs. The DLL is in the plugin folder, and the DLL containing the IBaseComponent interface is also in every one of the plugin directories. Am I going about this the wrong way?
Also is it required for me to keep a copy of the DLL containing IBaseComponent within each plugin subdirectory as well as the one used by the program itself, or am I doing something incorrectly that would allow me to remove this requirement?
I am aware of MEF which is what I wanted to use but unfortunately because I am required to support this on .net 2.0 I am unable to use MEF.
This is a LoadLibrary() failure. Sounds to me that you plugins have a dependency on some unmanaged DLLs. Yes, Windows is going to have a hard time finding these DLLs, it has no reason to look in the plugin directories. Maybe it works the first time because your app's default directory happens to be set to the correct directory. Which would then also be the workaround, use Environment.CurrentDirectory.
Finding out exactly which dependencies can not be found is key. Unmanaged ones are not going to show up in fuslogvw.exe, you can dig it out of a trace from SysInternals' ProcMon utility.

Prevent loading an assembly in c#

I want to prevent an assembly to be loaded from another application. So that it can be loaded from my application only.
Rigth now I'm using Assambly.LoadFrom to load the assembly.
Ultimately, no. It sounds like you are deploying a dll, but you want to retain sole control over how it is used. That is just an arms race; ultimately if somebody really, really wants to (ab)use it, they can. Even if that means disassembling, de-obfuscating, and disarming any preventative code you have added.
The only way to block that: don't give it to them. Consider using a web-service for some functions. Then they don't have the assembly.
You can try to validating entry assembly (Assembly.GetEntryAssembly) somewhere in your 'protected' assembly.
You can't stop people from using your DLL using technological approach. You can try to make it more difficult but a sufficiently skilled user will be able to modify the assembly so that they can use it.
You could try a legal approach. You can include a clause in your license agreement which disallows people from using your assembly in another application. But it won't stop everyone.
You could use the InternalsVisibleToAttribute in your assembly and specify your application assembly as a "friend". This will prevent other assemblies of using types provided they are marked as internal but will allow your application to still use those types.
From MSDN:
Ordinarily, types and members with
internal scope (in C#) and friend
scope (in Visual Basic) are visible
only in the assembly in which they are
defined. The
InternalsVisibleToAttribute attribute
makes them also visible to the types
in a specified assembly.
The attribute is applied at the
assembly level. This means that it can
be included at the beginning of a
source code file, or it can be
included in the AssemblyInfo file in a
Visual Studio project. You can use the
attribute to specify a single assembly
that can access the internal types and
members of the current assembly. To
make the assembly's internal types and
members visible to additional
assemblies, you must include a
separate InternalsVisibleToAttribute
attribute for each assembly.
Not that this does not prevent anyone from loading your assembly, it just prevents them from using the internal types within the assembly (at least not without some major effort, in the end anyone can just disassemble your code and use it that way).
Obfuscate it and keep documentation secret. Also include a key as in:
http://www.codeguru.com/columns/experts/article.php/c4643

Categories

Resources