Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with generating SDK from .NET Core assembly. #1159

Open
Boriszn opened this issue Jan 29, 2018 · 41 comments
Open

Issue with generating SDK from .NET Core assembly. #1159

Boriszn opened this issue Jan 29, 2018 · 41 comments

Comments

@Boriszn
Copy link

Boriszn commented Jan 29, 2018

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.

@Boriszn Boriszn changed the title Issue with generating SDK from .NET assembly.(Dot Net Core) Issue with generating SDK from .NET Core assembly. Jan 29, 2018
@RicoSuter
Copy link
Owner

RicoSuter commented Jan 30, 2018

Try adding

%USERPROFILE%/.nuget/packages

to the ReferencePaths

@RicoSuter
Copy link
Owner

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: 04576e4#diff-14dafe6661bab407ae5c0d7095ccd1f4

@slang25
Copy link
Contributor

slang25 commented Feb 7, 2018

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.

@RicoSuter
Copy link
Owner

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

@slang25
Copy link
Contributor

slang25 commented Feb 7, 2018

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.

@RicoSuter
Copy link
Owner

What is @(Reference)?

@slang25
Copy link
Contributor

slang25 commented Feb 7, 2018

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!

@slang25
Copy link
Contributor

slang25 commented Feb 7, 2018

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

@RicoSuter
Copy link
Owner

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

@RicoSuter
Copy link
Owner

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

@RicoSuter
Copy link
Owner

Is it also working with v11.14?

@slang25
Copy link
Contributor

slang25 commented Feb 7, 2018

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.

@slang25
Copy link
Contributor

slang25 commented Feb 7, 2018

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.

@slang25
Copy link
Contributor

slang25 commented Feb 7, 2018

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

@RicoSuter
Copy link
Owner

RicoSuter commented Feb 7, 2018

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>

@slang25
Copy link
Contributor

slang25 commented Feb 7, 2018

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

@slang25
Copy link
Contributor

slang25 commented Feb 7, 2018

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

@RicoSuter
Copy link
Owner

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

<PublishWithAspNetCoreTargetManifest>false</PublishWithAspNetCoreTargetManifest>

@comdw
Copy link

comdw commented Feb 12, 2018

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.

@RicoSuter
Copy link
Owner

RicoSuter commented Feb 12, 2018

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)" />

@comdw
Copy link

comdw commented Feb 12, 2018

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.

@RicoSuter
Copy link
Owner

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

@RicoSuter
Copy link
Owner

image

@comdw
Copy link

comdw commented Feb 12, 2018

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

@RicoSuter
Copy link
Owner

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

@comdw
Copy link

comdw commented Feb 12, 2018

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.

@RicoSuter
Copy link
Owner

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

@comdw
Copy link

comdw commented Feb 12, 2018

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

@RicoSuter
Copy link
Owner

Please retry with v11.15.1

@comdw
Copy link

comdw commented Feb 13, 2018

Works great thank you!

@RicoSuter
Copy link
Owner

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

@slang25
Copy link
Contributor

slang25 commented Feb 17, 2018

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.

@electricessence
Copy link

electricessence commented Feb 23, 2018

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

@RicoSuter
Copy link
Owner

@electricessence do you use the correct binary?

@electricessence
Copy link

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

@cvallance
Copy link
Contributor

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

@slang25
Copy link
Contributor

slang25 commented Jul 25, 2018

@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 👍

@RicoSuter
Copy link
Owner

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

@praveenv4k
Copy link

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

@simeyla
Copy link

simeyla commented Feb 1, 2019

@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!

@slang25
Copy link
Contributor

slang25 commented Feb 1, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants