How to use ServiceStack.GetAsync with ReactiveCommand (v6) - c#

I'm trying to combine ReactiveCommand with ServiceStack asynchronous API.
The x => _reactiveList.AddRange(x) is never called and the test res is null. I don't now how to convert ServiceStack's Task<TResponse> GetAsync<TResponse>(IReturn<TResponse> requestDto) result into reactive IObservable<T>.
public ReactiveCommand<IList<string>> ServiceReadCommand { get; protected set; }
public ReactiveList<string> ReactiveList
{
get { return _reactiveList; }
set { _reactiveList = this.RaiseAndSetIfChanged(ref _reactiveList, value); }
}
private ReactiveList<string> _reactiveList = new ReactiveList<string>();
public TestViewModel(IScreen screen = null)
{
HostScreen = screen;
ServiceReadCommand = ReactiveCommand.CreateAsyncTask(x => ServiceCommandTask(), RxApp.TaskpoolScheduler);
ServiceReadCommand.ThrownExceptions.Subscribe(x => Console.WriteLine((object)x));
ServiceReadCommand.Subscribe(x => _reactiveList.AddRange(x));
}
private async Task<IList<string>> ServiceCommandTask()
{
this.Log().Info("Service command task");
var baseUri = "http://localhost:9010";
var client = new JsonServiceClient(baseUri);
// Works
return await Observable.Return(new List<string> { "" });
// Don't
return await client.GetAsync(new TestRequest());
}
And test method:
[TestMethod]
public void TestMethod1()
{
IList<string> res = null;
new TestScheduler().With(sched =>
{
var viewModel = new TestViewModel();
viewModel.ServiceReadCommand.CanExecute(null).Should().BeTrue();
viewModel.ServiceReadCommand.ExecuteAsync(null).Subscribe(x => res = x);
sched.AdvanceByMs(1000);
return viewModel.ReactiveList;
});
res.Should().NotBeEmpty();
}
I have added console application with all code. Change ServiceCommandTask to IObservable<T> didn't helped. Adding Thread.Sleep() between
viewModel.ServiceReadCommand.ExecuteAsync(null).Subscribe(x => res = x);
//Thread.Sleep(1000);
sched.AdvanceByMs(1000);
resolves the issue but this is not an option.

OK, there are a couple things that could be wrong. Everything looks like it should run, but you never know.
I do know that there are usually some weird things in ReactiveUI when dealing directly with Tasks and the TestScheduler though, so there are a couple of things that you could try on that front.
You could use the ToObservable() extension method to convert the Task<TResponse> into an IObservable<TResponse>.
using System.Reactive.Linq;
// ...
return await (client.GetAsync(new TestRequest()).ToObservable());
The other idea has to do with forcing your ServiceCommandTask() method to return an IObservable and not use async/await. To do that you would have to change how you create your ReactiveCommand to use ReactiveCommand.CreateAsyncObservable and you would just use ToObservable() in ServiceCommandTask() on the Task that is returned from the ServiceStack call.
The reason why converting the Task into an IObservable might work is because the TestScheduler relies on virtual time to wait for things to happen. The TestSchedluer cannot interact properly with the Task and therefore when it "skips" ahead 1 second no time has actually passed in the real world. If the ServiceStack call does not return instantly then I would expect that to be the case and that problem may or may not be fixable by the above solutions.

You're doing everything right on the ReactiveUI end, something's going on with ServiceStack.

Related

Run an async method only once, and return the same result to all concurrent and future calls [duplicate]

