base.SendAsync -How symmetrical execution was done? - c#

In asp.net - using Message Handlers - I can customize the request/response by adding message handlers.
So, a request comes in , going through multiple message handlers and then the response is back through the same handlers( in opposite direction).
So, for example : if I attach 2 message handlers : (yes I know, async/await is preferred, but that's from a book)
public class CustomMessageHandler1 : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Debug.WriteLine("CustomMessageHandler1 request invoked");
return base.SendAsync(request, cancellationToken)
.ContinueWith(task =>
{
Debug.WriteLine("CustomMessageHandler1 response invoked");
var response = task.Result;
return response;
});
}
}
public class CustomMessageHandler2 : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Debug.WriteLine("CustomMessageHandler2 request invoked");
return base.SendAsync(request, cancellationToken)
.ContinueWith(task =>
{
Debug.WriteLine("CustomMessageHandler2 response invoked");
var response = task.Result;
return response;
});
}
}
Let's not forget to register those in global.asax :
var config = GlobalConfiguration.Configuration;
config.MessageHandlers.Add(new CustomMessageHandler1());
config.MessageHandlers.Add(new CustomMessageHandler2());
And the result is :
As you can see , like I said and like this article says : The execution is symmetrical.
Great.
But then I thought to myself - how did they do that symmetrical execution?
So I succeed creating my own demo of symmetrical execution using continuation:
void Main()
{
Method1() ;
}
public async Task Method1 ()
{
Console.WriteLine ("Method_1"); //alias to request
await Method2();
Console.WriteLine ("Finished Method_1"); //alias to response
}
public async Task Method2 ()
{
Console.WriteLine ("Method_2"); //alias to request
await Task.FromResult("...");//dummy
Console.WriteLine ("Finished Method_2"); //alias to response
}
And the result was indeed symetrical :
Method_1
Method_2
Finished Method_2
Finished Method_1
But in my code Method1 called Method2 and that's why it worked !.
But in the first code above - they do NOT call each other ! it's like something is invoking only the first part ( before the ContinueWith) from each method , and then run the second part( after the ContinueWith) from each method.
Something like :
So i've look at the reference source for base.Sendasync : But couldn't find how base.Sendasync is doing this symmetrical execution
Question
How does base.Sendasync is doing that symmetrical execution without having one method calling the other?

Here is the console-appified Web API pipeline for you.
abstract class BaseHandler // HttpHandler
{
public abstract Task MyMethodAsync();
}
abstract class Handler : BaseHandler // MessageHandler
{
public Handler InnerHandler { get; set; }
public override Task MyMethodAsync()
{
if (this.InnerHandler != null)
return this.InnerHandler.MyMethodAsync();
else
return Task.FromResult<object>(null);
}
}
class Handler1 : Handler
{
public override async Task MyMethodAsync()
{
Console.WriteLine("Method_1"); //alias to request
await base.MyMethodAsync();
Console.WriteLine("Finished Method_1"); //alias to response
}
}
class Handler2 : Handler
{
public override async Task MyMethodAsync()
{
Console.WriteLine("Method_2"); //alias to request
await base.MyMethodAsync();
Console.WriteLine("Finished Method_2"); //alias to response
}
}
class LastHandler : Handler
{
public override async Task MyMethodAsync()
{
// Does nothing
await base.MyMethodAsync();
}
}
class Program
{
static void Main(string[] args)
{
List<Handler> handlers = new List<Handler>();
// You do this when you add the handler to config
handlers.Add(new Handler1());
handlers.Add(new Handler2());
// This part is done by HttpClientFactory
Handler pipeline = new LastHandler();
handlers.Reverse();
foreach (var handler in handlers)
{
handler.InnerHandler = pipeline;
pipeline = handler;
}
pipeline.MyMethodAsync().Wait();
}
}

Each delegating handler is aware of its "next" handler, and DelegatingHandler.SendAsync does call SendAsync on the next ("inner") handler. You can think of it like a linked list, as such:
public abstract class MyDelegatingHandler
{
private readonly MyDelegatingHandler _next;
public MyDelegatingHandler(MyDelegatingHandler next = null)
{
_next = next;
}
public virtual Task SendAsync()
{
if (_next == null)
return Task.FromResult(0);
return _next.SendAsync();
}
}

