web-dev-qa-db-ja.com

.NET Core 2.1に移行するとSwagger UIが壊れる

最近、プロジェクトを.NET Core 2.0から.NET Core 2.1に移行しました。その結果、Swaggerドキュメントサイトが機能しなくなりました。引き続きアクセスできます。カスタマイズされたタイトルとバージョンは表示できますが、APIドキュメントはなく、No operations defined in spec!というメッセージのみがあります。

古いソリューションを試しました 。NET Core 2.0の場合 ですが、助けにはなりませんでした。次の2つの記事に基づいて 12 コントローラーメソッドからSwagger属性を削除し、コントローラークラスの上に[ApiController]属性を追加しようとしましたが、どちらかを助けます。誰でもこの問題を解決するのに役立ちますか?

。csproj

<Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <TargetFramework>netcoreapp2.1</TargetFramework>
        <RootNamespace>Company.Administration.Api</RootNamespace>
        <AssemblyName>Company.Administration.Api</AssemblyName>
        <PackageId>Company.Administration.Api</PackageId>
        <Authors></Authors>
        <Company>Company, Inc</Company>
        <Product>Foo</Product>
        <ApplicationInsightsResourceId>/subscriptions/dfa7ef88-f5b4-45a8-9b6c-2fb145290eb4/resourcegroups/Foo/providers/Microsoft.insights/components/foo</ApplicationInsightsResourceId>
        <ApplicationInsightsAnnotationResourceId>/subscriptions/dfa7ef88-f5b4-45a8-9b6c-2fb145290eb4/resourceGroups/Foo/providers/Microsoft.insights/components/foo</ApplicationInsightsAnnotationResourceId>
        <UserSecretsId>bf821b77-3f23-47e8-834e-7f72e2ab00c5</UserSecretsId>
    </PropertyGroup>

    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
        <DocumentationFile>bin\Debug\netcoreapp2.1\Administration.Api.xml</DocumentationFile>
    </PropertyGroup>

    <PropertyGroup>
        <!-- Try to set version using environment variables set by GitVersion. -->
        <Version Condition=" '$(Version)' == '' And '$(GitVersion_AssemblySemVer)' != '' ">$(GitVersion_AssemblySemVer)</Version>
        <InformationalVersion Condition=" '$(InformationalVersion)' == '' And '$(GitVersion_InformationalVersion)' != '' ">$(GitVersion_InformationalVersion)</InformationalVersion>

        <!-- If we don't have environment variables set by GitVersion, use default version. -->
        <Version Condition=" '$(Version)' == '' ">0.0.1</Version>
        <InformationalVersion Condition=" '$(InformationalVersion)' == '' ">0.0.1-local</InformationalVersion>
    </PropertyGroup>

    <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
        <DocumentationFile>bin\Release\netcoreapp2.1\Administration.Api.xml</DocumentationFile>
    </PropertyGroup>

    <PropertyGroup>
        <MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>
        <PreserveCompilationContext>false</PreserveCompilationContext>
    </PropertyGroup>

    <ItemGroup>
        <Folder Include="wwwroot\" />
    </ItemGroup>

    <ItemGroup>
        <PackageReference Include="IdentityModel" Version="3.7.0-preview1" />
        <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="2.6.0" />
        <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.3.0" />
        <PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.6" />
        <PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.0" />
        <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.1.0" />
        <PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
        <PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="2.4.0" />
    </ItemGroup>

    <ItemGroup>
        <WCFMetadata Include="Connected Services" />
    </ItemGroup>

</Project>

Startup.cs

using Company.Administration.Api.Controllers;
using Company.Administration.Api.Security;
using Company.Administration.Api.Services;
using Company.Administration.Api.Swagger;
using Company.Administration.Api.Swagger.Examples;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.PlatformAbstractions;
using Newtonsoft.Json.Converters;
using Swashbuckle.AspNetCore.Swagger;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Net.Http;

namespace Company.Administration.Api
{
    public class Startup
    {
        public Startup(IConfiguration configuration, ILogger<Startup> logger, IHostingEnvironment hostingEnvironment)
        {
            Configuration = configuration;
            Logger = logger;
            HostingEnvironment = hostingEnvironment;

            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
        }