This question already has answers here:
Enforce an async method to be called once
(4 answers)
Closed 6 months ago.
I'm writing an ASP.net Core 6 application (but the question is more about C# in general) where I have a controller action like this:
[HttpGet]
public async Task<IActionResult> MyAction() {
var result = await myService.LongOperationAsync();
return Ok(result);
}
Basically, the action calls a service that needs to do some complex operation and can take a bit of time to respond, up to a minute. Obviously, if in the meantime another request arrives a second run of LongOperationAsync() starts, consuming even more resources.
What I would like to do is redesign this so that the calls to LongOperationAsync() don't run in parallel, but instead wait for the result of the first call and then all return the same result, so that LongOperationAsync() only runs once.
I thought of a few ways to implement this (for example by using a scheduler like Quartz to run the call and then check if a relevant Job is already running before enqueueing another one) but they all require quite a bit of relatively complicated plumbing.
So I guess my questions are:
Is there an established design pattern / best practice to implement this scenario? Is it even practical / a good idea?
Are there features in the C# language and/or the ASP.net Core framework that facilitate implementing something like this?
Clarification: basically I want to run the long-running operation only once, and "recycle" the result to any other call that was waiting without executing the long-running operation again.
You could use an async version of Lazy<T> to do this.
Stephen Toub has posted a sample implementation of LazyAsync<T> here, which I reproduce below:
public class AsyncLazy<T> : Lazy<Task<T>>
{
public AsyncLazy(Func<T> valueFactory) :
base(() => Task.Run(valueFactory))
{ }
public AsyncLazy(Func<Task<T>> taskFactory) :
base(() => Task.Run(taskFactory))
{ }
public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); }
}
You could use it like this:
public class Program
{
public static async Task Main()
{
var test = new Test();
var task1 = Task.Run(async () => await test.AsyncString());
var task2 = Task.Run(async () => await test.AsyncString());
var task3 = Task.Run(async () => await test.AsyncString());
var results = await Task.WhenAll(task1, task2, task3);
Console.WriteLine(string.Join(", ", results));
}
}
public sealed class Test
{
public async Task<string> AsyncString()
{
Console.WriteLine("Started awaiting lazy string.");
var result = await _lazyString;
Console.WriteLine("Finished awaiting lazy string.");
return result;
}
static async Task<string> longRunningOperation()
{
Console.WriteLine("longRunningOperation() started.");
await Task.Delay(4000);
Console.WriteLine("longRunningOperation() finished.");
return "finished";
}
readonly AsyncLazy<string> _lazyString = new (longRunningOperation);
}
If you run this console app, you'll see that longRunningOperation() is only called once, and when it's finished all the tasks waiting on it will complete.
Try it on DotNetFiddle
As Matthew's answer points out, what you're looking for is an "async lazy". There is no built-in type for this, but it's not that hard to create.
What you should be aware of, though, is that there are a few design tradeoffs in an async lazy type:
What context the factory function is run on (the first invoker's context or no context at all). In ASP.NET Core, there isn't a context. So the Task.Factory.StartNew in Stephen Toub's example code is unnecessary overhead.
Whether failures should be cached. In the simple AsyncLazy<T> approach, if the factory function fails, then a faulted task is cached indefinitely.
When to reset. Again, by default the simple AsyncLazy<T> code never resets; a successful response is also cached indefinitely.
I'm assuming you do want the code to run multiple times; you just want it not to run multiple times concurrently. In that case, you want the async lazy to be reset immediately upon completion, whether successful or failed.
The resetting can be tricky. You want to reset only when it's completed, and only once (i.e., you don't want your reset code to clear the next operation). My go-to for this kind of logic is a unique identifier; I like to use new object() for this.
So, I would start with the Lazy<Task<T>> idea, but wrap it instead of derive, which allows you to do a reset, as such:
public class AsyncLazy<T>
{
private readonly Func<Task<T>> _factory;
private readonly object _mutex = new();
private Lazy<Task<T>> _lazy;
private object _id;
public AsyncLazy(Func<Task<T>> factory)
{
_factory = factory;
_lazy = new(_factory);
_id = new();
}
private (object LocalId, Task<T> Task) Start()
{
lock (_mutex)
{
return (_id, _lazy.Value);
}
}
private void Reset(object localId)
{
lock (_mutex)
{
if (localId != _id)
return;
_lazy = new(_factory);
_id = new();
}
}
public async Task<T> InvokeAsync()
{
var (localId, task) = Start();
try
{
return await task;
}
finally
{
Reset(localId);
}
}
}

How do I implement shared functionality across methods for diagnostic purposes in .NET Core?

