23

I feel like I've fixed this before, but I can't remember how.

I have a tasks file that looks like this (CustomTasks.tasks):

<UsingTask AssemblyFile="CustomTasks.dll" TaskName="MyCustomTask"/>

it references an assembly (namely Ionic.Zip.dll). Ionic.Zip.dll is not in the GAC (and I don't want it to be). It sits right next to my CustomTasks.dll.

I have a directory called MSBuild one level up from my sln file which has CustomTasks.tasks, CustomTasks.dll and Ionic.Zip.dll in it.

I have a csproj that references the tasks file and calls the custom task:

<Import Project="$(ProjectDir)\..\MSBuild\CustomTasks.tasks" />

<MyCustomTask ..... />

at build time, this yields:

The "MyCustomTask" task could not be loaded from the assembly ....MyCustomTasks.dll. Could not load file or assembly 'Ionic.Zip,......' or one of its dependencies.

Jeff
  • 35,755
  • 15
  • 108
  • 220

2 Answers2

28

Got tired and frustrated and took a direct approach...I don't think this is the same way I solved the problem previously...but maybe this will help someone else. Other, more elegant solutions are more than welcome.

  <Target Name="BeforeBeforeBuild" BeforeTargets="BeforeBuild">
    <HandleAssemblyResolve SearchPath="$(ProjectDir)\..\MSBuild\" />
  </Target>
  <UsingTask TaskName="HandleAssemblyResolve" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
      <SearchPath ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Using Namespace="System" />
      <Using Namespace="System.IO" />
      <Using Namespace="System.Reflection" />
      <Code Type="Fragment" Language="cs">
        <![CDATA[
AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => 
{ 
  var assemblySearchPath = Path.Combine(SearchPath, e.Name.Split(',')[0]);
  if (File.Exists(assemblySearchPath)) return Assembly.LoadFrom(assemblySearchPath);

  return null;
};
]]>
      </Code>
    </Task>
  </UsingTask>
Jeff
  • 35,755
  • 15
  • 108
  • 220
  • 1
    Heh - I was just about to write this exact code (or something quite similar), then decided to poke through SO for other approaches to the problem...Thanks, this ended up being quite useful! – JerKimball Dec 05 '12 at 17:01
  • 8
    This msbuild problem with references really makes continuos integration a pain in the ... – Johnny_D Nov 25 '13 at 09:13
  • @JerKimball , i am looking for similar approach , could you please explain what is searchpath here ? – ansar Dec 18 '15 at 11:49
  • 1
    Thx for a solution. I just had to add a + ".dll" to the first code line. – honzajscz May 08 '16 at 07:01
-1

This is actually easy to fix. Put your custom build tasks and dependencies in a different folder. Then dependencies are loaded correctly.

For example like so:

<UsingTask AssemblyFile="..\BuildTools\CustomTasks.dll" TaskName="MyCustomTask"/>
Bernd
  • 539
  • 3
  • 10
  • 5
    This doesn't work. Only the assembly file itself is properly loaded. Any dependencies for the assembly will not be found, even if they are in the same folder. At least, that's my experience with msbuild and this approach. – theta-fish Jul 30 '15 at 15:45
  • Maybe you shoud try it some time - it worked for me with MSBuild 4, that is why I left the comment here. – Bernd Jul 31 '15 at 18:42
  • 1
    I suppose I should have been less definitive in my statement rather than saying "This doesn't work," but perhaps you should read comments some time. I said "that's my experience with msbuild and this approach," which means of course that I tried it. I suspect something else assisted your build, rather than what you believe, but I don't know your config or environment, so I have no idea what it was. Having the assemblies in the same folder does not achieve the desired effect, because the Fusion assembly loader does not look there for them. The selected solution is fortunately a workable fix. – theta-fish Aug 02 '15 at 03:15
  • 1
    Frankly, I wish this had worked for me. It would have shown some intelligence on the part of the assembly loading. – theta-fish Aug 02 '15 at 03:17
  • I've had success with this locally, but it fails when I run it on AppVeyor. My task assembly has an external dependency in the same folder as itself but MSBuild is not picking it up all the time, for some reason. – Matthew Olenik Mar 20 '16 at 16:55
  • In Visual Studio 2015 Community, the assemblies next to the absolute paths don’t load properly. For me, it was `Microsoft.Build.Tasks.CodeAnalysis` which VS refused to resolve while MSBuild invoked from the command line was perfectly happy. I assume this was because MSBuild’s assembly resolution path included the folder were this assembly was because this is the same folder where MSbuild.exe resides. Not so for devenv.exe when running tasks for Intellisense (when running an overridden `Csc` Task), so [OP’s fix](http://stackoverflow.com/a/13549039/429091) was necessary to make VS happy for me. – binki Jun 28 '16 at 03:14
  • I'm surprised, but this worked for me. Thanks @Bernd – stuzor Nov 16 '18 at 08:27