1

I am currently building an authentication interface for a 3rd parting API. I have a class called FooCredential, when the class is destructed, it needs to send a post request to the auth server to revoke the current token, this is done through an async function.

My problem is that if I want the token to be automatically revoked, I have to put the method call in the finalizer. However, I can't seem to find a way that would allow me to wait on the async call to complete. And without waiting, the call would not be complete before the main thread exit, therefore leaving the token alive.

I tried many methods to wait, including spawning a new thread in the finalizer to run a static version of the async revoke method. The thread does not seem to be executing at all in the debugger, the breakpoint does not get hit. Coming from C++, this is very strange. I also tried to implement the IDisposable, does not seems to be working too.

No IAsyncDisposable since I'm stuck on .NET framework 4.7.2.

I am completely lost at the moment. Any help is appreciated.

class FooCredential
{
    public string Token { get; set; }

    ~FooCredential()
    {
        if (Token != null)
        {
            var data = new Dictionary<string, string>
            {
                {"token", Token}
            };

            Thread t = new Thread(RevokeTokenStatic);
            t.Start(data);
            t.Join();
        }
        
    }

    private static async void RevokeTokenStatic(object param)
    {
        var data = (Dictionary<string, string>) param;
        
        string token = data["token"];
        
        var body = new Dictionary<string, string>
        {
            {"token", token}
        };
        
        var content = new FormUrlEncodedContent(body);
        await new HttpClient().PostAsync(AuthBaseUrl + "/oauth/revoke", content);
    }
}
nyjC1v2Pu8
  • 33
  • 7
  • 5
    In short, if you are using a finalizer for anything you are likely doing something wrong – TheGeneral Feb 11 '21 at 04:20
  • @00110001 Could you please elaborate a little more? I'm fairly new to c#. – nyjC1v2Pu8 Feb 11 '21 at 04:23
  • I think to achieve your desires, you'd likely just want to use the Dispose pattern. Though, personally id actually want to have discrete control over this type of behavior in code and not abstracted in an object – TheGeneral Feb 11 '21 at 04:23
  • .NET has `IDisposable` interface which you can implement in your class, looks like this is a "tool for the job" in your case. Newer version of C# support asynchronous `IDisposable`. – Fabio Feb 11 '21 at 04:25
  • @Fabio `IAsyncDisposable` would be nice, however, I'm working in a large codebase and cannot change the language standard. Unless I'm implementing it wrong, `IDisposable` still does not solve my problem, since I will still need to await on the async call for it to complete. – nyjC1v2Pu8 Feb 11 '21 at 04:28
  • 3
    A finalizer (which happens to look like a C++ destructor) is called by the garbage collector when it feels it wants to. You have no control over this (and may never run), however you do have control over the dispose pattern and be can be assured when it runs. Since this is only calling a trivial remote resource and you cant use async dispose, you can probably just easily block the result in the dispose contract. However, i would really consider making this all explicit in code, especially if you cant move to a more modern framework – TheGeneral Feb 11 '21 at 04:31
  • @Pineapple0111 Please check https://stackoverflow.com/questions/43257958/async-operation-in-destructor – Nayan Feb 11 '21 at 04:34
  • Also, disregard the above link and example. Its not a good duplicate or fit at all – TheGeneral Feb 11 '21 at 04:37
  • Create extension method for running async methods synchronously (google for solutions using `SynchronizationContext`), then implement `IDisposable` and call your async method as sync in `Dispose` method. And don't forget to `avoid async void`! – Alexey Rumyantsev Feb 11 '21 at 05:00
  • I agree with [this comment](https://stackoverflow.com/questions/66148699/awaiting-an-async-function-in-class-finalizer?noredirect=1#comment116948097_66148699). Coming from C++ it seems you simply don't understand C# finalizers. The finalizer isn't the right place to do cleanup; implementing `IDisposable` is. If you can't implement `IAsyncDisposable`, or at least, can't take advantage of it -- you can still implement it, but `await using` won't be available in older C# versions -- you'll have to deal with that yourself...lots of options, see duplicate. – Peter Duniho Feb 11 '21 at 07:44

1 Answers1

-3

Instead of using a destructor, simply call the method when the program exits, if this is a winforms app, you can hook into the WindowClosed event, then run the method.

Luke Parker
  • 299
  • 1
  • 10
  • 2
    What if object is destroyed during program lifetime? And there are many other "what ifs" to your "answer", which is bad even for comments. – Alexey Rumyantsev Feb 11 '21 at 05:06