Giter Site home page Giter Site logo

microsoft / kiota-abstractions-dotnet Goto Github PK

View Code? Open in Web Editor NEW
16.0 19.0 19.0 493 KB

Abstractions library for the Kiota generated SDKs in dotnet

Home Page: https://aka.ms/kiota/docs

License: MIT License

C# 98.11% PowerShell 1.89%
kiota dotnet

kiota-abstractions-dotnet's Introduction

Kiota Abstractions Library for dotnet

Build, Test, CodeQl NuGet Version

The Kiota abstractions Library for dotnet is the dotnet library defining the basic constructs Kiota projects need once an SDK has been generated from an OpenAPI definition.

A Kiota generated project will need a reference to the abstraction package to build and run.

Read more about Kiota here.

Using the Abstractions Library

dotnet add package Microsoft.Kiota.Abstractions --prerelease

Debugging

If you are using Visual Studio Code as your IDE, the launch.json file already contains the configuration to build and test the library. Otherwise, you can open the Microsoft.Kiota.Abstractions.sln with Visual Studio.

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft's Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.

kiota-abstractions-dotnet's People

Contributors

andreatp avatar andrueastman avatar baywet avatar czemacleod avatar dependabot[bot] avatar edouardpoitras avatar github-actions[bot] avatar hwoodiwiss avatar ichbinsteffen avatar ievangelist avatar martinm85 avatar microsoft-github-operations[bot] avatar microsoftopensource avatar ricardoboss avatar samwelkanda avatar timandella avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kiota-abstractions-dotnet's Issues

NuGet package Project website points to moved url https://microsoft.github.io/kiota/

The NuGet package (including 1.1.4) has the project URL pointing to https://microsoft.github.io/kiota/
This page says it has moved to https://learn.microsoft.com/en-gb/openapi/kiota/

I think
https://github.com/microsoft/kiota-abstractions-dotnet/blob/5092424b4e2fe8106fa360a8506bd0f5c78f05d4/src/Microsoft.Kiota.Abstractions.csproj#L14C6-L14C23

Needs to be changed to

    <PackageProjectUrl>https://learn.microsoft.com/en-gb/openapi/kiota/</PackageProjectUrl>

Multipart body is missing the ability to add a filename

Hi there,

I am trying to use Multipart and AddOrReplacePart(string, string, Stream) to upload files to my ASP.NET API.
The API is unable to bind the submitted values to an IFormFile field.

After some trial-and-error I found out that it is because the request generated by kiota is missing the filename field in the Content-Disposition header.

I had to "hack" it in using this:

multipartBody.AddOrReplacePart("Screenshot\"; Filename=\"" + filename, contentType, stream);

Notice the \" to hijack the " from the WriteStringValue call in MultipartBody.

Do you plan to add support for adding parts with filenames/custom content-disposition values?

Add net8.0 as a supported TFM

At the moment, the Kiota libraries are trim-annotated for the the .NET 5 tfm, however I have a use-case where an application that transiently references the Kiota libraries via https://github.com/octokit/dotnet-sdk (currently testing against a local copy updated to the latest Kiota libraries) seems to instead prefer to select the netstandard2.0 package, my guess is this is because net5.0 is out of support. This causes trimmer warnings, which as of SDK version 9, are now included by TreatWarningsAsError.

I suspect this is also a cause for the significantly larger than expected binary size when this library is included (an additional 80MB) though that could be more down to the Octokit library.

It would be useful for this case for the Kiota libraries to be published targetting the net8.0 tfm as well, and have all of the AOT analyzers enabled in that case via <IsAotCompatible>.

Also of note, as of .NET SDK 9.0.100-preview.1.24101.2, I now get the warning:

C:\Program Files\dotnet\sdk\9.0.100-preview.1.24101.2\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(90,5): warning NETSDK1212: IsTrimmable and EnableTrimAnalyzer are not supported for the target framework. Consider multi-targeting to a supported framework to enable trimming, and set IsTrimmable only for the supported frameworks. For example: [R:\source\repos\kiota-abstractions-dotnet\src\Microsoft.Kiota.Abstractions.csproj]
C:\Program Files\dotnet\sdk\9.0.100-preview.1.24101.2\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(90,5): warning NETSDK1212: <IsTrimmable Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0'))">true</IsTrimmable> [R:\source\repos\kiota-abstractions-dotnet\src\Microsoft.Kiota.Abstractions.csproj]