Related

what pattern can be used here to preview this result?

I have a method to make an order,
public async Task<bool> Order(Request request)
{
// Each step does different things.
await Step1(request);
await Step2(request);
await Step3(request);
await Step4(request);
...
await StepN(request);
}
public async Task<bool> Step1(Request request)
{
var amount1 = await changeSomething1(request);
await Pay1(amount1);
}
public async Task<bool> Step2(Request request)
{
var amount2 = await changeSomething2(request);
await Pay2(amount2);
}
public async Task<bool> StepX(Request request)
{
var amountX = await changeSomethingX(request);
await PayX(amountX);
}
Now I need to preview the Order without any PayX(amount) is called. I don't want to add a boolen parameter to skip it, like the following code, which looks pretty ugly.
public async Task<bool> Order(Request request, bool preview = false)
{
await Step1(request, preview);
await Step2(request, preview);
await Step3(request, preview);
await Step4(request, preview);
....
await StepN(request, preview);
}
public async Task<bool> StepX(Request request, bool preview = false)
{
var amountX = await changeSomethingX(request);
if(!preview) await PayX(amountX);
}
What pattern can be applied here? Thanks a lot.
It seems to me that you need some middleware-like pattern (Just like middlewares in Asp.Net for example). That's my proposal:
First create An OrderMiddleware class that encapsulates your 2 methods, Step and Pay. In this case we pass step and pay as delegates to the constructor to achieve maximum flexibility
public delegate Task<int> StepDelegate(Request request);
public delegate Task PayDelegate(int amount);
public class OrderMiddleware
{
// Private fields
private readonly StepDelegate _step;
private readonly PayDelegate _pay;
// Initialization
public OrderMiddleware(StepDelegate step, PayDelegate pay)
{
_step = step;
_pay = pay;
}
// Public
public async Task Order(Request request, bool preview)
{
var amount = await _step.Invoke(request);
if (!preview)
await _pay.Invoke(amount);
}
}
Then you need a class to handle a list of OrderMiddlewares that represent your complete pipeline.
public class OrderPipeline
{
// Private fields
private readonly List<OrderMiddleware> _orderMiddlewares;
// Initialization
public OrderPipeline()
{
_orderMiddlewares = new()
{
new(Step1, Pay1),
new(Step2, Pay2)
};
}
// Order Handling
public async Task Order(Request request, bool preview = false)
{
foreach(var middleware in _orderMiddlewares)
await middleware.Order(request, preview);
}
// Middlewares
public async Task Step1(Request request)
{
var amount1 = await changeSomething1(request);
await Pay1(amount1);
}
public async Task Step2(Request request)
{
var amount2 = await changeSomething2(request);
await Pay2(amount2);
}
}
In this way you order method can work with a list of middlwares.
Just few notes:
If you need to pass other parameters to every middleware, in addiction to the preview bool, consider to create a OrderConfiguration class that encapsulates all these data, and pass it instead. In that way the signature remains clean and you do not need to do any refactoring
Maybe you want to separate you middleware registration logic from your OrderPipeline class in order to not violate the open-closed principle:
public class OrderPipeline
{
// Private fields
private readonly List<OrderMiddleware> _orderMiddlewares = new();
// Order Handling
public async Task Order(Request request, bool preview = false)
{
foreach(var middleware in _orderMiddlewares)
await middleware.Order(request, preview);
}
public void AddMiddleware(OrderMiddleware orderMiddleware)
{
_orderMiddlewares.Add(orderMiddleware);
}
}

How properly wrap async http requests into success and fail callbacks