I have a .NET Core 3.1 app. In this app, I have the following boilerplate methods:
public List<Item> GetAll()
{
// retrieve all items from the database
}
public async Task<List<Item>> GetAllAsync()
{
// retrieve all items from the database
}
public List<Item> GetAll(bool includeDeleted, DateTime? after)
{
// retrieve all items based on the query details passed in as parameters.
}
public Item Get(int id)
{
// retrieve a specific item from the database
}
public async Task<Item> GetAsync(int id)
{
// retrieve a specific item from the database.
// The id parameter is needed
}
public void DoSomething()
{
// No parameters are needed
}
In these methods, and other methods in my project, I have a lot of boilerplate code. That boilerplate code basically 1) logs performance and 2) provides generic error handling.At this time, the boilerplate stuff basically looks like this:
var log = new Log("<Friendly Method Name Goes Here">);
Stopwatch stopwatch = null;
try
{
stopwatch = Stopwatch.StartNew();
// method code
log.Result = null, Item, or List<Item> depending on which method is called
stopwatch.Stop();
log.ElapsedTicks = stopwatch.ElapsedTicks;
log.Success = true;
}
catch (Exception)
{
log.Success = false;
}
Instead of copying the above and putting it into every method, it seems like I should be able to pass in the "real work" that needs to be done into one method and populate something like a Result object that includes the real result and the metadata (i.e. performance, friendly method name, etc.) This lead me down the path of putting something like the following into each method:
var result = new Result();
Func<Task> task = async (result) =>
{
var outcome = // get item(s) from database
result.Result = outcome;
await Task.CompletedTask;
};
I was then going to put my boilerplate code into a shared method and pass in task. However, quickly ran into some problems:
How do I pass in zero, one, or more parameters?
I can write metadata on the Result object in the Func. However, how do I update properties on the Result object in the in the shared method (the thing that logs performance, etc.)?
I can't tell if I'm overlooking something in C# or if I have an architectural problem. I feel like having shared code that handles core things (i.e. measure performance), yet flexible enough to customize at a more granular level is reasonable. Is there a way to do this in C#? If so, how?
Thank you!
This is the way I would do it, it's not the most efficient way but it's pretty simple. Your parameters that you use become closures in the boilerplate context, no need to worry about that unless you're doing some heavy lifting in memory. First class defines the boilerplate operations, you get name of the method and source file that calls you for logging purposes automatically. Second class implements the boilerplate context. Supports sync and async overloads, you may need to add 2 more overloads without return types for void methods but that's easy. You can expand the Func<> definition with more types and pass something from the boilerplate to methods like DB context factory or something.
namespace Test
{
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
public static class Boilerplate
{
// Boilerplater (tm) for async methods
public static async Task<T> Run<T>(Func<Task<T>> operation, [CallerMemberName] string method = null, [CallerFilePath] string module = null)
{
// some boilerplate init
Console.WriteLine($"Method {method} started.");
var result = await operation.Invoke();
// some wrapup
Console.WriteLine($"Method {method} ended.");
return result;
}
// Boilerplater (tm) for sync methods
public static T Run<T>(Func<T> operation, [CallerMemberName] string method = null, [CallerFilePath] string module = null)
{
// some boilerplate init
Console.WriteLine($"Method {method} started.");
var result = operation.Invoke();
// some wrapup
Console.WriteLine($"Method {method} ended.");
return result;
}
}
/// <summary>
/// Example app
/// </summary>
public class MyApp
{
public async Task<List<string>> GetAllAsync(string input)
=> await Boilerplate.Run(async () =>
{
// do something async in the boilerplate context
var result = new List<string>();
await Task.Delay(1);
result.Add(input);
return result;
});
public List<string> GetAll(string input)
=> Boilerplate.Run(() =>
{
// do something non-async in the boilerplate context
var result = new List<string>();
result.Add(input);
return result;
});
}
}
And of course this has no error handling, it would just be too long to post, just a proof of concept.

Calling non-async methods