On the net5.0 builds, which indicates to me that the trim analysis on the net5.0 build is non-functional at the moment as well.

New Third Party package dependency Tavis.UriTemplates after migrating from Microsoft.Azure.ActiveDirectory.GraphClient

Having recently migrated code from using Microsoft.Azure.ActiveDirectory.GraphClient to Microsoft.Graph due to the package being deprecated and the service being slowly discontinued as of 30th June 2023, I now find my code has a new third-party package dependency - Tavis.UriTemplates.

At a surface glance, the package looks okay, and has substantial tests and an Apache-2.0 licence, so I am not immediately worried about its performance or correctness.
However, it seems odd, when MS are actively avoiding third-party package dependencies and/or using source generators for build time parsing etc., that this package is used here.
That and that it is used directly without some sort of abstraction layer, especially in an abstractions package required at runtime.

Can someone shed some light on this situation, and the providence of the package?

As a note, as far as I can tell, neither the nuget package, nor the dll contain a digital signature for instance.

Make properties in BaseRequestBuilder public

These properties are now marked as protected by making them public you could easily extend the requestbuilder using extension methods.

protected Dictionary<string, object> PathParameters { get; set; }
/// <summary>The request adapter to use to execute the requests.</summary>
protected IRequestAdapter RequestAdapter { get; set; }
/// <summary>Url template to use to build the URL for the current request builder</summary>
protected string UrlTemplate { get; set; }

Background

The new Graph SDK for .NET (even the beta version), does not contain all the endpoints available. By extending the request builder we could easily implement those additional endpoints and have the same experience. No we cannot use the PathParameters or the RequestAdapter even though these are available from other classes.

Please support trimming for self contained projects

When building a dotnet 7 self-contained project with Graph Beta SDK 5.24.0-preview, the following warning is observed:

C:\Users\{user}\.nuget\packages\microsoft.kiota.abstractions\1.1.0\lib\netstandard2.1\Microsoft.Kiota.Abstractions.dll : warning IL2104: Assembly 'Mi
crosoft.Kiota.Abstractions' produced trim warnings. For more information see https://aka.ms/dotnet-illink/libraries [C:\Users\{user}\source\repos\{project}.csproj]

Ideally, this warning would be resolved by supporting Trimming in the package - see https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-warnings/il2104

AddQueryParameters, in RequestInformation, is not adding parameters beginning with a capital to the URI

I am using Microsoft Kiota to generate an API client from an open api yaml file. In this file, one of the request parameters uses Pascal case

- name: TenantId
  in: query
  required: true
  schema:
    type: string

This was working fine when the generated API client was using version 1.3.1 of Microsoft.Kiota.Abstractions. However, when upgrading to 1.3.2, the generated uri is not including the parameter at all, which results in an error when the API is called as that parameter is required.

Here is a sample C# console app (target framework net7.0, running on Windows 10), using code I extracted from the generated API client

using Microsoft.Kiota.Abstractions;
using Microsoft.Kiota.Abstractions.Authentication;
using Microsoft.Kiota.Http.HttpClientLibrary;

namespace Kiota;

public class Program
{
    static void Main(string[] args)
    {
        var pathParameters = new Dictionary<string, object>
        {
            { "baseurl", "http://localhost:123" }
        };
        var requestAdapter = new HttpClientRequestAdapter(new AnonymousAuthenticationProvider())
        {
            BaseUrl = "http://localhost:123"
        };
        var requestBuilder = new TestRequestBuilder(pathParameters, requestAdapter);

        var queryParms = new TestRequestBuilder.TestRequestBuilderGetQueryParameters
        {
            TenantId = Guid.NewGuid().ToString()
        };

        var requestInfo = requestBuilder.ToGetRequestInformation(x => x.QueryParameters = queryParms);
        Console.Write(requestInfo.URI.ToString());
    }
}

