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;
}
}
Related
If I have a controller class, and I want to pass it to a different namespace that handles my HTTP calls, such as in the below scenario, Main task calls TaskA() which calls TaskG(), do I need to pass it to TaskG via A like the below? Or is there someway to just create it in the namespace HttpClassFurtherDown without the calling classes needing to pass it.
namespace Controllers{
public class Drawings : ControllerBase
{
private IHttpClientFactory _client {get;set;}
public Drawings(IHttpClientFactory client)
{
_client=client;
}
[Route("api/Drawings")]
[HttpPost]
public async Task<ActionResult> PostAsync([FromBody] JsonFileContent[] content)
{
HttpExample e = new HttpExample(_client);
e.TaskA();
TaskB();
return Accepted($"Drawings/Job/{id}");
}
}}
namespace HttpClassExample{
public class HttpExample
{
private IHttpClientFactory _client {get;set;}
public HttpExample(IHttpClientFactory client)
{
_client=client;
}
public void TaskA()
{
DoSomeProcessing();
HttpClassExampleFurtherDown e = new HttpClassExampleFurtherDown(client);
e.TaskG();
}
}
}
namespace HttpClassExampleFurtherDown{
public class HttpExampleFurtherDown
{
private IHttpClientFactory _client {get;set;}
public HttpExampleFurtherDown(IHttpClientFactory client)
{
_client=client;
}
public void TaskG(client)
{
//Finally Using It Here. I want to avoid having to generate it at the controller level and pass it all the way down.
client.CreateClient();
client.SendAsync();
}
}
}
I want to avoid having to generate it at the controller level and pass it all the way down.
If following DIP then inject explicit dependencies where they are actually needed instead of tightly coupling to implementation concerns.
While I believe the example provided are oversimplified, here is what the example above should look like
Controllers.Drawings
namespace Controllers{
using HttpClassExample;
//...
public class Drawings : ControllerBase {
private readonly IHttpExample client;
public Drawings(IHttpExample client) {
this.client = client;
}
[Route("api/Drawings")]
[HttpPost]
public async Task<ActionResult> PostAsync([FromBody] JsonFileContent[] content) {
await client.TaskA();
TaskB();
return Accepted($"Drawings/Job/{id}");
}
}
}
HttpClassExample.HttpExample
namespace HttpClassExample{
using HttpClassExampleFurtherDown;
//...
public class HttpExample : IHttpExample{
private readonly IHttpExampleFurtherDown client;
public HttpExample(IHttpExampleFurtherDown client) {
this.client = client;
}
public async Task TaskA() {
DoSomeProcessing();
await client.TaskG();
}
//...
}
}
HttpClassExampleFurtherDown.HttpExampleFurtherDown
namespace HttpClassExampleFurtherDown{
public class HttpExampleFurtherDown : IHttpExampleFurtherDown {
private readonly IHttpClientFactory factory;
public HttpExampleFurtherDown(IHttpClientFactory factory) {
this.factory = factory;
}
public async Task TaskG() {
HttpClient client = factory.CreateClient();
//...
var response = await client.SendAsync();
//...
}
}
}
This assumes that a container is being used to manage the resolution and injection of dependency implementations based on their registered abstractions
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.
I have a project using redis distributed cache based on asp.net core 2.1 solution. There's something that I haven't understood.
I have a class myClassName with a constructor subject to injection.
public class myClassName
{
private readonly IDistributedCache _userCache;
public myClassName(IDistributedCache distributedCache) => _userCache
= distributedCache;
public async Task FirstMethod(...)
private async Task SecondMethod(...)
}
from another class "myClassNameTwo" I have to create a "myClassName" instance and access to some methods.
So I have :
Public class myClassNameTwo : Hub
{
private readonly AssetsBroadcaster _broadcaster;
public myClassNameTwo(AssetsBroadcaster broadcaster)
{
_broadcaster = broadcaster;
}
public async Task DoSomething(...)
{
myClassName hello = new myClassName(???)
await hello.FirstMethod(...)
}
}
How can retrieve the IDistributedCache service instance to pass to myClassName constructor?
If you are using .Net Core, Using dependency injunction, You can inject the instants of the myClassName class if you have registered it in the startup.
like,
public class myClassName{
private readonly IDistributedCache _userCache;
public myClassName(IDistributedCache distributedCache) {
_userCache = distributedCache;
}
public async Task FirstMethod(...)
private async Task SecondMethod(...)
}
For the second class it can be like following
Public class myClassNameTwo : Hub
{
private readonly AssetsBroadcaster _broadcaster;
private readonly myClassName _myClassName;
public myClassNameTwo(AssetsBroadcaster broadcaster,
myClassName myClassName)
{
_broadcaster = broadcaster;
_myClassName = myClassName;
}
public async Task DoSomething(...)
{
await _myClassName.FirstMethod(...)
}
}
Dependencies for the myClassName will be automatically injected. So you don't need to inject it separately.
For more details
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.
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);
}