Giter VIP home page Giter VIP logo

kiota-http-dotnet's Introduction

Kiota Http Library for dotnet

Build and Test NuGet Version

The Kiota HTTP Library for dotnet is the dotnet HTTP library implementation with HttpClient.

A Kiota generated project will need a reference to a HTTP package to make HTTP requests to an API endpoint.

Read more about Kiota here.

Using the Kiota Http Library for dotnet

dotnet add package Microsoft.Kiota.Http.HttpClientLibrary --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.Http.HttpClientLibrary.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-http-dotnet's People

Contributors

andreatp avatar andrueastman avatar baywet avatar calebkiage avatar czemacleod avatar dependabot[bot] avatar dev-tony-hu avatar github-actions[bot] avatar gridlocdev avatar hwoodiwiss avatar jacob-morgan avatar microsoft-github-operations[bot] avatar microsoftopensource avatar zengin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  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

kiota-http-dotnet's Issues

ApiException should return mapped error response if it parses successfully

Current Behavior

At the moment, when an HTTP request receives an error response, the response is parsed using a ParsableFactory<IParsable> that's passed in as a dictionary of HTTP Status Code -> Factory.

At the moment, when the error response is successfully parsed, it's used to set an activity tag for telemetry, then checked whether it's an exception or not.

var result = rootNode?.GetObjectValue(errorFactory);
SetResponseType(result, activityForAttributes);
spanForDeserialization?.Dispose();
if(result is not Exception ex)
throw new ApiException($"The server returned an unexpected status code and the error registered for this code failed to deserialize: {statusCodeAsString}")
{
ResponseStatusCode = statusCodeAsInt,
ResponseHeaders = responseHeadersDictionary
};
if(result is ApiException apiEx)
{
apiEx.ResponseStatusCode = statusCodeAsInt;
apiEx.ResponseHeaders = responseHeadersDictionary;
}

Desired Behavior

It would be useful for the parsed response to be bubbled up to the caller in the thrown ApiException so that this can be accessed in the calling code.

API Changes

This would depend on an API change in Microsoft.Kiota.Abstractions in ApiException to accommodate the error response value.

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; }
}

Is there any way to get response body when status code is unsuccessful?

I generated a client with Kiota, based on an OpenAPI spec, which does not specify error codes, hence errorMapping is empty in Kiota-generated client. The ApiException that Kiota throws contains just the status code and response headers. Is there any way to read the actual response body (as string) without modifying the Kiota-generated client code?

Activity source memory leak

When the HttpClientRequestAdapter is resolved from a service provider using either transient or scoped lifetime and passing a HttpClient then it leaks memory. The leak is caused by the creation of an ActivitySource every time the HttpClientRequestAdapter is constructed but it's never disposed unless the HttpClientRequestAdapter created the HttpClient.

activitySource = new(obsOptions.TracerInstrumentationName);

if(createdClient)
{
activitySource?.Dispose();
client?.Dispose();
}

This problem was introduced in commit e44fbfb#diff-d9ae4f1159bbe7195bce06dbc06baeb882e3f3d4fcf280c3d31523bf8c0dada7

In a very simple test constructing 1 million HttpClientRequestAdapter objects which can easily happen in the use-case I have results in the following memory usage pattern. Once the test completes we have a large number of objects in gen2 of the GC.

    public static void DotPeekActivitySourceLeak()
    {
        HttpClient httpClient = new HttpClient();
        for (var i = 0; i < 1000000; i++)
        {
            using var adapter = new HttpClientRequestAdapter(new AnonymousAuthenticationProvider(), httpClient: httpClient);
        }
    }
Screenshot 2023-12-25 at 7 17 22 AM

Updating the HttpClientRequestAdapter constructor to register the ActivitySource in the same way as the HttpClient middleware implementations, since it's using the same ActivitySource name eliminates this leak.

