Discussion: Directions to take async interception
See original GitHub issueWe’ve had several discussions on issues and pull requests on this repo, and on Castle.Core, and I wanted to bring it together (if possible).
Firstly, I want to thank you guys for getting involved. I imagine we’ve all got day jobs, so any time we can give to this is fantastic.
Here is my current thinking, it’s by no means an exhaustive list, it’s just what’s top of mind at the moment.
- The design of
AsyncInterceptorBase
is a mistake.- In attempting to provide just two methods to override, both of which are asynchronous, it has made synchronous interception problematic with the potential of causing deadlocks when transitioning back from the asynchronous interceptor to the underlying synchronous method being intercepted.
- Here’s my comment on PR #54 going into a little more detail.
- I, therefore, agree with @brunoblank in his comment here on PR #40, specifically “I think the AsyncInterceptorBase should be deleted. But, it brings nice abstract methods.”
- What to do with return value?
- I think one of the challenges we’ve had with async before Proceed has been to do with the return value being out of band and as a result out of our control.
- I like the idea raised by @brunoblank in PR #40, and I wonder what other’s think.
- I believe you @stakx think differently, though I can’t remember the comment that gave me that impression.
- Closely align with the design of Castle.Core
- This is related to the return value discussion since the design of the IInvocaton has the return value as a property.
- I think it is a benefit to match the design of Castle.Core as it adheres to the Principle of least astonishment and developers familiar with Castle.Core will find it easier to pick up AsyncInterceptor.
- Close alignment to Castle.Core may improve the chances of this becoming incorporated into Castle.Core. This is something I considered when I first started this library, and I’ve received comments along that line on other issues. Thoughts @stakx?
The current alpha introduces some breaking changes, and I believe we must introduce more, given point 1. I think now is an excellent time to tackle some other gnarly issues if you guys are happy to get involved?
All views regretfully received.
Issue Analytics
- State:
- Created 4 years ago
- Comments:16 (4 by maintainers)
Top Results From Across the Web
Core/docs/dynamicproxy-async-interception.md at master
This article discusses several interception scenarios related to ... This article contains C# code examples that make use of the async / await...
Read more >Intercepting Asynchronous Methods Using Unity Interception
We discussed several strategies for intercepting asynchronous methods and demonstrated them on an example that logs the completion of asynchronous operations.
Read more >Using an async method in a RxJS NextObserver
I'm trying to use an async function in a NestJS interceptor. These interceptors use RxJS Observables like this:
Read more >Intercepting HTTP Requests with Playwright
In this post, we take a look at the benefits and possibilities while intercepting HTTP requests in your Playwright tests.
Read more >Interceptors | NestJS - A progressive Node.js framework
Hint Nest interceptors work with both synchronous and asynchronous intercept() methods. You can simply switch the method to async if necessary. With the...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
When using the Castle.Core - IInterceptor for synchronous operations is straight forward and works very well. So having the IAsyncInterceptor align with Castle.Core being asynchronous would look like this
note: that there must be two separate methods for synchronous vs asynchronous as we do not want to introduce sync-over-async or async-over-sync problems
However, when trying to use the same concept for asynchronous is hard. Accessing the ReturnValue and casting it is problematic as
Task<object>
is not compatible withTask<string>
. This could be solved by adding a generic based asynchronous “overload”.So when implementing an interceptor based on this interface (not addressing the async before proceed problem) is when can/should
invocation.ReturnValue
be read/written. Calling Proceed in the asynchronous case must read the return-value and await and the method must also set return-value before doing any await in order not to break.I think this should be handled by AsyncInterceptor. This can be solved by taking care of return-values which would make this IAsyncInterceptor look like this:
From the discussions in PR 428 - castle.core.
Now we make break out the
Proceed
usage to own method (also: handling the CaptureProceedInfo in library).The the last touch is to make an
IAsyncInvocation
that hidesProceed
andReturnValue
fromIInvocation
just to remove possibility to use it the wrong way.Hey everyone, I’d like to share something with you that I cooked up just now.
A little earlier today, I was looking at the code produced by the C# compiler for
async
methods containing anyawait
s. I had the thought that it might be possible to follow the same pattern inside a DynamicProxyIInterceptor
, and I came up with an alternateAsyncInterceptor
base class. (Its public interface is close to what I described in my above posts.)If you’re interested and if you would like to take a look, here’s the resulting code: https://github.com/stakx/DynamicProxy.AsyncInterceptor. (It’s only a draft at this stage, though it appears to work, at least in the few simple cases that I’ve tested.)