Class Library - References - Reusability with Copy Local? - c#

I have a class library project, lets call it CoreLib.
CoreLib has two references to 3rd party DLL files 1.dll and 2.dll
Because I love reusability so much, I want to be able to use CoreLib in as many places as possible/needed.
So if I had a project called BigProjectA and another project called BigProjectB and they needed to leverage the functionality provided by CoreLib, all I would have to do is add a reference to CoreLib in those projects (BigProjectA and BigProjectB).
That is fine, except when I go to copy over my output folder (bin directory) to another person's computer, I can't guarantee that they have 1.dll and 2.dll on their machines.
For that, I just set Copy Local to True for 1.dll and 2.dll references in the CoreLib project.
When building the CoreLib project I can see 1.dll, 2.dll, and CoreLib.dll files. That is PERFECT!
But in the projects referencing CoreLib, only CoreLib.dll is copied over, not 1.dll and 2.dll.
Am I missing something? Copy Local set to True, but only copies for the CoreLib project. So even though they are in the same solution, and I'm adding CoreLib as a project reference to the other projects, I still dont see 1.dll and 2.dll copying out to the other bin/Debug, bin/Release folders of the other projects (BigProjectA and BigProjectB).
Is there an easy solution?

The easy solution is to either:
reference 1.DLL and 2.DLL in projects which have a binary reference to CoreData.DLL
Add CoreData as a project reference to BigProjectA and BigProjectB instead of as a binary reference
In the first scenario, CoreData's dependencies are not automatically output by the compiler. If the CoreData project is added to the solution, its dependencies will be output. Hence, to use CoreData as a binary reference, you must also reference its dependencies.

There is nothing wrong. In projects BigProjectA and BigProjectB you have a references to only CoreLib, so they "care" about coping only it, cause they have no any clue about it's dependencies. What you can do to resolve these kind of issue, is to add for example PostBuildVEent in your BigProject.. to copy also CoreLib dependencies.
Or add reference to CoreLib project, if you can.
Another solution, is to consider DI like a technique to avoid strong coupling of references. So, if in BigProjectA or B you don't care about functionality provided by 3rd party libraries in CoreLib, for you should be enough to just copy CoreLib.

Good answers guys....but I actually just ended up using ILMerge. Seemed safer/less annoying.
Thank you though

Related

Is "Copy Local" transitive for project references?

