我正在使用 Azure Functions(隔离)并尝试导航到 Swagger UI 并获取:
加载API定义失败。 获取错误 未定义 https://localhost:7009/api/v1/swagger.json
这似乎是因为我的模型有一个实现 ICollection 的属性? 你在开玩笑吗?
问题似乎与此函数和响应正文有关。
[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;
}
}
如何
我对下面提到的文件做了一些更改并得到了预期的响应。
获取连接器-
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 页面。
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)