Config-dependent assembly reference - c#

I have an assembly generated from DSL, and I need to make a reference to it from my project.
However, I'd like to have reference to Debug assembly from Debug project config, and to Release from Release.
Is it possible to achieve?

Okay, so what I've found... assembly reference can be edited manually in the project file, putting $(Configuration) instead of "Debug"/"Release" path part. It works without problems.

Well, add assembly generation from DSL as a build event - that way, you can generate correct version (debug/release) of assembly. Configuration Name is available as macro [$(ConfigurationName)]. Also, you have to be smart in such command line to skip assembly generation if its already generated and DSL has not been modified - it means you need to have different intermediate target location based on configuration and then copy from that location to some other main location (if file is modified). This other location is the one from where you will reference the assembly in your project.

Related

C# assembly path issue when using ReferencedAssemblies

I'm trying to make a tool similar to Unity (obviously at a lower scale) and I need to be able to compile scripts which work in both the editor and the final game.
My approach to that is compiling the code in the editor using the ReferencedAssembly of my game executable, while the game executable already contains all the scripts which are present in compile time.
However I'm having a problem with the editor part. Basically I set
parameters.ReferencedAssemblies.Add ("path/to/Game.exe");
parameters.GenerateInMemory=true;
parameters.GenerateExecutable=false;
and then compile. There are no compilation errors but when trying to use
var typeArray=results.CompiledAssembly.GetTypes();
a ReflectionTypeLoadException exception is thrown:
Could not load file or assembly 'Game, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies.
However, copying my executable Game.exe to the tool's directory, and changing the reference assembly to
parameters.ReferencedAssemblies.Add ("Game.exe");
allows me to compile and access to GetTypes without errors.
So, my questions are:
a) how can I make GetTypes work when using an assembly which is in another directory? (note: I'd rather not add the path to the GAC, as it should be a generic tool)
b) would it be possible to access type info without loading the referenced assembly? I mean, in NET 4.5 Type and TypeInfo are supposed to be splitted just for this reason, isn't it?
Regarding your point a): "how can I make GetTypes work when using an assembly which is in another directory?
I think you could you use Assembly.LoadFrom Method (String) to load the assembly from another directory.
Regarding your point b): "would it be possible to access type info without loading the referenced assembly?"
I'm not sure you'd be able to access type info without loading it in some fashion, but are you aware of loading Assemblies into the Reflection-Only Context?
The reflection-only load context allows you to examine assemblies compiled for other platforms or for other versions of the .NET Framework. Code loaded into this context can only be examined; it cannot be executed. This means that objects cannot be created, because constructors cannot be executed. Because the code cannot be executed, dependencies are not automatically loaded. If you need to examine them, you must load them yourself.
On a second reading of your question, how does "game.exe" get referenced in your project file?
If it's a case of MSBuild needing to copy it to the build output folder of the project, you could add "game.exe as an item in the project, set the build action to "None" and the Copy to Output Directory Property to "Copy if newer".

Could not load type 'myinterface' from assembly

I have a solution that includes several projects. A few are libs that are building dll's used in my main project in this solution.
My main project builds with output type console application.
This all works fine.
When i change the build output type to a class library (since i want to use this project as a plugin eventually). The project will still build, this time to a dll.
When i use this plugin in an application where i use it as a dll however, it will run up to a certain point where it's trying to load a type defined in an external dll (so NOT built by my solution) and throw the exception:
Could not load type 'externalinterface' from assembly 'externallib, version=3.0.0.0, Culture=neutral, PublicKeyToken=null'.
The dll's are all in the correct folder,etc.
Also worth noting, the plugin is tested in another location than where i built it. The executable still works on this location, the dll/plugin does not. Same amount of dll's in their folders etc.
EDIT: I already used ILSpy (dll inspector) to open the actual dll that is being referenced (so externallib in the errormessage) and checked if 'externalinterface' was present and it is.
EDIT2: RESOLVED! The program that loaded my plugin was loading the same dll that caused the exception. The dll it loaded was of another version than the one i loaded.
Check whether the type externalinterface is present in the referred dll.
You didn't include the details of the exception the application is throwing. However, based on the message you gave, it appears your assembly does not have a strong name. If the application attempting to load your assembly as a plugin does have a strong name, then .NET will require all assemblies loaded by it also have a strong name, so you need to configure your assembly to have a strong name before continuing.
Maybe some supported dll's which is used by the 'externalinterface' is missing in the target machine. In the target machine, check is all the necessary dll's are present in the output folder.
Or blindly copy paste all the dlls in the output folder from the machine where the code is working to the target machine where you have the problem. After this, if the code is working in the target machine, then try to analyze which supporting dll you are missed to copy.

