C# async calls and realm instances - xamarin

I am using Realm with a Xamarin Forms project, and I have read about how realm entity instances can't be shared across threads.
Given the following code, is using the route obtained in line 100, and then accessed again on line 109 after the awaited call on 104, dangerous?
I am new to using Realm, but if this is true, then one must get a new instance of the Realm and any object being worked with after any/every awaited call. Seems onerous...

is using the route obtained in line 100, and then accessed again on line 109 after the awaited call on 104, dangerous?
Yes, on the next foreach iteration, you will end up with a different managed thread, and Realm will throw an different thread access exception.
The key is to use a SynchronizationContext so your await continuations are on the same thread (and, of course, since you will be in a different thread, skip the use of the Realm-based async methods)
Using Stephen Cleary's Nito.AsyncEx (he is the king of sync contexts 😜)
re: how can i force await to continue on the same thread?
var yourRealmInstanceThread = new AsyncContextThread();
await yourRealmInstanceThread.Factory.Run(async () =>
{
var asyncExBasedRealm = Realm.GetInstance();
var routes = asyncExBasedRealm.All<UserModel>();
foreach (var route in routes)
{
// map it
// post it
await Task.Delay(TimeSpan.FromMilliseconds(1)); // Simulate some Task, i.e. a httpclient request....
// The following continuations will be executed on the proper thread
asyncExBasedRealm.Write(() => route.Uploaded = true);
}
});
Using SushiHangover.RealmThread
I wrote a simple SynchronizationContext for Realm awhile back, it works for my needs and has a specialized API for Realm.
using (var realmThread = new RealmThread(realm.Config))
{
await realmThread.InvokeAsync(async myRealm =>
{
var routes = myRealm.All<UserModel>();
foreach (var route in routes)
{
// map it
// post it
await Task.Delay(TimeSpan.FromMilliseconds(1));
// The following continuations will be executed on the proper thread
myRealm.Write(() => route.Uploaded = true);
}
});
}
Note: For someone that does not understand SynchronizationContext well, I would highly recommend using Nito.AsyncEx as a generic solution that is well supported and due to the fact that is from Stephen Cleary... I use it in a vast majority of my projects.

Related

MassTransit - GetSendEndpoint for using In Memory

I am beginning with MassTransit, for a publisher/consumer scenario. In production we will be using SQS, however i would like to be able to use "In Memory" for development locally.
I am having trouble with forming the correct Uri for the call to ISendEndpointProvider.GetSendEnpoint(), as per:
//THE SET UP CODE:
x.AddConsumer<MTConsumer, MTMessageConsumerDefinition>()
.Endpoint(e =>
{
// override the default endpoint name
e.Name = "process-input-item";
//... more configurations as per docs here...
})
;
x.UsingInMemory((context, cfg) =>
{
cfg.ConfigureEndpoints(context);
});
});
//The Publish Code:
var endpoint = await SendEndpointProvider.GetSendEndpoint(new Uri("/ProcessInputItem"));
await endpoint.Send(new MTMessage { InputItemId = item.Id});
Note
I have tried the various cases for the endpoint string.
I do not want to capture the instance of IBus to call Send as that is not the 'closest' instance to the consumer, which according to the docs is important to consider.
Mass Transit document reference: https://masstransit-project.com/usage/configuration.html#receive-endpoints
Thank you for any guidance with this,
Dylan
As explained in the documentation, there are short endpoint addresses which can be used. In your case:
await SendEndpointProvider.GetSendEndpoint(new Uri("queue:process-input-item"));

Uno platform: invoke UI update from async thread

I have an async member which ultimately needs to invoke some UI updates, after getting some data from a server.
I think I need something like BeginInvokeOnMainThread, or Dispatcher.Invoke, but neither of these appear to be recognized in the Uno context.
Here's the essence of what I have:
public async Task LoadList()
{
...
// get data
Uri uri = new Uri("https://...");
response = await httpClient.GetAsync(uri);
// display
BeginInvokeOnMainThread () =>
{
... update the UI ...
});
}
But I get the error CS0103 The name 'BeginInvokeOnMainThread' does not exist in the current context UnoTest.Droid, UnoTest.UWP, UnoTest.Wasm
BeginInvokeOnMainThread / Dispatcher.Invoke / Control.Invoke were never a good idea.
Uno should have a SynchronizationContext that is automatically used by await, so manual thread marshaling should not be necessary:
public async Task LoadList()
{
...
// get data
Uri uri = new Uri("https://...");
response = await httpClient.GetAsync(uri);
// display
... update the UI ...
}

Web API - ConfigureAwait(true) not working as I thought

I'm having some trouble understanding the in's and out's of "continueOnCapturedContext" from a .NET v4.6 WebAPI 2 standpoint.
The problem I'm having is there doesn't appear to be any difference between ConfigureAwait(true) and ConfigureAwait(false).
I've put together a sample app that demonstrates what's happening:
public async Task<IHttpActionResult> Get(bool continueOnContext)
{
int beforeRunningExampleThreadId = Thread.CurrentThread.ManagedThreadId;
int runningExampleThreadId = await ExecuteExampleAsync(continueOnContext).ConfigureAwait(continueOnContext);
int afterRunningExampleThreadId = Thread.CurrentThread.ManagedThreadId;
return Ok(new
{
HasSyncContext = SynchronizationContext.Current != null,
ContinueOnCapturedContext = continueOnContext,
BeforeRunningExampleThreadId = beforeRunningExampleThreadId,
RunningExampleThreadId = runningExampleThreadId,
AfterRunningExampleThreadId = afterRunningExampleThreadId,
ResultingCulture = Thread.CurrentThread.CurrentCulture,
SameThreadRunningAndAfter = runningExampleThreadId == afterRunningExampleThreadId
});
}
private async Task<int> ExecuteExampleAsync(bool continueOnContext)
{
return await Task.Delay(TimeSpan.FromMilliseconds(10)).ContinueWith((task) => Thread.CurrentThread.ManagedThreadId).ConfigureAwait(continueOnContext);
}
For "/Test?continueOnContext=true", this returns me:
{"HasSyncContext":true,"ContinueOnCapturedContext":true,"BeforeRunningExampleThreadId":43,"RunningExampleThreadId":31,"AfterRunningExampleThreadId":56,"ResultingCulture":"fr-CA","SameThreadRunningAndAfter":false}
So you can see I have a Sync context, I'm doing ConfigureAwait(true) and yet the thread isn't "continuing" in any way - a new thread is assigned before, while running and after running the asynchronous code. This isn't working the way I would expect - have I some fundamental misunderstanding here?
Can someone explain to me why in this code ConfigureAwait(true) and ConfigureAwait(false) are effectively doing the same thing?
UPDATE -
I figured it out and have answered below. I also like the answer from
#YuvalShap. If you're stuck on this like I was I suggest you read both.
When an asynchronous handler resumes execution on legacy ASP.NET, the
continuation is queued to the request context. The continuation must
wait for any other continuations that have already been queued (only
one may run at a time). When it is ready to run, a thread is taken
from the thread pool, enters the request context, and then resumes
executing the handler. That “re-entering” the request context involves
a number of housekeeping tasks, such as setting HttpContext.Current
and the current thread’s identity and culture.
From ASP.NET Core SynchronizationContext Stephen Cleary's blog post.
To sum up, ASP.NET versions prior to Core uses AspNetSynchronizationContext as the request context, that means that when you are calling ConfigureAwait(true) (or not calling ConfigureAwait(false)) you capture the context which tells the method to resume execution on the request context.
The request context keeps HttpContext.Current and the current thread’s identity and culture consistent but it is not exclusive to a specific thread the only limitation is that only one thread can run in the context at a time.
OK I figured it out, so I'll post an answer in case it will help others.
In .NET 4.6 WebAPI 2 - the "Captured Context" that we are continuing on isn't the thread, it's the Request context. Among other things, the Request Context knows about the HttpContext. When ConfigureAwait(true) is specified, we're telling .NET that we want to keep the Request Context and everything about it (HttpContext & some other properties) after the await - we want to return to the context that we started with - this does not take into account the thread.
When we specify ConfigureAwait(false) we're saying we don't need to return to the Request Context that we started with. This means that .NET can just return back without having to care about the HttpContext & some other properties, hence the marginal performance gain.
Given that knowledge I changed my code:
public async Task<IHttpActionResult> Get(bool continueOnContext)
{
var beforeRunningValue = HttpContext.Current != null;
var whileRunningValue = await ExecuteExampleAsync(continueOnContext).ConfigureAwait(continueOnContext);
var afterRunningValue = HttpContext.Current != null;
return Ok(new
{
ContinueOnCapturedContext = continueOnContext,
BeforeRunningValue = beforeRunningValue,
WhileRunningValue = whileRunningValue,
AfterRunningValue = afterRunningValue,
SameBeforeAndAfter = beforeRunningValue == afterRunningValue
});
}
private async Task<bool> ExecuteExampleAsync(bool continueOnContext)
{
return await Task.Delay(TimeSpan.FromMilliseconds(10)).ContinueWith((task) =>
{
var hasHttpContext = HttpContext.Current != null;
return hasHttpContext;
}).ConfigureAwait(continueOnContext);
}
When continueOnContext = true:
{"ContinueOnCapturedContext":true,"BeforeRunningValue":true,"WhileRunningValue":false,"AfterRunningValue":true,"SameBeforeAndAfter":true}
When continueOnContext = false:
{"ContinueOnCapturedContext":false,"BeforeRunningValue":true,"WhileRunningValue":false,"AfterRunningValue":false,"SameBeforeAndAfter":false}
So from this example you can see that HttpContext.Current exists before the asynchronous method and is lost during the asynchronous method regardless of the ConfigureAwait setting.
The difference comes in AFTER the async operation is completed:
When we specify ConfigureAwait(true) we get to come back to the Request Context that called the async method - this does some housekeeping and syncs up the HttpContext so it's not null when we continue on
When we specify ConfigureAwait(false) we just continue on without going back to the Request Context, therefore HttpContext is null

