I have created a Web API app and don't understand how my Global Exception Handling works. The following code doesn't work:
public void Handle(ExceptionHandlerContext context){
if (context.Exception is ObjectNotFoundException)
{
var result = new HttpResponseMessage(HttpStatusCode.NotFound)
{
Content = new StringContent(context.Exception.Message),
ReasonPhrase = "Nothing here for you"
};
context.Result = new ObjectNotFoundException(context.Request, result);
}
}
But this works fine:
public override void Handle(ExceptionHandlerContext context){
if (context.Exception is ObjectNotFoundException)
{
var result = new HttpResponseMessage(HttpStatusCode.NotFound)
{
Content = new StringContent(context.Exception.Message),
ReasonPhrase = "Nothing here for you"
};
context.Result = new ObjectNotFoundException(context.Request, result);
}
}
In you code, the only difference is the override keyword. Hence that's the source of problem here.
Since the method Handles requires to be overridden from the base abstract class ExceptionHandler, you need to use the override keyword.
Without override, you are creating a new implementation and removing the base implementation out there. Hence the method invocation gets removed from pipeline and is equivalent to no such method being present out there.
if you want to do async handling, you need to use "HandleAsync" method instead of "Handle".. https://msdn.microsoft.com/en-us/library/system.web.http.exceptionhandling.exceptionhandler.handleasync(v=vs.118).aspx
Any async handler will be just enable non-blocking execution. Hence if your logging/handling takes quite long, or there's an expected load out there due to too many requests in pipeline, use async.
Related
I am using log4net (.Net) to write kafka appender and I am running into an issue where I cannot use await ProduceAsync.
Error
An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%# Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it. ,
StackTrace : at
System.Web.AspNetSynchronizationContext.OperationStarted(at System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Create()
Code
public class CustomAppender: AppenderSkeleton
{
private IProducer<Null, string> p;
public override void ActivateOptions()
{
// Setup kafka producer
}
protected override void Append(LoggingEvent loggingEvent)
{
// Get JSON from application
// Add additional data to the json
callBroker(json, topic);
}
private async void callBroker(string json, string topic)
{
var result = await p.ProduceAsync(Topic, new Message<Null, string>{Value=json});
}
}
I can return Task in my callBroker method but then there is no async override for Append method.
So my question is, Can I use Producer.Produce instead of ProduceAsync in a high volume environment? this program will be logging >500 messages/sec, is there a preference on which works better? I also need to handle some exceptions and take some action if it fails for specific error codes.
Sync version
protected override void Append(LoggingEvent loggingEvent)
{
CallBroker(topic, json);
}
private void CallBroker(string topic, string message)
{
producer.Produce(topic, new Message<Null, string> { Value = message });
}
Semi-async version
If you can't change the signature of the Append method
then you can call an async method in blocking mode via the following way:
protected override void Append(LoggingEvent loggingEvent)
{
CallBrokerAsync(topic, json).GetAwaiter().GetResult();
}
private async Task CallBrokerAsync(string topic, string message)
{
await producer.ProduceAsync(topic, new Message<Null, string> { Value = message });
}
Async shines when it is used all the way down (from the top most entry-point through all the layers till the lowest component which calls the async I/O operation)
As always measure, measure and measure to understand how does this change affect your application.
I have a AuthorizationHandler depending on a Service offering async methods for .NET Core 3.1's Authorization Middleware. I have o call some of these async methods inside the HandleRequirementAsync method. The overall code looks like this:
{
public class MyAuthorizationHandler : AuthorizationHandler<MyRequirement, Tuple<string, string>>
{
private readonly IAuthIntelRepository authIntelRepository;
public UserAssistanceAuthorizationHandler(IAuthIntelRepository authIntelRepository)
{
this.authIntelRepository = authIntelRepository;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyRequirement requirement, Tuple<string, string> someRessource)
{
//some async calls to authIntelRepository
if (/*someCondition*/false)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
public class MyRequirement : IAuthorizationRequirement { }
}
As soon is I use an await statement though, I get an error that the signature isn't explicitly set as async. Adding async to the inherited method's signature causes the following error.
a return keyword must not be followed by an object expression. Did you intend to return 'Task<T>'?
This thread elaborates a similar issue but the solution doesn't seem to work in .NET Core 3.1.
Using Result in the following manner works, but AFAIK this will result in a blocking call:
Task<Object> obj= this.authIntelRepository.getSomeAsync(...);
obj.Result.property //do Something to check the requirement
I'm not sure what the correct solution would look like here.
If the return type of your async method is Task, then, apart from the await keyword, your treat your method as if it was void returning:
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, MyRequirement requirement, Tuple<string, string> someRessource)
{
await authIntelRepository....
if (/*someCondition*/false)
{
context.Succeed(requirement);
}
return;
}
Adding async to HandleRequirementAsync and use await to call the async method inside HandleRequirementAsync breaks the authorization, try calling external db or httpClient (delays), Type in the browser the route address with authorization. The route will be redirected to the non authorized page even though the context.Succeed(requirement) is executed .
The working solution for me (blazor server .NET 5) is keeping the HandleRequirementAsync as it is, execute the async method we need to call using pattern for executing async method inside non async method.
My sample working code derived from https://stackoverflow.com/a/43148321/423356
my sample async method:
public async Task<IList<Permission>> GetGroupPermissions(int userId)
{
HttpResponseMessage response = await _httpClient.GetAsync(string.Format("Auth/GroupPermissions/{0}", userId));
try
{
var payload = await response.Content.ReadFromJsonAsync<List<Permission>>();
response.EnsureSuccessStatusCode();
return payload;
}
catch
{
return new List<Permission>();
}
}
HandleRequirementAsync:
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
var t2 = (Task.Run(() => GetGroupPermissions(userId)));
t2.Wait();
var userGroupPermissions = t2.Result;
if (!userGroupPermissions.Contains(requirement.Permission))
{
//context.Fail(); //no need to fail, other requirement might success
return Task.CompletedTask;
}
context.Succeed(requirement);
return Task.CompletedTask;
}
I'm using a client library for accessing a 3rd party API. The library was generated by NSwagStudio from Swagger documentation.
The app I'm working on is entirely synchronous in all its calls and updating it to be async is out of scope of what I'm working on.
When I test the client library from a unit test, it works fine. When I try to call it from within an ASP.Net app, I get the following error:
The CancellationTokenSource has been disposed.
I've distilled the client library down to the essentials for demonstrating the problem, I selected an option to provide sync methods as well as async:
public class ClientApi
{
private readonly HttpClient _httpClient;
public ClientApi(HttpClient httpClient)
{
_httpClient = httpClient;
}
public string BaseUrl { get; set; }
public object Get()
{
return Task.Run(async () => await GetAsync(CancellationToken.None)).GetAwaiter().GetResult();
}
/// <returns>OK</returns>
/// <param name="cancellationToken">
/// A cancellation token that can be used by other objects or threads to receive notice of
/// cancellation.
/// </param>
public async Task<string> GetAsync(CancellationToken cancellationToken)
{
var client_ = _httpClient;
try
{
using (var request_ = new HttpRequestMessage())
{
request_.Method = new HttpMethod("GET");
request_.RequestUri = new System.Uri(BaseUrl, System.UriKind.RelativeOrAbsolute);
var response_ = await client_.SendAsync(
request_,
HttpCompletionOption.ResponseHeadersRead,
cancellationToken
).ConfigureAwait(false);
try
{
// Exception occurs on following line
var responseData_ = response_.Content == null
? null
: await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
return responseData_;
}
finally
{
response_?.Dispose();
}
}
}
finally { }
}
}
Here's the code that calls it:
protected void OnClick(object sender, EventArgs e)
{
var httpClient = new HttpClient();
var client = new ClientApi(httpClient)
{
BaseUrl = "https://www.google.com"
};
var html = client.Get();
}
The code calling this is just an asp.net page with a button, and the button events runs the same code as the unit test that passes.
When I compare the runs in a debugger: from a unit test, the response_.Content object does not have a cancellation token, however when run from asp.net it does. In fact they almost seem to be different objects, despite the fact GetType() reports them both as being System.Net.Http.StreamContent. From decompiling the class, this doesn't have a _cancellationtoken property, so where is the debugger getting it from?
I'm guessing that the http request to my asp.net web app has it's own token and source, that is somehow getting used by the HttpClient. However, the client is awaiting all the async calls to get the result synchronously, so I don't understand how the underlying CTS could be disposed as we haven't returned from the call the client library yet.
Can anyone understand what's happening and is there a resolution?
First of, you should really rethink of rewriting your client app so you can implement async all the way.
“Async all the way” means that you shouldn’t mix synchronous and
asynchronous code without carefully considering the consequences. In
particular, it’s usually a bad idea to block on async code by calling
Task.Wait or Task.Result.
Taken from this great guide.
Basicaly, by running async code sync you will allways do things wrong.
But if you really need one solution, start by wrapping your disposable objects in using statements instead of manually disposing them.
Here's a simplified solutions of your ClientApi class which does what you need(But it can deadlock). The code is basically the same as in this answer.
public class ClientApi
{
public object Get(string url)
{
using (var client = new HttpClient())
{
var response = client.GetAsync(url).Result;
if (response.IsSuccessStatusCode)
{
var responseContent = response.Content;
return responseContent.ReadAsStringAsync().Result;
}
}
}
}
Read more about deadlock here
Suppose I'm writing a custom MVC filter which does some asynchronous calls within the method overrides, like so:
public class MyActionFilter : System.Web.Mvc.ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext ctx)
{
var stuff = ConfigureAwaitHelper1().Result;
// do stuff
}
public override void OnActionExecuting(ActionExecutingContext ctx)
{
var stuff = ConfigureAwaitHelper2().Result;
// do stuff
}
private async Task<string> ConfigureAwaitHelper1()
{
var result = await client.GetAsStringAsync("blah.com").ConfigureAwait(false);
return result;
}
private async Task<string> ConfigureAwaitHelper2()
{
return await client.GetAsStringAsync("blah.com").ConfigureAwait(false);
}
}
Why does OnActionExecuting deadlock, whereas OnActionExecuted does not? I don't see the fundamental difference between the two. The act of returning happens only after the asynchronous task is complete, which is rather like putting the result into an "anonymous return" local var before returning it, so I don't see why the former should deadlock.
Why does OnActionExecuting deadlock, whereas OnActionExecuted does not?
I'm surprised it works at all. The reason you're experiencing the deadlock is due to the fact that you're invoking a .Result on a Task. This is evil and you should only ever invoke .Result and .Wait in console applications.
How can I make IsAuthorized return my custom object while function returns false?
In my WebAPI project I have a class like;
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
{
StandardWebAPIResponse invalidUserResponse = new StandardWebAPIResponse()
{
code = (int) Constants.ErrorCodes.InvalidCredentials,
data = "InvalidCredentials.",
StatusCode = HttpStatusCode.Unauthorized
};
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized,
invalidUserResponse);
// if I set this to true I am getting 401 with my custom object
// otherwise it gives me default error message
// {"Message":"Authorization has been denied for this request."}
return false;
}
}
For some reason when I return false from IsAuthorized function, it does not return my custom invalidUserResponse object. But if I return true it returns it.
How can I resolve this issue?
I know this question has been answered but I feel like it is slightly wrong. I don't think that a message for unauthorized request should be handled by OnAuthorization but should be handled by HandleUnauthorizedRequest. I'm not sure if it will cause any major problems putting it in OnAuthorization, but presumably the reason you were getting the message when true and not false is because the base class writes over your response in HandleUnauthorizedRequest.
It is a subtle thing but the OnAuthorization directs to the HandleUnauthorizedRequest for a reason. It is mainly a separation of responsibilities thing, but if you ever want to do more than just sending an error message, like log bad request your OnAuthorization method will probably get crowded. You should used the methods given to you for clarity sake if nothing else.
Yes I agree. You would need to implement custom filter derived from AuthorizeAttribute.
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
base.HandleUnauthorizedRequest(actionContext);
actionContext.Response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.Unauthorized,
Content = new ObjectContent(typeof(ErrorMessage),
new ErrorMessage()
{
StatusCode = (int)HttpStatusCode.Unauthorized,
Message = Constants.UnauthorisedErrorMessage,
ErrorCode = Constants.UnauthorisedErrorCode
}, new JsonMediaTypeFormatter())
};
}
You should override the OnAuthorization method, that use the IsAuthorized and flushs the response, or force a flush at your method. Makes more sense fill the response where the filter manipulates It.