activitySource = ActivitySourceRegistry.DefaultInstance.GetOrCreateActivitySource(obsOptions.TracerInstrumentationName);
Screenshot 2023-12-25 at 7 25 22 AM

System.Text.Json dependency constraint for .NET 8 scenarios

Hey, I use Microsoft.Graph package for the dotnet/Scaffolding project. For the new .NET 8 release of the scaffolding package, the dependency constraint this project has on System.Text.Json being [6.0, 8.0) is causing issues since it causes the default .NET 8 project's dependency on System.Text.Json to downgrade causing an error (dependency downgrade). Unless you have a workaround you can suggest.

Blazor WASM client unable to send web requests through HttpClient BaseAddress

This issue occurs for Blazor WASM applications consuming an OpenAPI spec that does not supply a base URL. Blazor WASM does not support the System.Net.Http.HttpClientHandler class, so those apps must supply an HttpClient to the HttpClientRequestAdapter to work.

The issue is that the BaseAddress property on the supplied HttpClient object does not infer that as the HttpClientRequestAdapter's BaseUrl, and it must be set separately for requests to be sent appropriately.

How to reproduce:

  1. Create a Blazor WASM application with .NET 7 using the empty template (For the sake of example, named "KiotaTestApp.FrontEnd")

  2. Generate a client from an API spec that does not supply a Base URL. E.g. (kiota generate -d http://<url>/swagger/v1/swagger.json -n KiotaTestApp.FrontEnd.Client -o ./Client -l CSharp -c ApiClient

    Note: The dotnet-aspnet-codegenerator tool can be used to scaffold an API with an OpenAPI spec that reproduces the above scenario.

  3. Note the following warning that appears in the console output:

    warn: Kiota.Builder.KiotaBuilder[0]
          OpenAPI warning: #/ - A servers entry (v3) or host + basePath + schemes properties (v2) was not present in the OpenAPI description. The root URL will need to be set manually with the request adapter.
    warn: Kiota.Builder.KiotaBuilder[0]
          No server url found in the OpenAPI document. The base url will need to be set when using the client.
    
  4. Add the Kiota API client service setup in a Blazor WASM application's Program.cs file like so:

    // ...
    var authProvider = new AnonymousAuthenticationProvider();
    var client = new HttpClient { BaseAddress = new Uri("http://<url>") };
    var requestAdapter = new HttpClientRequestAdapter(authProvider, httpClient: client );
    builder.Services.AddScoped<ApiClient>(_ => new ApiClient(requestAdapter));
    // ...
  5. In the Index.razor (or any other page) inject the client and create a method that sends an HTTP request with it

  6. Launch the application, and view that requests are not sent to the HttpClient's BaseAddress

Workaround

Explicitly setting the BaseUrl after adding an HttpClient applies the parameter value, allowing the client to send requests.

// ...
var authProvider = new AnonymousAuthenticationProvider();
var client = new HttpClient { BaseAddress = new Uri("http://<url>") };
var requestAdapter = new HttpClientRequestAdapter(authProvider, httpClient: client );
requestAdapter.BaseUrl = "http://<url>";
builder.Services.AddScoped<ApiClient>(_ => new ApiClient(requestAdapter));
// ...

Configurable defaults for `ObservabilityOptions` in http middleware

The default telemetry configuration results in creating and an ActivitySource and Activity for each request, and then disposing those objects after a response is returned. ActivitySource.Dispose calls SynchronizedList.Remove (https://github.com/dotnet/runtime/blob/main/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivitySource.cs#L299) as shown in the Azure Profiler output where the lock is present (https://github.com/dotnet/runtime/blob/main/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivitySource.cs#L402).

As we are doing this in each of the client middleware irrespective of the whether the telemetry is being listened to (e.g.

activitySource = new ActivitySource(obsOptions.TracerInstrumentationName);
) , the use of the SynchronizedList in the underlying telemetry implementation can be perfomance bottleneck.

A temporary workaround is to add middleware to remove the default ObservabilityOptions created from the request. But the action below should probably be configurable and "opt-in"

message.Options.Set(new HttpRequestOptionsKey<IRequestOption>(typeof(ObservabilityOptions).FullName!), obsOptions);

cc @baywet

map XXX error status code

related to microsoft/kiota#4025
add a 3rd case in the error handling of the request adapter for XXX (must be the 3rd in the order, first sepcific code, then 4XX or 5XX depending on the first number, then XXX)

KiotaClientFactory is missing key helper methods in C#

Maybe I am missing something but this is painful....

A key scenario is that someone wants to use Kiota "out of the box" but with one more MessageHandler. e.g. CompressionHandler because it isn't there by default yet.

To customize the message handling pipeline it is necessary to pass in a "custom" HttpClient. e.g.

var requestAdapter = new HttpClientRequestAdapter(new AnonymousAuthenticationProvider(), httpClient:client);

You can create your own HttpClient by doing

var client = KiotaClientFactory.Create();

This is great if you want to set custom headers that are sent with every request. Having said that, if you set an Accept header it will get overridden by RequestBuilders. That's not ideal.
However, if you want to add a message handler, you need to use the overload that accepts a messagehandler pipeline. I'm not sure why we dropped this terminology for "chain" as pipeline has been the term used since HttpClient was originally created.

You can create a customized set of handlers by calling the CreateDefaultHandlers method and adjusting it. e.g.

       var handlers = KiotaClientFactory.CreateDefaultHandlers();
        handlers.Insert(0, new CompressionHandler());

However, there is no obvious way to use that list. I tried this

var pipeline = KiotaClientFactory.ChainHandlersCollectionAndGetFirstLink(KiotaClientFactory.GetDefaultHttpMessageHandler(), handlers);

but unfortunately, we made ChainHandlersCollectionAndGetFirstLink accept "params". I had to Bing how to use a list to provide "params". So in the end, this works.

        var handlers = KiotaClientFactory.CreateDefaultHandlers();
        handlers.Insert(0, new CompressionHandler());
        var pipeline = KiotaClientFactory.ChainHandlersCollectionAndGetFirstLink(KiotaClientFactory.GetDefaultHttpMessageHandler(), handlers.ToArray());
        var client = KiotaClientFactory.Create(pipeline);
        var requestAdapter = new HttpClientRequestAdapter(new AnonymousAuthenticationProvider(), httpClient:client);

I would like us to consider adding an overload to Create() that accepts a list of handlers and optionally a non-default finalhandler. This would allow a developer to do the following.

        var handlers = KiotaClientFactory.CreateDefaultHandlers();
        handlers.Insert(0, new CompressionHandler());
        var client = KiotaClientFactory.Create(handlers);
        var requestAdapter = new HttpClientRequestAdapter(new AnonymousAuthenticationProvider(), httpClient:client);

I don't see a whole lot of value making our customers convert the list to a pipeline. We can do that as an implementation detail.

Pass HttpCompletionOption.ResponseHeadersRead to HttpClient for Stream responses

Related to microsoftgraph/msgraph-sdk-dotnet#1954

For calls to SendPrimitiveAsync<Stream> we should pass the HttpCompletionOption.ResponseHeadersRead to the HttpClient to avoid the loading of the entire stream buffer into memory as the requested stream may be unnecessarily large.
This could be done by passing the optional parameter once the return type is determined to be that of a Stream.
https://github.com/microsoft/kiota-http-dotnet/blob/main/src/HttpClientRequestAdapter.cs#L410

We can avoid this for other scenarios as typed return are not expected to run into this issue as the size is not expected to grow as much compared to an unknown Stream size.

Add static analyzers dotnet Abstraction libraries

Add static anaylzers for Core and Abstraction libraries and cleanup the readmes to reflect this

This will mainly involves setting up Sonar cloud for the abstraction libs and fixing validation pipelines once the abstraction libs are moved to a separate repo.

AB#10960

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.