Env.: .NET / VS2008
Hi All,
My app uses a 3rd party DLL assembly separately installed on some systems (clearly identified) but not all of them.
Which means that on some systems, the DLL is not there hence must not be called. To solve this, I have 2 versions of the app (using 2 configurations) for the 2 use cases. In one of them, all calls to the DLL are #if'ed out.
Since there are no calls to the DLL compiled at all in the app(they're #if'ed out), is it safe to assume that the app won't try to load the DLL even though it is referenced?
Or should I also exclude the reference?
Note: Asked in reaction to womp's comment in this question.
TIA,
IIRC, the C# compiler will omit references to dll's that are never actually used in the code. So if all code is inside #ifs, the reference to the dll will not be there in your compiled app, and the dll will never be loaded.
You can check this using Reflector, by the way. Just drag & drop your compiled app into Reflector, and look at the References node. ILDASM also provides this feature, I think.
Caveat: DllImports and dynamic type loading (e.g., Type.GetType("type,dll")) will dynamically load dlls without the C# compiler knowing or caring. But again, if inside the proper #ifs, nothing will be loaded.
I would exclude it. It might load it no matter what and if you have a type reference, then that also could cause a problem.
Why not load the the assembly dynamically if needed/available? And then if its gets added at a later date you can just make use of it? You'll only need one version of your app also.
You are safe with a reference but without the actual DLL if you never (obviously) instantiate and referenced class AND never refer to the Class in any instantiated or referenced object.
Typically your DLL will be loaded the first time the Class Constructor of a referenced Class is run.
HTH
Jan
Related
My project(some kind of processing engine) is separated into 2 dlls: one with interface declarations and one with functionality.Usually the project is used by external Delphi project via COM technology.
Lets say my program slices fruits. External delphi programm creates Fruit object and fills its properties: weight (int), Name (string) and ProgressUpdater (of type IProgressUpdater which is declared in second dll with interfaces).After this exst programm creater Slicer, makes Slicer.AddFruit(newFruit) and calls Slicer.Slice().
Nothing special. In real life delphi project is Outlook addin. But here is the problem - sometimes some VSTO addins makes Outlook work in "shadow copy files" mode, so when delphi project starts and creats Slicer object, our c# assembly will be put in temp folder and assembly will be created with this local path. Well... this is still not an issue. But the problem is when delphi project creates newFruit and then passes ProgressUpdater object, in my Slicer assembly I can not get external ProgressUpdater: "Return argument has an invalid type", but still can get field with simple types(Weight, Name).
It only happens when shadowCopyFiles mode is on. So my guess is - external ProgressUpdater's assembly and Slicer assembly are placed to different places, so they can not be passed. My question is how to avoid my dll being "shadow copied"? Or is there some different solution?
So as a result I still have no answer for exact question. But the problem is solved (thanks to HansPassant) by using GAC, because assemblies at GAC will be never shadow-copied (actually linker will always first probe assemblies in GAC and then in other places).
Possible answer to the question is to go currentDomain.AssemblyResolve way, but I could not apply this solution to dll which contains public interfaces(types) only. Maybe it will be suitable solution for some cases.
You can use reflection to load DLL dynamically from any location you want. If you can go this way, I can provide further code for loading DLLs.
I have created a dll in c#. I added a reference to this dll in MATLAB as shown below. Everything works fine. The problem is that when I want to update my dll I have to close MATLAB otherwise I cannot rebuild my dll, which is rather annoying. How in MATLAB can I remove the reference to this dll - I thought there would just be a line of code to do this?
% add reference to dll
cls = NET.addAssembly('C:\MyFolder\MyDllFolder\bin\Debug\MyDll.dll');
% reference my class
mycls = MyNameSpace.MyClass();
As a workaround, you can start a new Matlab instance from Matlab itself with a system call and the Matlab command line options and only load the libraries in the new instance. This is described in an answer to the qestion: Release a .NET assembly from MATLAB
Have you tried cls.delete and then add the reference again?
I seem to remember clear classes being useful as well. Sorry I can't be more definitive, I don't have Matlab handy to set up an example.
Edit
Looks like I was wrong, according to this link, "you cannot unload an assembly from MATLAB."
If the most important thing is the downtime while an assembly is being swapped, then you can do this without having to load a new MATLAB instance at all (which is very slow).
Even in pure .NET, it's not possible to unload an assembly from an AppDomain. Too much state is affected by the JIT process -- bits of code from that assembly could have been inlined into many other functions. This is actually one of the big reasons for having the AppDomain feature in the first place.
So, you will need a .NET assembly that acts as a wrapper and never changes. Its function will be to create an AppDomain and load the assembly to test into that child AppDomain. And, when it changes, to destroy the child AppDomain and create a new one.
It's complicated, but isolates MATLAB from the complexity.
I have a C# .Net 2.0CF application where I would like to load a .NET 'plug-in' DLL at runtime.
As I understand it, I should be able to use the System.Reflection.Assembly.LoadFrom() to load the DLL to an Assembly. Then use Assembly.GetTypes() to get the list of types within the plugin to match them to my expected interfaces.
The problem is that when I call GetTypes(), I get a System.TypeLoadException(). Based on the exception message, I assume this is because this particular plugin references some other assembly that this program knows nothing about. But, that's part of the point of it being a plugin! I don't want my application to have to know anything about these other assemblies.
How can I load this plug-in DLL without having my application reference every assembly used in the plugin?
Thanks,
PaulH
The situation is not that your app should reference every assembly that a plug-in uses. The plug-in references another DLL, not your app, and the plug-in should be "installed" (maybe simply put in a directory) along with everything it needs. This is unavoidable.
In msvc i can write
#pragma comment(lib, "my.lib");
which includes my.lib in the linking stage. In my solution i have 2 projects. One is a class project the other is my main. How do i include the reference dll in code instead of adding the reference in the project?
Contrary to popular belief, it is possible :-)
To statically link .NET assemblies check out ILMerge. It's a utility that can be used to merge multiple .NET assemblies into a single one. Be it an executable or a DLL.
You could create a batch script that packages your assemblies together as a post-build step.
Edit: One thing to note however is that this does not remove the need to reference the library. The reference is still needed in order to compile your code that is dependent the external types. Much like including header files under C(++). By default c# assemblies are independent, there is no linking involved. However the tool I mentioned above allows you to create a new assembly with the external dependencies included.
As far as I know, you can't. If you need to access type that are included in a non referenced assembly, you'll have to use Assembly.Load().
I'm afraid you can't.
You can dynamically load the assembly via Assembly.Load(...) but then you have use reflection to explicitly create each Type you need to use.
I don't think you can include a dll from code without adding a reference. What you can do however is to use reflection to load that assembly and use a type from that assembly.
Assembly.Load() will get you a handle on the assembly and then you should be able to iterate through the types in the assembly.
Managed code doesn't use a linker. The C/C++ equivalent of a reference assembly is the #include directive, you need that in C/C++ to allow the compiler to generate code for an external type. Exact same thing in C#, you can't use an external type unless the compiler has a definition for it. The reference assembly supplies that.
The equivalent of C/C++ linking is done at runtime in a managed program. The JIT compiler loads assemblies as needed to generate machine code.
One thing you can do in a C# program that you can't do in a C/C++ program is using Reflection. It allows you to invoke a constructor and call a type's methods with type and method names as strings. Start that ball rolling with Assembly.GetType() and the methods of the Type class. However, consider a plug-in model with, say, the System.AddIn namespace first.
If you want to load an assembly at runtime, you can use Assembly.LoadFrom(filePath). But that way you are not referencing the assembly, and you can't use strong typing.
For example, you can have different plugins implementing a known interface (the one which is in a separate, referenced assembly), and have them all placed in a folder. Then you can check the folder and load all implementing classes at runtime (like in this example).
My C# project - we'll call it the SuperUI - used to make use of a class from an external assembly. Now it doesn't, but the compiler won't let me build the project without the assembly reference in place. Let me elaborate.
This project used to throw and catch a custom exception class - the SuperException - which was derived from the standard System.Exception and lived in a separate, precompiled assembly, SuperAssembly.DLL, which I referenced.
Eventually, I decided this was a pointless exercise and replaced all SuperExceptions with a System.SuitableStandardException in each case. I removed the reference to SuperException.DLL, but am now met with the following on trying to compile the project:
The type 'SuperException' is defined in an assembly that is not referenced. You must add a reference to assembly 'SuperException, Version=1.1.0.0 (...)'
The source file referenced by the error doesn't seem relevant; it's the project namespace that gets highlighted in the IDE.
Now, here's the thing:
All uses of SuperException have been eliminated from the project's code.
Compared to another project that compiles fine without a reference to SuperException.DLL, I only reference one more assembly - and that references nothing that my project doesn't reference itself. While it's possible that any of these dependencies could throw SuperExceptions, I'm only catching the base Exception class and in any case... the other project builds fine!
I've done Visual Studio's "Clean Solution" and cleared everything out by hand, many times.
It's not the end of the world to include this reference, I just don't see why it's necessary any more. Nrrrgg. Any pointers welcome!
It's likely a transitive reference, where some type method call returns an instance of SuperException boxed ("downcast") as e.g. Exception, but from inspecting the code in the transitively included code, i.e. code from your external method calls, the compiler knows that you need to be able to have information about that type at some point.
Resharper would tell you where it's the case that you need to add a reference, and you could use Lütz Roeder's aka RedGate's Reflector to scan compiled IL for a reference to this type in two ways: 1) use the search-facility, 2) open each public type you're using and for that one which requires the "ghost" assembly, it will ask you to specify its location.
This most often happends to me when I reference Castle.Windsor but not Castle.MicroKernel. :p
Exit Visual Studio
Delete the bin and obj Folders in your solution directory
Restart and see what happens
I agree with the other comments here.. There is a reference, in plain text somewhere !
I have had similar problems in the past where searching through the project files returned nothing, turns out it was in some other file that wasn't automatically picked up in the search.
I don't think that creating a new project is the solution here.. You need to be positive that NONE of the references in your dependency tree use SuperException.. NONE
I have never experienced this to the point where I have needed to literally wipe the project, I have always found the reference somewhere. Ensure you are searching every file.
EDIT:
Just a point to add, if the location pointed to by the error seems random, that can often mean there is a mismatch between the compiled source and the source code file.. Is this a ASP.NET application? I have had it before where the compiled DLL's haven't been replaced on a rebuild in the ASP.NET temp folder causing things to get.. Interesting when debugging :)
I don't think this is a code issue. What I can see happening is that one of your existing references probably rely on that type in their own types which you are probably creating in your application.
If that is the case you do need that reference even if you don't explicitly use the type and even though the other referenced assembly has its own reference. You sometimes get that issue with 3rd party components which need references to types that you haven't referenced. The compiler is obviously seeing something in one of your existing referenced assemblies and is expecting you to referenced the dependent one.
Since it's a compiler error, there must be a reference or use of SuperException somewhere in the project.
Do a find/replace in the entire project or solution for that type and remove every reference (it's possible you already did this).
If you reference any types that inherits from SuperException (even if the type defined in another assembly), you need a reference to the assembly that SuperException is defined in.
Take the line that the compiler is showing the error on and start tracing the inheritance tree of the objects used on that line, you might find the source of it that way.
Thanks for your answers so far. I've tried every suggestion (except one) to no avail.
The suggestion I haven't tried is to create a new project and add all my stuff to it, the thought of which really tests my will to live. ;) I may try this tomorrow if I can be bothered. Thanks again.
There is really nothing very mysterious about VS projects nowadays - it's all text files, etc. SOMETHING must reference that class/dll, and that something must be part of your project.
Have you really grep'd or findstr'd the whole solution tree, every single file, for a reference to that exception?
This sounds pretty strange. Here's what I would check next:
Check that there's nothing lingering in your Properties/AssemblyInfo.cs file.
Check that there's nothing lingering in your SuperUI.csproj file.
Delete all references and re-add them.
Try creating a new project, and adding all your classes to it.
grep your project folder. It could be a hidden reference in your project, or a project that your project references. Cleanse with Notepad if needed.
If you reference any types that inherits from SuperException (even if the type defined in another assembly), you need a reference to the assembly that SuperException is defined in.
Seconded on that.
You might not be referencing SuperException, but you might be referencing SpecializedSuperException, which is derived from, or somehow otherwise uses SuperException - your grep of the project for SuperException won't be catching it though.
Try have a hack with the trial of NDepend
This is where tools like Resharper really pay off -- a simple Find Usages usually tells me of such "ghost dependencies" several times.
Maybe you could go to your definition of the SuperException class and try to Find All References(). You might also want to investigate if the assembly SuperException is has a circular dependency on your main assembly (e.g., main assembly depends on exception assembly depends on main assembly...).
I’ve had a very similar assembly reference issue that was happening when my C# library had a dependent C++/CLI assembly.
The problem that was I was inheriting a public class from that C++/CLI assembly in my C# assembly library. That meant that the inheritance chain was spanning across multiple assemblies.
I was hoping that any client would be smart enough to indirectly load the C++/CLI assembly any time the C# library needed it, but that was not the case even at compile time.
I got rid of this problem by breaking the inheritance between the classes that were spanning across those two assembly libraries and using aggregation instead.
My client was finally happy and did not require the C++/CLI assembly as a dependency anymore.
In your word you would probably have to make sure that SuitableStandardException does not inherit from SuperException in order to eliminate the SuperException.DLL as a reference.
Use encapsulation instead of inheritance and create a SuperException data member in your new SuitableStandardException.
If that does not solve it, you might have more classes spanning inheritance across some assemblies, in your case SuperAssembly.DLL and superException.dll.
If you can't find all of them try this trick:
Make all your public members and classes in SuperAssembly.DLL internal.
In the SuperAssembly.DLL make friends with SuperException.DLL:
[assembly:InternalsVisibleTo("SuperException, PublicKey=0024000004800000....)]
Make sure that they build and remove the SuperAssembly.DLL reference from any client that already references SuperException.DLL.
grep -R SuperException * in the base of your project (get grep from somewhere first) just to be sure.