Maintain dependency object instance within the thread - asynchronous

Need help on below issue, I have below method:
public IHttpActionResult Test()
{
Task.Run(() => DoTheStuff())
Return Ok()
}
Note: Here I don't want to use async/await keyword, as I don't care about the result of DoTheStuff() method. I just need to open one thread and execute the code.
DoTheStuff() method refers the objects which are injected through dependency injection (Autofac). and in Module.Config I have registered all the required dependencies with lifetimescope.
Below issue I am facing call to Task.Run(() => DoTheStuff()) starts new thread executing DoTheStuff() method.
At the same time Test() method completes it execution with return Ok(), but DoTheStuff method is still running asynchronously.
With execution of Test() method, the registered dependencies gets disposed, and DoTheStuff() method throws below exception:
Nested lifetime cannot be created from the LifetimeScope as it has
already been disposed
Can someone please let me know how to maintain dependency object instance within the thread?

I can see a couple options.
Extract DoTheStuff into its own service. Register the services that you're injecting and using in DoTheStuff as InstancePerDependency so that the service gets its own instance. See https://autofaccn.readthedocs.io/en/latest/lifetime/instance-scope.html.
Add a Wait:
var t = Task.Run(() => DoTheStuff());
t.Wait();
return Ok();
Let me know if neither of those works.

Related

Facing a rare issue in async method - .net core 3.1

we developed an API using .net core 3.1 with async methods.
here the issue is current object value has been overwritten by the subsequent request value.
example:
async Task function(request)
{
var devUser = GetUserDetail(request.userType, request.userId);
var response = await ExecureRequest(request, devUser.name);
}
in the above example
"devUser" object value of Api Request 1 call has been overwritten by the Api Request 2 call
is there any possibilities get this issue in async methods.?
please share me your experience and comments.
The async keyword turns a method into an async method, which allows you to use the await keyword in its body. When the await keyword is applied, it suspends the calling method and yields control back to its caller until the awaited task is complete. await can only be used inside an async method.
"devUser" local variable is no possibilities get this issue in async methods.

JilOutputFormatter: Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead

I have this formatter in my .NET Core 3.1 project (which I recently upgraded from 2.1):
public class JilOutputFormatter : TextOutputFormatter {
public JilOutputFormatter() =>
JilFormatterConfig.AddSupportedHeaders(SupportedMediaTypes, SupportedEncodings);
public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) {
using (var writer = new StreamWriter(context.HttpContext.Response.Body)) {
JSON.Serialize(context.Object, writer, MyOptions);
writer.Flush();
}
return Task.FromResult(true);
}
}
And I'm adding it to pipeline with this snippet:
services.AddMvcCore(o => {
o.OutputFormatters.Insert(0, new JilOutputFormatter());
}).AddOthersBlahBlah();
It was working like a charm when the application was on 2.1. But now on 3.1 I'm getting this error:
An unhandled exception occurred while processing the request.
InvalidOperationException: Synchronous operations are disallowed. Call
WriteAsync or set AllowSynchronousIO to true instead.
I tried to async the write operation, but can't find the method on Jil. Do you have any idea please?
NOTE: I know there are some answers - like this one - that are saying how to AllowSynchronousIO. But I'm interested on how to async write in Jil.
You'll have to use the 3.0 alpha versions. Jil doesn't even include the word Task in the source code in the latest stable version, 2.17 (or Github search is having some issues).
Version 3.0 uses Pipelines directly. You can use the SerializeAsync(T, PipeWriter , Encoding, Options, CancellationToken). Maybe you can work with HttpContext.Response.BodyWriter. I haven't tested this though.
Eg :
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context,
Encoding selectedEncoding)
{
var data=context.Object;
var writer=contest.Response.BodyWriter;
await JSON.SerializeAsync(data,writer,selectedEncoding);
}
Errors can revolve around ReadAsync, WriteAsync, and FlushAsync with outputs similar to what is listed below.
Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead.
Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.
Synchronous operations are disallowed. Call FlushAsync or set AllowSynchronousIO to true instead.
As a temporary workaround, you can set the value of AllowSynchronousIO in your ConfigureServices method found in your Startup class.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<KestrelServerOptions>(options =>
{
options.AllowSynchronousIO = true;
});
// If using IIS:
services.Configure<IISServerOptions>(options =>
{
options.AllowSynchronousIO = true;
});
// other services
}
It isn’t a great workaround, but it will keep you moving forward. The better solution is to upgrade your libraries and perform all your actions asynchronously.
See the detailed post .NET Core 3.0 AllowSynchronousIO Workaround by Khalid Abuhakmeh
TLDR: As of Dotnet Core 5.0, the default web-server (Kestral) is designed to perform only Async Level work to be the most performant. Enable Sync within Kestral.
Rational: Due to to the majority of software being more IO Dependent than CPU Dependent, Async Programming allows for the system to perform other work, while waiting for the IO to complete (IE; Writing to Disk, Reading something from the network).
Place this within Startup.cs within the ConfigurationService function.
services.Configure<KestrelServerOptions>(options =>
{
options.AllowSynchronousIO = true;
});

