Name element in *.csproj - visual-studio-2010

So, being completely obsessive compulsive, I was digging around in the .csproj file for one of my assemblies and was looking at the schema for the XML. I noticed in the <ItemGroup>, the various .dll files are referenced using an element called <Reference Include="..." />.
Out of curiosity, I did some digging and found that I can change things up a bit by modifying it with an included <Name> element. Like so ...
<Reference Include="Microsoft.CSharp">
<Name>System.Dynamics</Name>
</Reference>
I of course expected this to crash everything, but behold, when I reloaded the project and compiled, everything ran just fine.
Is this just there for aesthetics? Or am I doing damage by changing names around? Are there any long term effects of this? I did not experience any build, runtime, or editor issues from doing this.

I think it's just the display name of the reference.
Edit: The MSBuild schema defines the Reference\Name element as "Friendly display name (optional)."
The schema for MSBuild is located here: C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Build.xsd
Also, check out the MSBuild Reference.

Related

How to break a large VS solution into smaller solutions

We have a VS2008 solution file that contains around 80 projects (yes i know it sucks).
The projects are arranged in various folders, and some may depend on other 3rd party DLLs in a top level "Libs" folder.
We'd like to refactor this into several smaller .sln files, each containing a reasonable number of projects.
The problem is, when moving the project files around, the relative paths stored within them will break and so we will have to do lots of manual "patch ups" to fix that.
Is there any tool or any proven technique for doing something like this ?
We did something similar, and to fix the references, we wrote a quick utility that would parse the .csproj or .vbproj files (which are basically xml files) and fix the affected paths based on where the .proj file itself was located after the refactoring. this was better than manually changing the project xml or adding removing references to avoid human errors.
Once you know where the proj file is and where common files (or other files) will be, you modify the Reference node in the project file with the relative path. So for e.g., you might have to change the original
<Reference Include="NHibernate">
<HintPath>..\..\ServicesShared\Library\NHibernate.dll</HintPath>
</Reference>
in the .proj file to
<Reference Include="NHibernate">
<HintPath>..\Common\ServicesShared\Library\NHibernate.dll</HintPath>
</Reference>
if that's where the NHibernate.dll lives now.
Hopefully this will work for you guys.

F#: Is the Condition attribute not supported in some (or all) tags in .fsproj files?