Wrt. the proposed dupe: Since this here queston suggests the opposite of the linked question, I'd rather like to think it is not a dupe.
First, I did read What is the best practice for “Copy Local” and with project references? (also this) and I'll have to try this out anyway, but getting general feedback on this seems necessary as the docs on this stuff are horrible and I'm only on VS2010 and maybe they changed something in newer versions that'll be nice to know.
Second, I'm only interested in project references for this question as I've read that assemblies from the GAC are handled differently and the GAC is irrelevant for my problem.
Third, after reading the suggested dupe, but more so the nice answer here by #Albireo, it would also appear that it is important to differentiate file dependencies, where the dependency references a dll assembly file and project dependencies (i.e. what I'm asking about), where the dependency references a project and implicitly the output file of that project.
Anyway, here's the situation, somewhat peculiar I think, but still:
2 C# executable projects
n C# dll assembly projects
The 2 executables have different output directories as they will be deployed separately and that way they're also separate on the developer machine
The 2 executables have dependencies on some of the DLL assemblies (which may depend on each other)
There are three output directories:
/x1 for executable 1 project
/x2 for executable 2 project
/lib for all the dll assemblies
The DLL assemblies all have Copy Localset to false for their project references, as they all build to the same output directory.
The 2 executable projects have set Copy Local to true for all the DLL assembly project references they reference directly, so that the DLLs will be copied into /x1 /x2 respectively.
The question now is wrt. to DLLs that are not directly referenced by an executable project, but only transitively through a referenced assembly: Will assemblies, that are only referenced transitively through another assembly, be copied into the output folder of the executable, when "Copy Local" is set to true on the first assembly?
Example:
x1.csproj (e.g.Output = x1/one.exe)
Reference: dlA.csproj ( e.g. Output = lib/a.dll) with Copy Local = *true*
(no direct reference on b.dll)
dlA.csproj ( e.g. Output = lib/a.dll)
Reference: dlB.csproj ( e.g. Output = lib/b.dll) with Copy Local = **false**
(no direct reference on c.dll)
dlC.csproj ( e.g. Output = lib/c.dll)
(no further relevant references)
Thus, we have a logical dependency of one.exe -> a.dll -> b.dll -> c.dll, where only a.dll with obviously be copied to the output directory of one.exe. Will the other two dlls also be copied to the output directory? Is this documented somewhere?
And, yes, I tried it. And, yes, it seems to work, but I haven't poked it hard enough yet and anyway there maybe something more to it that I may have missed. (And also there's the question wrt. any official docs.)
it would also appear that it is important to differentiate file dependencies, where the dependency references a dll assembly file and project dependencies (i.e. what I'm asking about), where the dependency references a project and implicitly the output file of that project.
Not really, no.
MSBuild doesn't really care if the reference points to another project in the solution or to a DLL.
If ProjectA depends on ProjectB to build ProjectA ProjectB must be already built (and up-to-date), MSBuild will then pull its DLL (not its C# code) and link it to ProjectA.
Adding a project reference instead of a DLL is "syntactic sugar" for your convenience: this way MSBuild knows it must pick the output of the referenced project, whatever the output is.
Otherwise, you'll have to manually pre-build the dependency, find its DLL and link it to the project, repeating the process whenever you switch build configuration, move or rename things. Not really practical.
Will the other two dlls also be copied to the output directory?
If any kind of element from a dependency is used directly from the project where the assembly is referenced, that reference will be copied.
An example could be this solution layout:
MySolution
MySolution.ConsoleApplication
MySolution.FirstDependency
MySolution.SecondDependency
MySolution.ThirdDependency
MySolution.FourthDependency
With this dependency chain:
MySolution.ConsoleApplication
MySolution.FirstDependency
MySolution.SecondDependency
MySolution.ThirdDependency
MySolution.FourthDependency
If you build this solution you'll notice that in MySolution.ConsoleApplication output directory there will be the DLLs for MySolution.FirstDependency, MySolution.SecondDependency and MySolution.ThirdDependency but no DLL for MySolution.FourthDependency.
Why is it so? When MSBuild builds MySolution.SecondDependency it notices that there's a dependency declared to MySolution.FourthDependency, but since it can't find any usage of any kind of element from MySolution.FourthDependency in MySolution.SecondDependency code it decides to perform some "optimization" and omits MySolution.FourthDependency assembly from the output.
This same issue bit me in the past when I added through NuGet AutoMapper to a "deep dependency": adding AutoMapper adds two assembly references, AutoMapper and AutoMapper.Net4, where the second assembly is loaded by the first through reflection when it needs to perform certain kind of action on the new collection objects introduced by the .NET Framework 4. Since the second assembly is loaded through reflection MSBuild thinks it's unused and doesn't bother to copy it around.
So, yes, they will be copied as long as you're using them directly and not through reflection.
Is this documented somewhere?
This behavior seems to be a "feature" of MSBuild, I managed to find a blog post by some folks from Microsoft back when I experienced this issue, but I can't find it again at the moment.
It is very straight forward, doesn't have anything to do with Copy Local. MSBuild looks in the metadata of an assembly to see what the dependencies are for an assembly. So can you, run ildasm.exe on the assembly and double-click the Manifest. Be sure to try this to get insight. You'll see the .assembly directives. Inserted by the compiler when it built the assembly, only the referenced assemblies you actually used in your code will be listed.
If MSBuild can find such an assembly in the same directory then it will automatically copy it. If not then it will silently skip the copy.
From this, you can deduce the failure modes. It cannot copy unmanaged DLLs, they do not appear in the metadata. It cannot copy assemblies that you have an indirect dependency on through Assembly.Load/From(), they don't appear in the metadata either. It cannot copy assemblies that haven't been built yet, a build order problem. And it cannot copy assemblies whose Copy Local property you set to False. Which is normally only a valid choice if the assembly is present in the GAC, no copy required.
For such cases you need to help, XCOPY in a post-build event gets the job done.

Referencing a project in another project creates unwanted dependencies

I have a project ProjectA in which I am keeping utility classes. I want to use this project in multiple solutions so I do not have to copy files, link files and update files every time I make changes in classes of Project.
But there seems to be a problem: if I am referencing ProjectA in ProjectB, the compiled application of ProjectB can not run unless there's a compiled application from ProjectA next to it. So if the output of ProjectB is ProjectB.exe, ProjectB.exe gives an error upon execution if ProjectA.exe is not next to it. Why is that? I just want to use namespaces from ProjectA in ProjectB, I do not need ProjectA to depend on a compiled version of ProjectB.
Can anyone tell me how to reference ProjectA in ProjectB without needing the output of ProjectA to run the output of ProjectB?
You probably need a shared dll.
You have created utility classes in project A out because they are shared all across project A (Application A?), now you have introduced project B (Application B) and as you state it needs to get hold of the code from projectA.dll/exe.
So create a new project in your solution (Ab.Shared.dll maybe:-)) and move your utiilty classes into it. You can now reference that dll from both project A and project B.
Update: Just read about your comment about sucking code out.
The shared dll is the most common way of sharing the code about, but there are other ways. Theoretically you can simply "include" the same *.cs files in both projects and share them that way (use the drop down on the Add existing item dialog and select Add as link) . However in practice it becomes more awkward maintaining this scenario so most people use a shared dll.
Namespaces are not restricted to one assembly - you can use the same namespace across several assemblies if you wish, and one assembly can contain as many namespaces as you like.
If you are referencing a class/type from another assembly, then that assembly must be present (or locatable) when you run the original assembly. If all you are doing is coding then a simple project reference in your solution will do the trick. If you don't have the source code to Project A then you will need it in its compiled form - without it the CLR cannot inspect it and know what it contains.
In that case add the ProjectA compiled dll in your bin folder and add the reference to that dll from your other project. Do not add reference to your ProjectA project.
When you add reference to the project using Visual studio, Add Reference -> Projects, then it requires the project to be compiled and it copies the dll/exe to the other project bin folder.
Open your csproj file in text editor and insert xml:
<Reference Include="AssemblyName.dll">
<HintPath>$(EnvironmentVariable)\bin\AssemblyName.dll</HintPath>
<Private>False</Private>
</Reference>
If I understand correctly, you have code in ProjectA.exe that you want to use in ProjectB.exe, but at run time, you'd like to run ProjectB.exe without requiring the user to have a copy of ProjectA.exe.
This is not possible. When you use a type from another assembly, that assembly is loaded at run time. The type is not copied from ProjectA to ProjectB.
It sounds to me like you should extract the common utility classes into ProjectUtility.dll, and then reference that from both your ProjectA.exe and ProjectB.exe applications.
EDIT: ILMERGE might be the way to go. See Linking statically in C# for more information.

Adding a ProjectReference to a project that is not in the same solution

While doing some refactoring of our projects and solution files, i have separated some .sln files to contain less projects.
Occasionally i need to reference some projects from outside the scope of the current .sln file.
For example, my initial state was this:
SOLUTION A
PROJ A
PROJ B
After refactoring it would look like this:
SOLUTION A_NEW
PROJ A
SOLUTION B_NEW
PROJ B
My question is -- Is it possible to add a ProjectReference node to a project that is not defined in the same VS solution? (in my case, having PROJ A have a project reference to PROJ B).
Also, if it is possible, is that recommended?
I know that this is not possible from the VS IDE, only by editing the .csproj file manually.
You can't do this. A project reference includes an identifying GUID for the referenced project, which is maintained in the solution file in order to track solution build options and dependencies. If you try to reference a project that is not in the solution, Visual Studio will complain.
You can add a file reference to the assembly produced by a project that's not in the solution, of course.
UPDATE: Since this got downvoted, I'll refine my answer.
Though it's technically possible to craft a project file that references another project outside the same solution, Visual Studio won't help you to do it easily. One very good reason why it's a bad idea to do this (that I've observed) is that whatever Solution Configuration and Platform you're building (the referencing project) will be ignored if MSBuild decides to build the referenced project - the default Configuration and Platform specified in that referenced project file will be used instead. Thus you may end up with a mixture of binary types in different folders.
Temporarily add the project to the solution, add a reference to it, unload the project that now has a reference added to it, remove the referenced project, reload the project with the reference.
If you don't unload the project then the reference will be automatically removed by Visual Studio when the referenced project is removed.
As you can probably tell, Visual Studios not designed to do this and you'd be better defining a build order for the solutions and use assembly references instead.
You can definitely add a project to a solution A that is in solution B. There is not any problem with that. From my experience, it's not something that I usually have done or do, but sometimes need to. This can be especially true on large projects where you need different nodes of your architecture to reuse same code base.
Hope this helps.