Realm doesn’t work with xUnite and .net core

I’m having issues running realm with xUnite and Net core. Here is a very simple test that I want to run
public class UnitTest1
{
[Scenario]
public void Test1()
{
var realm = Realm.GetInstance(new InMemoryConfiguration("Test123"));
realm.Write(() =>
{
realm.Add(new Product());
});
var test = realm.All<Product>().First();
realm.Write(() => realm.RemoveAll());
}
}
I get different exceptions on different machines (Windows & Mac) on line where I try to create a Realm instace with InMemoryConfiguration.
On Mac I get the following exception
libc++abi.dylib: terminating with uncaught exception of type realm::IncorrectThreadException: Realm accessed from incorrect thread.
On Windows I get the following exception when running
ERROR Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. at
System.Net.Sockets.NetworkStream.Read(Span1 destination) at
System.Net.Sockets.NetworkStream.ReadByte() at
System.IO.BinaryReader.ReadByte() at
System.IO.BinaryReader.Read7BitEncodedInt() at
System.IO.BinaryReader.ReadString() at
Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.LengthPrefixCommunicationChannel.NotifyDataAvailable() at
Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TcpClientExtensions.MessageLoopAsync(TcpClient client, ICommunicationChannel channel, Action1 errorHandler, CancellationToken cancellationToken) Source: System.Net.Sockets HResult: -2146232800 Inner Exception: An existing connection was forcibly closed by the remote host HResult: -2147467259
I’m using Realm 3.3.0 and xUnit 2.4.1
I’ve tried downgrading to Realm 2.2.0, and it didn’t work either.
The solution to this problem was found in this Github post
The piece of code from that helped me to solve the issue
Realm GetInstanceWithoutCapturingContext(RealmConfiguration config)
{
var context = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
Realm realm = null;
try
{
realm = Realm.GetInstance(config);
}
finally
{
SynchronizationContext.SetSynchronizationContext(context);
}
return realm;
}
Though it took a while for me to apply this to my solution.
First and foremost, instead of just setting the context to null I am using Nito.AsyncEx.AsyncContext. Because otherwise automatic changes will not be propagated through threads, as realm needs a non-null SynchronizationContext for that feature to work. So, in my case the method looks something like this
public class MockRealmFactory : IRealmFactory
{
private readonly SynchronizationContext _synchronizationContext;
private readonly string _defaultDatabaseId;
public MockRealmFactory()
{
_synchronizationContext = new AsyncContext().SynchronizationContext;
_defaultDatabaseId = Guid.NewGuid().ToString();
}
public Realm GetRealmWithPath(string realmDbPath)
{
var context = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(_synchronizationContext);
Realm realm;
try
{
realm = Realm.GetInstance(new InMemoryConfiguration(realmDbPath));
}
finally
{
SynchronizationContext.SetSynchronizationContext(context);
}
return realm;
}
}
Further, this fixed a lot of failing unit tests. But I was still receiving that same exception - Realm accessed from incorrect thread. And I had no clue why, cause everything was set correctly. Then I found that the tests that were failing were related to methods where I was using async realm api, in particular realm.WriteAsync. After some more digging I found the following lines in the realm documentation.
It is not a problem if you have set SynchronisationContext.Current but
it will cause WriteAsync to dispatch again on the thread pool, which
may create another worker thread. So, if you are using Current in your
threads, consider calling just Write instead of WriteAsync.
In my code there was no direct need of using the async API. I removed and replaced with sync Write and all the tests became green again! I guess if I find myself in a situation that I do need to use the async API because of some kind of bulk insertions, I'd either mock that specific API, or replace with my own background thread using Task.Run instead of using Realm's version.

