I want to check if this possible, I have an MVC Controller Action method (POST) which should have 2 parallel tasks, completing one of them should return the view based on the result from task that has completed.
Task is not aweb service which has asynchronous options. Assume its more like creating a bunch of file. I really want my task as simple as this.
private static string DoStuff(int sleepTime, string input)
{
Thread.Sleep(sleepTime);
return input;
}
Task would be like - but i dont if this is correct or not because there is not 'await'
public async Task<string> DelayTimerCallAsync()
{
string msgs = DoStuff(Convert.ToInt32(
ConfigurationManager.AppSettings["DelayTimer"]),
"Timeout");
return msgs;
}
Let me know if my question is not clear or if you need more information.
From below update my 2 tasks are like this
public Task<String> DelayTimerCallAsync(CancellationToken cancellationToken)
{
return Task.Run(() =>
{
String messages = null;
return DelayTimer();
}, cancellationToken);
}
public Task<String> BlazeCallAsync(CancellationToken cancellationToken)
{
return Task.Run(() =>
{
String messages = null;
return BlazeCall();
}, cancellationToken);
}
How can I call them and use Task.WhenAny(task1, task2) ?
Not sure if I understand the question, however I'll take a stab at it.
Assuming you have "work" to do (that would normally run synchronously) but would like to wrap that in an async method, it would look sort of like the following:
public Task<String> DelayTimerCallAsync(CancellationToken cancellationToken)
{
return Task.Run(() => {
String messages = null;
/* do work here (assign messages a value) */
return messages;
}, cancellationToken);
}
If you're looking to do the opposite (run a Task synchronously) you can do so easily as well. To help, here's a simple class that makes things a bit easier:
public static class AsyncHelper
{
private static readonly TaskFactory taskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);
public static void RunSync(Func<Task> func)
{
taskFactory
.StartNew<Task>(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
return taskFactory
.StartNew<Task<TResult>>(func)
.Unwrap<TResult>()
.GetAwaiter()
.GetResult();
}
}
You then have the ability to execute Task methods without await. Something like:
// (referencing DelayTimeCallAsync above:
String messages = AsynHelper.RunSync(DelayTimeCallAsync(CancellationToken.None));
Related
I am trying to understand how MediatR works. Never used this library before. Below code is not actual production code. It is only for understanding purpose.
Lets say I have two RequestHandlers. Each handler takes ProductModel as request but returns different type of response.
public class GetOrdersHandler : IRequestHandler<ProductModel, IEnumerable<Order>>
{
private readonly FakeDataStore _fakeDataStore;
public GetOrdersHandler(FakeDataStore fakeDataStore)
{
_fakeDataStore = fakeDataStore;
}
public async Task<IEnumerable<Order>> Handle(ProductModel request,CancellationToken cancellationToken
{
return await _fakeDataStore.GetAllOrdersForProduct(request);
}
}
public class SaveProductHandler : IRequestHandler<ProductModel, Product>
{
private readonly FakeDataStore _fakeDataStore;
public SaveProductHandler(FakeDataStore fakeDataStore)
{
_fakeDataStore = fakeDataStore;
}
public async Task<Product> Handle(ProductModel request,CancellationToken cancellationToken)
{
return await _fakeDataStore.SaveProduct(request);
}
}
Then in the same controller I have two action methods
public class ProductsController : ControllerBase
{
private readonly IMediator _mediator;
public ProductsController(IMediator mediator) => _mediator = mediator;
[HttpPost]
public async Task<ActionResult> GetAllOrders(ProductModel model)
{
var product = await _mediator.Send(model);
return Ok(product);
}
[HttpPost]
public async Task<ActionResult> SaveProduct(ProductModel model)
{
var product = await _mediator.Send(model);
return Ok(product);
}
}
Based on the MediatR code this may not work. Looks like the Send method creates instance of handler based on Request type. It keeps dictionary of RequestType and corresponding handler.
If my assumption is correct then does that mean I will have to create unique request model for each action method that will be using Send method?
I have a standard .Net core Api and want to use a Open Generic IReposistory and decorate that with a DomainEventPublisher for pushing out events to servicsBus after persisting.
However, I have used Simple Injector a lot earlier which I'm a big fan of. But now when using MediatR Im trying to simplify DI by using just .net Core DI together with Scrutor package for decorating.
Problem is an error I get:
"The number of generic arguments provided doesn't equal the arity of the generic type definition." from Scrutor when trying to register decorator in Startup (2nd line below).
services.AddSingleton(typeof(IRepository<>), typeof(Repository<>));
services.Decorate(typeof(IRepository<>), typeof(DomainEventPublisher<>));
I have closed these generic classes/interfaces and then it works. But Im not good with that. I would to i the right way like I used to do in Simpleinjector, and register open generic decorator.
Any suggestions what might be the problem?
public class Repository<TEntity> : IRepository<TEntity>
{
private readonly CosmosClient _client;
private readonly IDataContext<TEntity> _context;
private readonly Container _container;
public Repository(CosmosClient client, IDataContext<TEntity> context)
{
_client = client;
_context = context ?? throw new ArgumentNullException(nameof(context));
_container = _client.GetContainer(_context.GetDatabase(), _context.GetContainer());
}
public virtual async Task Add(TEntity entity)
{
try
{
var response = await _container.CreateItemAsync(entity, new PartitionKey(_context.GetPartitionKey(entity)));
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
public virtual async Task<TEntity> Get(string id)
{
var response = await _container.ReadItemAsync<TEntity>(id, new PartitionKey(_context.GetPartitionKey(id)));
return response.Resource;
}
public virtual async Task<TEntity> Update(TEntity entity)
{
var response = await _container.UpsertItemAsync(entity, new PartitionKey(_context.GetPartitionKey(entity)));
return response.Resource;
}
public async Task Remove(string id)
{
var response = await _container.DeleteItemAsync<TEntity>(id, new PartitionKey(_context.GetPartitionKey(id)));
}
public class DomainEventPublisher<TEntity> : IRepository<TEntity>
{
private readonly IRepository<TEntity> _decoratedRepository;
private readonly ITopicAdapter _bus;
private readonly IMapper _mapper;
private List<IDomainEvent> _eventsToProcess = new List<IDomainEvent>();
public DomainEventPublisher(IRepository<TEntity> decoratedRepository, ITopicAdapter bus, IMapper mapper)
{
_decoratedRepository = decoratedRepository ?? throw new ArgumentNullException(nameof(decoratedRepository));
_bus = bus ?? throw new ArgumentNullException(nameof(bus));
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
}
public async Task Add(TEntity entity)
{
// Get all domain events raised by source entity
var events = CollectEvents(entity);
await _decoratedRepository.Add(entity);
await HandleEvents(events);
}
public async Task<TEntity> Get(string id)
{
return await _decoratedRepository.Get(id);
}
public async Task<TEntity> Update(TEntity entity)
{
// Get all domain events raised by source entity
var events = CollectEvents(entity);
var result = await _decoratedRepository.Update(entity);
await HandleEvents(events);
return result;
}
public async Task Remove(string id)
{
await _decoratedRepository.Remove(id);
}
private List<IDomainEvent> CollectEvents(TEntity entity)
{
if (entity is IEntity entityWithEvents)
return entityWithEvents.Events;
return new List<IDomainEvent>();
}
private async Task HandleEvents(List<IDomainEvent> events)
{
// if we ended up on this line we know that repository persisted changes and now send events to bus
foreach (var domainEvent in events)
{
await _bus.Send(_mapper.MapTo(domainEvent));
}
}
}
It's impossible to apply decorators to open-generic registration with Scrutor. This is discussed here on the Scrutor forum. This is due to a limitation of the underlying Microsoft DI Container. This is a limitation that can't be circumvented by Scrutor.
Instead, switch to one of the mature DI Containers that do support this.
I just started using xamarin android with MVVMcross platform. I need to cancel an IMvxAsyncCommand but I try a lot of way, it still not work. Does anyone have any ideas or sample of this?
You can actually cancel a MvxAsyncCommand directly without creating any additional CancellationTokenSource.
Just call Cancel() on the object itself.
So instead of having the property being ICommand or IMvxCommand use MvxAsyncCommand or IMvxAsyncCommand.
This way when you have a CancellationToken as argument in your Task and you call Cancel() on the command, it will cancel that token.
private async Task MyAsyncStuff(CancellationToken ct)
{
await abc.AwesomeAsyncMethod(ct);
// and/or
ct.ThrowIfCancellationRequested();
}
So if you modify #fmaccaroni's answer, you will get this:
public class MyClass
{
public MyClass()
{
MyAsyncCommand = new MvxAsyncCommand(MyAsyncStuff);
CancelMyTaskCommand = new MvxCommand(() => MyAsyncCommand.Cancel());
}
public IMvxAsyncCommand MyAsyncCommand {get; private set; }
public ICommand CancelMyTaskCommand { get; private set; }
private async Task MyAsyncStuff(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await foo.BlablaAsync();
cancellationToken.ThrowIfCancellationRequested();
await bar.WhateverAsync();
cancellationToken.ThrowIfCancellationRequested();
await foo2.AnotherAsync();
}
}
EDIT: or even better if your async methods also allow passing along the CancellationToken cancelling them directly, the MyAsyncStuff method could be written like:
private async Task MyAsyncStuff(CancellationToken cancellationToken)
{
await foo.BlablaAsync(cancellationToken);
await bar.WhateverAsync(cancellationToken);
await foo2.AnotherAsync(cancellationToken);
}
Or if you don't care which order they get started and complete in:
private Task MyAsyncStuff(CancellationToken cancellationToken)
{
return Task.WhenAll(
foo.BlablaAsync(cancellationToken),
bar.WhateverAsync(cancellationToken),
foo2.AnotherAsync(cancellationToken));
}
So basically a IMvxAsyncCommand just calls a Task like this:
MyCommand = new MvxAsyncCommand(MyTask);
...
private async Task MyTask()
{
// do async stuff
}
In order to cancel a Task you need to use a CancellationToken, which you can get it from a CancellationTokenSource and use another command or whatever you want to call the Cancel() on the CancellationTokenSource, so one way you could do it would be:
public class MyClass
{
private CancellationTokenSource cts;
public MyClass()
{
MyAsyncCommand = new MvxAsyncCommand(MyTask);
CancelMyTaskCommand = new MvxCommand(() => cts.Cancel());
}
public ICommand MyAsyncCommand {get; private set; }
public ICommand CancelMyTaskCommand { get; private set; }
private async Task MyTask()
{
cts = new CancellationTokenSource();
await MyAsyncStuff(cts.CancellationToken);
cts.Dispose();
cts = null;
}
private async Task MyAsyncStuff(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await foo.BlablaAsync();
cancellationToken.ThrowIfCancellationRequested();
await bar.WhateverAsync();
cancellationToken.ThrowIfCancellationRequested();
await foo2.AnotherAsync();
}
}
You can then improve the code to avoid duplicate calls to the Task, handle the cancellation exception, use an MvxNotifyTask and many other things but this is the basics.
More info in Cancellation in Managed Threads
HIH
I am working on a project where I want to keep users logged in using access tokens/refresh tokens. I store these values in a cookie and whenever a user visits the site, I want to automatically log him in regardless of the page that he uses to access the site. To do this, I created a BaseController, that all other controllers inherit from. The BaseController looks like this:
public abstract class BaseController : Controller
{
public BaseController()
{
LoginModel.SetUserFromAuthenticationCookie();
}
}
This constructor gets executed every time before an action is executed and is therefore exactly what I want. The problem is that SetUserFromAuthenticationCookie() is an async method, because it has to do calls to other async methods. It looks like this:
public async static Task SetUserFromAuthenticationCookie()
{
// Check if the authentication cookie is set and the User is null
if (AuthenticationRepository != null && User == null)
{
Api api = new Api();
// If a new authentication cookie was successfully created
if (await AuthenticationRepository.CreateNewAuthenticationCookieAsync())
{
var response = await api.Request(HttpMethod.Get, "api/user/mycredentials");
if(response.IsSuccessStatusCode)
{
User = api.serializer.Deserialize<UserViewModel>(await response.Content.ReadAsStringAsync());
}
}
}
}
The problem is that the execution order is not as I anticipated and because of that the user does not get logged in. I tried to work with .Result for the async methods, but that resulted in a deadlock. Besides that I read many threads on SO concerning the issue and eventually also found one that managed to get the login to work: How would I run an async Task<T> method synchronously?. It is somewhat hacky though and works with this helper:
public static class AsyncHelpers
{
/// <summary>
/// Execute's an async Task<T> method which has a void return value synchronously
/// </summary>
/// <param name="task">Task<T> method to execute</param>
public static void RunSync(Func<Task> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
synch.Post(async _ =>
{
try
{
await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
}
/// <summary>
/// Execute's an async Task<T> method which has a T return type synchronously
/// </summary>
/// <typeparam name="T">Return Type</typeparam>
/// <param name="task">Task<T> method to execute</param>
/// <returns></returns>
public static T RunSync<T>(Func<Task<T>> task)
{
var oldContext = SynchronizationContext.Current;
var synch = new ExclusiveSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(synch);
T ret = default(T);
synch.Post(async _ =>
{
try
{
ret = await task();
}
catch (Exception e)
{
synch.InnerException = e;
throw;
}
finally
{
synch.EndMessageLoop();
}
}, null);
synch.BeginMessageLoop();
SynchronizationContext.SetSynchronizationContext(oldContext);
return ret;
}
private class ExclusiveSynchronizationContext : SynchronizationContext
{
private bool done;
public Exception InnerException { get; set; }
readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false);
readonly Queue<Tuple<SendOrPostCallback, object>> items =
new Queue<Tuple<SendOrPostCallback, object>>();
public override void Send(SendOrPostCallback d, object state)
{
throw new NotSupportedException("We cannot send to our same thread");
}
public override void Post(SendOrPostCallback d, object state)
{
lock (items)
{
items.Enqueue(Tuple.Create(d, state));
}
workItemsWaiting.Set();
}
public void EndMessageLoop()
{
Post(_ => done = true, null);
}
public void BeginMessageLoop()
{
while (!done)
{
Tuple<SendOrPostCallback, object> task = null;
lock (items)
{
if (items.Count > 0)
{
task = items.Dequeue();
}
}
if (task != null)
{
task.Item1(task.Item2);
if (InnerException != null) // the method threw an exeption
{
throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException);
}
}
else
{
workItemsWaiting.WaitOne();
}
}
}
public override SynchronizationContext CreateCopy()
{
return this;
}
}
If I then change the content of the BaseController constructor to:
AsyncHelpers.RunSync(() => LoginModel.SetUserFromAuthenticationCookie());
the functionality works as anticipated.
I would like to know though if you have any suggestions on how to do this in a nicer manner. Perhaps I should move the call to the SetUserFromAuthenticationCookie() to another location, but at this time I do not know where that would be.
I found this solution on another stack. Synchronously waiting for an async operation, and why does Wait() freeze the program here
Your constructor would need to look like this.
public BaseController()
{
var task = Task.Run(async () => { await LoginModel.SetUserFromAuthenticationCookie(); });
task.Wait();
}
I’m trying to log out Web API Request Content – i.e. the json string. I implemented an ITraceWriter class (example) and configured it so that Web API calls it in the pipeline. But if I read the request.Content or copy into to a stream to read it is not available for the method resulting in a null model. This post talks about that issue a little. Anyone have experience logging out inbound Web API request content and know what the best approach is?
Thanks
Update A
I created a simple sample Web API project to rule out anything in my project and I still see that the model will be null because of logging. I simply test a few times in a row by posting via Fidder and see my model comes in null. With breakpoints in place, it might work which is why I think there is a sync/timing issue. Any thoughts on how to get this to work?
Header:
User-Agent: Fiddler
Host: localhost:56824
Content-Type: application/json
Content-Length: 22
Body:
{
"A":1,"B":"test"
}
Here's the code:
Controller:
public class ValuesController : ApiController
{
[HttpPost]
public void Post(ValuesModel model)
{
if (model == null)
{
Debug.WriteLine("model was null!");
}
else
{
Debug.WriteLine("model was NOT null!");
}
}
}
Model:
public class ValuesModel
{
public int A { get; set; }
public string B { get; set; }
}
Logger:
public class APITraceLogger : DelegatingHandler
{
protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
if (request.Content != null)
{
// This can cause model to be null
request.Content.ReadAsStringAsync().ContinueWith(s =>
{
string requestText = s.Result;
Debug.WriteLine(requestText);
});
// and so can this
//request.Content.ReadAsByteArrayAsync()
// .ContinueWith((task) =>
// {
// string requestText = System.Text.UTF8Encoding.UTF8.GetString(task.Result);
// Debug.WriteLine(requestText);
// });
}
// Execute the request, this does not block
var response = base.SendAsync(request, cancellationToken);
// TODO:
// Once the response is processed asynchronously, log the response data
// to the database
return response;
}
}
Wiring up logger in WebApiConfig class:
config.MessageHandlers.Add(new APITraceLogger());
Update B
It seems like it is now working if I change the logger to the following code adding the await, async and returning the result. Seems like something I'm not understanding in the async code or truly a timing issue or something.
public class APITraceLogger : DelegatingHandler
{
protected async override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
if (request.Content != null)
{
// This does seem to work - is it because it is synchronous? Is this a potential problem?
var requestText = await request.Content.ReadAsStringAsync();
Debug.WriteLine(requestText);
}
// Execute the request, this does not block
var response = base.SendAsync(request, cancellationToken);
// TODO:
// Once the response is processed asynchronously, log the response data
// to the database
return response.Result;
}
}
As Filip mentions in that post ReadAsStringAsync or ReadAsByteArrayAsync methods buffer the request content internally. This means that even if your incoming request's stream type is a non-buffered stream, you could safely do a ReadAsStringAsync/ReadAsByteArrayAsync at a message handler for example, and also expect the model binding to work fine.
By default, a request's stream is buffered in both webhost and selfhost cases. But if you would like to check if using ReadAsStringAsync/ReadAsByteArrayAsync and model biding works fine even in non-buffered mode, you can do the following to force non-buffered mode:
public class CustomBufferPolicySelector : WebHostBufferPolicySelector
{
public override bool UseBufferedInputStream(object hostContext)
{
//NOTE: by default, the request stream is always in buffered mode.
//return base.UseBufferedInputStream(hostContext);
return false;
}
}
config.Services.Replace(typeof(IHostBufferPolicySelector), new CustomBufferPolicySelector());
Just FYI...the above policy selector works only for Web Host currently. If you would like to do a similar test in SelfHost, then do the following:
//NOTE: by default, the transfer mode is TransferMode.Buffered
config.TransferMode = System.ServiceModel.TransferMode.StreamedRequest;
After Update B of the post above:
You could modify your handler like below:
public class LoggingHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Content != null)
{
string requestContent = await request.Content.ReadAsStringAsync();
}
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
if (response.Content != null)
{
string responseContent = await response.Content.ReadAsStringAsync();
}
return response;
}
}