vendredi 1 février 2019

C# : Whether this approach is thread-safe

I have a service class, which does request to some external service. That external service requires sessionId, time of live of this sessionId is unknown (can be some seconds, can be minutes, can be hours, can be days. Can be 1 request, can be 1000 requests. Nobody knows it. We can't link to it at all).

I created a method, which get sessionId:

    private async Task<string> LoginAsync()
    {
        using (HttpClient clientLogin = new HttpClient())
        {
            //....
        }
        return sessionId;
    }

I declared the following variable inside my class

public class BillComService : IBillComService
{
    private static Lazy<string> SessionId;

and init it in constructor:

    public BillComService()
    {
        if (SessionId == null)
            SessionId = new Lazy<string>(() => LoginAsync().Result);
        //....
    }

then I use it inside my methods:

    private async Task<T> Read<T>(string id, string endpoint)
    {
        var nvc = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("devKey", devKey),
                new KeyValuePair<string, string>("sessionId", SessionId.Value)
            };

ok, it's fine. Think about sessionId is expired. Method with throw BillComInvalidSessionException

Right now I wrote the following method to repeat my request after calling LoginAsync method if sessionId is expired. Common method:

    private async Task<T> Retry<T>(Func<Task<T>> func)
    {
        try
        {
            return await func();
        }
        catch (BillComInvalidSessionException)
        {
            SessionId = new Lazy<string>(() => LoginAsync().Result);
            return await Retry(func);
        }
    }

and for Read:

    private async Task<T> ReadWithRetry<T>(string id, string endpoint)
    {
        return await Retry(async () => await Read<T>(id, endpoint));
    }

so, my public method is:

    public async Task<Customer> GetCustomerAsync(string id)
    {
        return await ReadWithRetry<Customer>(id, "Crud/Read/Customer.json");
    }

it works and work fine. But I'm not sure, whether it's thread-safe :)

Aucun commentaire:

Enregistrer un commentaire