Azure / Xamarin - SyncContext.InitializeAsync Deadlock

I have a Xamarin.Forms App which use Azure App Service with SQLLite Offline Sync.
When calling SyncContext.InitializeAsync a deadlock appears and the function InitializeAsync never finished.
In this Thread in found the solution: Azure/Xamarin Mobile App Hangs at SyncContext.InitializeAsync
This works:
System.Threading.Tasks.Task.Run(() => this.IDataProvider.IMobileServiceClient.SyncContext.InitializeAsync(localStore, _syncHandler)).Wait();
This not:
await this.IDataProvider.IMobileServiceClient.SyncContext.InitializeAsync(localStore, _syncHandler);
Whole function:
public override async System.Threading.Tasks.Task Init()
{
string storePath = System.IO.Path.Combine(Microsoft.WindowsAzure.MobileServices.MobileServiceClient.DefaultDatabasePath, localStoreName);
Microsoft.WindowsAzure.MobileServices.SQLiteStore.MobileServiceSQLiteStore localStore = new Microsoft.WindowsAzure.MobileServices.SQLiteStore.MobileServiceSQLiteStore(storePath);
localStore.DefineTable<CPM.Recruitment.Mobile.Freelancer.DataObjects.Entities.Promoter>();
System.Threading.Tasks.Task.Run(() => this.IDataProvider.IMobileServiceClient.SyncContext.InitializeAsync(localStore, _syncHandler)).Wait();
//await this.IDataProvider.IMobileServiceClient.SyncContext.InitializeAsync(localStore, _syncHandler);
_promoters = new Azure.AppService.DataObjects.Client.Sync.List<CPM.Recruitment.Mobile.Freelancer.DataObjects.Entities.Promoter>(this, this.IDataProvider.IMobileServiceClient.GetSyncTable<CPM.Recruitment.Mobile.Freelancer.DataObjects.Entities.Promoter>());
}
But why? I dont want to use Wait();
The differences between await and Wait method are:
await means the current task will be executed in a separated thread asynchronously and the calling thread won't be blocked. If the calling thread is UI thread. the UI thread will continue to run other operations.
Wait method are synchronization method. It causes the calling thread to wait until the current task has completed. If the calling thread is UI thread, UI operations will be blocked.
It seems that a deadlock will be caused if you use await to run the task which will not block UI thread.

SIgnalR to group registration fails on Connect method

I am using this part of code in the hub (with interface IConnected) of signalr. The problem is when I call Group.Add in Connect method, a client really isn't in the group and I can't send him a message throw this group. When I call later some method from the client to register in a group, everything is ok. What I don't understand, in both methods(in Connect() even in registerClientToGroup()) has the same Groups.Add method.
public System.Threading.Tasks.Task Connect()
{
Groups.Add(this.Context.ConnectionId, "group");
return null;
}
Some ideas? Thanks a lot.
I'm not sure if this is the direct cause of your problem, but I'm surprised you are not getting errors because you are returning a null value for the Task from Connect. You probably are getting errors, you're just not debugging/catching them.
If you don't have any other work to do in Connect that necessitates your own Task then simply return the Task from the call to Groups.Add like so:
public Task Connect()
{
return Groups.Add(this.Context.ConnectionId, "group");
}

Resources