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â„¢
Related
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.
I've run into difficulty testing System.Net.Http.HttpClient with FakeItEasy. Consider this scenario:
//Service that consumes HttpClient
public class LoggingService
{
private readonly HttpClient _client;
public LoggingService(HttpClient client)
{
_client = client;
_client.BaseAddress = new Uri("http://www.example.com");
}
public async Task Log(LogEntry logEntry)
{
var json = JsonConvert.SerializeObject(logEntry);
var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
await _client.PostAsync("/api/logging", httpContent);
}
}
public class LogEntry
{
public string MessageText { get; set; }
public DateTime DateLogged { get; set; }
}
Unit Testing
From a unit testing perspective, I want to verify that HttpClient posts the specified logEntry payload to the appropriate URL (http://www.example.com/api/logging). (Side Note: I can't test the HttpClient.PostAsync() method directly because my service uses the concrete implementation of HttpClient and Microsoft does not provide an interface for it. However, I can create my own HttpClient that uses a FakeMessageHandler (below) as a dependency, and inject that into the service for testing purposes. From there, I can test DoSendAsync()
//Helper class for mocking the MessageHandler dependency of HttpClient
public abstract class FakeMessageHandler : HttpMessageHandler
{
protected sealed override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
return DoSendAsync(request);
}
public abstract Task<HttpResponseMessage> DoSendAsync(HttpRequestMessage request);
}
In theory, I should be able to use the Matches() method in FakeItEasy to write a custom matching function. This would look something like this:
//NUnit Test
[TestFixture]
public class LoggingServiceTests
{
private LoggingService _loggingService;
private FakeMessageHandler _fakeMessageHandler;
private HttpClient _httpClient;
[SetUp]
public void SetUp()
{
_fakeMessageHandler = A.Fake<FakeMessageHandler>();
_httpClient = new HttpClient(_fakeMessageHandler);
_loggingService = new LoggingService(_httpClient);
}
[Test]
public async Task Logs_Error_Successfully()
{
var dateTime = new DateTime(2016, 11, 3);
var logEntry = new LogEntry
{
MessageText = "Fake Message",
DateLogged = dateTime
};
await _loggingService.Log(logEntry);
A.CallTo(() => _fakeMessageHandler.DoSendAsync(
A<HttpRequestMessage>.That.Matches(
m => DoesLogEntryMatch("Fake Message", dateTime, HttpMethod.Post,
"https://www.example.com/api/logging", m)))
).MustHaveHappenedOnceExactly();
}
private bool DoesLogEntryMatch(string expectedMessageText, DateTime expectedDateLogged,
HttpMethod expectedMethod, string expectedUrl, HttpRequestMessage actualMessage)
{
//TODO: still need to check expectedMessageText and expectedDateLogged from the HttpRequestMessage content
return actualMessage.Method == expectedMethod && actualMessage.RequestUri.ToString() == expectedUrl;
}
}
Checking the URL and the HttpMethod is easy enough (as demonstrated above). But, in order to check the payload, I need to check the content of the HttpRequestMessage. Here's where it gets tricky. The only way I've found to read the content of an HttpRequestMessage is to use one of the built-in async methods (i.e. ReadAsStringAsync, ReadAsByteArrayAsync, ReadAsStreamAsync, etc.) As far as I can tell, FakeItEasy does not support async/await operations inside of the Matches() predicate. Here's what I tried:
Convert DoesLogEntryMatch() method to async, and await the ReadAsStringAsync() call (DOES NOT WORK)
//Compiler error - Cannot convert async lambda expression to delegate type 'Func<HttpRequestMessage, bool>'.
//An async lambda expression may return void, Task or Task<T>,
//none of which are convertible to 'Func<HttpRequestMessage, bool>'
A.CallTo(() => _fakeMessageHandler.DoSendAsync(
A<HttpRequestMessage>.That.Matches(
async m => await DoesLogEntryMatch("Fake Message", dateTime, HttpMethod.Post,
"http://www.example.com/api/logging", m)))
).MustHaveHappenedOnceExactly();
private async Task<bool> DoesLogEntryMatch(string expectedMessageText, DateTime expectedDateLogged,
HttpMethod expectedMethod, string expectedUrl, HttpRequestMessage actualMessage)
{
var message = await actualMessage.Content.ReadAsStringAsync();
var logEntry = JsonConvert.DeserializeObject<LogEntry>(message);
return logEntry.MessageText == expectedMessageText &&
logEntry.DateLogged == expectedDateLogged &&
actualMessage.Method == expectedMethod && actualMessage.RequestUri.ToString() == expectedUrl;
}
Leave DoesLogEntryMatch as a non-async method, and don't await ReadAsStringAsync(). This seems to work when I tested it, but I have read that doing this could cause deadlocks in certain situations.
private bool DoesLogEntryMatch(string expectedMessageText, DateTime expectedDateLogged,
HttpMethod expectedMethod, string expectedUrl, HttpRequestMessage actualMessage)
{
var message = actualMessage.Content.ReadAsStringAsync().Result;
var logEntry = JsonConvert.DeserializeObject<LogEntry>(message);
return logEntry.MessageText == expectedMessageText &&
logEntry.DateLogged == expectedDateLogged &&
actualMessage.Method == expectedMethod && actualMessage.RequestUri.ToString() == expectedUrl;
}
Leave DoesLogEntryMatch as a non-async method, and await ReadAsStringAsync() inside of a Task.Run(). This spawns a new thread that will await the result, but allows the original method call to run synchronously. From what I've read, this is the only "safe" way to call an asynchronous method from a synchronous context (i.e. no deadlocks). This is what I wound up doing.
private bool DoesLogEntryMatch(string expectedMessageText, DateTime expectedDateLogged,
HttpMethod expectedMethod, string expectedUrl, HttpRequestMessage actualMessage)
{
var message = Task.Run(async () => await actualMessage.Content.ReadAsStringAsync()).Result;
var logEntry = JsonConvert.DeserializeObject<LogEntry>(message);
return logEntry.MessageText == expectedMessageText &&
logEntry.DateLogged == expectedDateLogged &&
actualMessage.Method == expectedMethod && actualMessage.RequestUri.ToString() == expectedUrl;
}
So, I got this working, but it seems like there should be a better way of doing this in FakeItEasy. Is there something equivalent to a MatchesAsync() method that would take a predicate that supports async/await?
There's no MatchesAsync in FakeItEasy; maybe it's something that could be added (though of course it could only work for async methods).
Leave DoesLogEntryMatch as a non-async method, and don't await ReadAsStringAsync(). This seems to work when I tested it, but I have read that doing this could cause deadlocks in certain situations.
In fact, I think that's the correct approach here. Using .Wait() or .Result is strongly discouraged in application code, but you're not in application code, you're in a unit test. The deadlock that can occur is caused by the presence of a SynchronizationContext, which exists in some frameworks (desktop frameworks like WPF or WinForms, classic ASP.NET), but not in the context of a unit test, so you should be fine. I used the same approach successfully in the past.
Nethereum uses an Async method to get the TransactionCount of an address.
I have put the method into a async task:
public async Task<object> GetTxCount(string address)
{
return await web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(address).ConfigureAwait(false);
}
And attempting to test it with...
[TestMethod]
public async Task TestMethodAsync()
{
string address = "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae";
EthTest.Eth et = new EthTest.Eth();
var encoded = et.GetTxCount(address);
encoded.Wait();
}
How should I call the GetTxCount from a unit test to get the actual result.
I have used the "wait" command even though it is not recommended, but still cannot get it to return a result.
The Unit test bombs out - it does not even hit the API that Nethereum calls.
You have already made the test async then use async all the way through by using await to call GetTxCount
[TestMethod]
public async Task TestMethodAsync() {
string address = "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae";
var et = new EthTest.Eth();
var encoded = await et.GetTxCount(address);
}
Given that GetTxCount is just returning the task then there really is no need to await it in the method.
Refactor to
public Task<HexBigInteger> GetTxCount(string address) {
return web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(address);
}
or
public async Task<HexBigInteger> GetTxCount(string address) {
var result = await web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(address).ConfigureAwait(false);
return result.
}
Reference Async/Await - Best Practices in Asynchronous Programming
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.
I'm looking at examples, just trying to understand the await keyword in a MVC AsyncController. I feel like the following should work as I am just trying to return a list asynchronously. This was just an example for understanding the async keyword:
public async Task<ActionResult> Index()
{
var s = await SelectAsync();
return View(s);
}
private async Task<IEnumerable<Student>> SelectAsync()
{
var ctx = new Test.MVC4.Repository.StudentDataContext;
return await ctx.Students.ToList();
}
I get that Task<IEnumerable<Student>> is not awaitable. I was under the impression that Tasks are awaitable.
Updated: What about something like this (assuming the EF code has been abstracted to the .Select method?
public async Task<ActionResult> Index()
{
var s = await SelectAsync();
return View(s);
}
private async Task<IEnumerable<Student>> SelectAsync()
{
return _repo.Select();
}
Or do I also need to use Task.Run inside the SelectAsync method as well? I'm used to doing this sort of thing in client-side so I appreciate the help here with these methods...
You are calling awaiton ctx.Students.ToList(). This method (ToList()) does not return a Task and therefor is not awaitable.