Oğuzhan Soykan
Oğuzhan Soykan

Reputation: 2710

How to invoke a NSwag client method that needs bearer token on request header?

I didn't get exactly how NSwag interact with IdentityServerX bearer tokens and adds it request header conventionally? My host api application implements IdentityServer3 with LDAP auth, so as far as i understand; if any host needs to a token for authentication then any client must send it on request header. So how can i deal with it while working NSwag clients ?

Any idea appreciated. Thanks.

Upvotes: 32

Views: 26790

Answers (4)

Oğuzhan Soykan
Oğuzhan Soykan

Reputation: 2710

I've resolved the issue by using a partial method e.g.

CampaignClient.cs

public partial class CampaignClient
{
    partial void PrepareRequest(HttpClient request, ref string url);

    partial void ProcessResponse(HttpClient request, HttpResponseMessage response);
   
    // Some code...
}

CampaignClient.Extensions.cs - partial class:

public partial class CampaignClient
{
    private readonly IRequestContext _requestContext;
    private readonly IStartupConfiguration _startupConfiguration;

    public CampaignClient(IRequestContext requestContext, IStartupConfiguration startupConfiguration)
    {
        _requestContext = requestContext;
        _startupConfiguration = startupConfiguration;
    }

    partial void PrepareRequest(HttpClient request, ref string url)
    {
        request.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _requestContext.GetBearerTokenOrTriggerUnauthException());
    }
}

Method override has saved me!

Upvotes: 25

Peter
Peter

Reputation: 1391

For the c# client you can specifcy UseHttpClientCreationMethod or UseHttpRequestMessageCreationMethod

(Cf. https://github.com/RicoSuter/NSwag/blob/master/src/NSwag.CodeGeneration.CSharp/CSharpClientGeneratorSettings.cs)

That way NSwag expects you to implement the methods for Creating A HttpClient or HttpRequest. You can set your headers there without any magic

Upvotes: 9

Hakan Fıstık
Hakan Fıstık

Reputation: 19511

If you want to use interfaces instead of abstract classes, then this is the solution for that case

  1. Set the option to generate the interface for the Client

    <OpenApiReference Include="OpenAPIs\swagger.json" CodeGenerator="NSwagCSharp" Namespace="YourNameSpace" ClassName="YourClient" >
        <Options>/GenerateClientInterfaces:true</Options>
    </OpenApiReference>
    
  2. Add a second part to the partial interface that is generated by NSwag

    public partial interface IYourClient
    {
        void SetBearerToken(string token);
    }
    
  3. Add a second part to the partial client that is generated by NSwag

    public partial class YourClient
    {
        private string? _token;
    
        public void SetBearerToken(string token) =>
            _token = token;
    
        partial void PrepareRequest(HttpClient client, HttpRequestMessage request, string URL)
        {
           if (!string.IsNullOrEmpty(_token))
              request.Headers.Authorization = new("Bearer", _token);   
        }
    }
    

The benefit of using the interface over abstract classes is all the operations will be defined in the interface, but the base class does not create abstract methods in the base class

Upvotes: 5

Aaron Hudon
Aaron Hudon

Reputation: 5839

@oguzhan-soykan and @peter answers are both good - Here's an expansion of @peter's answer to show how you can implement a base class and not repeat yourself for every API client.

Requirements

  • NSwag.MSBuild package
  • Swagger .JSON definition

Create a base 'Client' class that exposes the functionality you need. Likely a bearer token property.

public abstract class MySwaggerClientBase
{
    public string BearerToken { get; private set; }

    public void SetBearerToken(string token)
    {
        BearerToken = token;
    }

    // Called by implementing swagger client classes
    protected Task<HttpRequestMessage> CreateHttpRequestMessageAsync(CancellationToken cancellationToken)
    {
        var msg = new HttpRequestMessage();
        // SET THE BEARER AUTH TOKEN
        msg.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", BearerToken);
        return Task.FromResult(msg);
    }

}

Edit your swagger code generation command to make use of the base class for all generated clients and use the UseHttpRequestMessageCreationMethod option.

<Project>
 ...
<Exec Command="$(NSwagExe) swagger2csclient /input:path-to-swagger-definition.json /output:$(ProjectDir)\Swagger.generated.cs /Namespace:MyNameSpace /ClientBaseClass:MySwaggerClientBase /UseHttpRequestMessageCreationMethod:true" />
 ...
</Project>

Upvotes: 32

Related Questions