RicoSuter / NSwag

The Swagger/OpenAPI toolchain for .NET, ASP.NET Core and TypeScript.
http://NSwag.org
MIT License
6.79k stars 1.29k forks source link

NSwag.MSBuild fails under NetCore_31: System.InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.Configuration.IConfiguration' while attempting to activate 'Startup' #2641

Closed Meberem closed 4 years ago

Meberem commented 4 years ago

I get the following error using NSwag.MSBuild to generate clients. The project should have been set up to

System.InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.Configuration.IConfiguration' while attempting to activate 'Startup'.
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetServiceOrCreateInstance(IServiceProvider provider, Type type)
   at Microsoft.AspNetCore.Hosting.StartupLoader.LoadMethods(IServiceProvider hostingServiceProvider, Type startupType, String environmentName)
   at Microsoft.AspNetCore.Hosting.WebHostBuilderExtensions.<>c__DisplayClass3_0.<UseStartup>b__1(IServiceProvider sp)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
...

The .csproj has this set

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>

  <Target Name="NSwag" AfterTargets="Build">
    <Copy SourceFiles="@(ReferencePath)" DestinationFolder="$(OutDir)References" />
    <Exec Command="$(NSwagExe_Core31) run nswag.json /variables:FilePath=&quot;$(OutDir)$(AssemblyName).dll&quot;" />
    <RemoveDir Directories="$(OutDir)References" />
  </Target>
</Project>

nswag.json looks like so:

{
    "runtime": "NetCore31",
    "defaultVariables": null,
    "documentGenerator": {
        "aspNetCoreToOpenApi": {
            "project": null,
            "msBuildProjectExtensionsPath": null,
            "configuration": null,
            "runtime": null,
            "targetFramework": null,
            "noBuild": false,
            "verbose": true,
            "workingDirectory": null,
            "requireParametersWithoutDefault": true,
            "apiGroupNames": null,
            "defaultPropertyNameHandling": "Default",
            "defaultReferenceTypeNullHandling": "NotNull",
            "defaultDictionaryValueReferenceTypeNullHandling": "NotNull",
            "defaultResponseReferenceTypeNullHandling": "NotNull",
            "defaultEnumHandling": "Integer",
            "flattenInheritanceHierarchy": false,
            "generateKnownTypes": true,
            "generateEnumMappingDescription": false,
            "generateXmlObjects": false,
            "generateAbstractProperties": false,
            "generateAbstractSchemas": true,
            "ignoreObsoleteProperties": false,
            "allowReferencesWithProperties": false,
            "excludedTypeNames": [],
            "serviceHost": null,
            "serviceBasePath": null,
            "serviceSchemes": [],
            "infoTitle": "My Title",
            "infoDescription": null,
            "infoVersion": "1.0.0",
            "documentTemplate": null,
            "documentProcessorTypes": [],
            "operationProcessorTypes": [],
            "typeNameGeneratorType": null,
            "schemaNameGeneratorType": null,
            "contractResolverType": null,
            "serializerSettingsType": null,
            "useDocumentProvider": true,
            "documentName": "v1",
            "aspNetCoreEnvironment": null,
            "createWebHostBuilderMethod": null,
            "startupType": null,
            "allowNullableBodyParameters": true,
            "output": "swagger.json",
            "outputType": "Swagger2",
            "assemblyPaths": [
                "$(FilePath)"
            ],
            "assemblyConfig": null,
            "referencePaths": [],
            "useNuGetCache": false
        }
    },
    "codeGenerators": {
        "openApiToTypeScriptClient": {
            "className": "{controller}Client",
            "moduleName": "",
            "namespace": "",
            "typeScriptVersion": 2.7,
            "template": "Axios",
            "promiseType": "Promise",
            "httpClass": "HttpClient",
            "withCredentials": false,
            "useSingletonProvider": false,
            "injectionTokenType": "OpaqueToken",
            "rxJsVersion": 6.0,
            "dateTimeType": "Date",
            "nullValue": "Undefined",
            "generateClientClasses": true,
            "generateClientInterfaces": false,
            "generateOptionalParameters": false,
            "exportTypes": true,
            "wrapDtoExceptions": false,
            "exceptionClass": "ApiException",
            "clientBaseClass": null,
            "wrapResponses": false,
            "wrapResponseMethods": [],
            "generateResponseClasses": true,
            "responseClass": "SwaggerResponse",
            "protectedMethods": [],
            "configurationClass": null,
            "useTransformOptionsMethod": false,
            "useTransformResultMethod": false,
            "generateDtoTypes": true,
            "operationGenerationMode": "MultipleClientsFromOperationId",
            "markOptionalProperties": true,
            "generateCloneMethod": false,
            "typeStyle": "Class",
            "classTypes": [],
            "extendedClasses": [],
            "extensionCode": null,
            "generateDefaultValues": true,
            "excludedTypeNames": [],
            "excludedParameterNames": [],
            "handleReferences": false,
            "generateConstructorInterface": true,
            "convertConstructorInterfaceData": false,
            "importRequiredTypes": true,
            "useGetBaseUrlMethod": false,
            "baseUrlTokenName": "API_BASE_URL",
            "queryNullValue": "",
            "inlineNamedDictionaries": false,
            "inlineNamedAny": false,
            "templateDirectory": null,
            "typeNameGeneratorType": null,
            "propertyNameGeneratorType": null,
            "enumNameGeneratorType": null,
            "serviceHost": null,
            "serviceSchemes": null,
            "output": "../@company/product-api/ApiClient.generated.ts"
        }
    }
}
RicoSuter commented 4 years ago

