Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Referenced DLL not being copied to referencing project

This question might have been asked multiple times and maybe I'm just bad at using the search functions here aswell as google but I've not found an answer to this question as of yet.

I've currently got two projects, project X, project Y and project Z (which only holds the mappings)

Project X is a FluentNhibernate project which holds my sessionfactories and things like this. So this is also where the mappings are loaded and things (this is important and i suspect it might be the whole reason for the problem I'm having)

Now in Project X I've referenced an assembly that uses Microsoft.SqlServer.Types.dll.

Project Y is a service which uses project X for it's database connections.

All probjects build find and run perfectly on my development machine, however when deployed to our server they failed to function (runtime errors). The error was pretty obscure since it pointed to a missing FluentNHibernate assembly which was not the case.

Procmon.exe luckily showed the code trying to load the Microsoft.SqlServer.Types.dll which since the server does not have SQL Server installed (my client doesn't either but it has a management studio which most likely installs this .DLL aswell).

So far so good, copied the DLL over and it worked (yay!).

Now I figured i'd add the assembly to project X to make sure that this reference is copied over to other projects using project X. This didn't happen.... So i tried setting the 'Copy Local' setting to true.

Sadly this still does not copy the .dll to the referencing project Y.

Is there a way to make this happen or is this Visual Studio beeing clever and realizing Project Y doesn't need this .dll and thus refusing to copy it over?

(Since Project Z needs the actual reference and Project X loads this assembly @ run time there is not 'hard' reference between Z and X)

Could any Stackoverflow genius shed some light on this since honestly I'd like to know why it's behaving this way (and ideally a way to make it behave like I want it to).

like image 764
F.B. ten Kate Avatar asked Oct 02 '13 08:10

F.B. ten Kate


2 Answers

This question has been answered already but I figured I'll include a generic fail-safe method for copying all indirect references into your projects' output directories.

  1. Set Copy Local to true for all references you want to be included with your output.
  2. Save the copy indirect dependencies code (see below) into a file with the name CopyIndirectDependencies.targets and place the targets file in your project directory.
  3. Edit your .csproj or .vbproj to include an import to the .targets file you added. See example below.
  4. Build your project and you should have secondary dependencies automatically copied to the build output.

CopyIndirectDependencies.targets File Content

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <CopyIndirectDependencies   
      Condition="'$(CopyIndirectDependencies)'==''">true</CopyIndirectDependencies>
    <CopyIndirectDependenciesPdb
      Condition="'$(CopyIndirectDependenciesPdb)'==''">false</CopyIndirectDependenciesPdb>
    <CopyIndirectDependenciesXml
      Condition="'$(CopyIndirectDependenciesXml)'==''">false</CopyIndirectDependenciesXml>
  </PropertyGroup>


  <!-- BuildXxx part -->

  <Target Name="CopyIndirectDependencies"
          Condition="'$(CopyIndirectDependencies)'=='true'"
          DependsOnTargets="DetectIndirectDependencies">
    <Copy Condition="'%(IndirectDependency.FullPath)'!=''"
          SourceFiles="%(IndirectDependency.FullPath)"
          DestinationFolder="$(OutputPath)"
          SkipUnchangedFiles="true" >
      <Output TaskParameter="CopiedFiles"
              ItemName="IndirectDependencyCopied" />
    </Copy>
    <Message Importance="low"
             Condition="'%(IndirectDependencyCopied.FullPath)'!=''
               and '%(IndirectDependencyCopied.Extension)'!='.pdb'
               and '%(IndirectDependencyCopied.Extension)'!='.xml'"
             Text="Indirect dependency copied: %(IndirectDependencyCopied.FullPath)" />
  </Target>

  <Target Name="DetectIndirectDependencies"
          DependsOnTargets="ResolveAssemblyReferences">

    <Message Importance="low"
             Text="Direct dependency: %(ReferencePath.Filename)%(ReferencePath.Extension)" />
    <Message Importance="low"
             Text="Indirect dependency: %(ReferenceDependencyPaths.Filename)%(ReferenceDependencyPaths.Extension)" />

    <!-- Creating indirect dependency list -->
    <CreateItem Include="%(ReferenceDependencyPaths.FullPath)"
                Condition="'%(ReferenceDependencyPaths.CopyLocal)'=='true'">
      <Output TaskParameter="Include"
              ItemName="_IndirectDependency"/>
    </CreateItem>
    <CreateItem Include="%(ReferenceDependencyPaths.RootDir)%(ReferenceDependencyPaths.Directory)%(ReferenceDependencyPaths.Filename).xml"
                Condition="'%(ReferenceDependencyPaths.CopyLocal)'=='true' and '$(CopyIndirectDependenciesXml)'=='true'">
      <Output TaskParameter="Include"
              ItemName="_IndirectDependency"/>
    </CreateItem>
    <CreateItem Include="%(ReferenceDependencyPaths.RootDir)%(ReferenceDependencyPaths.Directory)%(ReferenceDependencyPaths.Filename).pdb"
                Condition="'%(ReferenceDependencyPaths.CopyLocal)'=='true' and '$(CopyIndirectDependenciesPdb)'=='true'">
      <Output TaskParameter="Include"
              ItemName="_IndirectDependency"/>
    </CreateItem>

    <!-- Filtering indirect dependency list by existence -->
    <CreateItem Include="%(_IndirectDependency.FullPath)"
                Condition="Exists('%(_IndirectDependency.FullPath)')">
      <Output TaskParameter="Include"
              ItemName="IndirectDependency"/>
    </CreateItem>

    <!-- Creating copied indirect dependency list -->
    <CreateItem Include="@(_IndirectDependency->'$(OutputPath)%(Filename)%(Extension)')">
      <Output TaskParameter="Include"
              ItemName="_ExistingIndirectDependency"/>
    </CreateItem>

    <!-- Filtering copied indirect dependency list by existence -->
    <CreateItem Include="%(_ExistingIndirectDependency.FullPath)"
                Condition="Exists('%(_ExistingIndirectDependency.FullPath)')">
      <Output TaskParameter="Include"
              ItemName="ExistingIndirectDependency"/>
    </CreateItem>

  </Target>


  <!-- Build sequence modification -->

  <PropertyGroup>
    <CoreBuildDependsOn>
      $(CoreBuildDependsOn);
      CopyIndirectDependencies
    </CoreBuildDependsOn>
  </PropertyGroup>
</Project>

Sample project with import

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  ...

  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <Import Project="CopyIndirectDependencies.targets" /> <!-- ADD THIS LINE!! -->

  ...

</Project>

Source: http://blog.alexyakunin.com/2009/09/making-msbuild-visual-studio-to.html

like image 151
Alex Essilfie Avatar answered Oct 31 '22 12:10

Alex Essilfie


Now I figured i'd add the assembly to project X to make sure that this reference is copied over to other projects using project X. This didn't happen.... So i tried setting the 'Copy Local' setting to true.

You are still talking about the Microsoft.SqlServer.Types.dll right?

I had the same issues some time ago, actually sqlserver types should not be copied and redistributed with your installation. The correct way to "install" it is downloading the sql server runtime (which is included in the sql server management tools, that's why it works for you locally).

Because it is some time ago, I'm not 100% sure if the following information is correct and will work, but simply try to install the Microsoft® System CLR Types for Microsoft® SQL Server® 2012 only. On this download page expand Install Instructions and scroll down to the CLR Types download...

Use this link for SQL Server 2008

Install this on the target server. This will only install the stuff needed to run this types dll...

like image 42
MichaC Avatar answered Oct 31 '22 12:10

MichaC