I would to call an asynchronous function in an Unity injection factory, like so...
Container.RegisterType<HttpClient>(new InjectionFactory(
async c => await Create()));
... but it says...
Error CS4010: Cannot convert async lambda expression to delegate type
'Func'. An async lambda expression may return
void, Task or Task, none of which are convertible to
'Func'.
Is there a way around this?
Register the factory as Task<HttpClient> using the DelegateInjectionFactory. Then you can await it after it is injected, in code that you control.
public static IUnityContainer CompositionRoot()
{
var container = new Unity.UnityContainer();
container.RegisterType<Application>();
container.RegisterType<Task<HttpClient>>
(
new DelegateInjectionFactory
(
new Func<Task<HttpClient>>
(
async () => await Create()
)
)
);
return container;
}
public static async Task<HttpClient> Create()
{
await Task.Delay(1); //Simulate doing something asynchronous
return new HttpClient();
}
Example of a class that would receive the injection:
public class Example
{
protected readonly Task<HttpClient> _client; //Injected
public Example(Task<HttpClient> client)
{
_client = client;
}
public async Task<string> Run()
{
var result = await (await _client).GetAsync("http://www.StackOverflow.com");
var text = await result.Content.ReadAsStringAsync();
return text;
}
}
Now Create() will be executed asynchronously, but is not awaited by the container (which isn't set up for that). Instead, it is awaited by your own code, in the class that consumes it, which you have control over.
Note: While this example demonstrates that it is possible, I would probably not do this in production code. It is more common to write a factory class, give it an async method, inject the factory class, and await the method in the class receiving the injection.
Related
I have code:
private async Task Enqueue(object request)
{
try
{
await _client.Enqueue(request);
}
catch (Exception e)
{
await Task.Delay(_delay);
await Queue(request);
}
}
I am trying to make this bunch of code more testible, and be able to check this line:
await Task.Delay(_delay);
for that I got an idea that I could use Func<>, meaning, that I should pass it to constructor and then I will be able to check what number is passed to delay. Since I am not new to Func usage I was wondering whether it's as easy as I am thinking and all I need is:
private readonly Func<int, int> _delayFunc;
and then:
await Task.Delay(_delayFunc(_retryDelayMs));
or whether some Task should be returned (like Func<int, Task> etc)?
If you use Fun<int> then would will have to pass the return value of your func to task delay like await Task.Delay(_fun()). This enables you to assert in your unit tests whether _fun was invoked or not...but not more.
If you wan't to test the daly it would be better to create a DelaySevice inject this into your class and use a (mock) during testing.
something like:
interface IDelayService
{
Task Delay(int delay);
}
class DelayService : IDelayService
{
public async Task Delay(int delay)
{
await Task.Delay(delay);
}
}
in your test:
var mock = new Mock<IDelayService >();
mock.Setup(x => x.Delay(10)).Returns(()=>Task.Completed);
var target = new YourClass(mock.Object);
await target.Enqueue();
mock.Verify(x => x.Delay(10), Times.Once);
In my application I need to call a method before all the API request. If a specific condition met then I need to execute set of statements in that method.
In order to generalize this I created a helper class something like this.
public class CertificateValidator {
readonly IDependencyService _serviceLocator;
public CertificateValidator(IDependencyService serviceLocator) {
_serviceLocator = serviceLocator;
}
public async Task <T> TryExecuteWithCertificateValidationAsync <T> (Task <T> operation) {
var service = _serviceLocator.Get <IDeviceService> ();
if (service.CertificateValidationRequired()) {
// My Code.
}
T actualResult = await operation;
return actualResult;
}
}
And In my viewmodel I have done something like this.
public CertificateValidator ValidateCertificate => new CertificateValidator(_serviceLocator);
var response = await ValidateCertificate
.TryExecuteWithCertificateValidationAsync(MyMethodAsync());
private async Task<RequestResult<Response>> MyMethodAsync()
{
// Some code
}
But when I implement like this the execution flow is
First MyMethodAsync() will be called.
And when it reaches the await method it the executes the
TryExecuteWithCertificateValidationAsync method and runs the remaining code there.
And then when it reaches T actualResult = await operation; return
actualResult; the control go back to MyMethodAsync() - await statement.
And my doubt here is,
I need to execute the TryExecuteWithCertificateValidationAsync completely and then followed by MyMethodAsync.
In short as I said early, I need to execute set of code before I call all my API calls. How I can achieve something similar using async an await.
Rather than passing a Task pass a function:
public async Task<T> TryExecuteWithCertificateValidationAsync<T>(Func<Task<T>> operation)
{
var service = _serviceLocator.Get<IDeviceService>();
if (service.CertificateValidationRequired())
{
// My Code.
}
T actualResult = await operation();
return actualResult;
}
var response = await ValidateCertificate
.TryExecuteWithCertificateValidationAsync(MyMethodAsync);
Update as per comment
If the method requires arguments, the types need to be prepended as additional generic arguments to Func:
private async Task<RequestResult<Response>> MyMethodAsync(int i)
{
// Some code
}
public async Task<T> TryExecuteWithCertificateValidationAsync<T>(Func<int, Task<T>> operation) // Add int as second generic argument
{
T actualResult = await operation(1); // Can now be called with an integer
return actualResult;
}
In the Call asynchronous method in constructor? question is no answer that, starts the async Operation in the constructor and store the Task in a member and an awaits it before using the resource:
public class DeviceAccess
{
private readonly Task<Container> containerTask;
public DeviceAccess(Database database)
{
containerTask = GetContainer(database);
}
private async Task<Container> GetContainer(Database database)
{
var conatinerResponse = await database.CreateContainerIfNotExistsAsync("Device");
return conatinerResponse.Container;
}
public async Task<Device> GetDevice(string deviceId)
{
var container = await containerTask;
return await doSomething(container);
}
}
In my case every Operation needs the resource, so I see no advantage to use some lazy loading.
Is it valid to start a async Operation in a constructor or can result this into problems?
The biggest problem I can see here is that [Value]Task[<T>] is an API that enables async, not a promise to be async; just because CreateContainerIfNotExistsAsync is named *Async and returns Task<T> - that doesn't actually mean it is async - it could run synchronously and return a result via Task.FromResult (aka "async over sync"). If you're not concerned about that problem, then fine I guess. But I wonder whether an OpenAsync() method that you call after construction would be more appropriate, i.e.
public class DeviceAccess
{
private Container _container;
public DeviceAccess() {}
public async ValueTask OpenAsync(Database database) {
if (_container == null)
_container = await GetContainerAsync(database);
}
public async Task<Device> GetDeviceAsync(string deviceId)
{
var container = _container ?? throw new InvalidOperationException("not open");
return await doSomething(container); // might be able to inline the "await" here
}
}
I have a WebApi controller which calls a third party API in asynchronous mode.
All works ok and now I want to sort the result in a separate action method.
Now, when I call the API, the callback with the result never happens after running "await client.GetAsycn(...)" in the DAL. What am I missing?
This is my API controller:
// GET api/lookup
[ResponseType(typeof(RestaurantModel))]
public async Task<IHttpActionResult> Get(string outcode)
{
if (string.IsNullOrEmpty(outcode)) throw new ArgumentNullException(nameof(outcode));
var result = await _repository.GetRestaurantsByOutcode(outcode);
return Ok(new RestaurantModel()
{
Result = result
});
}
// GET api/sorted
[System.Web.Http.Route("~/api/sorted")]
public List<Restaurant> GetSorted(string outcode)
{
if (string.IsNullOrEmpty(outcode)) throw new ArgumentNullException(nameof(outcode));
return _repository.GetSortedRestaurantsByOutcode(outcode);
}
This is my repository with a new method to sort the result:
public class RestaurantRepository : IRestaurantRepository
{
private readonly IContext _context;
public RestaurantRepository(IContext context)
{
_context = context;
}
public Task<ApiResult> GetRestaurantsByOutcode(string outcode)
{
return _context.GetRestaurantsByOutcode(outcode);
}
public List<Restaurant> GetSortedRestaurantsByOutcode(string outcode)
{
return _context.GetRestaurantsByOutcode(outcode).Result.Restaurants
.OrderBy(x => x.Name).ToList();
}
}
This is my DAL to call the third party API:
public async Task<ApiResult> GetRestaurantsByOutcode(string outcode)
{
using (var client = new HttpClient())
{
ConfigureHttpClient(client);
var response = await client.GetAsync(
$"restaurants?q={WebUtility.UrlEncode(outcode)}");
return response.IsSuccessStatusCode
? await response.Content.ReadAsAsync<ApiResult>()
: null;
}
}
You have a mix-match of sometimes you use async/await and other times you don't. Async / await (can and does by default) ensures that the call resumes on the calling thread so the context is resulted. You need to allign your code so you make use of the async/await in the whole stack. Otherwise you are creating a deadlock for your self.
[System.Web.Http.Route("~/api/sorted")]
// missing async in signature (not good if you are calling it with await in your controller)
public async Task<List<Restaurant>> GetSorted(string outcode)
{
if (string.IsNullOrEmpty(outcode)) throw new ArgumentNullException(nameof(outcode));
// added await in call
return await _repository.GetSortedRestaurantsByOutcode(outcode);
}
DAL
public class RestaurantRepository : IRestaurantRepository
{
private readonly IContext _context;
public RestaurantRepository(IContext context)
{
_context = context;
}
// added async and await
public async Task<ApiResult> GetRestaurantsByOutcode(string outcode)
{
return await _context.GetRestaurantsByOutcode(outcode);
}
// added async and await
public async Task<List<Restaurant>> GetSortedRestaurantsByOutcode(string outcode)
{
// here you were not using await but then using result even though you were calling into a method marked as async which in turn used an await. this is where you deadlocked but this the fix.
return (await _context.GetRestaurantsByOutcode(outcode)).Restaurants
.OrderBy(x => x.Name).ToList();
}
}
I need to create a unit test for the following class's InvokeAsync method. What it merely does is calling a private method in the same class which includes complex logical branches and web service calls. But the unit test are written only for the public methods. So what should I do in this scenario? What should I test in here? Any suggestions would be greatly appreciated.
public class MyCustomHandler
{
private readonly ILogger _logger;
private readonly HttpClient _httpClient;
public MyCustomHandler(HttpClient client, ILogger logger)
{
_httpClient = httpClient;
_logger = logger;
}
public override async Task<bool> InvokeAsync()
{
return await InvokeReplyPathAsync();
}
private async Task<bool> InvokeReplyPathAsync()
{
// Lot of code with complex logical branches and calling web services.
}
}
If your testing framework supports it (MsTest does) you can declare your test method async and call the method from there. I'd mock the web services using a mock framework such as Rhino Mocks so you don't need to depend on the actual web service.
public interface IWebService
{
Task<bool> GetDataAsync();
}
[TestClass]
public class AsyncTests
{
[TestMethod]
public async void Test()
{
var webService = MockRepository.GenerateStub<IWebService>();
webService.Expect(x => x.GetDataAsync()).Return(new Task<bool>(() => false));
var myHandler = new MyCustomHandler(webService);
bool result = await myHandler.InvokeAsync();
Assert.IsFalse(result);
}
}
[TestMethod]
public async void TestWebServiceException()
{
var webService = MockRepository.GenerateStub<IWebService>();
webService.Expect(x => x.GetDataAsync()).Throw(new WebException("Service unavailable"));
var myHandler = new MyCustomHandler(webService);
bool result = await myHandler.InvokeAsync();
Assert.IsFalse(result);
}