Await a task in anonymous object selected with Linq select - linq

When I try to run this code, it throws this error:
System.AggregateException: One or more errors occurred. (A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.)
---> System.InvalidOperationException: A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.
var returnFacilitators = facilitators.Select(async f => new
{
Name = f.DisplayNameLastFirstDegreeTitles(),
Value = f.FacilitatorId,
FirstName = f.FirstName,
LastName = f.LastName,
DegreeTitles = f.DegreeTitles,
CanDelete = await facilitatorService.CanRemoveFacilitatorAsync(f.FacilitatorId)
}).ToList();
CanRemoveFacilitator is an async Task<bool>.

Related

how to define BusinessNetworkConnection in hyperledger-composer transaction processor?

In my hyperledger-composer app, I have a transaction processor:
async function doSomething(transaction) {
//some code
// the following line results in error message:
const connection = new BusinessNetworkConnection();
await connection.connect('admin#tmy-network');
const result = await connection.query(selectPatientByEmail, { inputValue: email });
//some more code
}
However, the line
const connection = new BusinessNetworkConnection();
causes the following error messsage:
ReferenceError: BusinessNetworkConnection is not defined
How can I define the BusinessNetworkConnection?
*******************************UPDATE**************************************
Following the comment by Paul O'Mahony, I used the following line of code in my transaction processor function (in order to get the patient with the email address 'adam#gmail.com'):
let result = await query('selectPatientByEmail', {
"email": "adam#gmail.com"
});
The query is defined in the queries.qry file as follows:
query selectPatientByEmail {
description: "Select the patient with the given email address"
statement:
SELECT org.comp.app.Patient
WHERE (email == _$email)
}
However, the query returns "undefined" (i.e. variable "result" is undefined) .
What for god's sake is wrong with the code? I just can't see what might be the causing this behaviour.
***************************Update2*****************************************
I have to correct myself ... the query returns something ... but when I want to access the id of the returned patient, this is not possible. That is,
result.id is "undefined"
How can I access the id of the patient returned?
this is because you are (above) writing client code inside a native transaction function - you don't need to set these. Transaction processor functions are automatically invoked by the runtime when transactions are submitted (eg using the BusinessNetworkConnection API under the covers, but it is already part of the transaction - you don't need to specify) . See https://hyperledger.github.io/composer/latest/reference/js_scripts for more info - and the sample networks for common use cases and examples -> https://github.com/hyperledger/composer-sample-networks/tree/master/packages/

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

Microsoft Bot Framework: Exception: The data is changed

I have a bot with the following conversation scenario:
Send text to LUIS
LUIS intent calls context.Call(...) to launch a Dialog
This dialog terminates, save some info in the userData:
private static async Task storeBotData(IDialogContext context, BotData userData)
{
Activity activity = (Activity)context.Activity;
StateClient sc = activity.GetStateClient();
await sc.BotState.SetUserDataAsync(activity.ChannelId, activity.From.Id, userData);
}
And after it call another dialog, again with context.Call(...).
Then the last dialog runs and terminates.
My problem is that when updating the user data at the end of the first dialog (step 3), I have the following exception in the Bot Framework Channel Emulator:
`Exception: The data is changed [File of type 'text/plain']`...
What happens here ? I think that when a dialog terminates, it call setUserData by itself, but I don't understand why I can't update userData anywhere in the code...
I have tried to catch the exception, but nothing is catched.. But I know that the userData is updated, because when I try to retrieve it back, it is updated...
Any help is welcome :)
Thanks
Botframework restores/saves state of conversation after each act of activity, so under the covers typical flow looks like the following:
[23:15:40] <- GET 200 getUserData
[23:15:47] <- GET 200 getConversationData
[23:15:47] <- GET 200 getPrivateConversationData
...
[23:16:42] <- POST 200 setConversationData
[23:16:42] <- POST 200 setUserData
[23:16:42] <- POST 200 setPrivateConversationData
As it is mentioned here : These botData objects will fail to be stored if another instance of your bot has changed the object already. So in your case the exception occurs at the termination of dialog, when framework calls setUserData by himself and figures out that the BotData has been changed already (by your explicit call of BotState.SetUserDataAsync). I suppose that's why you were not able to catch the exception.
Solution:
I used the following code and it fixed the issue:
private static void storeBotData(IDialogContext context, BotData userData)
{
var data = context.UserData;
data.SetValue("field_name", false);
}
The reason it works is that we modify the object of UserData but allow botFramework to "commit" it himself, so there is no conflict
I agree with #Artem (this solved my issue too, thanks!). I would just add the following guideline.
Use
var data = context.UserData;
data.SetValue("field_name", false);
whenever you have a IDialogContext object available, so you let the Bot Framework commit changes.
Use instead
StateClient sc = activity.GetStateClient();
await sc.BotState.SetUserDataAsync(activity.ChannelId, activity.From.Id, userData);
when you don't have an IDialogContext object, e.g. in the MessageController class.

