Visual Studio project platform dependent references - c#

I have a WP project for which I use a runtime module from a separate project.
If I reference the runtime module project from the main project, the platform/configuration (e.g.: x86/Debug vs ARM/Release) is handled automagically by visual studio at build time.
Now, I would like to remove the project dependency and only reference the binaries from the main project in such a way that when I chose a specific platform/configuration the correct reference will be used to build.
For example if I build for ARM/Release it should use the binaries from ./lib/ARM/Release/MyLibrary.winmd and if I build for x86/Debug it should use the binaries from ./lib/x86/Debug/MyLibrary.winmd.
I tried multiple ways but still could not find a solution that works both for Visual Studio and msbuild.

I actually have it working making the hint path use Platsform and Configuration variables.
<Reference Include="MyLibrary, Version=255.255.255.255, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\lib\$(Platform)\$(Configuration)\MyLibrary\MyLibrary.winmd</HintPath>
</Reference>

You might be able to use some macros dependent on your build selection in VS.
Example the two macros found within the linker are as follows:
$(ProcessorArchitecture) which for my example = x86
$(ProcessorArchitectureAsPlatform) which for me = Win32
and depending on the configuration you selected it will build in either Debug / Release.
Similar to what Pinco said.

Related

Visual Studio project reference that isn't version specific at runtime

We have a multi-project solution. The references between projects are done as Project References rather than Assembly Reference (as one would expect). This works fine for our deployment, but creates a runtime dependency that is version specific. The trouble is that we would like to start creating hot fix installers that only update the specific dlls that changed. Updating all dlls is not an option for our current customer situation.
The 'Specific Version' property on project references is disabled and i'm having trouble finding out a workaround other than switching to Assembly References and using Choose blocks in the csproj to switch between debug/release bins based on build config.
Is there another alternative to allow any version to be used at runtime?
MAINTENANCE FREE
The approach we went with was to set the Assembly version to be a fixed number and only update the File version when we build.(we used to keep both in sync with each other). We went with this approach since it was maintenance free and let us keep our references by Project.
The assembly version is what .net uses to find specific versions of a dependent dll. File version is what will display if you view property details on a file via windows explorer.
If you want to be able to hotfix any dll then you'll need to update all of your Assembly References to be versionSpecific=false and set all of your projects to have a fixed assembly version. If you only want to be able to hotfix specific project dlls then you need only fix the assembly version on those projects. The referencing projects could then keep whatever assembly version scheme you want.
Assembly version is set in ProjectFolder/Properties/AssemblyInfo.cs. We've now fixed ours to be 1.0.0.0 and only increment the file version when building.
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.2.3.45678")]
REQUIRES MAINTENANCE
If you are unable to set a fixed Assembly version then another approach can be to use a File reference. The trouble here is that the path your project dlls will vary based on your active build configuration (debug vs release). To get around this you can make your reference be conditional based on the config.
The major downside being that you'll need to maintain the build sequence manually. Also, if you add a new project then you'll need to remember to use these dynamic references again.
<Choose>
<When Condition="'$(Configuration)'=='Release'">
<ItemGroup>
<Reference Include="Your.AssemblyName">
<HintPath>..\Your.AssemblyName\bin\x86\release\Your.AssemblyName.dll</HintPath>
</Reference>
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Your.AssemblyName">
<HintPath>..\Your.AssemblyName\bin\x86\debug\Your.AssemblyName.dll</HintPath>
</Reference>
</ItemGroup>
</Otherwise>
</Choose>
You can also leave Debug as being a project reference if so desired, this would allow you to see what build sequence visual studio automatically generates due to the project references. You would then be able to mimic that sequence for your release config.

TFS Build failing since it seems to be looking in the wrong place for references

TFS (2012) Build is checking C:\Windows\Microsoft.NET... for a few of my project references even though the dlls are included as project references (set to copy local) in a folder I'm checking in.
Building outside of TFS, both in VS and using MSBuild.exe command line succeeds.
I can see in the errors and warnings that the references it is complaining about not being to find 'Could not resolve this reference. Could not locate...' are all due to it simply not checking in the checkin dependency folder as defined in the proj file.
Any ideas on how to correct this?
I believe there is a "check gac first" rule for DotNet dependency resolution.
So I do my references like this.
\MySolution.sln
\BALLayer\Biz.csproj
\DALLayer\Data.csproj
\PresLayer\MyWebsite.csproj
\ThirdPartyReferences\
\ThirdPartyReferences\SuperCoolDll111.dll
\ThirdPartyReferences\SuperCoolDll222.dll
\ThirdPartyReferences\SuperCoolDll333.dll
This way, all csprojects reference the needed dll(s) with a relative path.
All cs projects reference the SAME dll.
This has helped me avoid the "I'm gonna look in the GAC no matter what you want me to do" issue.
Nuget does this similarly.
\packages\
\packages\repositories.config
\packages\SomeLibrary\SomeDll.dll
\packages\SomeLibrary\MyNugetDll.dll
and cs projects reference the same .dll with a relative path.
............
Footnote:
Open up your .csproj file(s) in notepad, and look for the HintPath.
Mine always say something like
<Reference Include="MyNugetDll.dll>
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\SomeLibrary\MyNugetDll.dll</HintPath>
</Reference>
OR
<Reference Include="SuperCoolDll333.dll>
<SpecificVersion>False</SpecificVersion>
<HintPath>..\ThirdPartyReferences\SuperCoolDll333.dll</HintPath>
</Reference>
.........
But I think the crux of your issue is "copy local" and the "gac first" rule.
.........
PS
Here is another question that discusses the order...better than I could.
In what order are locations searched to load referenced DLLs?
EDIT::::
So lessons learned:
If you have your third party references checked into source control, and the build machine says "i cannot find xyz.dll", then make sure that dll is actually in source control. There are alot of "voodoo" paths on (the local development) machine with visual studio installed, and subsequently will NOT be on the "build machine".
If you use nuget and you check in your dlls, make sure they are all checked in. You might add a new entry to the packages.config and then forget to put the actual dll(s) into source control.
There are some ways to use nuget that you only put the packages.config in source control, and not the third party dlls. Check the comments of this post for articles about that.