Have you tried using "project" parameter (with path to .csproj) and "noBuild": true instead of "assemblyPaths"? This is the preferred and more tested way to load the project from CLI.

Meberem commented 4 years ago

Ah ok, I wasn't aware that was the case, I was able to compile and generate the client with the following changes. Thanks for your help! It really is appreciated.

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
-   <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>

  <Target Name="NSwag" AfterTargets="Build">
    <Copy SourceFiles="@(ReferencePath)" DestinationFolder="$(OutDir)References" />
-   <Exec Command="$(NSwagExe_Core31) run nswag.json /variables:FilePath=&quot;$(OutDir)$(AssemblyName).dll&quot;" />
+   <Exec Command="$(NSwagExe_Core31) run nswag.json /variables:ProjectPath=&quot;$(MSBuildProjectFullPath)&quot;" />
    <RemoveDir Directories="$(OutDir)References" />
  </Target>
</Project>
{
    "runtime": "NetCore31",
    "defaultVariables": null,
    "documentGenerator": {
        "aspNetCoreToOpenApi": {
-           "project": null,
+           "project": "$(ProjectPath)",
            "msBuildProjectExtensionsPath": null,
            "configuration": null,
            "runtime": null,
            "targetFramework": null,
-           "noBuild": false,
+           "noBuild": true,
            "verbose": true,
            "workingDirectory": null,
            "requireParametersWithoutDefault": true,
            "apiGroupNames": null,
            "defaultPropertyNameHandling": "Default",
            "defaultReferenceTypeNullHandling": "NotNull",
            "defaultDictionaryValueReferenceTypeNullHandling": "NotNull",
            "defaultResponseReferenceTypeNullHandling": "NotNull",
            "defaultEnumHandling": "Integer",
            "flattenInheritanceHierarchy": false,
            "generateKnownTypes": true,
            "generateEnumMappingDescription": false,
            "generateXmlObjects": false,
            "generateAbstractProperties": false,
            "generateAbstractSchemas": true,
            "ignoreObsoleteProperties": false,
            "allowReferencesWithProperties": false,
            "excludedTypeNames": [],
            "serviceHost": null,
            "serviceBasePath": null,
            "serviceSchemes": [],
            "infoTitle": "My Title",
            "infoDescription": null,
            "infoVersion": "1.0.0",
            "documentTemplate": null,
            "documentProcessorTypes": [],
            "operationProcessorTypes": [],
            "typeNameGeneratorType": null,
            "schemaNameGeneratorType": null,
            "contractResolverType": null,
            "serializerSettingsType": null,
            "useDocumentProvider": true,
            "documentName": "v1",
            "aspNetCoreEnvironment": null,
            "createWebHostBuilderMethod": null,
            "startupType": null,
            "allowNullableBodyParameters": true,
            "output": "swagger.json",
            "outputType": "Swagger2",
+           "assemblyPaths": [],
-           "assemblyPaths": [
-               "$(FilePath)"
-           ],
            "assemblyConfig": null,
            "referencePaths": [],
            "useNuGetCache": false
        }
    },
    "codeGenerators": {
        "openApiToTypeScriptClient": {
            "className": "{controller}Client",
            "moduleName": "",
            "namespace": "",
            "typeScriptVersion": 2.7,
            "template": "Axios",
            "promiseType": "Promise",
            "httpClass": "HttpClient",
            "withCredentials": false,
            "useSingletonProvider": false,
            "injectionTokenType": "OpaqueToken",
            "rxJsVersion": 6.0,
            "dateTimeType": "Date",
            "nullValue": "Undefined",
            "generateClientClasses": true,
            "generateClientInterfaces": false,
            "generateOptionalParameters": false,
            "exportTypes": true,
            "wrapDtoExceptions": false,
            "exceptionClass": "ApiException",
            "clientBaseClass": null,
            "wrapResponses": false,
            "wrapResponseMethods": [],
            "generateResponseClasses": true,
            "responseClass": "SwaggerResponse",
            "protectedMethods": [],
            "configurationClass": null,
            "useTransformOptionsMethod": false,
            "useTransformResultMethod": false,
            "generateDtoTypes": true,
            "operationGenerationMode": "MultipleClientsFromOperationId",
            "markOptionalProperties": true,
            "generateCloneMethod": false,
            "typeStyle": "Class",
            "classTypes": [],
            "extendedClasses": [],
            "extensionCode": null,
            "generateDefaultValues": true,
            "excludedTypeNames": [],
            "excludedParameterNames": [],
            "handleReferences": false,
            "generateConstructorInterface": true,
            "convertConstructorInterfaceData": false,
            "importRequiredTypes": true,
            "useGetBaseUrlMethod": false,
            "baseUrlTokenName": "API_BASE_URL",
            "queryNullValue": "",
            "inlineNamedDictionaries": false,
            "inlineNamedAny": false,
            "templateDirectory": null,
            "typeNameGeneratorType": null,
            "propertyNameGeneratorType": null,
            "enumNameGeneratorType": null,
            "serviceHost": null,
            "serviceSchemes": null,
            "output": "../@company/product-api/ApiClient.generated.ts"
        }
    }
}
shivanaru commented 4 years ago

