Swagger 加载失败

问题描述 投票:0回答:1

我正在使用 Azure Functions(隔离)并尝试导航到 Swagger UI 并获取:

加载API定义失败。 获取错误 未定义 https://localhost:7009/api/v1/swagger.json

这似乎是因为我的模型有一个实现 ICollection 的属性? 你在开玩笑吗?

enter image description here

问题似乎与此函数和响应正文有关。

[Function("GetConnector")]
[OpenApiOperation("GetConnector", AppConst.FunctionTags.Connectors, Summary = "Get an existing Connector.")]
[OpenApiParameter("id", Type = typeof(Guid), In = ParameterLocation.Path, Required = true, Summary = "Specifies the id of the Connector to get.")]
[OpenApiResponseWithBody(HttpStatusCode.OK, MediaTypeNames.Application.Json, typeof(ConnectorResponse), Description = "Returns the details of the Connector.")]
public async Task<HttpResponseData> GetConnectorAsync([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "connectors/{id}")] HttpRequestData httpReq,
    Guid id,
    CancellationToken cancellationToken)
{
    // omitted not important
}

ConnectorResponse 对象:

public class ConnectorResponse(Guid id, string name)
{
    public Guid Id
    {
        get;
        set;
    } = id;
    
    public string Name
    {
        get;
        set;
    } = name;
    
    public AuthConfigCollection AuthConfigurations
    {
        get;
        set;
    } = [];
}

AuthConfigConnection 似乎导致了该问题,因为它实现了 ICollection。

public class AuthConfigCollection() : ICollection<AuthConfigurationDto>
{
private List<AuthConfigurationDto> configs = new List<AuthConfigurationDto>();

public IEnumerator<AuthConfigurationDto> GetEnumerator()
{
    return configs.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
    return GetEnumerator();
}

public void Add(AuthConfigurationDto item)
{
    throw new NotImplementedException();
}

public void Clear()
{
    throw new NotImplementedException();
}

public bool Contains(AuthConfigurationDto item)
{
    throw new NotImplementedException();
}

public void CopyTo(AuthConfigurationDto[] array, int arrayIndex)
{
    throw new NotImplementedException();
}

public bool Remove(AuthConfigurationDto item)
{
    throw new NotImplementedException();
}

public int Count
{
    get;
}

public bool IsReadOnly
{
    get;
}
}

如何

azure-functions swagger-ui azure-functions-isolated
1个回答
0
投票

我对下面提到的文件做了一些更改并得到了预期的响应。

获取连接器-

using _78600033.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using System.Net.Mime;
using System.Net;
using Microsoft.OpenApi.Models;

namespace _78600033
{
    public class GetConnector
    {
        [Function("GetConnector")]
        [OpenApiOperation(operationId: "GetConnector", tags: new[] { "Connectors" }, Summary = "Get an existing Connector.")]
        [OpenApiParameter(name: "id", In = ParameterLocation.Path, Required = true, Type = typeof(Guid), Summary = "Specifies the id of the Connector to get.")]
        [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: MediaTypeNames.Application.Json, bodyType: typeof(ConnectorResponse), Description = "Returns the details of the Connector.")]
        public async Task<HttpResponseData> GetConnectorAsync(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "connectors/{id}")] HttpRequestData httpReq,
        Guid id,
        FunctionContext executionContext)
        {
            //creating a dummy response
            var connector = new ConnectorResponse(id, "Example Connector")
            {
                AuthConfigurations = new List<AuthConfigurationDto>
                {
                    new AuthConfigurationDto { Type = "OAuth", Config = "OAuthConfigDetails" },
                    new AuthConfigurationDto { Type = "API Key", Config = "ApiKeyDetails" }
                }
            };

            var response = httpReq.CreateResponse(HttpStatusCode.OK);
            await response.WriteAsJsonAsync(connector);

            return response;
        }
    }
}

AuthConfigCollection-

using _78600033.Models;
using System.Collections;

namespace _78600033
{
    public class AuthConfigCollection : ICollection<AuthConfigurationDto>
    {
        private List<AuthConfigurationDto> configs = new List<AuthConfigurationDto>();