Asp.net Web Api [duplicate]

This question already has answers here:
Why should I create async WebAPI operations instead of sync ones?
(2 answers)
Closed 5 years ago.
I was going through some code to learn how to Consume a web API.
public async Task<List<TodoItem>> RefreshDataAsync ()
{
// RestUrl = http://developer.xamarin.com:8081/api/todoitems/
var uri = new Uri (string.Format (Constants.RestUrl, string.Empty));
var response = await client.GetAsync (uri);
if (response.IsSuccessStatusCode) {
var content = await response.Content.ReadAsStringAsync ();
Items = JsonConvert.DeserializeObject <List<TodoItem>> (content);
}
}
I found this code.All i want to know is why we use Async and Await.
As i observed Await is mandatory in method body when function is encapsulated as Async keyword.
It depends on your application. For GUI apps, it keeps the user interface from freezing and allows this thread to do other things while the call is being made. For apis, it can allow for scalability if you have blocking IO operations. Here is a similar question with some great explanations: Why should I create async WebAPI operations instead of sync ones?

calling asynchronous method in windows phone 7

Is there any way to use server methods not asynchronously in windows phone 7 application?
I have a list of data. In foreach loop, send a request to server for each data but they are not completed in the order of my calling. How can i do that?
I have a list of data. In foreach loop, send a request to server for each data but they are not completed in the order of my calling. How can i do that?
Well you can effectively make them synchronous - get rid of it being an actual foreach loop, and instead set up the appropriate asynchronous callbacks so that when the first response comes in, you send the second request, etc, until there are no more requests. (You might want to use a Queue<T> to queue up the requests to send.)
Do not revert to synchronous ways simply because something appears to not work. There are many benefits to working in an asynchronous world. There are also some dangers. The key is knowing how to avoid those dangers.
Here is an example using WebClient that will have harmful effects.
foreach (var item in items)
{
WebClient client = new WebClient();
client.DownloadStringCompleted += (sender, args) =>
{
item.Stuff = args.Result;
};
client.OpenReadAsync(new Uri("http://mydomain.com/stuff"));
}
When the client is returned, there is no guarantee that item is the same item that "created" the client request. This is known as "Access to modified closer". Which simply means you might be trying to modify something that doesn't exist anymore, or is not the same.
The proper approach to this is to capture your item within the foreach like such:
foreach (var item in items)
{
var internalItem = item;
WebClient client = new WebClient();
client.DownloadStringCompleted += (sender, args) =>
{
internalItem.Stuff = args.Result;
};
client.OpenReadAsync(new Uri("http://mydomain.com/stuff"));
}
This ensures that you are using the correct item because it has been captured within the scope of the foreach.

Resources