For an F# project with dual platforms "Xbox 360" and "x86," I have the following in my project file:
<ItemGroup Condition="'$(Platform)' == 'Xbox 360'">
<Reference Include="Arands.ContentTracker.Xbox">
<HintPath>..\..\..\..\..\..\_Libs\XNA\ContentTracker\ContentTracker\bin\Xbox 360\Release\Arands.ContentTracker.Xbox.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'x86'">
<Reference Include="Arands.ContentTracker">
<HintPath>..\..\..\..\..\..\_Libs\XNA\ContentTracker\ContentTracker\bin\x86\Release\Arands.ContentTracker.dll</HintPath>
</Reference>
</ItemGroup>
For some reason, neither Arands.ContentTracker.dll nor Arands.ContentTracker.Xbox.dll are added as references in my project, regardless of which platform I select (Xbox 360 or x86).
The result is the same with the following:
<Reference Condition="'$(Platform)' == 'Xbox 360'" Include="Arands.ContentTracker.Xbox">
<HintPath>..\..\..\..\..\..\_Libs\XNA\ContentTracker\ContentTracker\bin\Xbox 360\Release\Arands.ContentTracker.Xbox.dll</HintPath>
</Reference>
<Reference Condition="'$(Platform)' == 'x86'" Include="Arands.ContentTracker">
<HintPath>..\..\..\..\..\..\_Libs\XNA\ContentTracker\ContentTracker\bin\x86\Release\Arands.ContentTracker.dll</HintPath>
</Reference>
Is the Condition attribute simply ignored in .fsproj files?
Splitting a project in two sucks. I want the current chosen platform to determine the current configuration and what goes on in a build, not (for example) which project tree I had expanded when I double-clicked a .fs code file in the Solution Explorer. Having multiple projects just to accommodate different platforms has caused me some fairly significant headaches, and even confuses Intellisense (e.g. not identifying System.Collections.Generic.HashSet as unavailable when my platform is set to Xbox 360).
UPDATE: I've managed to get it working. My mistake was expecting the Solution Explorer to reflect a change in configuration, e.g. for the References in the F# project to actually show the relevant references, as I'm used to seeing for C# projects with conditional tags. Apparently, F# projects simply display nothing in the References section when there are conditionals involved (unfortunately).
Once I got past the assumption that the Solution Explorer would accurately reflect the relevant assets after a platform change, I was able to focus on other areas of the solution (namely, the Configuration Manager and References to the F# project in the C# projects) that required more attention.
Thanks for your assistance, all! I'd prefer to award the points to Preet Sangha, since it was his question that provided the insight that allowed me to get past the aforementioned assumption.
This should just be an MSBuild thing, and should work... it may be useful to run msbuild -v:diag ... to diagnose what's going wrong; perhaps things are in the project file in the wrong order?

VS targeting wrong assembly

I had to rebuild the Krypton.Toolkit.dll from it's source in order to remove a license error message on runtime. In the references I have removed and replaced the old Krypton assemblies with the ones from source.
I am now getting the error: (and a related cast type error)
Could not load file or assembly 'ComponentFactory.Krypton.Toolkit, Version=4.0.0.0, Culture=neutral, PublicKeyToken=a87e673e9ecb6e8e'
I understand the error message. Although the my new reference has the same name it does not have a strong name at all, so there is no PublicKeyToken.
What I don't understand is why it's still looking for the old PublicKeyToken when the reference is being replaced completely? This DLL is not in the GAC.
At first these DLLs with matching PKT where referenced in my main projects .csproj file. I gave my two assemblies a strong name and replaced the old references.
I have then cleaned and rebuilt the project and the new strong name has been replaced in the csproj file. However Visual Studio is still looking for a87e673e9ecb6e8e in the aforementioned project, as shown in the error window.
Sorted.
A reference was referencing the same 3rd party DLL as my project and they where conflicting.
Something in your solution seems to still hold a reference to the strong-named version.
You can open your .csproj (or I think .vbproj if you're doing VB) and look for that reference in your favorite text editor. Look for a line similar to:
<Reference Include="ComponentFactory.Krypton.Toolkit, Version=4.0.0.0, Culture=neutral, PublicKeyToken=a87e673e9ecb6e8e, processorArchitecture=MSIL">
</Reference>
Searching for the PublicKeyToken is probably sufficient.
If you find it, you will know which project still references the strong named version.
You may see a sub node like
<Reference ... >
<HintPath>..\SomePath\ComponentFactory.Krypton.Toolkit.dll</HintPath>
</Reference>
directing the linker to look in a specific path to resolve the reference.
You can manually edit the project file (back it up first), or use that knowledge to update the reference through VS if you're more comfortable with that.
UPDATE
If it turns out (as it did in this case) that the issue is with a referenced DLL that in turn references the other Krypton version, a good tool for diagnosing the issue is the Fusion Log Viewer
http://msdn.microsoft.com/en-us/library/e74a18c4.aspx
Note that Fusion Log Viewer must run as Administrator. If not, it will not show any results but will otherwise not complain.

Set "Copy Local" to False by default?

Can I set the default-option of "Copy Local" in Visual Studio to False? In most times, when I add a dll as dependency of a project, I want the Copy Local property set to False. Per default, it is True. Is there a way to change the default behaviour of Visual Studio? (2008)
No - Visual Studio uses an internal set of rules to determine what to set Copy Local to.
From MSDN:
If the reference is another project, called a project-to-project reference, then the value is true.
If the assembly is found in the global assembly cache, the value is false.
As a special case, the value for the mscorlib.dll reference is false.
If the assembly is found in the Framework SDK folder, then the value is false.
Otherwise, the value is true.
Actually, you can. You need a couple things:
Create .targets file that makes copylocal (<Private> tag, to be precise) false by default.
Import the target in .csproj files. You can add it in the very last line, before closing </Project> tag, it'll look like <Import Project="..\Build\yourtarget.targets" />.
Now each project with this target has copylocal disabled by default.
The drawback is that you need to modify each and every csproj file, including new ones. You can work around the new project issue by modifying the VS project template. Instead of Class.cs described in the blog article, you need to modify Class.vstemplate (in the same zip file).
With that approach, there's one more problem - the path itself. If you use hardcoded relative path in newly-generated csproj files, they may be wrong (unless you have flat project structure).
You can:
Make VS generate correct relative path. Not sure how to do that and if that's even possible.
Ignore it and change the path manually for each new csproj (depending on the number of new project you have, while not ideal, that may be tolerable).
Use the environment variable instead of relative path. In that case every developer will need the same variable set.
There must be better solution for that, but haven't found it yet.
Starting with msbuild v 15 you can copy a single file called Directory.Build.props in the root folder that contains your source:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemDefinitionGroup>
<Reference>
<Private>False</Private>
</Reference>
<ProjectReference>
<Private>False</Private>
</ProjectReference>
</ItemDefinitionGroup>
</Project>
Nothing more to do! This works well with Visual Studio 2017 and also the vNext Build. You might have to close Visual Studio and than open your solution again to take the file effect.
https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build#directorybuildprops-and-directorybuildtargets
We don't use a .targets files (as suggested in the answer by ya23), so we just edit the .csproj project file manually in a text editor and add the <Private> element to the reference, like this:
<Reference Include="[...]">
<Private>False</Private>
[...]
</Reference>
The value of the <Private> element matches the value of the "Copy local" property. For instance, if <Private> is set to False, then "Copy local" is also false..
Bumping this because it seems there's now a nuget package allowing exactly this...
https://nuget.org/packages/CopyLocalFalse
Haven't tried yet, just hoping it helps.
Regarding the solution posted by #herzbube, if you want to turn off "Copy Local" for all (or most) of the references in your .csproj file, you don't need to set <Private>False</Private> individually on each Reference, you can just put the following directly in the .csproj:
<ItemDefinitionGroup>
<Reference>
<Private>False</Private>
</Reference>
</ItemDefinitionGroup>
This doesn't affect projects referenced with <ProjectReference>, but you can do the same thing--either instead or as well--for those:
<ItemDefinitionGroup>
<ProjectReference>
<Private>False</Private>
</ProjectReference>
</ItemDefinitionGroup>
If you want both of these, you can merge them into a single group:
<ItemDefinitionGroup>
<Reference>
<Private>False</Private>
</Reference>
<ProjectReference>
<Private>False</Private>
</ProjectReference>
</ItemDefinitionGroup>
Make sure you put these overrides prior to the first actual <Reference … > or <ProjectReference … > that you want to affect because these blocks will only apply to those references that appear below them. Then, if there are a few that you do actually want to be locally copied, you can just override those back individually (i.e., within the individual tag itself), this time using True.
For more advanced cases you can switch the overriding value back and forth between True and False multiple times in the same .csproj file. Another advanced technique would be to strategically place some of your references below these blocks, and others above, so the latter won't be affected.
All of this should make the XML in your .csproj much cleaner and easier to read. But there's even more good news, so read on...
As for selecting which projects should be be marked <Private>False</Private> this will usually depend on the specific situation, but there is something fundamental everyone can and should do for starters. It's a step so basic, simple and effective and it delivers such huge MSBuild reliability improvements1. and build-time speedup--and with little downside--that every large solution that uses the default (i.e. local per-project) C# output locations should almost always make this adjustment:
In any and every Visual Studio solution which builds multiple C# class libraries with any non-trivial number of <ProjectReference> inter-dependencies, and which culminates in building one more applications (i.e. executables):
Near the top the .csproj for every class library, insert the <ProjectReference> block shown above.
REASON: There is no need for any .dll to gather any of the libraries it references into a sub-directory of its own, since no executable is ever run from that location. Such rampant copying is useless busywork and may be unnecessarily slowing down your build, possibly quite dramatically.
On the other hand, do not modify the .csproj for any of your solution's applications.
REASON: Executables need to have all the privately-built libraries they need in their respective sub-directories, but the build for each app alone should be responsible for individually gathering each dependency, directly from its respective sub-directory, into the app's sub-directory.
This works perfectly because the .csproj for a class library may reference multiple other class libraries, but the .csproj for an executable usually never references another executable. Thus, for every locally-built library, the only .dll in its bin folder will be itself, whereas every locally-built application will contain the full set of locally-built libraries it references.
Conveniently, nothing changes for the referenced libraries that are not built by your solution, since these usually use <Reference> instead of <ProjectReference>, and we didn't modify the former tag at all. But do note the assumption just mentioned; if it is violated by some of your projects, you may need to make some adjustments.
[1.] Reliability improvements could be related to file collisions that may occur when gathering the same library from multiple disjoint paths in a dependency graph, especially in concurrent builds.

Visual Studio 2008 resolving wrong reference

In my project file, I have the following entry:
<Reference Include="Microsoft.Practices.Unity, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\..\Libraries\Microsoft.Practices.Unity.dll</HintPath>
</Reference>
which in absolute terms translates to:
C:\dev\LUT600 2.1.1\OCC600\Libraries
Somehow, when I try to compile the project, Visual Studio loads a reference from a totally different path:
/reference:"C:\Program Files\Microsoft Enterprise Library 4.1 - October 2008\Bin\Microsoft.Practices.Unity.dll.
How it resolves to this location is a complete mystery as this DLL is not referenced anywhere in this project.
I have set Specific Verion to true but it still resolves the reference from this location.
Any ideas?
TIA.
Klaus
It may be that the reference does not have the same version number as the assembly in that particular location, so it starts searching elsewhere to find a "better" match.
Rather than just taking the file you specified, VS always uses a probe path to try to find referenced assemblies. This often provides a random "pick anything with the same name" effect. On our build server I once found 996 copies of an assembly. 995 were the same, correct version, and one was the wrong version. And one day our build stopped working when for no apparent reason it suddenly decided to use the single wrong copy!
Try deleting and recreating the reference. That often helps.
In the worst case scenario, delete all copies of that assembly from your PC, except the version you wish to link to. (if possible without destorying anything you hold dear)
You most likely added the reference from the GAC(Global Assembly Cache). The long list of references that take a while to load are references from the GAC. Try removing your reference, and re-adding it by browsing to that assembly in the Add References dialog.
It could be finding the dll in the Search Path before it evaluates the HintPath. As mentioned in this post, there are two places that are searched before HintPath.
Files from the current project – indicated by {CandidateAssemblyFiles}.
$(ReferencePath) property that comes from .user/targets file.

Resources