I'm refactoring old code which does synchronous http requests and returns Callback object with success and fail events. How to properly wrap code into async/await?
I've added HttpClient class and I'm using SendAsync method on which I await, but I'm not sure how properly make transition from await into events. I've added async void Execute method in class but it does not seem like correct way of handling - avoid async void. Below more explanation in (short version of) code.
public class HttpExecutor(){
public event Action<string> Succeed;
public event Action<ErrorType, string> Failed;
private bool isExecuting;
//I know that async void is not the best because of exceptions
//and code smell when it is not event handler
public async void Execute()
{
if (isExecuting) return;
isExecuting = true;
cancellationTokenSource = new CancellationTokenSource();
try
{
httpResponseMessage =
await httpService.SendAsync(requestData, cancellationTokenSource.Token).ConfigureAwait(false);
var responseString = string.Empty;
if (httpResponseMessage.Content != null)
{
responseString = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
}
if (httpResponseMessage.IsSuccessStatusCode)
{
Succeed?.Invoke(responseString);
return;
}
Failed?.Invoke(httpResponseMessage.GetErrorType(),
$"{httpResponseMessage.ReasonPhrase}\n{responseString}");
}
//Catch all exceptions separately
catch(...){
}
finally
{
Dispose();
}
}
}
public class UserService(){
public CallbackObject<User> GetUser(){
var executor = new HttpExecutor(new RequestData());
//CallbackObject has also success and fail, and it hooks to executor events, deserializes string into object and sends model by his own events.
var callback = new CallbackObject<User>(executor);
executor.Execute();//in normal case called when all code has possibility to hook into event
return callback;
}
}
I feel that I should change method to:public async Task ExecuteAsync(){...} but then I would need take thread from thread pool by doing: Task.Run(()=>executor.ExecuteAsync());
It seems like it's a bit of fire and forget, but with callbacks (I await for response from network). How to handle this properly?
I'm refactoring old code which does synchronous http requests and returns Callback object with success and fail events. How to properly wrap code into async/await?
You get rid of the callbacks completely.
First, consider the failure case. (ErrorType, string) should be made into a custom Exception:
public sealed class ErrorTypeException : Exception
{
public ErrorType ErrorType { get; set; }
...
}
Then you can model Succeed / Failed callbacks as a single Task<string>:
public async Task<string> ExecuteAsync()
{
if (isExecuting) return;
isExecuting = true;
cancellationTokenSource = new CancellationTokenSource();
try
{
httpResponseMessage = await httpService.SendAsync(requestData, cancellationTokenSource.Token).ConfigureAwait(false);
var responseString = string.Empty;
if (httpResponseMessage.Content != null)
{
responseString = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
}
if (httpResponseMessage.IsSuccessStatusCode)
return responseString;
throw new ErrorTypeException(httpResponseMessage.GetErrorType(),
$"{httpResponseMessage.ReasonPhrase}\n{responseString}");
}
catch(...){
throw ...
}
finally
{
Dispose();
}
}
Usage:
public Task<User> GetUserAsync()
{
var executor = new HttpExecutor(new RequestData());
var text = await executor.ExecuteAsync();
return ParseUser(text);
}

(A)wait for class to finish instantiate

I try to wait for the class to be finished with instantiate.
My architecture is the following. Cook is inheriade from CookChief.
And if I instantiate cook, CookChief is creating himself, but CookChief is calling 1 other class named Cookhelper the cookhelper is waiting for a input and for this input method i want to wait in Cook.
The thing is iam creating this in MVVM Galasoft and my entry point is the CookViewmodel, with a relaycommand.
In the code below you can see my architecture. To say it short I want to wait until this bool processed = await Task.Run(() => ValidateForDeviceId()); is finished.
My first step was to outsource the constructer of each class. And create a init method.
This is my code:
public CookViewModel()
{
startCookButtonCommand = new RelayCommand(Cook);
}
private async Task Cook()
{
cook.Init();
}
public class Cook : CookChief
{
public Cook()
{
}
public async Task Init()
{
await this.CookChiefInit();
//here I want to wait until CookChiefInit is finished
Cooking();
}
public void Cooking()
{
MessageBox.Show("Input received");
}
}
Now the Cookchief:
public Cookchief()
{
}
protected async Task CookchiefInit()
{
this.Cookhelper = new Cookhelper();
Cookhelper.CookHelperInit();
}
And in the CookHelper we do this:
public CookHelper()
{
}
public void CookHelperInit()
{
this.driverWindow = new DriverWindow();
startProc();
}
private async void startProc()
{
ShowOrCloseDriverWindow(true);
//this is the task what we wait for before we can repeat
bool processed = await Task.Run(() => ValidateForDeviceId());
if(processed)
{
ShowOrCloseDriverWindow(false);
}
else
{
MessageBox.Show("DriverError");
}
}
private bool ValidateForDeviceId()
{
for (; ; )
{
this.deviceId = Input.deviceId;
if (deviceId > 0)
{
break;
}
}
return true;
}
Per the discussion in the comments, the problem here was that the initialization routine mixed synchronous and asynchronous methods and calls. Additionally, some async methods were called without the await keyword. The solution was to make all calls asynchronous and await them.
cook.Init() needs an await:
private async Task Cook()
{
await cook.Init();
}
In CookchiefInit(), the CookHelperInit() call needs to be awaited:
protected async Task CookchiefInit()
{
this.Cookhelper = new Cookhelper();
Cookhelper.CookHelperInit();
}
In order to await CookHelperInit(), it needs to be made asynchronous. The startProc() call is to an async method, so it must also be awaited:
public async Task CookHelperInit()
{
this.driverWindow = new DriverWindow();
await startProc();
}