        public IEnumerator<AuthConfigurationDto> GetEnumerator()
        {
            return configs.GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        public void Add(AuthConfigurationDto item)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            configs.Add(item);
        }
        public void Clear()
        {
            configs.Clear();
        }
        public bool Contains(AuthConfigurationDto item)
        {
            return configs.Contains(item);
        }
        public void CopyTo(AuthConfigurationDto[] array, int arrayIndex)
        {
            configs.CopyTo(array, arrayIndex);
        }
        public bool Remove(AuthConfigurationDto item)
        {
            return configs.Remove(item);
        }
        public int Count => configs.Count;
        public bool IsReadOnly => false;
    }
}

连接器响应-

List<AuthConfigurationDto> AuthConfigurations
 文件中使用 AuthConfigurations
 代替 
ConnectorResponse

using _78600033.Models;

namespace _78600033
{
    public class ConnectorResponse
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
        public List<AuthConfigurationDto> AuthConfigurations { get; set; } = new List<AuthConfigurationDto>();

        public ConnectorResponse(Guid id, string name)
        {
            Id = id;
            Name = name;
        }
    }
}

程序.cs-

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication()
    .ConfigureServices(services =>
    {
        services.AddApplicationInsightsTelemetryWorkerService();
        services.ConfigureFunctionsApplicationInsights();
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "API", Version = "v1" });
        });
    })
    .Build();

host.Run();

.csproj-

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
    <OutputType>Exe</OutputType>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <RootNamespace>_78600033</RootNamespace>
  </PropertyGroup>
  <ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.22.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.2.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="1.3.1" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.OpenApi" Version="2.0.0-preview2" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.3-preview2" />
    <PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
  <ItemGroup>
    <Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext" />
  </ItemGroup>
</Project>

使用给定的代码,我能够成功访问 Swagger UI 页面。

enter image description here

enter image description here


Azure Functions Core Tools
Core Tools Version:       4.0.5801 Commit hash: N/A +5ac2f097******ea9ef68ff (64-bit)
Function Runtime Version: 4.34.1.22669

[2024-06-12T08:52:11.303Z] Found C:\Users\*****\repos\78600033\78600033\78600033.csproj. Using for user secrets file configuration.
[2024-06-12T08:52:16.113Z] Azure Functions .NET Worker (PID: 15152) initialized in debug mode. Waiting for debugger to attach...
[2024-06-12T08:52:16.157Z] Worker process started and initialized.

Functions:

        GetConnector: [GET] http://localhost:7175/api/connectors/{id}

        RenderOAuth2Redirect: [GET] http://localhost:7175/api/oauth2-redirect.html

        RenderOpenApiDocument: [GET] http://localhost:7175/api/openapi/{version}.{extension}

        RenderSwaggerDocument: [GET] http://localhost:7175/api/swagger.{extension}

        RenderSwaggerUI: [GET] http://localhost:7175/api/swagger/ui

For detailed output, run func with --verbose flag.
[2024-06-12T08:52:21.270Z] Host lock lease acquired by instance ID '000000000000000000000000BF6D1ED5'.
[2024-06-12T08:52:37.375Z] Executing 'Functions.RenderSwaggerUI' (Reason='This function was programmatically called via the host APIs.', Id=b43b9a2c-0021-4841-be41-0304378dd477)
[2024-06-12T08:52:37.721Z] SwaggerUI page was requested.
[2024-06-12T08:52:38.031Z] Executed 'Functions.RenderSwaggerUI' (Succeeded, Id=b43b9a2c-0021-4841-be41-0304378dd477, Duration=675ms)
[2024-06-12T08:52:38.186Z] Executing 'Functions.RenderSwaggerDocument' (Reason='This function was programmatically called via the host APIs.', Id=a9dfe31d-d362-465c-a22c-4d201e46a185)
[2024-06-12T08:52:38.216Z] swagger.json was requested.
[2024-06-12T08:52:40.904Z] Executed 'Functions.RenderSwaggerDocument' (Succeeded, Id=a9dfe31d-d362-465c-a22c-4d201e46a185, Duration=2719ms)
[2024-06-12T08:55:04.973Z] Executing 'Functions.GetConnector' (Reason='This function was programmatically called via the host APIs.', Id=bacfcce3-b5f1-431f-a4ae-5e132635ff18)
[2024-06-12T08:55:05.025Z] Executed 'Functions.GetConnector' (Succeeded, Id=bacfcce3-b5f1-431f-a4ae-5e132635ff18, Duration=52ms)
© www.soinside.com 2019 - 2024. All rights reserved.