Have a class library that makes use of a DbContext to return results from sql.
If I want to build a
Class library method that might take a few seconds. This class is injected into an asp.net core webapp in its Startup
class Util
{
public string DoStuff(string colorVal) {
string ourValue = (from a in ctx.BigTable where a.color == colorVal select a.DoneFlag).FirstOrDefault();
return ourValue;
}
}
Do I need to make this method async also if I intend to use it from code like this
Web project
Util o;
public async Task<IViewComponentResult> InvokeAsync()
{
var item = await GetMatchingColorAsync();
return View(item);
}
private Task<string> GetMatchingColorAsync()
{
string matchingColor = o.DoStuff("red");
return Task.FromResult(matchingColor);
}
Ideally yes. You could even use FirstOrDefaultAsync while you're at it (depending on what your underlying data source is):
public async Task<string> DoStuff(string colorVal) {
string ourValue = await (from a in ctx.BigTable where a.color == colorVal select a.DoneFlag).FirstOrDefaultAsync();
var someColor = await GetMatchingColorAsync();
return ourValue;
}
Microsoft has a series of articles about Asynchronous programming with async and await that are quite well written. They're worth the read.
If you absolutely can't change the calling methods, then you could just synchronously wait:
public string DoStuff(string colorVal) {
string ourValue = (from a in ctx.BigTable where a.color == colorVal select a.DoneFlag).FirstOrDefault();
var someColor = GetMatchingColorAsync().GetAwaiter().GetResult();
return ourValue;
}
Easy right? Except it blocks the thread (you lose the benefit of the asynchronous methods) and you risk deadlocking, as explained in this article: Don't Block on Async Code.
That's Bad™

c# Task.WhenAll to block while awaiting completion

I have a simple Winforms application. I would like to background TCP connections/print requests and check the output of all tasks at a set point in my code.
I would expect ReportOnTasks to block until WaitAll is complete. Please could someone explain why this is not the case? I'm also worried I haven't structured this correctly.
Edit, to clarify my intentions:
I would like to send the print jobs as soon as I receive the data. Then continue with some other DB operations. Once all the print operations are complete, I would like to update the UI to state the result.
I've attempted to simplify the code as much as I can. Maybe too much. HomeController just inits some stuff. There are buttons on the form and file watchers that trigger the main functionality.
public class HomeController
{
public HomeController(){
MessageBox.Show("1");
oPrintController.PrintAsync("192.168.2.213", Encoding.ASCII.GetBytes("string to print"));
MessageBox.Show("2");
// Block here untill tasks are complete
ReportOnTasks();
MessageBox.Show("Report on tasks complete");
}
public async void ReportOnTasks()
{
await Task.WhenAll(oPrintController.Tasks);
foreach(Task<PrintController.PrintResult> PR in oPrintController.Tasks)
{
// do something with the result of task
}
}
}
and the PrintController
public class PrintController
{
public List<Task<PrintResult>> Tasks = new List<Task<PrintResult>>();
public async void PrintAsync(string sIP, List<byte[]> lsToPrint, int iPort = 9100)
{
var s = await Task.Run(() => PrintAsync1(sIP, lsToPrint));
}
public async System.Threading.Tasks.Task<PrintResult> PrintAsync1(string sIP, List<byte[]> lsToPrint, int iPort = 9100)
{
using (TcpClient tc = new TcpClient())
{
await tc.ConnectAsync(sIP, iPort);
using (var ns = tc.GetStream())
{
foreach (byte[] btLabel in lsToPrint)
{
await ns.WriteAsync(btLabel, 0, btLabel.Length);
}
}
}
Thread.Sleep(10000);
return new PrintResult();
}
}
public class PrintResult
{
bool bSuccess = false;
}
You are not awaiting the call to ReportOnTasks()
Moreover, you can't await within a ctor, because they can't be async.
Depending on how your HomeController is used, you could use a static async method which returns an instance of HomeController, created by a private ctor instead:
Something like this:
public class HomeController
{
//notice private - you can't new up a HomeController - you have to use `CreateInstance`
private HomeController(){
MessageBox.Show("1");
//not clear from your code where oPrintController comes from??
oPrintController.PrintAsync("192.168.2.213", Encoding.ASCII.GetBytes("string to print"));
MessageBox.Show("2");
MessageBox.Show("Report on tasks complete");
}
public static async Task<HomeController> CreateInstance() {
var homeController = new HomeController();
await homeController.ReportOnTasks();
return homeController;
}
//don't use async void! Change to Task
public async Task ReportOnTasks()
{
//not clear from your code where oPrintController comes from??
await Task.WhenAll(oPrintController.Tasks);
foreach(Task<PrintController.PrintResult> PR in oPrintController.Tasks)
{
// do something with the result of task
}
}
}
Usage:
var homeControllerInstance = await HomeController.CreateInstance();
It's generally not recommended to perform heavy operations in class constructors, but I suppose you won't change that part, so in order to wait for ReportOnTasks to finish, you need to make it synchronous.
Take into account, that constructor itself doesn't support async/await, it's not possible to mark it async.
Having said that, you won't have real performance enhancement marking void ReportOnTasks as async. In addition, it is not recommended to mark void methods as async due to issues with exceptions handling, which is usually not possible.
So, you can either postpone ReportOnTasks like Alex showed you, or you can synchronously wait until all tasks are finished (which is possible inside ctor).
public void ReportOnTasks()
{
Task.WhenAll(oPrintController.Tasks).GetAwaiter().GetResult(); //synchronously wait
foreach(Task<PrintController.PrintResult> PR in oPrintController.Tasks)
{
// do something with the result of task
}
}
However, I wouldn't suggest this approach, because instance creation will take a while and most importantly block UI thread - and that's usually signal something is really fishy