csc.exe reference external .dll file

I am trying to make a simple c# program using Growl C# API.
I tried to compile my program in two different ways:
1) I kept my .dll file in the same directory as my .cs file. Than I ran
csc /r:Growl.Connector.dll,Growl.CoreLibrary.dll /out:test.exe *.cs
It compiled fine and also ran fine.
2) Now I have created a directory inside my current working directory named growl and kept all my .dll references there.
Now when I try to compile it using the below command
csc /r:"D:\Modified\Growl_NET_Connector_SDK\libraries\growl\Growl.Connector.dll","D:
\Modified\Growl_NET_Connector_SDK\libraries\growl\Growl.CoreLibrary.dll" /out:test.exe *.cs
It compiled fine but when I tried to run it the below mentioned exception occurred.
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'Growl.Connector, Version=2.0.0.0, Culture=n
eutral, PublicKeyToken=980c2339411be384' or one of its dependencies. The system cannot find the file specified.
at GrowlNotification.Program.Main(String[] args)
So, my question is what is the correct way to reference .dll file in csc when files are in an external folder.
Here is the directory structure for 2nd case.
So, my question is what is the correct way to reference .dll file in csc when files are in an external folder.
You're already referencing them at build time. You just need to make them available at execution time too, but copying them into the same directory as the executable, when you want to run it.
You could also investigate using the Global Assembly Cache if these are signed assemblies, but personally I'd stick with just keeping the executable with the libraries on which it depends.
You can add these using the /lib and /reference command-line switches while compiling.
http://msdn.microsoft.com/en-us/library/s5bac5fx.aspx
But (Quote from the article)
An alternative to using /lib is to copy into the working directory any
required assemblies; this will allow you to simply pass the assembly
name to /reference. You can then delete the assemblies from the
working directory. Since the path to the dependent assembly is not
specified in the assembly manifest, the application can be started on
the target computer and will find and use the assembly in the global
assembly cache.
Because the compiler can reference the assembly does not imply the
common language runtime will be able to find and load the assembly at
runtime. See How the Runtime Locates Assemblies for details on how the
runtime searches for referenced assemblies.
so Jon Skeet's answer is better. (I'm just adding this to provide more info than I could in a comment, not as an answer. Jon's answer is the best IMO)
You can create symlinks to the assemblies in your libraries folder so you would only need to keep them updated in one location.

How to save DLLs in a different folder when compiling in Visual Studio?

