Open Boriszn opened 6 years ago
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:
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+
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
Hi Rico,
Could you please help.
When I try to generate SDK from .net core assembly project it rises an exception:
But the assembly exists.