Dynamics CRM saving Entity Changes - Getting Errors

I'm really scratching my head with this. I'm trying to use the Dynamics CRM SDK to update an account record. No matter what I try, it's failing. Here goes.
Account sampleAccount = CrmAccount.GetAccountsBySubmissionCode(crmService, "ERZZUP").Single<Account>();
sampleAccount.Name = "AMC Edited";
crmService.Update(sampleAccount);
Gives the error: EntityState must be set to null, Created (for Create message) or Changed (for Update message)
XrmServiceContext ctx = new XrmServiceContext(crmService);
Account sampleAccount = CrmAccount.GetAccountsBySubmissionCode(crmService, "ERZZUP").Single<Account>();
sampleAccount.Name = "AMC Edited";
ctx.UpdateObject(sampleAccount);
ctx.SaveChanges();
Gives the error: The context is not currently tracking the 'account' entity.
XrmServiceContext ctx = new XrmServiceContext(crmService);
Account sampleAccount = CrmAccount.GetAccountsBySubmissionCode(crmService, "ERZZUP").Single<Account>();
sampleAccount.Name = "AMC Edited";
ctx.Attach(sampleAccount);
ctx.UpdateObject(sampleAccount);
ctx.SaveChanges();
Gives the error: The 'account' entity is already attached to a context.
For reference,
1. The Account object is created by the SDK Early Bound Code Generation Tool
2. crmService is the IOrganizationService connection object
3. GetAccounts ... performs a LINQ query and return an IEnumerable
Please help.
Thanks,
Chris.
Refer to http://msdn.microsoft.com/en-us/library/gg695783.aspx, particularly the "Multiple Data Contexts" part. It seems you're using multiple contexts to track the entities. The CrmAccount.GetAccountsBySubmissionCode method just hides this from you.
Make sure within the CrmAccount.GetAccountsBySubmissionCode method to dispose of the context/service before returning the IEnumerable<Account>, or make sure you use the same context/service to Update.

LINQ CRM 2011 Update - Create

I notice the the CRM moderator David Jennaway on the technet forum states that you can't use LINQ to update/Create records in CRM 2011 see here http://social.microsoft.com/Forums/en-IE/crmdevelopment/thread/682a7be2-1c07-497e-8f58-cea55c298062
But I have seen a few threads that make it seem as if it should work. Here is my attempt which doesn't work. Any ideas why not?
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
OrganizationServiceContext orgContext = new OrganizationServiceContext(service);
EntityState state = new EntityState();
state = EntityState.Changed;
var counter = from c in orgContext.CreateQuery<pcx_entitycounter>()
where c.pcx_name.Contains("pcx_candidate")
select new pcx_entitycounter
{Id = c.Id,
pcx_name = c.pcx_name, pcx_Sequence = c.pcx_Sequence, pcx_Prefix = c.pcx_Prefix
};
foreach (var c in counter)
{
string prefix = c.pcx_Prefix.ToString(); ;
string sequence = c.pcx_Sequence.ToString();
c.pcx_Sequence = c.pcx_Sequence + 1;
c.EntityState = state;
**service.Update(c);** //FAILS HERE
}
In my experience, it's been difficult-to-impossible to retrieve an entity from the Context, update it, then use the Service to save the changes. It has caused me headaches figuring it out!
Since your retrieval code uses a query from the Context, all of those entities should be attached to the Context and their states are being tracked. Thus you need to use the Context's method for updating:
foreach (var c in counter) {
string prefix = c.pcx_Prefix.ToString(); ;
string sequence = c.pcx_Sequence.ToString();
c.pcx_Sequence = c.pcx_Sequence + 1;
// Use the Context to save changes
orgContext.UpdateObject(c);
orgContext.SaveChanges();
}
Since a lot of my code will retrieve entities in different ways (i.e. Service or Context) depending on the situation, I have developed a simple method that knows how to update the entity correctly. To expand on your example, you might have an update method that looks like:
public void UpdatePcxEntityCounter(pcx_entitycounter c) {
if (!orgContext.IsAttached(c)) {
service.Update(c);
}
else {
orgContext.UpdateObject(c);
orgContext.SaveChanges();
}
}
This assumes both orgContext and service are available at a scope above that of the method. Otherwise, they'd have to be passed as additional parameters.
Without seeing the difficult its difficult to discern what the issue is but have you tried using orgContext.UpdateObject(c); before doing the update step? Also, not sure why you are assigning the prefix and sequence to local variables within your loop since they don't appear to be being used. Its possible that you are getting a SOAP Exception or something for assigning values that don't work. Do you have any plugins registered on the entity?
See the following links for possible resolutions -
How to update a CRM 2011 Entity using LINQ in a Plugin?
http://social.microsoft.com/Forums/en-US/crmdevelopment/thread/7ae89b3b-6eca-4876-9513-042739fa432a

Resources