Non async method, call async method, and need to work with the result

I have a syncronized method and class which is static. I have to call Mandrill and use the result.
My method, looks like this
public static void MyMethod(Association association , Person p)
{
MandrillApi mandrill = new MandrillApi(mandrillAPIKey);
var mail = GetMandrillMessage(fromEmail, clubAdmin.ProfileInfo.Email);
mail.AddGlobalVariable("Key", value);
mail.AddGlobalVariable("Key", value);
mail.AddGlobalVariable("AssociationBaseUrl", SettingsHelper.GetSetting("AssociationBaseUrl"));
mail.AddGlobalVariable("Key", value);
mail.AddGlobalVariable("UserFirstname", clubAdmin.Firstname);
mail.Subject = "Subject goes here";
var messageRequest = new SendMessageTemplateRequest(mail, "template");
var result = mandrill.SendMessageTemplate(messageRequest);
}
I need result.Result. I can't make my method to async.
So is there any way to get result.Result and use it in a new method?
i was thinking to do something like
var messageRequest = new SendMessageTemplateRequest(mail, "template");
var result = mandrill.SendMessageTemplate(messageRequest);
CallMyMethod(result.Result.First().Id)
but this wont work, it will just stop the program. Really need help. Ask for more information. I am really bad at explaining myself.
You are experiencing a deadlock. The correct wait to call asynchronous code from synchronous code is to make your whole call stack (starting at the controller's action method) asynchronous. IMO not doing this is an unreasonable constraint.
Changes:
Make MyMethod return Task instead of void so it can be awaited
Add async to MyMethod
Add await to wait for the result from IMandrilApi.SendMessageTemplate
Rename MyMethod to MyMethodAsync, not required but it follows a commonly accepted naming convention
Make controller method async and return a Task. If the controller is returning something then return Task<T> where T is the current return type.
Controller method awaits the result of MyMethodAsync
public static async Task MyMethodAsync(Association association , Person p)
{
/* your existing code has been removed for brevity as there are no changes in that code */
var result = await mandrill.SendMessageTemplate(messageRequest);
}
Controller method
I had to make an assumption this code but you did state in the comments the call stack is controller → MyMethod. Also note that only the relevant part to the question is shown and I had no other info to go on.
[HttpPost]
public async Task SendMessage()
{
await MyMethodAsync(association, person);
}
You can put your method to a Task and await it
public static object MyMethod(Association association , Person p)
{
MandrillApi mandrill = new MandrillApi(mandrillAPIKey);
var mail = GetMandrillMessage(fromEmail, clubAdmin.ProfileInfo.Email);
mail.AddGlobalVariable("Key", value);
mail.AddGlobalVariable("Key", value);
mail.AddGlobalVariable("AssociationBaseUrl", SettingsHelper.GetSetting("AssociationBaseUrl"));
mail.AddGlobalVariable("Key", value);
mail.AddGlobalVariable("UserFirstname", clubAdmin.Firstname);
mail.Subject = "Subject goes here";
var messageRequest = new SendMessageTemplateRequest(mail, "template");
var result = mandrill.SendMessageTemplate(messageRequest);
return result;
}
[HttpPost]
public async Task<HttpResponseMessage> Post([FromBody]MyObject obj)
{
var task = Task.Run(() => MyMethod(a,p));
var result = await task;
return Request.CreateResponse(...);
}
But async in the controller does not make the user experience async. User will have to wait as long as task finishes. So why do we do async ?

Categories

Resources