conditional assembly references based on solution

I have a rather large solution consisting of about 10 different projects. Until now we have shipped the entire solution as a whole to customers, but we are looking into shipping a stripped version of our software.
To this end I would like to exclude several projects from the solution. I know that you can prevent projects from being built in the solution configuration manager. Using macros all code references can be disabled when the stripped configuration is chosen. Unfortunately this does not take care of the project references. Can I make these references conditional depending on the chosen configuration?
It should be a pretty simple matter to remove the project references from the project file using a small script - it would just be a case of removing lines adding those references. The project file format is quite simple.
I suspect that's likely to be the easiest solution.
I think that this should be done when you build your projects for production. Simply enclose all code that needs to disappear between a compiler-level IF, that checks for a defined compiler directive. If on, then the code between the IF and ENDIF will not compile. This works for code files only.
For anything other that you need to take out, just make up your own way, depending on the file format, as Jon Skeet mentioned. But once you put that into build scripts, you need not care about it any more - no switching configurations, etc.
Your best bet is to create separate projects for your "stripped down" solution that references only those other projects you want. Reference the same code. Create a separate solution to hold those projects together.
They can all live together in the same folder structure, too.
For example:
MySolution/MySolution.sln
MySolution/MyStrippedDownSolution.sln
MySolution/MyProject1/MyProject1.csproj
MySolution/MyProject1/MyStrippedDownProject1.csproj
MySolution/MyProject1/MyClass1.cs
MySolution/MyProject2/MyProject2.csproj
MySolution/MyProject2/MyStrippedDownProject2.csproj
MySolution/MyProject2/MyClass2.cs
MySolution/MyProject2/MyProject3.csproj
MySolution/MyProject2/MyClass3.cs
MyProject1 and MyStrippedDownProject1 reference MyClass1
MyProject2 and MyStrippedDownProject2 reference MyClass2
MyProject3 and MyStrippedDownProject3 reference MyClass3
MySolution references MyProject1 and MyProject2 and MyProject3
MyStrippedDownSolution references MyStrippedDownProject1 and MyStrippedDownProject2
MyProject1 references MyProject2 and MyProject3
MyStrippedDownProject1 only references MyStrippedDownProject2 -- it does not reference - MyProject3
There's lots of info in http://bytes.com/topic/net/answers/444853-conditional-assembly-reference that I found very useful for resolving a similar question (it pertains more to assembly references than project references though). MSBuild get assembly reference from ProjectReference might help with bridging between.

Assembly dependencies with .Net projects

If I have an assembly (A) which references another assembly (B).
I want to reference A in a project, I add the reference and it copies A into my BIN directory. It does not copy B as well, even though A depends on it, so the code doesn't compile.
How can I set things up so that whenever I reference A, both A and B get copied to my bin directory?
In Visual Studio, add each project to the same solution. Ensure you use Project References instead of direct file references (ie browsing for the assembly).
I dont think there is any way around what you ask other than to explicitly add both. I dont think however adding projects for the sake of getting references copied is a viable solution to the issue. Not all projects that a solution depends on should necassarily be added to the solution. This would completely depdend on your overall project structure, processes, source control, division of labour, etc
Reference both A and B.
Unfortunately you'll have to manually add both. This is what happens to me as well whenever I use pre-3.5 versions of NHibernate: it requires both log4net and Iesi.Collections assemblies. So I have no choice but to manually include a reference to both in all my solutions that implement NHibernate.
This is more of an issue, of course, if you only have the DLLs. If it's a project that you have a codebase to Visual Studio itself will warn you beforehand that the references are missing.
How about adding them to Global Assembly Cache?

Categories

Resources