BufferBlock.ReceiveAsync hangs in a HostedService

I'm trying to use an IHostedService as a fire-and-forget email sender in an ASP.NET Core application. It looks like the best way to do this is using the BufferBlock class; the trouble is, ReceiveAsync never finishes, even when I post new items into the BufferBlock.
Here is the HostedService base class:
public abstract class HostedService
{
private Task _executingTask;
private CancellationTokenSource _cts;
public Task StartAsync(CancellationToken cancellationToken)
{
_cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
_executingTask = ExecuteAsync(_cts.Token);
return _executingTask.IsCompleted ? _executingTask : Task.CompletedTask;
}
public async Task StopAsync(CancellationToken cancellationToken)
{
if (_executingTask == null)
{
return;
}
_cts.Cancel();
await Task.WhenAny(_executingTask, Task.Delay(-1, cancellationToken));
cancellationToken.ThrowIfCancellationRequested();
}
protected abstract Task ExecuteAsync(CancellationToken cancellationToken);
}
from which my EmailService is derived as follows:
public sealed class EmailService : HostedService, IEmailService
{
private readonly ISendEmail _emailClient;
private readonly BufferBlock<MailMessage> _emailQueue;
public EmailService(ISendEmail emailClient)
{
_emailClient = emailClient;
_emailQueue = new BufferBlock<MailMessage>();
}
public void EnqueueEmail(MailMessage email)
{
var accepted = _emailQueue.Post(email);
}
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
var nextEmail = await _emailQueue.ReceiveAsync(cancellationToken).ConfigureAwait(false);
await _emailClient.SendMailAsync(nextEmail);
}
}
}
The IEmailService interface is just a simple fire-and-forget method:
public interface IEmailService : IHostedService
{
void EnqueueEmail(MailMessage email);
}
So this should all be enough. Within my controllers, I should be able to inject an IEmailService, and then enqueue messages as required. The problem is that when I run the following test:
[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
[InlineData(10)]
public async Task Emails_are_sent_after_they_are_enqueued(int emailCount)
{
for (var i = 0; i < emailCount; ++i)
{
_emailService.EnqueueEmail(new MailMessage());
}
await _testEmailClient.WaitForEmailsToBeSentAsync(emailCount);
}
the ReceiveAsync method never completes. I have tried using ConfigureAwait(false), but this seems to have no effect.
Within my tests, the HostedService is started by the ASP.NET Core pipeline, and ExecuteAsync is entered. I would expect ReceiveAsync to complete when an item is available in the BufferBlock, but there must be some threading subtlety I'm missing.
The problem was that my IoC container was wiring up multiple instances of IEmailService, and the instance that was calling ReceiveAsync was different to the instance that was calling Post. This is because EmailService was an instance both of IEmailService and IHostedService.
The answer was to ditch IEmailService altogether. To use EmailService in production code, I can inject an IEnumerable<IHostedService> instance, then pull my EmailService from that collection using OfType<EmailService>().First().

DelegatingHandler not getting invoked if exception caught by ExceptionHandler

I am trying to understand how Web API Http pipeline works!
In my Web API project, I am using the following technique to log/handle exceptions:
ExceptionHandler -> Handle exceptions at the global level
ExceptionFilterAttribute -> Handle custom exception thrown by user
DelegatingHandler -> log request and response data
Sample code for each implementation:
ExceptionFilter:
public class CustomExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
var request = context.ActionContext.Request;
if (context.Exception is ItemNotFoundException)
{
context.Response = request.CreateResponse(HttpStatusCode.NotFound, context.Exception.Message);
}
else if (context.Exception is InvalidRequestException)
{
context.Response = request.CreateResponse(HttpStatusCode.BadRequest, context.Exception.Message);
}
}
}
Exception Handler:
public class GlobalExceptionHandler : ExceptionHandler
{
public override void Handle(ExceptionHandlerContext context)
{
var result = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent(Constant.ErrorMessage.InternalServerError)
};
context.Result = new ErrorMessageResult(context.Request, result);
}
}
public class ErrorMessageResult : IHttpActionResult
{
private readonly HttpRequestMessage _request;
private readonly HttpResponseMessage _httpResponseMessage;
public ErrorMessageResult(HttpRequestMessage request, HttpResponseMessage httpResponseMessage)
{
_request = request;
_httpResponseMessage = httpResponseMessage;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
return Task.FromResult(_httpResponseMessage);
}
}
DelegatingHandler:
public class LogRequestAndResponseHandler : DelegatingHandler
{
private readonly ILoggingService _loggingService;
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
string requestBody = await request.Content.ReadAsStringAsync();
_loggingService.FirstLevelServiceLog(requestBody);
var result = await base.SendAsync(request, cancellationToken);
if (result.Content != null)
{
var responseBody = await result.Content.ReadAsStringAsync();
_loggingService.FirstLevelServiceLog(responseBody);
}
return result;
}
}
Observation:
When there is an custom exception CustomExceptionFilter is getting invoked and later the response is logged in LogRequestAndResponseHandler.
However, if the exception is not handled, it goes in GlobalExceptionHandler then the response DOES NOT come to LogRequestAndResponseHandler for logging.
Could anyone let me know, what code change have to be done in CustomExceptionFilter/GlobalExceptionHandler in order to receive the response in DelegatingHandler?
Solution: (Updated 10/09/2018)
Okay, so i found the solution here
By modifying ExceptionHandler code, i am able to catch the response in DelegatingHandler
Key was to inherit from IExceptionHandler rather than ExceptionHandler
Code:
public class GlobalExceptionHandler : IExceptionHandler
{
public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
var httpResponse = context.Request.CreateResponse(HttpStatusCode.InternalServerError, Constant.ErrorMessage.InternalServerError);
context.Result = new ResponseMessageResult(httpResponse);
return Task.FromResult(0);
}
}
Question:
I am still not able to understand how it's working? What is the difference between IExceptionHandler & ExceptionHandler?
Could anyone shed some light on this?
ExceptionHandler implements IExceptionHandler like this:
Task IExceptionHandler.HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
if (context == null)
throw new ArgumentNullException(nameof (context));
ExceptionContext exceptionContext = context.ExceptionContext;
if (!this.ShouldHandle(context))
return TaskHelpers.Completed();
return this.HandleAsync(context, cancellationToken);
}
Where I suspect you're seeing the difference is in that ShouldHandle check, which is implemented like this:
public virtual bool ShouldHandle(ExceptionHandlerContext context)
{
if (context == null)
throw new ArgumentNullException(nameof (context));
return context.ExceptionContext.CatchBlock.IsTopLevel;
}
I'm not intimately familiar with the pipeline, but from what I've seen it appears that exceptions can be handled at various points, and the ExceptionHandler base class assumes you probably only want to handle exceptions at the top level of the execution stack. I've seen cases where other handlers like CORS get in the way of this, and the catch block never ends up being at the top level.
If this is what you're seeing, you can still extend ExceptionHandler, and override the ShouldHandle method to just always return true. Or you could be more surgical and specifically detect whether CORS is likely to get in the way of the top-level check as suggested in this comment.

Categories