¿Cuál es la forma preferida de hacer que un servicio conectado VS (NSwag) se inyecte en clases/controladores? He encontrado muchas sugerencias en la red para usar este formulario:
services.AddHttpClient<IClient, Client>((provider, client) => { client.BaseAddress = new System.Uri("https://some.baseurl/"); });Sin embargo, esto da como resultado el error.
{"errorMessage":"Unable to resolve service for type 'System.String' while attempting to activate 'xxx.Client'."} Esto proviene de la clase de cliente generada automáticamente en obj , que parece forzar una cadena BaseUrl en el constructor, que por supuesto DI no puede resolver:
public Client(string baseUrl, System.Net.Http.HttpClient httpClient) { BaseUrl = baseUrl; _httpClient = httpClient; _settings = new System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings); }Esta URL base luego se fuerza en el código del generador de URL, por lo que realmente no se puede omitir. Sin embargo, incluso las soluciones en la red que usan extensiones parciales para las clases de clientes parecen ignorar por completo baseUrl en la clase de generación automática (como aquí ). Como si no existiera (lo cual es raro, ¿el NSwag antes generó diferentes constructores?). La clase se genera a través de csproj:
<ItemGroup> <OpenApiReference Include="OpenAPIs\swagger.json" CodeGenerator="NSwagCSharp" Namespace="xxx" ClassName="Client"> <SourceUri>https://localhost:44353/swagger/v1/swagger.json</SourceUri> </OpenApiReference> </ItemGroup>Y esto da como resultado la llamada de compilación dirigida:
2>GenerateNSwagCSharp: 2> "C:\.<path>./tools/Win/NSwag.exe" openapi2csclient /className:Client /namespace:xxx /input:"C:\<projpath>\OpenAPIs\swagger.json" /output:"obj\swaggerClient.cs" 2>NSwag command line tool for .NET 4.6.1+ WinX64, toolchain v13.13.2.0 (NJsonSchema v10.5.2.0 (Newtonsoft.Json v11.0.0.0))Entonces, ¿cómo se está haciendo esto? potencialmente, sin crear otra clase de proxy para una clase de proxy, preferiría que DI maneje la duración de mis objetos. También me gustaría evitar NSwagStudio si es posible y me gustaría mantener las herramientas proporcionadas por VS.
Ok, en realidad resolví este problema hurgando en OpenApiReference , pero requiere la modificación manual del archivo csproj. Se debe agregar el nodo Options adicionales al grupo de elementos OpenApiReference , para indicar a NSwag que NO exponga BaseUrl y también para generar una interfaz, lo que facilita el trabajo con la configuración de DI sin código adicional.
El equipo de Visual Studio realmente debería agregar estas dos casillas de verificación a las pantallas/configuración de Servicios conectados para OpenAPI.
<ItemGroup> <OpenApiReference Include="OpenAPIs\swagger.json" CodeGenerator="NSwagCSharp" Namespace="xxx" ClassName="Client"> <SourceUri>https://localhost:44353/swagger/v1/swagger.json</SourceUri> <Options>/UseBaseUrl:false /GenerateClientInterfaces:true</Options> </OpenApiReference> </ItemGroup> Ahora solo hay un constructor HttpClient , y el proxy del cliente NSwag usa la dirección base de él, por lo que AddHttpClient funciona correctamente a través de DI.
Como la clase generada se marca como parcial, puede proporcionar un constructor adicional y marcarlo con el atributo [ActivatorUtilitiesConstructor] . La aplicación del atributo garantiza que el constructor se use con la inyección de dependencia. También puede implementar la interfaz en su extensión parcial. Aquí hay un ejemplo de esto;
public partial class MyApiClient : IMyApiClient { [ActivatorUtilitiesConstructor] // This ctor will be used by DI public MyApiClient(HttpClient httpClient, IOptions<MyApiClientOptions> clientOptions) : this(clientOptions.Value.Url, httpClient) // Call generated ctor { } }