        public IHostingEnvironment HostingEnvironment { get; }
        public IConfiguration Configuration { get; }
        public ILogger Logger { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<HttpClient>();
            services.AddTransient<AuthService>();
            services.AddTransient<FooAdministrationService>();

            services.AddMvc()
                .AddJsonOptions(options =>
                {
                    options.SerializerSettings.Converters.Add(new StringEnumConverter());
                });

            services.AddFooAuthentication(Configuration);

            services.AddFooAuthorization();

            services.AddCors();

            services
                .AddSwaggerGen(c =>
                {
                    c.SwaggerDoc("v1", new Info { Title = "Administration", Version = "v1" });

                    var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                    var xmlPath = Path.Combine(basePath, "Administration.Api.xml");
                    if (File.Exists(xmlPath))
                    {
                        c.IncludeXmlComments(xmlPath);
                    }
                    else
                    {
                        Logger.LogWarning($@"File does not exist: ""{xmlPath}""");
                    }

                    string authorityOption = Configuration["IdentityServerAuthentication:Url"] ?? throw new Exception("Failed to load authentication URL from configuration.");
                    string authority = $"{authorityOption}{(authorityOption.EndsWith("/") ? "" : "/")}";

                    var scopes = new Dictionary<string, string>
                    {
                        { "api", "Allow calls to the Foo administration API." }
                    };

                    c.AddSecurityDefinition("OpenId Connect", new OAuth2Scheme
                    {
                        Type = "oauth2",
                        Flow = "implicit",
                        AuthorizationUrl = $"{authority}connect/authorize",
                        TokenUrl = $"{authority}connect/token",
                        Scopes = scopes
                    });

                    c.DescribeAllEnumsAsStrings();

                    c.OperationFilter<ExamplesOperationFilter>(services.BuildServiceProvider());
                })
                .ConfigureSwaggerGen(options =>
                {
                    options.CustomSchemaIds(t => t.FullName);

                    options.OperationFilter<SecurityRequirementsOperationFilter>();
                });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseCors(builder => builder
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials()
                .WithExposedHeaders(AdministrationControllerBase.ExposedHeaders));

            app.UseAuthentication();

            app.UseMvc()
                .UseSwagger(x => x.RouteTemplate = "api-docs/{documentName}/swagger.json")
                .UseSwaggerUI(c =>
                {
                    c.OAuthClientId("foo-administration.swagger");
                    c.RoutePrefix = "api-docs";
                    c.SwaggerEndpoint("v1/swagger.json", "Foo Administration API");
                });

            app.UseReDoc(options =>
            {
                options.RoutePrefix = "api-docs-redoc";
                options.SpecUrl = "../api-docs/v1/swagger.json";
            });

        }
    }
}
8
lss

同じソリューションを行ごとに再作成しようとしました。 Swaggerは、<PreserveCompilationContext>false</PreserveCompilationContext>.csprojファイルに追加するまで機能しました。この属性を削除すると、Swagger UIが再表示されました。

9
lss

C#.Netコアでは、デコレータ[HttpPost]または[HttpGet]でいくつかのメソッドを使用する場合、すべてのPOST =またはGETメソッド。

ローカルで正常に動作しているが、IISホスティング後に問題が発生している場合、swagger.json相対パス。

次にConfigureServices内でこれを試してください:

app.UseSwaggerUI(c =>
{
string swaggerJsonBasePath = string.IsNullOrWhiteSpace(c.RoutePrefix) ? "." : "..";
c.SwaggerEndpoint($"{swaggerJsonBasePath}/swagger/v1/swagger.json", "My API");
});
3
Rousonur Jaman

私はこれがすでに答えられていることを知っています、しかし、私はこれに出くわし、まだ答えを探している人のためにチャイムだと思っただけです。 jsonファイルに直接アクセスしようとすると、動作しない理由がわかります。

例:

アドレスバーで: https:// localhost:44300/swagger/v1/swagger.json

返されるエラーメッセージ:

{"パス": "/ swagger/v1/swagger.json"、 "Started":false、 "State": "Internal Server Error"、 "Msg": "アクションのあいまいなHTTPメソッド-Controllers.ChatMessageController.ListFriends(Project .API)。アクションにはSwagger 2.0の明示的なHttpMethodバインディングが必要です}

0
Briana Finney

私には、コントローラーv1で[ApiVersionNeutral]属性を使用し、コントローラーv2で[ApiVersion( "2.0")]を使用しようとしたため、このエラーが表示されました。とにかく、出力または診断ツール([イベント]タブ)で完全なエラーメッセージを取得できます。そして、私はこのメッセージを受け取りました:

System.NotSupportedException:HTTPメソッド「GET」およびアクションによってオーバーロードされたパス「api/Employees」-Api.V2.Controllers.EmployeesController.Get、Api.V1.Controllers.EmployeesController.Get.

アクションにはSwagger 2.0の一意のメソッド/パスの組み合わせが必要です。回避策としてConflictingActionsResolverを使用してください

0

このエラーは、APIの他の問題によって引き起こされる場合もあります。私の場合、swaggerには、コントローラーの1つで2つのGetアクションを使用したオーバーロードの理解に問題がありました。うまくいったのは、次のようにOpen API仕様をロードすることで発生した例外を最初に調査することでした。

{https:// {Host}:{port}/swagger/{SwaggerSpecName} /swagger.json}

その後、OpenAPI仕様の読み込みを妨げるエラーが表示されました。後で、この仕様をswager genメソッドに適用することで、エラー(上記のgetアクションのオーバーロード)を解決しました。

 services.AddSwaggerGen(c => 
  { 
    other configs...;
    c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
  });

ここ は私を答えに導く投稿です

0
Damien Doumer