Nswag: Issue with generating SDK from .NET Core assembly.

Created on 29 Jan 2018  路  41Comments  路  Source: RicoSuter/NSwag

Hi Rico,

Could you please help.

When I try to generate SDK from .net core assembly project it rises an exception:

tem.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.AspNetCore.JsonPatch, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' or one of its dependencies. The system cannot find the file specified.
File name: 'Microsoft.AspNetCore.JsonPatch, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'

Check if .NET Core is installed and 'dotnet' is globally available.

But the assembly exists.

NSwag.AssemblyLoader await-retest question

Most helpful comment

Wow, this is really amazing!

  <Target Name="NSwag" AfterTargets="Build">
    <Copy SourceFiles="@(Reference)" DestinationFolder="$(OutDir)References" />
    <Exec Command="$(NSwagExe_Core20) run nswag.json /variables:Configuration=$(Configuration)" />
    <RemoveDir Directories="$(OutDir)References" />
  </Target>

All 41 comments

Try adding

%USERPROFILE%/.nuget/packages

to the ReferencePaths

v11.14.0:

We improved the assembly loader (mainly for .NET Core) so that it runs in a more isolated space and the loaded DLLs should better match the requested versions. Please test this with your projects to ensure that we didnt introduce regressions.

Important if you have DLL loading problems:

  • Check that the DLL in question is available in the output directory (where the selected assembly is located) or in ReferencePaths
  • Check that you selected the correct runtime: Either in NSwagStudio UI, as /runtime parameter in the NPM CLI or execute the correct exe binary

For more information regarding assembly loading: https://github.com/RSuter/NSwag/wiki/Assembly-loading

Main commit: https://github.com/RSuter/NSwag/commit/04576e4d1b714ac5bd9b5df11d72469a23f7c0ff#diff-14dafe6661bab407ae5c0d7095ccd1f4

We found referencing the .nuget folder problematic as you cannot guarantee you'll pick up the correct version of the assembly.

Try:

<Copy SourceFiles="@(Reference)" DestinationFolder="$(OutDir)WebApi2SwaggerReferencePath" />

And point to WebApi2SwaggerReferencePath in ReferencePaths.

The later cleanup with:

<RemoveDir Directories="$(OutDir)WebApi2SwaggerReferencePath" />

Once we adopted this, life was bliss.

Correct, in versions prior to v11.14 it was often the problem that the wrong DLL was loaded. In the latest version (v11.14) I try to find the best version based on the requested version:

https://github.com/RSuter/NSwag/blob/master/src/NSwag.AssemblyLoader/AssemblyLoader.cs#L133

However, this also does not work very well because some DLLs/package versions are strangely missing from the cache (even if they are used) and also scanning the cache directory takes a lot of time...

So using the nuget package cache directory is just a shortcut to test if assembly loading can work...

I'd suggest recommending the above approach, it has been bullet proof for us, and you don't need to publish and build again, it's all done in one hit.

What is @(Reference)?

That is the resolved references from the .NET build target in MSBuild.

By the way, this library has saved us many hours in our current project, so a massive thank you is due!

You would put that in a target with AfterTargets="Build"

I think it is not needed to add WebApi2SwaggerReferencePath to ReferencePaths as NSwag automatically searches in the directory where the specified assembly is located...

But thanks, I'll try that... looks promising..

Is it also working with v11.14?

In projects that use the new PackageReference, i.e. .NET Core projects, the @(Reference) will be an item group where all of the assemblies are scatter in the .nuget folder, and quickly exceed the max length to pass to NSwag, the copy puts them all in 1 folder for that purpose. Alse in a regular build the output folder won't have the framework assemblies, but they will be in the @(Reference) for example.

We researched this extensively and believe this is the optimal solution.

Haven't testing in v11.14, but it should work as it puts all of the required assemblies in a folder and says "hey use these", and they are ones you want.

If there was a version of NSwag.MSBuild that didn't just shell out, you might be able to avoid that copy too.

Wow, this is really amazing!

  <Target Name="NSwag" AfterTargets="Build">
    <Copy SourceFiles="@(Reference)" DestinationFolder="$(OutDir)References" />
    <Exec Command="$(NSwagExe_Core20) run nswag.json /variables:Configuration=$(Configuration)" />
    <RemoveDir Directories="$(OutDir)References" />
  </Target>

Yeah, we have been using this for months (sorry for keeping it a secret), and it's lovely

Credit to @shaynevanasperen who reduced our solution to that little nugget

Yes, its much better than using "dotnet publish" with

<PublishWithAspNetCoreTargetManifest>false</PublishWithAspNetCoreTargetManifest>

Is there a way to make use of the Configuration variable in nswag.json? Currently I have the assemblyPaths as bin/Debug/netcoreapp2.0/<assembly>.dll so this only works when building in Debug and not when building Release.

In the nswag.json set

"defaultVariables": "Configuration=Debug"

and in nswag.json use the placeholder

$(Configuration)

in the .csproj task use

    <Exec Command="$(NSwagExe_Core20) run nswag.json /variables:Configuration=$(Configuration)" />

Did you mean a different file for defaultVariables="Configuration=Debug" as the format is wrong for nswag.json?

I tried it anyway as "defaultVariables": "Configuration=Debug" and I already have the .csproj task as you stated above. I'm getting error "Could not find a part of the path ...\bin$(Configuration)\netcoreapp2.0" when building.

Sorry, it's "defaultVariables": "Configuration=Debug" in nswag.json...
This only works in v11.14+

image

Ok yep, I had too early a version. It works fine when I upgraded to v11.14.1, but I get an different error for v11.15 (not sure if this has been reported elsewhere):