I have the same issue and tried the above suggestion but no luck. Info: Using Lamar IoC with .Net core 3.1. So, in startup.cs I have ConfigureContainer(ServiceRegistry services) method in addition to the ConfigureServices() and Configure() methods. I think that is the culprit but not sure how to work around it?

Below is the error message on NSwag Studio while trying to generate the Typescript client:

Launcher directory: C:\Program Files (x86)\Rico Suter\NSwagStudio\NetCore31 System.InvalidOperationException: Swagger generation failed with non-zero exit code '1'.

Runtime: NetCore31 at NSwag.Commands.Generation.AspNetCore.AspNetCoreToSwaggerCommand.RunAsync(CommandLineProcessor processor, IConsoleHost host) in C:\projects\nswag\src\NSwag.Commands\Commands\Generation\AspNetCore\AspNetCoreToOpenApiCommand.cs:line 221 at NSwag.Commands.NSwagDocumentBase.GenerateSwaggerDocumentAsync() in C:\projects\nswag\src\NSwag.Commands\NSwagDocumentBase.cs:line 279 at NSwag.Commands.NSwagDocument.ExecuteAsync() in C:\projects\nswag\src\NSwag.Commands\NSwagDocument.cs:line 81 at NSwag.Commands.Document.ExecuteDocumentCommand.ExecuteDocumentAsync(IConsoleHost host, String filePath) in C:\projects\nswag\src\NSwag.Commands\Commands\Document\ExecuteDocumentCommand.cs:line 86 at NSwag.Commands.Document.ExecuteDocumentCommand.RunAsync(CommandLineProcessor processor, IConsoleHost host) in C:\projects\nswag\src\NSwag.Commands\Commands\Document\ExecuteDocumentCommand.cs:line 32 at NConsole.CommandLineProcessor.ProcessSingleAsync(String[] args, Object input) at NConsole.CommandLineProcessor.ProcessAsync(String[] args, Object input) at NConsole.CommandLineProcessor.Process(String[] args, Object input) at NSwag.Commands.NSwagCommandProcessor.Process(String[] args) in C:\projects\nswag\src\NSwag.Commands\NSwagCommandProcessor.cs:line 56

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> Lamar.IoC.LamarMissingRegistrationException: No service registrations exist or can be derived for NSwag.Generation.IOpenApiDocumentGenerator at Lamar.IoC.Scope.GetInstance(Type serviceType) at Lamar.Container.Microsoft.Extensions.DependencyInjection.ISupportRequiredService.GetRequiredService(Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) at NSwag.Commands.Generation.AspNetCore.AspNetCoreToSwaggerCommand.GenerateDocumentWithDocumentProviderAsync(IServiceProvider serviceProvider) in C:\projects\nswag\src\NSwag.Commands\Commands\Generation\AspNetCore\AspNetCoreToOpenApiCommand.cs:line 286 at NSwag.Commands.Generation.AspNetCore.AspNetCoreToSwaggerCommand.GenerateDocumentAsync(AssemblyLoader assemblyLoader, IServiceProvider serviceProvider, String currentWorkingDirectory) in C:\projects\nswag\src\NSwag.Commands\Commands\Generation\AspNetCore\AspNetCoreToOpenApiCommand.cs:line 276 at NSwag.Commands.Generation.AspNetCore.AspNetCoreToOpenApiGeneratorCommandEntryPoint.<>c__DisplayClass0_0.<b__0>d.MoveNext() in C:\projects\nswag\src\NSwag.Commands\Commands\Generation\AspNetCore\AspNetCoreToOpenApiGeneratorCommandEntryPoint.cs:line 30 --- End of stack trace from previous location where exception was thrown --- at NSwag.Commands.Generation.AspNetCore.AspNetCoreToOpenApiGeneratorCommandEntryPoint.Process(String commandContent, String outputFile, String applicationName) in C:\projects\nswag\src\NSwag.Commands\Commands\Generation\AspNetCore\AspNetCoreToOpenApiGeneratorCommandEntryPoint.cs:line 29 --- End of inner exception stack trace --- at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) at NSwag.AspNetCore.Launcher.Program.Main(String[] args) in C:\projects\nswag\src\NSwag.AspNetCore.Launcher\Program.cs:line 170

RicoSuter commented 4 years ago

IOpenApiDocumentGenerator is registered with a call to AddOpenApiDocument() on the service collection..

shivanaru commented 4 years ago

Thank you for your reply - @RicoSuter . I figured out the issue was the csproj file had x64 . Once I removed it and saved the csproj file, Lamar worked fine and then NSwag had no issue. It worked with either AddOpenApiDocument or AddSwaggerDocument. Either one was fine. The swagger output was different based on which option. I went to OpenApi spec and that was what I needed. So switched to that. NSwag is fantastic!! Thank you again for all your work on it!