public class TestRequestBuilder : BaseRequestBuilder
{
    public TestRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/api/v1/Test{?TenantId*}", pathParameters)
    {
    }

    public class TestRequestBuilderGetQueryParameters
    {
        public string TenantId { get; set; }
    }

    public class TestBuilderGetRequestConfiguration
    {
        public RequestHeaders Headers { get; set; }
        public IList<IRequestOption> Options { get; set; }
        public TestRequestBuilderGetQueryParameters QueryParameters { get; set; } = new TestRequestBuilderGetQueryParameters();

        public TestBuilderGetRequestConfiguration()
        {
            Options = new List<IRequestOption>();
            Headers = new RequestHeaders();
        }
    }

    public RequestInformation ToGetRequestInformation(Action<TestBuilderGetRequestConfiguration>? requestConfiguration = default)
    {
        var requestInfo = new RequestInformation
        {
            HttpMethod = Method.GET,
            UrlTemplate = UrlTemplate,
            PathParameters = PathParameters,
        };
        requestInfo.Headers.Add("Accept", "application/problem+json");
        if (requestConfiguration != null)
        {
            var requestConfig = new TestBuilderGetRequestConfiguration();
            requestConfiguration.Invoke(requestConfig);
            requestInfo.AddQueryParameters(requestConfig.QueryParameters);
            requestInfo.AddRequestOptions(requestConfig.Options);
            requestInfo.AddHeaders(requestConfig.Headers);
        }
        return requestInfo;
    }
}

With 1.3.1, the uri is generated as http://localhost:123/api/v1/Test?TenantId=8d20c652-1466-444f-af2a-403a03476187

With 1.3.2 the uri is generated as http://localhost:123/api/v1/Test

Note: If I change all instances of "TenantId " to "tenantId" in the above code, then it works successfully (although this is not really a satisfactory fix as we don't really want to change the original API).

IRequestAdapter should have `sendEnum` and `sendEnumCollection` methods

To align with other languages like go/java, IRequestAdapter should have sendEnum and sendEnumCollection methods to handle APIs that return enums.

At the moment this is mapped to sendPrimitive methods which does not align with other languages. This is a breaking change and should be resolved in the next major version of the lib.

Project condition for IsTrimmable is incorrect

Current Behaviour

Currently IsTrimmable is not set on a number of the Microsoft.Kiota .NET libraries as they share this incorrect condition:

<PropertyGroup Condition="'$(TargetFrameworkVersion)' == 'net5.0'">  
  <IsTrimmable>true</IsTrimmable>
</PropertyGroup>

Expected Behaviour

I would expect build errors when non-trim-safe code as added to the libraries.

Fix

The property group condition should be changed to:

<PropertyGroup Condition="'$(TargetFramework)' == 'net5.0'">  
  <IsTrimmable>true</IsTrimmable>
</PropertyGroup>

Which causes the IsTrimmable property to be correctly set, and any expected trimming related compilation failures to occur.

I've found this issue in these projects:

RequestInformation.AddQueryParameters should add parameters based on the template as well as object

Using

  • Kiota 1.1.3
  • Microsoft.Kiota.Abstractions 1.1.1

Given:

//Generated ApiRequestBuilder

UrlTemplate = "{+baseurl}/api{?Parameter*}"

and

// Generated ApiRequestBuilder query parameters class

public class RequestBuilderGetQueryParameters {
    public string? Parameter { get; set; }
}

(Note no QueryParameterAttribute was generated)

and user code like

var response = await apiClient.Api.GetAsync(request =>
    request.QueryParameters = new()
    {
        Parameter = someParameter
    });

Then something like this happens:

  1. The generated code has a call to requestInfo.AddQueryParameters(requestConfig.QueryParameters)
  2. AddQueryParameters uses x.Name.ToFirstCharacterLowerCase(), which makes the Parameter property add itself as parameter
  3. The later getter of URI, which uses parsedUrlTemplate.SetParameter(queryStringParameter.Key, GetSanitizedValue(queryStringParameter.Value)) will not set the value due to the casing mismatch
  4. The full request is missing a query parameter set at a high level using the unmodified generated code

My solution was to adjust the template, but ideally I want to keep generated code unmodified. Given all that, can we please clarify:

  • Is this expected, or is a QueryParameterAttribute missing from the generated code?
  • Is there a requirement in the OpenAPI document to have a specific casing to lead to the URL template to use camelCase?
  • Is there a reason to have case-sensitivity between the URL template, the query class, and the mechanism that converts the query class to the request URL?

Serialization/Deserialization of Date format

I have Request class with Date datatype property.
When sending in request Date api expects it in format DD.MM.YYYY, and sending back Date in that format.
Is it possible to do that without changing generated code?

	var client = new PostsClient(httpClientRequestAdapter);

	var body = new Request()
	{
		PromjenaOd = new Microsoft.Kiota.Abstractions.Date(2020, 01, 01),
	};
	var response =  await client.Shema.GetStates.PostAsync(body,null);
	response.Dump();
	}