2>Executing file 'nswag.json'...
2>System.BadImageFormatException: Could not load file or assembly 'System.Runtime, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Reference assemblies should not be loaded for execution.  They can only be loaded in the Reflection-only loader context. (Exception from HRESULT: 0x80131058)
2>File name: 'System.Runtime, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' ---> System.BadImageFormatException: Cannot load a reference assembly for execution.
2>   at System.Reflection.RuntimeAssembly.GetExportedTypes(RuntimeAssembly assembly, ObjectHandleOnStack retTypes)
2>   at System.Reflection.RuntimeAssembly.GetExportedTypes()
2>   at NSwag.SwaggerGeneration.WebApi.WebApiToSwaggerGenerator.GetControllerClasses(Assembly assembly) in C:\projects\nswag\src\NSwag.SwaggerGeneration.WebApi\WebApiToSwaggerGenerator.cs:line 50
2>   at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()
2>   at System.Linq.Enumerable.SelectEnumerableIterator`2.ToArray()
2>   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
2>   at System.Linq.OrderedEnumerable`1.ToArray()
2>   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
2>   at NSwag.Commands.SwaggerGeneration.WebApiToSwaggerCommand.GetControllerNames(AssemblyLoader assemblyLoader) in C:\projects\nswag\src\NSwag.Commands\Commands\SwaggerGeneration\WebApiToSwaggerCommand.cs:line 261
2>   at NSwag.Commands.SwaggerGeneration.WebApiToSwaggerCommand.<RunIsolatedAsync>d__88.MoveNext() in C:\projects\nswag\src\NSwag.Commands\Commands\SwaggerGeneration\WebApiToSwaggerCommand.cs:line 185

how are you executing nswag? via NSwag.MSBuild? do you also copy the references or publish first?

Yes NSwag.MSBuild, same as your example above:

  <Target Name="NSwag" AfterTargets="Build">
    <RemoveDir Directories="$(OutDir)References" />
    <Copy SourceFiles="@(Reference)" DestinationFolder="$(OutDir)References" />
    <Exec Command="$(NSwagExe_Core20) run nswag.json /variables:Configuration=$(Configuration)" />
  </Target>

Not publishing first.

Can you provide a sample project where i can reproduce this?

Sure, see attached. The build fails unless I downgrade the NSwag packages to 11.14.1.
NSwagIssue.zip

Please retry with v11.15.1

Works great thank you!

@Boriszn and @slang25 Is it working for you too?

It works for us as we use the @References copy approach, I think this makes sense when using from a csproj.

The assembly loading improvements are fantastic if running separately.

So I've encountered a couple of issues here. (Possibly a new problem or at least recent)
[ASP.NET Core 2 WebApi Application]

I can get my config to render if done through NSwagStudio. (added %USERPROFILE%\.nuget\packages reference to get it to work.)

But after I added NSwag.MSBuild, I get this:

1>System.IO.FileNotFoundException: Could not load file or assembly 'System.ServiceModel.Primitives, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.
1>File name: 'System.ServiceModel.Primitives, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' ---> System.IO.FileNotFoundException: Could not load the specified file.
... etc ...

_And from then on could not load assemblies using NSwagStudio. :(_

To correct this, I removed the NSwag.MSBuild reference, deleted the bin & obj folders, republished locallay, and it would then load the assemblies again.

As @comdw commented, I also encountered the same error there (BadImageFormatException) and had to blow away my entire repo to fix. Problem would not go away.

If I remove System.ServiceModel.Primitives dependency, this problem also goes away. :(

@electricessence do you use the correct binary?

@RSuter. When I was investigating this (still unresolved), I had the latest version from nuget. It was as if the DLL hint was wrong. But again, I did this a few times from a blown away repo.

@RSuter & @slang25 - this was causing an issue in our project... we reference a dll that we have locally. So we have something like:

<Reference Include="OurNamespace.ServerClient, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
  <HintPath>..\ExternalLibraries\OurNamespace.ServerClient.dll</HintPath>
</Reference>

But now the @(Reference) contains the string OurNamespace.ServerClient, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null which didn't work with Copy because it isn't a file. I think it's the same issue @electricessence was running into.

Anyway, to cut a long story short, this fixed it:

<Copy SourceFiles="@(ReferencePath)" DestinationFolder="$(OutDir)References" />

Let me know if that's going to mess anything up... otherwise I suggest you update the documentation.

@cvallance Nice find, looking at this again, I cannot find much info about Reference, however ReferencePath seems to be the correct property to use, and is the primary output of ResolveAssemblyReferences, so I think that would be the more correct property to use.

I think it's worth updating the docs :+1:

@slang25 looks good to me. Pleas update the docs if you have time...

@cvallance Your suggestion really saved my day! Thank you!
@RSuter I love using NSwag :)

@cvallance So I read this thread months ago, but I didn't realize the subtle difference between these two

<Copy SourceFiles="@(Reference)" DestinationFolder="$(OutDir)References" />

and - the one that works:

<Copy SourceFiles="@(ReferencePath)" DestinationFolder="$(OutDir)References" />

Interestingly for me the first would work OK with a Build, but not a Rebuild All. I don't fully understand why, I could guess - but trying to explain my guess here wouldn't be productive here!

If you want to start making sense of this sort of stuff, I recommend turning on binary logging and using MSBuildStructuredLog, you just add /bl to your msbuild command and you'll get a msbuild.binlog you can open and make sense of.

So here you'd run msbuild /t:Rebuild /bl

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Peter554 picture Peter554  路  3Comments

akamyshanov picture akamyshanov  路  4Comments

RawsomeGH picture RawsomeGH  路  4Comments

danroth27 picture danroth27  路  3Comments

Rui90 picture Rui90  路  4Comments