Let's suppose I have a Window Forms / Console Application C# project with some external references and references to other class library projects in the same solution too.
When I build the Window Form project, I want the referenced libraries be stored in a different location (eg: bin\Release\Libraries), and not in the same folder as the .exe.
Is it possible to do?
There are 2 parts of your question:
How to configure solutions to build assemblies/EXE into folders of your choice - this is configured through properties of the project in VS (project properties -> build -> output path). Also value of check "copy local" property on each reference.
How to load assemblies files from non-default locations (i.e. from your ...\Libraries folder) - you need to make changes to your app.config file to add this non-default paths to assembly search location..
Link to Microsoft site no longer works, so summary from wayback machine: How to load an assembly at runtime that is located in a folder that is not the bin folder of the application:
Method 1: Install the assembly in the global assembly cache (GAC).
The GAC is a computer-wide code cache where the common language runtime is installed. The GAC stores assemblies that you specifically designate to be shared by several applications.
Note You can only install strong-named assemblies in the GAC.
Method 2: Use an application configuration (.config) file with the tags
A .config file contains the following settings:
• Settings that are specific to an application
• Settings that the common language runtime reads, such as the assembly binding policy settings and the remoting objects settings
• Settings that the application reads
The <codeBase> tags specify where the common language runtime can find an assembly. The common language runtime applies the settings of the <codeBase> tags from the .config file. The settings of the <codeBase> tags determine the version and the location of the assembly.
Method 3: Use the AssemblyResolve event
The AssemblyResolve event fires whenever the common language runtime tries to bind to an assembly and fails. You can use the AddHandler method to add an event handler to the application that returns the correct assembly whenever the AssemblyResolve event fires.
The AssemblyResolve event handler must return an [Assembly] object, and the common language runtime must bind to this object. Typically, you can use the Assembly.LoadFrom method to load the assembly and then to return the object.
Correct answers were given earlier. I'll just mention that there is a nuget package for this called PrettyBin.
Install it on your startup project. DLLs and XMLs will go to a lib folder and you'll have a working example of how it's done, if you won't to customize.
Set Reference path in project peoperties.
You can also specify where your compiled exe goes by specifying Output path in project peoperties.
You'll find best practices for organizing project references here: http://codebetter.com/patricksmacchia/2009/01/11/lessons-learned-from-the-nunit-code-base/
Look under chapter "The VisualStudio Project Reference + Copy Local true option is evil!"
Yes it is possible, you'd do it in your msbuild script. While I can't give you an exact answer, look here at this question on SO Copy all files and folders using msbuild

Fixing conflicting types in C# .NET caused by ILMerge

I have an interesting problem which I would like an easy fix for. I have a "library" assembly that is referenced in both a "client" project and a "test" project in a solution in Visual Studio. The problem is that the test project also references the client project, and we must use ILMerge to merge the library assembly with the client assembly for deployment. Since the library assembly is merged with the client assembly, I get an error about types in my library assembly existing in both the originally referenced library assembly and in the merged assembly when the test project attempts to build.
The real problem is that we have ILMerge running in a post-build step on the client project; the best solution would be to move that to the actual deployment process. However, our current tooling would make that difficult to implement.
Is there a way to tell .NET that the type might be in more than one assembly and that's OK (considering they're actually the same assembly, but just merged with another assembly in one case)?
So, if i understand it correctly, your test project has a reference to the library and to the client, which in turn has the library merged in...So, at build time for test you get two references of the same library. I think the solution is to remove the library reference from the test project and only reference the client, which will have everything you need.
If I understood correctly, if you were to reference the merged assembly only in your tests, you will get access to all types, making a reference to the library assembly unnecessary, and thus eliminating the problem with ILMerge.
You might want to add a reference to the binary "client" output (which would be the merged file), and add a manual build dependency to control the correct compilation order.
I did this in a project of mine by editing the CSPROJ file manually, overriding the "CopyFilesToOutputDirectory" target to not only compile, but also merge the "client" during the build, but a post build event should also do the trick (I did some other unrelated changes at the same time which forced me to change the target behavior).
I then edited the other project file referencing the merged DLL to use the reference like this:
<Reference Include="MyMergedLib, Version=1.2.3.4, Culture=neutral, PublicKeyToken=3d58c5c8efc41aa9, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\MyMergedLib\$(OutputPath)MyMergedLib.dll</HintPath>
</Reference>
This makes sure that VS always takes the correct version (debug/release). Maybe this helps.
Well, you could use a customized version of ILLink (instead of ILMerge) to fix this issue.
Or, you could just tweak it to remove the duplicate assembly.
See Source Code here. Note that ILLink is a C++ program..

Categories