Generate DateOnly type for newer .net releases

For { type: "string", format: "date" } models, Kiota references a Date struct that is shipped in its Abstractions package.

In newer .net releases, it would be nice to use the built-in System.DateOnly type, so that the model integrates more naturally with the rest of the code.

downgrade kiota libraries (and graph SDK) to netstandard2.0

The Kiota libraries are currently targeting netstandard2.1, which is not supported by dotnet framework (classic).
This makes for a steep adoption curve for people who have existing projects.
I don't believe we actually need 2.1, I think the history there is that we created the projects with net5.0 at the time, and then downgraded to standard 2.1 when came time to reach public preview.

netstandard2.0 should bring the libs back to compatibility with the framework (classic).

If we're using something specific to 2.1, the alternative would be to multi-target 2.1, and 4.6.2, 4.7.2 and 4.8.

readme updates

Readmes of all the kiota dotnet repos are very "raw" at the moment.

  1. Fix the github actions badge link
  2. Add a nuget badge
  3. Add sections to debug/contribute (see kiota readme)
  4. Remove the information about the private feed

ApiException should have a property for parsed response data for parsable error responses

This is related to a suggestion I made here: microsoft/kiota-http-dotnet#188

Description

I think it would make sense that in the case that there is a known Error response type for a given status code, then the response should be parsed (which in the HttpClientRequestAdapter it already is) and added to the ApiException so that is accessible to the calling code handling the exception.

API Changes

To facilitate this, a new property would need to be added to ApiException:

public class ApiException : Exception
{
    public ApiException() : base()
    public ApiException(string message) : base(message)
    public ApiException(string message, Exception innerException) : base(message, innerException)

    public int ResponseStatusCode { get; set; }
    public IDictionary<string, IEnumerable<string>> ResponseHeaders { get; set; }
+   public object? ResponseObject { get; set; }
}

I would then expect the type of the ResponseObject to be disambiguated in calling code.

Multi-targeting considerations

This library is targeting netstandard2.0, netstandard2.1, and net5.0. I believe it's in our best interest and the interest of the consuming libraries that this keeps up with .NET versions.

  • net5.0 is out of support, and support ended May 10, 2022 (going on nearly two years ago).

Here's the latest details of the supported versions, https://dotnet.microsoft.com/platform/support/policy.

It would be awesome to try to follow along with these major releases.

Add function overloads with Type as parameter for KiotaSerializer.Deserialize<T>

We (@MichaMican and I) have implemented an TextFormatter extension to use Kiota as thge standard serializer for IParsable objects when working with ASP.NET Controllers.

See: microsoftgraph/msgraph-sdk-dotnet#2343 (comment)

In our TextInputFormatter we have to fallback to using Reflection because we work with an implementation of IParsable object that we have to set as the generic type of KiotaSerializer.Deserialize<T> during run time. As of now the function unfortunately has no overload to specify the Type as a parameter which would be super usefull in our case as we could then imrpove code readability by not using reflection.

Snippet from the TextInputFormatter:

