Async lazy initialization in static class not compiling - c#

I am attempting to incorporate async lazy initialization in a static class per Stephen Cleary's blog post (http://blog.stephencleary.com/2012/08/asynchronous-lazy-initialization.html):
internal static class ThirdPartyCommunicator
{
private static readonly AsyncLazy<IClient> myClient = new AsyncLazy<IClient>
(
async () => { var client = await CreateClient(); return client; }
);
private static async Task<IClient> CreateClient()
{
var identity = service.GetIdentity();
await identity.AuthenticationAsync();
return identity.Client();
}
internal static async void DoWork()
{
var client = await this.myClient; //compilation error
....
In DoWork(), I get the error:
Cannot access static field "myClient" in non-static context
I'm unclear as to what non-static context is causing this issue.

A static method cannot use, in any sense, the this keyword. There is no this when static :)
Delete the this keyword and everything will compile fine because myClient is also static.

Related

One httpClient for many method in one class

I would like to use one httpclient to many method in class.
Below is the simplified code:
public class test{
private readonly HttpClient _httpClient;
public Test(){
_httpClient = new HttpClient();
}
public void method1(){
using (_httpClient){
//...
}
}
public void method2(){
using (_httpClient){
//...
}
}
public void method3(){
using (_httpClient){
//...
}
}
}
Then it calls the method data:
public async static void TestHttpClient()
{
Test test1 = new Test();
test1.Method1();
test1.Method2();
test1.Method3();
}
Method 1 is working. When calling the second one I get the message: "You cannot access a deleted object."
Thanks for helps.
Regards
using calls the Dispose() method after the scope - which destroys the object - keep the instance of your HttpClient within the instance of your object
public class test : IDisposable
{
private readonly HttpClient _httpClient;
public test()
{
_httpClient = new HttpClient();
}
public void Dispose()
{
_httpClient.Dispose();
}
public void method1()
{
//...
}
}
then you can dispose your object instead of the HttpClient
using(test myObject = new test())
{
myObject.method1();
myObject.method2();
}
If you want Test to create and reuse a disposable resource (e.g. HttpClient, then Test should implement IDisposable and should dispose of the resource in its Dispose method. That means that the class using Test should use a using block:
public async static void TestHttpClient()
{
using (Test test1 = new Test())
{
test1.Method1();
test1.Method2();
test1.Method3();
}
}
One way to do it is to create a private variable and a get accessor
private HttpClient _httpClient;
private HttpClient MyClient
{
get {
if (_httpClient == null)
{
_httpClient = new HttpClient
{
BaseAddress = new Uri($"https://your.url/")
};
//Other client logic goes here
}
return _httpClient;
}
}
Then from your method, you just reference the accessor
public async Task method1()
{
await MyClient.Post() //post logic here
//...
}
You don't need to dispose HttpClient, MS recommends leaving the object in place, unless you know you need to forcibly close the connection.

.NET Core: Correct way of using async/await modifier in C# console application [duplicate]

public class test
{
public async Task Go()
{
await PrintAnswerToLife();
Console.WriteLine("done");
}
public async Task PrintAnswerToLife()
{
int answer = await GetAnswerToLife();
Console.WriteLine(answer);
}
public async Task<int> GetAnswerToLife()
{
await Task.Delay(5000);
int answer = 21 * 2;
return answer;
}
}
if I want to call Go in main() method, how can I do that?
I am trying out c# new features, I know i can hook the async method to a event and by triggering that event, async method can be called.
But what if I want to call it directly in main method? How can i do that?
I did something like
class Program
{
static void Main(string[] args)
{
test t = new test();
t.Go().GetAwaiter().OnCompleted(() =>
{
Console.WriteLine("finished");
});
Console.ReadKey();
}
}
But seems it's a dead lock and nothing is printed on the screen.
Your Main method can be simplified. For C# 7.1 and newer:
static async Task Main(string[] args)
{
test t = new test();
await t.Go();
Console.WriteLine("finished");
Console.ReadKey();
}
For earlier versions of C#:
static void Main(string[] args)
{
test t = new test();
t.Go().Wait();
Console.WriteLine("finished");
Console.ReadKey();
}
This is part of the beauty of the async keyword (and related functionality): the use and confusing nature of callbacks is greatly reduced or eliminated.
Instead of Wait, you're better off using
new test().Go().GetAwaiter().GetResult()
since this will avoid exceptions being wrapped into AggregateExceptions, so you can just surround your Go() method with a try catch(Exception ex) block as usual.
Since the release of C# v7.1 async main methods have become available to use which avoids the need for the workarounds in the answers already posted. The following signatures have been added:
public static Task Main();
public static Task<int> Main();
public static Task Main(string[] args);
public static Task<int> Main(string[] args);
This allows you to write your code like this:
static async Task Main(string[] args)
{
await DoSomethingAsync();
}
static async Task DoSomethingAsync()
{
//...
}
class Program
{
static void Main(string[] args)
{
test t = new test();
Task.Run(async () => await t.Go());
}
}
As long as you are accessing the result object from the returned task, there is no need to use GetAwaiter at all (Only in case you are accessing the result).
static async Task<String> sayHelloAsync(){
await Task.Delay(1000);
return "hello world";
}
static void main(string[] args){
var data = sayHelloAsync();
//implicitly waits for the result and makes synchronous call.
//no need for Console.ReadKey()
Console.Write(data.Result);
//synchronous call .. same as previous one
Console.Write(sayHelloAsync().GetAwaiter().GetResult());
}
if you want to wait for a task to be done and do some further processing:
sayHelloAsyn().GetAwaiter().OnCompleted(() => {
Console.Write("done" );
});
Console.ReadLine();
If you are interested in getting the results from sayHelloAsync and do further processing on it:
sayHelloAsync().ContinueWith(prev => {
//prev.Result should have "hello world"
Console.Write("done do further processing here .. here is the result from sayHelloAsync" + prev.Result);
});
Console.ReadLine();
One last simple way to wait for function:
static void main(string[] args){
sayHelloAsync().Wait();
Console.Read();
}
static async Task sayHelloAsync(){
await Task.Delay(1000);
Console.Write( "hello world");
}
public static void Main(string[] args)
{
var t = new test();
Task.Run(async () => { await t.Go();}).Wait();
}
Use .Wait()
static void Main(string[] args){
SomeTaskManager someTaskManager = new SomeTaskManager();
Task<List<String>> task = Task.Run(() => marginaleNotesGenerationTask.Execute());
task.Wait();
List<String> r = task.Result;
}
public class SomeTaskManager
{
public async Task<List<String>> Execute() {
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:4000/");
client.DefaultRequestHeaders.Accept.Clear();
HttpContent httpContent = new StringContent(jsonEnvellope, Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage httpResponse = await client.PostAsync("", httpContent);
if (httpResponse.Content != null)
{
string responseContent = await httpResponse.Content.ReadAsStringAsync();
dynamic answer = JsonConvert.DeserializeObject(responseContent);
summaries = answer[0].ToObject<List<String>>();
}
}
}
try "Result" property
class Program
{
static void Main(string[] args)
{
test t = new test();
t.Go().Result;
Console.ReadKey();
}
}
C# 9 Top-level statements simplified things even more, now you don't even have to do anything extra to call async methods from your Main, you can just do this:
using System;
using System.Threading.Tasks;
await Task.Delay(1000);
Console.WriteLine("Hello World!");
For more information see What's new in C# 9.0, Top-level statements:
The top-level statements may contain async expressions. In that case, the synthesized entry point returns a Task, or Task<int>.

How to set a readonly property in a C# async constructor

I have a service in an ASP .Net Core 2.2 Web API. The constructor is async because it calls an async method. But because the constructor is async, it's complaining about trying to initialize a property.
public class MyService
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public async Task MyService(IServiceScopeFactory serviceScopeFactory)
{
this._serviceScopeFactory = serviceScopeFactory;
await DoSomething();
}
}
It gives me this error:
"A readonly field cannot be assigned to (except in a constructor or a variable initializer)"
Any ideas?
As users mentioned in the comments above, I was mistaken to think that I could make a constructor async.
Mathew Watson and Stephen Cleary provided me with a link with a good alternative to my problem: https://blog.stephencleary.com/2013/01/async-oop-2-constructors.html
Summary:
Factory Pattern
Use a static creation method, making the type its own factory:
public sealed class MyClass
{
private MyData asyncData;
private MyClass() { ... }
private async Task<MyClass> InitializeAsync()
{
asyncData = await GetDataAsync();
return this;
}
public static Task<MyClass> CreateAsync()
{
var ret = new MyClass();
return ret.InitializeAsync();
}
}
public static async Task UseMyClassAsync()
{
MyClass instance = await MyClass.CreateAsync();
...
}
One common example to solve your problem is to create a static method on the class and call the async method from there and well as the constructor.
public class MyService
{
private readonly IServiceScopeFactory _serviceScopeFactory;
public static async Task<MyService> BuildMyService(IServiceScopeFactory serviceScopeFactory)
{
await DoSomething();
return new MyService(serviceScopeFactory);
}
public MyService(IServiceScopeFactory serviceScopeFactory)
{
this._serviceScopeFactory = serviceScopeFactory;
}
}

Use an async InjectionFactory

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.

Unit testing an async method with Task<bool> return type

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);
}

Categories

Resources