Visual Studio 2008: Cannot find reference to a project

We have an application wrote in C#, which broken into several projects. These projects have reference to others.
When someone gets the source from version control and opens the solution contains these projects on its own machine, Visual Studio cannot find the references between projects, even though referenced project is build successfully. That person have to re-add the reference to solve this.
Seems to me that Visual Studio keeps some data in `suo' file, so next time it knows where to find that re-added reference, and this problem won't appear next time the person opens the solution.
Since `suo' file keeps absolute path to references, we cannot commit it in our source control.
The problem is, We've got a separate machine, which builds this big application automatically (as our nightly-build releases) When the build-automation tool opens the solution, and calls Visual Studio's compiler to build it, the references cannot be find. (automation tool cleans everything, and get the latest version of the source again, so it dose not have `suo' file.)
Any solution?
Extra information
Visual Studio version: 2008 - 9.0.21022.8
.Net framework: 3.5 SP1
OS: Windows XP Professional (SP2 & SP3 - we have both of them)
Update
Seems that Visual Studio changes <ProjectReference> tag to <Reference> in `.csproj' files sometimes. Our developers commit the file, and this problem happens.
I couldn't find if it's a bug in Visual Studio. The only solution that comes into my mind is to write a tool to correct this in `.csproj' files, before pass it to the automation tool.
References are defined in the .csproj file for each project. They may be defined in one of two ways (in my experience).
Either with a hint path to find the referenced assembly:
<Reference Include="CommonServiceLocator.NinjectAdapter, Version=2.2.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\Dependencies\CommonServiceLocator.NinjectAdapter.dll</HintPath>
</Reference>
Or without one:
<Reference Include="CommonServiceLocator.NinjectAdapter, Version=2.2.0.0, Culture=neutral, processorArchitecture=MSIL"/>
You need to make sure that the references are in the first form, that the hint path exists, and that it's a relative path so that it works no matter where you check out the solution.
You can edit the .csproj files either with an external editor, or by right clicking the project, choosing "Unload project" from the context menu, then right clicking again on the unloaded project and choosing "Edit projectname.csproj". After you 're done editing, right click again and reload the project.
Open the project files (*.csproj) and look what are they referencing. Mostly sure the paths are relative to the solution path and your build script might use other paths.
One way of solving this:
Define an environment variable SOURCE_PATH that holds the path to your sources root folder
Edit the project files so they have reference relative to this path (use $(SOURCE_PATH)) in csproj files to reference it
Repeat steps 1-2 on each dev/build machine and add extra env variables if needed.
PS: The *.suo should not be in the version control system.
Why won't you use msbuild rather then automated visual studio compiler?
It's a bug in VisualStudio 2008 and before that.
If you open a solution that contains a project that have reference to another project, but referenced project doesn't included in the solution, VS finds the referenced project, but changes the reference in a way that it refers to the output DLL, not the project itself.
This bug is fixed in VS2010, and MSBuild 4.

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..

C# / VS2008: Add separate debug / release references to a project

When adding a user control or a project reference to a VS 2008 C# project, I can add only one configuration of the assembly. Is it possible to add separate configurations, depending on the configuration of the container project.
E.g. I am developing a user control, and I am working on a sample application. I want to add the user control so that a debug build of the sample will use the debug build of the user control, and the release build of the sample the release build of the user control.
Any suggestions?
<Reference Include="MyLibrary">
<HintPath>..\$(Configuration)\MyLibrary.dll</HintPath>
</Reference>
This add a reference "..\Debug\MyLibrary.dll" if compiled in debug mode or ..\Release\MyLibrary.dll" if compiled in release mode.
You can do this by editing the csproj file; add a "Condition" attribute to the reference.
<Reference Include="Foo" Condition="'$(Configuration)'=='Debug'"/>
<Reference Include="Bar" Condition="'$(Configuration)'=='Release'"/>
However, I would have concerns about what this means for unit testing.
While #Marc Gravell's suggestion will work, is there a reason that you don't want both projects in the same solution? If they are in the same solution, you can add a Project Reference when referencing the User Control project to the sample app's project. When a Project Reference is used, Visual Studio will automatically add the Debug version for a Debug build, and the Release version for the Release build.
Instead of adding reference to a .dll directly, which forces you to choose between the .dll from debug or release folder, you should add reference by choosing 'Project reference'. This link explains how to add reference through .dll vs project-project reference. For your purpose, you should choose the latter.
Also refer to my answer to know when to add reference as a .dll vs reference as a project.

Categories