I have a synchronous, generic method that looks like this
public TResponse Execute<TResponse>(Request request) where TResponse : Response
{
return (TResponse) proxy.ExecuteRequest(request);
the proxy is a WCF service reference
It just has one method that takes a request and returns a response. But it is used by passing derived requests and returning derived responses. As you can see above the wrapper method is casting the response to the derived type specified by the generic parameter (TResponse).
You call the method with derived requests and responses
e.g.
Execute<GetSomeDataResponse>(new GetSomeDataRequest());
I am now generating an async service reference so can make use of Tasks
So I would like a method that looks like this
public Task<TResponse> ExecuteAsync<TResponse>(Request request) where TResponse : Response
{
// need to cast to a Task<TResponse>
return proxy.ExecuteRequestAsync(request
that can be called like this
Task<GetSomeDataResponse> res = ExecuteAsync<GetSomeDataResponse>(new GetSomeDataRequest());
So I need a way to cast the Task<Response> to a Task<TResponse>
I've been reading this which seems kind of the opposite of what I need, but cant quite figure out how to bend it to my use case
How to convert a Task<TDerived> to a Task<TBase>?
any ideas?
Easy way is use async\await pattern:
public static async Task<TResponse> ExecuteAsync<TResponse>(Request request) where TResponse : Response {
var response = await proxy.ExecuteRequestAsync(request);
return (TResponse) response;
}
A bit more complicated (taken from your linked question) is to use TaskCompletionSource:
public static Task<TResponse> ExecuteAsync2<TResponse>(Request request) where TResponse : Response {
var tcs = new TaskCompletionSource<TResponse>();
proxy.ExecuteRequestAsync(request).ContinueWith(t => {
if (t.IsFaulted)
tcs.TrySetException(t.Exception.InnerExceptions);
else if (t.IsCanceled)
tcs.TrySetCanceled();
else
tcs.TrySetResult((TResponse) t.Result);
}, TaskContinuationOptions.ExecuteSynchronously);
return tcs.Task;
}
Related
I am having a service class which contains a method GetSalespersonsAsync(). It will create an object for Data Service and calls a method dataService.GetSalesPersonsAsync(). Here I need all the Data Service method calls to pass to another method in the service InitiateApiCallAsync().
public async Task<List<Salesperson>> GetSalespersonsAsync()
{
using (var dataService = DataServiceFactory.CreateDataService())
{
var response = await InitiateApiCallAsync(dataService.GetSalesPersonsAsync());
return response?.code == 0 ? response.data : null;
}
}
public async Task<TResponse> InitiateApiCallAsync<TResponse>(Task<TResponse> dataService) where TResponse : BaseAPIResponse
{
TResponse response = await dataService;
await BaseProcess(response); // async process of some internal actions with response from the method call
return response;
}
If any of the data service methods failed to pass into the InitiateApiCallAsync() method, then the compiler need to show compile time error, so that it won't be missed to pass into it in future.
Kindly provide the possible solution to handle this to avoid missing this behavior in future.
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 have implemented Mediatr in my .NET framework project and would like to use a IPipelineBehavior.
I have implemented and registered the container using the example from the project: https://github.com/jbogard/MediatR/blob/master/samples/MediatR.Examples.Unity/Program.cs
This is my Behavior
public class AuditPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly ILeaveAuditTrail _auditor;
public AuditPipelineBehavior(ILeaveAuditTrail auditor)
{
_auditor = auditor;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
if (AuditPrevented(request))
return await next();
var response = await next();
var auditLog = _auditor.CreateAuditLog(request, response);
//Dispatch audit
return response;
}
private static bool AuditPrevented<TInput>(TInput query)
{
return query.GetType().GetCustomAttributes(typeof(PreventAuditAttribute), true).Any();
}
}
And i register is like this together with my Mediatr
container.RegisterMediator(new HierarchicalLifetimeManager());
container.RegisterMediatorHandlers(applicationAssembly);
container.RegisterType(typeof(IPipelineBehavior<,>), typeof(AuditPipelineBehavior<,>));
container.RegisterType<ILeaveAuditTrail, DefaultAuditor>();
When i send the IRequest with Mediatr it is handled fine and i get the results but the AuditPipeline is not called.
If i remove the async keyword and just return next(); It works. But this way i cannot correctly intercept my response.
Also on the example Github the handle is implemented async: https://github.com/jbogard/MediatR/wiki/Behaviors
The issue was not related to the registration of Mediatror the PipelineBehavior.
When calling the mediator.Send()method it was not in an async method. .Resultwas used instead of await. Because of this the handling of the pipeline only worked when the asynckeyword was not present.
Make sure to never use the .Result to chain these async calls. Mark the controller method async and await the mediator.Send()
First of all
var myString = await actionContext.Request.Content.ReadAsStringAsync();
should always work. But it doesn't. Here we go:
AirplaneController.cs
[ValidateAirplane]
[HydrateAirplane]
public class AirplaneController : ApiController
ValidateAirplane.cs (see the amazing magic line)
public class ValidateAirplaneAttribute : FilterAttribute, IAuthorizationFilterpublic class ValidateAirplaneAttribute : FilterAttribute, IAuthorizationFilter
...
public async Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
var json = await actionContext.Request.Content.ReadAsStringAsync(); // <-- amazing magic line
return await continuation();
}
HydrateAirplane.cs
public class HydrateAirplaneAttribute : FilterAttribute, IActionFilter
...
public async Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
var json = await actionContext.Request.Content.ReadAsStringAsync();
return await continuation();
}
If I comment out the amazing magic line then json in ExecuteAuthorizationFilterAsync comes back as an empty string. However if I don't comment out the amazing magic line I get the json (the airplane JSON that came from the client).
At first I thought this might be a timing issue so I tried doing a await Task.Delay(5000) in HydrateAirplane.cs just before trying to read the json but it has no effect.
Any idea what the problem is?
This is more of a work around than an answer. If you have a better answer please share. I noticed there's a ReadAsStreamAsync and I was able to get that to work. Maybe this is a bug in WebAPI? I couldn't find the code on github so I don't know for sure. My work around is to use this extension method instead of ReadAsStringAsync:
public async static Task<string> GetRequestBody(this HttpActionContext actionContext)
{
var bodyStream = await actionContext.Request.Content.ReadAsStreamAsync();
bodyStream.Position = 0;
var bytes = new byte[bodyStream.Length];
await bodyStream.ReadAsync(bytes, 0, bytes.Length);
bodyStream.Position = 0; // <-- i don't know why but this line is important. it doesn't work on subsequent calls without this. ...to be clear, it absolutely should work. i consider this to be a WebAPI work around. that is, i should not have to ever even think about this.
return Encoding.ASCII.GetString(bytes);
}
The reason this isn't wrapped in a using is it was wrapped in a using but then WebAPI started throwing a stream is not readable error which I guess means they use the exact same stream that they return to you internally.
I've made a nice controller helper in my MVC project that allows me to return similarly structured result payloads when I make any ajax request. It looks like this:
public static JsonNetResult Responsify<T>(Func<T> func)
{
AjaxResponse response;
var result = new JsonNetResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
try
{
var resp = func();
response = AjaxResponse.SuccessResponse(resp);
result.Data = response;
}
catch (Exception e)
{
response = AjaxResponse.ErrorResponse(e.Message);
result.Data = response;
}
return result;
}
and it gets used like this:
[HttpPost]
public JsonNetResult Link(LinkInstruction instruction)
{
return ControllerHelper.Responsify(() => _linkHandler.Link(instruction));
}
where _linkHandler.Link is not async.
My issue is I have some async handlers that I would like to invoke using this pattern and I can't figure out how to await the function. I've tried Task.Factory.StartNew as well as wrapping the lambda in async/await and I can't quite figure it out.
Create a version of Responsify - call it ResponsifyAsync - that specifies that the passed Func must return a Task<T> (therefore meaning you can await it):
public async static JsonNetResult ResponsifyAsync<T>(Func<Task<T>> func)
{
...
}
This would do much what your current function does, but would await func() instead of just executing it.
You must then pass a Func delegate that returns a Task to this method. When calling an async library in the delegate, since the async method you're calling already returns a Task, this will simply take the form:
var x = await ResponsifyAsync(() => _someClass.MyMethodAsync(someParameter));
Or, if the method is parameterless...
var x = await ResponsifyAsync(_someclass.MyMethodAsync);
I'll let you flesh out the method but this format should set you off on the right lines.