locked
Async on interface not allowed, how to await then? RRS feed

  • Question

  • I have a class with async method, but this class is not exposed to client code directly only via interface. The problem is that I can't await result in client code, so looks like I have to mess with ContinueWith but it ruins all the beauty.

    Any ideas? Thanks!

    • Moved by John Boylan Monday, January 14, 2013 9:32 PM
    Thursday, October 13, 2011 1:10 PM

Answers

All replies

  • You should be able to declare your interface method as returning Task or Task<TResult>.

    The class could use async/await to implement the method.

    Clients of the interface should be able to use async/await to consume the method. Note that it is the Tasks that are awaitable, not async methods.

           -Steve


    Programming blog: http://nitoprograms.blogspot.com/
      Including my TCP/IP .NET Sockets FAQ
      and How to Implement IDisposable and Finalizers: 3 Easy Rules
    Microsoft Certified Professional Developer

    How to get to Heaven according to the Bible

    Thursday, October 13, 2011 2:43 PM
  • Clients should be but can't. I try to await interface method I get:

    The 'await' operator can only be used in a method or lambda marked with the 'async' modifier

    Thursday, October 13, 2011 2:56 PM
  • Ok, I just misread error. :)
    Thursday, October 13, 2011 2:58 PM
  • Does Microsoft you have any article, blog or msdn article outlining the design pattern mentioned here?
    Thursday, October 27, 2011 1:03 AM
  • Hi Hamish-

    An article on the task-based async pattern?  I'd suggest this article:

    http://www.microsoft.com/download/en/details.aspx?id=19957

    I hope that helps.

    Sunday, October 30, 2011 2:29 AM
    Moderator
  • So, I have been reading other blog posts about Interfaces not being able to be declared as async and that this is because it is an implementation detail.  But as Jabberwok points out in this question the consumer of the interface cannot await the async implementation of the method.

    This is no different than it was before .NET 4.5 as async was not around then.  However, now that we have async wouldn't we want the ability to use the syntactic sugar and enforce an interface implementation to be asynchronous?  If we were able to force a method to be async at the interface level, then on the consumer we would be able to use await.


    Patrick

    Thursday, January 3, 2013 9:58 PM
  • Jabberwock misread his error.

    Clients can await the async implementations of Task-returning methods.

           -Steve


    Home page: http://stephencleary.com/
    Programming blog: http://nitoprograms.blogspot.com/

    How to get to Heaven according to the Bible

    Friday, January 4, 2013 10:28 PM
  • Did you ever get a response?  I've read this page, but don't see a solution.  I see the same errors you describe here.

    Friday, July 26, 2013 10:06 PM
  • Spelled out in more detail:

    This is the signature of an async method that can be awaited and which uses await internally:

    public async Task<int> GetNextNumberAsync(int numberBefore) {
    /* ... */
    }

    Of the parts in the signature, "async" tells the compiler to enable use of "await" inside the method body, making sure that you only need to return something of type int. "async" is not carried through to the method listing of the class (it shows up as "public Task<int>...") and does not magically make the method run asynchronously (indeed you'll get a warning if awaits are missing, and you can write asynchronous methods that are not marked as "async" by providing the asynchrony in some other way). "async" is only used to tell the compiler what to do with that method implementation.

    In an interface, the implementation is by definition in the class implementing the interface, not in the interface itself. So the type is the same but "async" can't be provided because there's no implementation of the method inside the interface. "async" isn't used to make the method awaitable (although thanks to returning Task<T>, it is indeed awaitable), it is used so that the method implementation may itself await things.

    So what goes in the interface for the above method?

    interface INumberAdder { Task<int> GetNextNumberAsync(int numberBefore); } class ImplementationOfNumberAdder : INumberAdder { public async Task<int> GetNextNumberAsync(int numberBefore) {
    /* implementation using await on some other methods here */
    } }

    class OtherImplementationOfNumberAdder : INumberAdder {
    // no async here:
    public Task<int> GetNextNumberAsync(int numberBefore) {
    // implement by some other mechanism
    }
    }

    // in other code // assuming INumberAdder numberAdder int nextNumber = await numberAdder.GetNextNumberAsync(42);

    So how can you still await that method? No matter which class the object in "numberAdder" is an instance of in the sample, the result can be awaited because "async" does not make the method awaitable, the correct return type does - in this case, Task<T>.


    • Edited by JesperTreetop Tuesday, July 30, 2013 12:40 AM Clarify (var swapped for int)
    Monday, July 29, 2013 11:28 PM
  • the problem I am having is the compiler doesn't know the implementation

    I'm importing my interfaces with MEF. I have not been able to get the compiler to let me do this. I really don't expect it to without some level of interface / contract enforcement.

    // interface is in contract assembly
    public interface IDataService
    {
       Task<DataItem> GetData();
    }
    
    
    // implemented in a service assembly
    public class DataService : IDataService
    {
       public async Task<DataItem> GetData()
       {
          return await db.DataItems.FirstAsync();
       }
    }
    
    
    // consumer - mvc controller using async pattern
    
    [Import]
    IDataService _dataService;
    
    public async Task<ActionResult> Index()
    {
       var data = await _dataService.GetData(); // Error here
       return View(data);
    }

    Thursday, December 19, 2013 12:24 AM
  • You don't await a method, and the compiler doesn't need to know the implementation. You're awaiting the Task returned by the method.

    That's why you don't include "async" in an interface declaration. Because it doesn't matter how the implementation produces its Task. It only matters that it returns one. All Task instances are awaitable, no matter where they come from.

    So the following are equivalent:

    var data = await _dataService.GetData();
    var data = await (_dataService.GetData()); // this is the precedence applied
    Task<DataItem> task = _dataService.GetData();
    var data = await task;

    And the following compiles without error:

    public interface IDataService
    {
        Task<int> GetData();
    }
    
    class Usage
    {
        IDataService _dataService;
    
        public async void Method()
        {
            int data = await _dataService.GetData();
            Console.WriteLine(data);
        }
    }
    Saturday, December 28, 2013 10:29 PM