7

These days it is common for the data layer to interact asynchronously with the DB:

public async Task<Customer> GetCustomer(int id)
{
  using (db = new AppDbContext())
  {
    return await db.Customers.FindAsync(id);
  }
}

With this technique, it is my understanding that all calling methods, all the way to the UI layer, then must also be defined with the async keyword. Thus you end up with an application where every method or function that eventually interacts with the DB be an async method.

This seems terribly messy and "pollutes" all the application layers with knowledge of an implementation detail inside the data layer.

Am I misunderstanding something or is this simply what one has to do?

Roger
  • 2,118
  • 1
  • 20
  • 25
  • 4
    I fail to see how you can view the difference between "I return the promise of customer information later" and "I return customer information immediately" as an implementation detail. You don't need to use the `async` contextual keyword everywhere, but it *does* make sense for it to be synchronous all the way down or asynchronous all the way down. The only exemption to this I can think of would be where you compose multiple asynchronous operations to query multiple sources, then synchronously return a composite data structure. – Jon Skeet Jan 23 '17 at 21:31
  • `"Am I misunderstanding something"` - Yes. The code should be "async all the way down". The idea is that the top-level application layer can manage operations which have asynchronous components in deeper layers that it doesn't need to know about. The components themselves still return the same information and still encapsulate how they arrive at that information. The only difference is when they return it, which is an architectural consideration and not an implementation detail. – David Jan 23 '17 at 21:32
  • Jon - It's an implementation detail in the sense that my sole reason for doing it is to increase scalability. (I'm thinking in terms of web app, not fat client where a second reason might be UI responsiveness.) There seems to be no way to implement this without it having a dramatic effect on all layers. I just wish it didn't. – Roger Jan 23 '17 at 21:57
  • 1
    @Roger: Asynchronous operations aren't an implementation detail. An implementation detail may be what *forced* you to re-structure your code to allow asynchronous operations, but that restructuring itself should ideally happen anyway in an environment where operations may or may not be synchronous. I don't see why you would want to perform asynchronous operations without your application layer knowing about it, that seems like a recipe for problems you otherwise don't need. The application host is what manages synchronization, so async operations should be known to it. – David Jan 23 '17 at 22:04

1 Answers1

10

Am I misunderstanding something or is this simply what one has to do?

No, you're right. It's just something you have to do.

This seems terribly messy and "pollutes" all the application layers with knowledge of an implementation detail inside the data layer.

Yes, those implementation details do leak, and this is unfortunate. It's just the reality of how the vast majority of computer languages work.

I tend to compare the async details to the IDisposable details. If one class implements IDisposable, then its containing (owning) classes should, etc., etc. But whether a class owns resources should really be an implementation detail.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810