public override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
{
    var httpContext = context.HttpContext;

    if (httpContext.Request.Body.CanRead)
    {
        var targetType = context.ModelType; // <- This is where we get the Type for Deserialize per runtime

        #region Reflection to define Generic type T of KiotaJsonSerializer.Deserialize<T> dynamically
        var methodInfo = typeof(KiotaJsonSerializer).GetMethod("Deserialize", BindingFlags.Public | BindingFlags.Static, [typeof(Stream)]);
        if (methodInfo == null)
        {
            throw new Exception("KiotaJsonSerializer.Deserialize changed. Please update implementation");
        }

        // This line types the KiotaJsonSerializer.Deserialize<T> to T equals to targetType
        var methodWithForcedTargetType = methodInfo.MakeGenericMethod(targetType);

        // obj is null because KiotaJsonSerializer.Deserialize is a static function
        // This function is analog to KiotaJsonSerializer.Deserialize<T>(httpContext.Request.Body) -> Where T = targetType
        var deserializedObject = methodWithForcedTargetType.Invoke(null, [httpContext.Request.Body]);

       // As we used reflection deserializedObject is of type object, hence we have to continue to use Reflection to access the BackingStore/InitializationCompleted property.
        var backingStoreProperty = (deserializedObject?.GetType().GetProperty("BackingStore"));
        var backingStoreValue = backingStoreProperty?.GetValue(deserializedObject);

        backingStoreValue?.GetType().GetProperty("InitializationCompleted")?.SetValue(backingStoreValue, false);

        #endregion

        return Task.FromResult(InputFormatterResult.Success(deserializedObject));
    }

    return Task.FromResult(InputFormatterResult.Failure());

}

C# - Required parameters are omitted if empty

When trying to use this endpoint without all parameters being set, I would expect Kiota to send empty parameters as they have the property "allowEmptyValue" but also are "required".

    "/{currentCompany}/Erp.BO.LaborSvc/GetRows": {
      "get": {
        "tags": [ "Custom methods" ],
        "summary": "Invoke method GetRows",
        "description": "Returns a dataset containing all rows that satisfy the where clauses.",
        "operationId": "Get_GetRows",
        "parameters": [
          { "$ref": "#/parameters/currentCompany" },
          { "$ref": "#/parameters/X-API-Key" },
          {
            "name": "whereClauseLaborHed",
            "in": "query",
            "description": "whereClauseLaborHed",
            "required": true,
            "type": "string",
            "allowEmptyValue": true
          },
          {
            "name": "whereClauseLaborDtl",
            "in": "query",
            "description": "whereClauseLaborDtl",
            "required": true,
            "type": "string",
            "allowEmptyValue": true
          },
          {
            "name": "whereClauseLaborDtlAttch",
            "in": "query",
            "description": "whereClauseLaborDtlAttch",
            "required": true,
            "type": "string",
            "allowEmptyValue": true
          },
          {
            "name": "whereClauseLaborDtlComment",
            "in": "query",
            "description": "whereClauseLaborDtlComment",
            "required": true,
            "type": "string",
            "allowEmptyValue": true
          },
          {
            "name": "whereClauseLaborEquip",
            "in": "query",
            "description": "whereClauseLaborEquip",
            "required": true,
            "type": "string",
            "allowEmptyValue": true
          },
          {
            "name": "whereClauseLaborPart",
            "in": "query",
            "description": "whereClauseLaborPart",
            "required": true,
            "type": "string",
            "allowEmptyValue": true
          },
          {
            "name": "whereClauseLbrScrapSerialNumbers",
            "in": "query",
            "description": "whereClauseLbrScrapSerialNumbers",
            "required": true,
            "type": "string",
            "allowEmptyValue": true
          },
          {
            "name": "whereClauseLaborDtlGroup",
            "in": "query",
            "description": "whereClauseLaborDtlGroup",
            "required": true,
            "type": "string",
            "allowEmptyValue": true
          },
          {
            "name": "whereClauseSelectedSerialNumbers",
            "in": "query",
            "description": "whereClauseSelectedSerialNumbers",
            "required": true,
            "type": "string",
            "allowEmptyValue": true
          },
          {
            "name": "whereClauseSNFormat",
            "in": "query",
            "description": "whereClauseSNFormat",
            "required": true,
            "type": "string",
            "allowEmptyValue": true
          },
          {
            "name": "whereClauseTimeWeeklyView",
            "in": "query",
            "description": "whereClauseTimeWeeklyView",
            "required": true,
            "type": "string",
            "allowEmptyValue": true
          },
          {
            "name": "whereClauseTimeWorkHours",
            "in": "query",
            "description": "whereClauseTimeWorkHours",
            "required": true,
            "type": "string",
            "allowEmptyValue": true
          },
          {
            "name": "pageSize",
            "in": "query",
            "description": "pageSize",
            "required": true,
            "type": "integer",
            "format": "int32"
          },
          {
            "name": "absolutePage",
            "in": "query",
            "description": "absolutePage",
            "required": true,
            "type": "integer",
            "format": "int32"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "schema": { "$ref": "#/definitions/GetRows_output" }
          },
          "500": { "description": "Internal server error. Server is unable to process the request." }
        }
      }
    },

