Search code examples
.netasp.net-mvcdependency-injectionflurl

Can you change Flurl's authentication credentials after a client has been created via DI?


I have a service that uses Flurl; the service always sets BasicAuth credentials based on a configuration flag. This is no longer the case, and I need to change the credentials based on data that isn't available when the dependency is provided.

Is there a way to modify how Flurl authenticates after creating a new client?

The setup (greatly simplified but sufficient) is as follows:

public class MyClient : IMyClient, IDisposable
{

    private readonly IFlurlClient _client;

    public MyClient(IFlurlClientFactory flurlClientFactory)
    {
        var baseUrl = config.BaseUrl;
        _client = flurlClientFactory
            .Get(new Url(baseUrl))
            .WithBasicAuth("my", "credentials");
    }

    public async Task<MyProcessResponse> MyProcess(MyProcessRequest processRequestData)
    {
        var resource = GetProcessResource();
        // I need to change credentials here, based on data within resouce.
        var response = await _client.Request(resource)
            .PostJsonAsync(processRequestData)
            .ReceiveJson<MyProcessResponse>();

        return response;
    }
}

The service is used as such:

public class Process : IProcess
{
    private readonly IMyClient _myClient

    public Process(IMyClient myClient)
    {
        _myClient = myclient;
    }

    private async Task<bool> RunProcess()
    {
        var processRequestData = GetProcessRequestData()
        await _myClient.MyProcess(processRequestData);
        // do stuff
    }
}

As the environment is no longer the only factor, I need to change/set the credentials based on data defined within processRequestData.

It is my understanding I shouldn't be creating multiple clients, hence creating the one which has (so far) served its purpose.

What's the sanest way of achieving this?

Using the dated .NET 4.8 with MVC with AutoFac handling the DI.


Solution

  • You can call WithBasicAuth at any point, so this is a case of moving WithBasicAuth outside of the constructor, into MyProcess and then providing the relevant parameters.

    public class MyClient : IMyClient, IDisposable
    {
    
        private readonly IFlurlClient _client;
    
        public MyClient(IFlurlClientFactory flurlClientFactory)
        {
            var baseUrl = config.BaseUrl;
            _client = flurlClientFactory
                .Get(new Url(baseUrl));
        }
    
        public async Task<MyProcessResponse> MyProcess(MyProcessRequest processRequestData)
        {
            var resource = GetProcessResource();
            var credentials = BuildCredentials(resource);
            _client.WithBasicAuth(credentials.Username, credentials.Password);
            var response = await _client.Request(resource)
                .PostJsonAsync(processRequestData)
                .ReceiveJson<MyProcessResponse>();
    
            return response;
        }
    }
    

    I didn't realise this and obviously wasn't paying enough attention to IntelliSense and/or documentation.