What Kiota actually does, is it omits these parameters resulting in an error.

As an example, this is the url that swagger generates when I select to sent empty values for all parameters where allowed:

https://{Servername}/api/v2/odata/{Company}/Erp.BO.LaborSvc/GetRows?whereClauseLaborHed=&whereClauseLaborDtl=&whereClauseLaborDtlAttch=&whereClauseLaborDtlComment=&whereClauseLaborEquip=&whereClauseLaborPart=&whereClauseLbrScrapSerialNumbers=&whereClauseLaborDtlGroup=&whereClauseSelectedSerialNumbers=&whereClauseSNFormat=&whereClauseTimeWeeklyView=&whereClauseTimeWorkHours=&pageSize=0&absolutePage=0

Versus Kiota where all parameters that have not been set are omitted:

https://{Servername}/api/v2/odata/{Company}/Erp.BO.LaborSvc/GetRows?pageSize=0&absolutePage=0

I have tried to set the parameters to string.Empty and to null but both result in the parameters being omitted. The only workaround I found was setting the parameters to a whitespace which will be set by Kiota.

Create types for untyped nodes

To support untyped JSON (microsoft/kiota#2319), create the following types:

UntypedObject
UntypedArray
UntypedString
UntypedNumber
UntypedBoolean
UntypedNull
These types need to derive from UntypedNode.
UntypedObject needs a property called properties that is a map of UntypedNode.

Extend IParseNode interface with UntypedNode? GetUntypedValue()

Extend ISerializationWriter interface with void WriteUntypedValue(string? key, UntypedNode? value)

Published kiota packages depend on DiagnosticSource < 8.0.0

kiota packages such as Microsoft.Kiota.Abstractions 1.7.1 (published today) require System.Diagnostics.DiagnosticSource (>= 6.0.0 && < 8.0.0).

The explicit failure to work with 8.0.0 creates a lot of problems for packages released together with dotnet 8 which bring in DiagnosticSource 8.0.0. For example we get build failures with Microsoft.Extensions.Http 8.0.0 -> Microsoft.Extensions.Diagnostics 8.0.0 -> Microsoft.Extensions.Diagnostics.Abstractions 8.0.0 -> System.Diagnostics.DiagnosticSource (>= 8.0.0) .

URI propertery getter on RequestInformation throws Method not found: 'System.String Std.UriTemplate.Expand(System.String, System.Collections.Generic.Dictionary`2<System.String,System.Object>)

Found when calling through Microsoft.Graph .NET SDK:

System.MissingMethodException
HResult=0x80131513
Message=Method not found: 'System.String Std.UriTemplate.Expand(System.String, System.Collections.Generic.Dictionary2<System.String,System.Object>)'. Source=Microsoft.Kiota.Abstractions StackTrace: at Microsoft.Kiota.Abstractions.RequestInformation.get_URI() at Microsoft.Kiota.Abstractions.Authentication.BaseBearerTokenAuthenticationProvider.<AuthenticateRequestAsync>d__7.MoveNext() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Kiota.Http.HttpClientLibrary.HttpClientRequestAdapter.<GetHttpResponseMessage>d__34.MoveNext() at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Kiota.Http.HttpClientLibrary.HttpClientRequestAdapter.<SendAsync>d__201.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Graph.ServicePrincipals.ServicePrincipalsRequestBuilder.d__14.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

Attempting to get URI in RequestInformation, results in an error when one of the query parameters is a Guid

(This is a similar issue to #127, but I felt it was better raised separately)

I am using Microsoft Kiota to generate an API client from an open api yaml file. In this file, one of the request parameters is a guid

- name: TenantId
  in: query
  required: true
  schema:
    type: string
    format: uuid

This was working fine when the generated API client was using version 1.3.1 of Microsoft.Kiota.Abstractions. However, when upgrading to 1.3.2, when attempting to access the URI property results in an error.

Here is a sample C# console app (target framework net7.0, running on Windows 10), using code I extracted from the generated API client

using Microsoft.Kiota.Abstractions;
using Microsoft.Kiota.Abstractions.Authentication;
using Microsoft.Kiota.Http.HttpClientLibrary;

namespace Kiota;

public class Program
{
    static void Main(string[] args)
    {
        var pathParameters = new Dictionary<string, object>
        {
            { "baseurl", "http://localhost:123" }
        };
        var requestAdapter = new HttpClientRequestAdapter(new AnonymousAuthenticationProvider())
        {
            BaseUrl = "http://localhost:123"
        };
        var requestBuilder = new TestRequestBuilder(pathParameters, requestAdapter);

        var queryParms = new TestRequestBuilder.TestRequestBuilderGetQueryParameters
        {
            TenantId = Guid.NewGuid()
        };

        var requestInfo = requestBuilder.ToGetRequestInformation(x => x.QueryParameters = queryParms);
        Console.Write(requestInfo.URI.ToString());
    }
}

public class TestRequestBuilder : BaseRequestBuilder
{
    public TestRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/api/v1/Test{?tenantId*}", pathParameters)
    {
    }

    public class TestRequestBuilderGetQueryParameters
    {
        [QueryParameter("tenantId")]
        public Guid TenantId { get; set; }
    }

    public class TestBuilderGetRequestConfiguration
    {
        public RequestHeaders Headers { get; set; }
        public IList<IRequestOption> Options { get; set; }
        public TestRequestBuilderGetQueryParameters QueryParameters { get; set; } = new TestRequestBuilderGetQueryParameters();

        public TestBuilderGetRequestConfiguration()
        {
            Options = new List<IRequestOption>();
            Headers = new RequestHeaders();
        }
    }

    public RequestInformation ToGetRequestInformation(Action<TestBuilderGetRequestConfiguration>? requestConfiguration = default)
    {
        var requestInfo = new RequestInformation
        {
            HttpMethod = Method.GET,
            UrlTemplate = UrlTemplate,
            PathParameters = PathParameters,
        };
        requestInfo.Headers.Add("Accept", "application/problem+json");
        if (requestConfiguration != null)
        {
            var requestConfig = new TestBuilderGetRequestConfiguration();
            requestConfiguration.Invoke(requestConfig);
            requestInfo.AddQueryParameters(requestConfig.QueryParameters);
            requestInfo.AddRequestOptions(requestConfig.Options);
            requestInfo.AddHeaders(requestConfig.Headers);
        }
        return requestInfo;
    }
}

With 1.3.1, the uri is generated as http://localhost:123/api/v1/Test?TenantId=8d20c652-1466-444f-af2a-403a03476187

With 1.3.2 when attempting to write the uri to the console, the following error is thrown
System.ArgumentException: 'Illegal class passed as substitution, found System.Guid at col:33'

Note: If I change the type to string in the above code, then it works successfully

IParseNode enum methods should be marked DynamicallyAccessedMemberTypes.PublicFields

Currently GetCollectionOfEnumValues and GetEnumValue are marked DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All). This causes IL3050 to be emitted by ILC at the moment, as All indicates that Enum.GetValues(Type) could be called dynamically.

Given current usage in the serialization libraries, PublicFields or PublicFields | NonPublicFields should be sufficient, and will prevent this warning.

This was indicated to me in dotnet/runtime#98864, as I had originally thought this was a false positive.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.