Assigning new value to object field in await blocks further instructions - asynchronous

I'm stuck on this, I have no clue why won't the last print execute past object value initialization.
await _client
.get(Uri.parse(_url), headers: {"location": "Mars"})
.then((result) => result.body)
.then(json.decode)
.then((json) => json.forEach((person) {
print(person); // this gets executed and printed over and over
Person newPerson;
print('hehe lolz'); // this gets executed too
newPerson.status = person['status'];
print('hello'); // this never gets executed...
Person class is just a model with all String fields and a constructor.
What could be blocking the execution of last print?

That's because newPerson is null and when you are trying to call newPerson.status - the NullPointer exception appears and all the code below doesn't execute. Just make:
Person newPerson = Person();

Related

Set HttpContext.Current is not the same in continuation of await

From this answer from Stephen Cleary, I understand that the HttpContext flows with the SynchronizationContext. Therefore, given the following piece of code:
public async Task<ActionResult> Index()
{
var outerContext = System.Web.HttpContext.Current = new HttpContext(
new HttpRequest(null, "http://test.com", null),
new HttpResponse(new StreamWriter("C:/Path")));
Console.WriteLine(outerContext.Equals(System.Web.HttpContext.Current));
await Task.Run(
delegate
{
Console.WriteLine(outerContext.Equals(System.Web.HttpContext.Current));
});
Console.WriteLine(outerContext.Equals(System.Web.HttpContext.Current));
return View();
}
I would expect the console output to be:
True
False
True
However, the actual output is:
True
False
False
After debugging, it appears that the context in the continuation is set to the original context of the request, the one it had before I manually set it by calling HttpContext.Current = .... What is the reason for this? Does it get set to the request context somewhere before the code after the await gets executed?
The HttpContext.Current value is not saved and restored by await. await will capture SynchronizationContext.Current and use that to resume execution.
When the request starts, a new request context is created (which includes a specific HttpContext.Current instance). Whenever AspNetSynchronizationContext resumes execution on that request context, it sets HttpContext.Current to the instance for that request context.
So, after the await, HttpContext.Current will be the same instance it was at the beginning of Index, not whatever instance your code assigns to it.

Error when getAsync after adding column EF core

I init a User info table only not have FacebookID column, and there were 2 record. Now I add a FacebookID column to practice register by Facebook using migration EF core Framework. In first called, a record added and 2 FacebookID under is null. And I want to second called, It have to check that FacebookID is exist, If it is exist, please return message that FacebookID is exist. If it is not exist, add new User
I wrote a function to check that, because 2 Facebookid in image is null so It not working
RuleFor(model => model).MustAsync((x, cancellationToken) => FacebookIdMustUnique(x.FacebookId, cancellationToken))
.WithMessage(string.Format(Resource.Validation_Existed, Resource.FacebookId));
async Task<bool> FacebookIdMustUnique(string facebookId, CancellationToken cancellationToken = default(CancellationToken))
{
var user = await userService.GetAsync(x =>
x.FacebookId.Equals(facebookId, StringComparison.InvariantCultureIgnoreCase),
cancellationToken
);
return user == null;
}
image description here
I wrote a function to check that, because 2 Facebookid in image is null so It not working
Your following code will throw in this line when the Facebookid is null :
x.FacebookId.Equals(facebookId, StringComparison.InvariantCultureIgnoreCase)
To fix it, you need take consideration whether it is null before invoke its .Equals() method:
async Task FacebookIdMustUnique(string facebookId, CancellationToken cancellationToken = default(CancellationToken))
{
if(facebookId ==null){ return true; }
var user = await userService.GetAsync(
x => x.FacebookId.Equals(facebookId, StringComparison.InvariantCultureIgnoreCase),
cancellationToken
);
return user == null;
}
(In your case, it likely be fine if the facebook id is null, so I just return true)
As a reminder: it' always a good practice to check null for Nullable types.

NullReferenceException in unittesting with NUnit, NSubstitute, and async method

I'm doing some unit testing in C# using NUnit and NSubstitute. I have a class called Adapter, which has a method, GetTemplates(), I want to unit test. GetTemplates() uses httpclient, which I have mocked out using an interface.
The call in GetTemplates looks something like:
public async Task<List<Template>> GetTemplates()
{
//Code left out for simplificity.
var response = await _client.GetAsync($"GetTemplates");
if (!response.IsSuccessStatusCode)
{
throw new Exception();
}
}
I want _client.GetAsync to return a HttpResponseMessage with a HttpStatusCode.BadRequest so that I can test if the exception is being thrown.
The test method looks like:
[Test]
public void GetTemplate_ReturnBadRequestHttpMessage_ThrowException()
{
//Arrange.
var httpMessage = new HttpResponseMessage(HttpStatusCode.BadRequest);
_client.GetAsync("").Returns(Task.FromResult(httpMessage));
//Act.
var ex = Assert.ThrowsAsync<Exception>(async () => await _Adapter.GetSigningTemplates());
//Assert.
Assert.IsInstanceOf<Exception>(ex);
}
When the method has run, it returns
System.NullReferenceException: Object reference not set to an instance of an object.
What did I do wrong?
That is because the arrangement of the mocked client does not match what is actually invoked when the test is exercised.
The client expects
var response = await _client.GetAsync($"GetTemplates");
but the setup is for
_client.GetAsync("")
note the different arguments passed. When mocks do not get exactly what was setup they usually return the default value of their return type, which in this case is null.
Change the test to use the expected parameter
_client.GetAsync($"GetTemplates").Returns(Task.FromResult(httpMessage));
Reference Return for specific args
or use an argument matcher
_client.GetAsync(Arg.Any<string>()).Returns(Task.FromResult(httpMessage));
Reference Argument matchers

Rebus saga data state issue

I'm trying out the simple deferred message timeout pattern in Rebus along the outline here http://mookid.dk/oncode/archives/3043 in order to have alternative behaviors depending on whether or not I receive a timely response from an other service hooked up to the same bus. Code has been modified to use async/await.
(yes, I know that article is really about unit testing. I'm just trying out the same timeout thing)
The handler in my case is a saga. Two message send operations are awaited as the last two calls of the handler of the message that starts the saga. First message uses request/reply from the external service and the reply is also eventually handled in the same saga.
Second message is a deferred message that is supposed to enforce the alternative action in case timeout occurs, just like in the Rebus unit test example. I've verified that messages are sent from and received by the saga/handler without any problems. It looks something like this:
public class TestSaga : Saga<TestSagaData>, IAmInitiatedBy<SomeMessage>, IHandleMessages<SomeReply>, IHandleMessages<TimeOutMessage>
{
private readonly IBus _bus;
public TestSaga(IBus bus)
{
_bus = bus;
}
protected override void CorrelateMessages(ICorrelationConfig<TestSagaData> config)
{
config.Correlate<SomeMessage>(s => s.Identifier, d => d.OriginalMessageIdentifier);
config.Correlate<SomeMessage>(s => s.Tag, d => d.CorrelationIdentifier);
config.Correlate<SomeReply>(s => s.Tag, d => d.CorrelationIdentifier);
config.Correlate<TimeOutMessage>(s => s.Tag, d => d.CorrelationIdentifier);
}
public async Task Handle(SomeMessage message)
{
if (!IsNew)
return;
Data.CorrelationIdentifier = message.Tag;
Data.OriginalMessageIdentifier = message.Identifier;
Data.ReplyReceived = false;
await _bus.Send(new SomeRequest {Tag = message.Tag});
await _bus.Defer(TimeSpan.FromSeconds(30), new TimeOutMessage() {Tag = message.Tag});
}
public async Task Handle(SomeReply message)
{
// Even if we would get here loooong before...
Data.ReplyReceived = true;
await DoStuffIfNotTimedout();
}
public async Task Handle(TimeOutMessage message)
{
// ...this, DoStuffIfTimeout below is always called
// since state is preserved from the _bus.Defer call. Correct?
if (!Data.ReplyReceived)
await DoStuffIfTimedout();
}
private async Task DoStuffIfNotTimedout()
{
// some more async stuff here
MarkAsComplete();
}
private async Task DoStuffIfTimedout()
{
// some more async stuff here
MarkAsComplete();
}
}
I have added a boolean saga data flag/property to indicate that the reply to the first message was received first, setting it to false initially before the both await Send/Defer calls
and setting it to true immediately in the message handler of the reply.
The flag was supposed to be used to prevent the timeout actions to start in case the deferred timeout thing was received after the first reply but before the subsequent actions were done with and the saga marked completed.
However, in this case the state of the saga seems to 'follow' the message received. So if the first message reply handler is entered first and sets the saga data flag to true. Then when the deferred message handler is entered later,
something has reset the flag again, seemingly ignoring the action taken in the first reply handler (setting the flag true). Not sure whether the 'Revision' number of the saga is supposed to change or not but it remains unchanged (zero) all the time it seems.
Also noted that it doesn't matter if the timeout occurs long after the reply handler is entered, when the timeout handler is entered, the the flag is 'false'.
Is this saga state behavior by design? I thought saga state would somehow be persisted between message handler calls. If it's the wrong behavior, what could possibly cause it?
I quite new to Rebus so I'm sure I've misunderstood something here but in that case I would like to know what :).
Transport used under the hood is RabbitMQ.
Test code: saga state test

Parallel exceptions are being caught

somehow my exceptions seem to being caught by method they are executing in. Here is the code to call the method. As you can see I create a cancellation token with a time out. I register a method to call when the cancellation token fires and then I start a new task. The cancellation token appears to be working OK. As does the registered method.
var cancellationToken = new CancellationTokenSource(subscriber.TimeToExpire).Token;
cancellationToken.Register(() =>
{
subscriber.Abort();
});
var task = Task<bool>.Factory.StartNew(() =>
{
subscriber.RunAsync((T)messagePacket.Body, cancellationToken);
return true;
})
.ContinueWith(anticedant =>
{
if (anticedant.IsCanceled)
{
Counter.Increment(12);
Trace.WriteLine("Request was canceled");
}
if (anticedant.IsFaulted)
{
Counter.Increment(13);
Trace.WriteLine("Request was canceled");
}
if (anticedant.IsCompleted)
{
Counter.Increment(14);
}
The next piece of code is the method that seems to be not only throwing the excetion (expected behavior. but also catching the exception.
public async override Task<bool> ProcessAsync(Message input, CancellationToken cancellationToken)
{
Random r = new Random();
Thread.Sleep(r.Next(90, 110));
cancellationToken.ThrowIfCancellationRequested();
return await DoSomethingAsync(input);
}
The exception is being thrown by the cancellation token but according to intellitrace it is being caught at the end of the method. I have tried a number of different options including throwing my own exception, but no matter what the continuewith function always executes the IsComleted or ran to completion code.
Any ideas on what I am doing wrong?
Thanks
I assume that RunAsync is the same as ProcessAsync.
The exception is being thrown by the cancellation token but according to intellitrace it is being caught at the end of the method.
Yup. Any async method will catch its own exceptions and place them on its returned Task. This is by design.
no matter what the continuewith function always executes the IsComleted or ran to completion code.
Well, let's take another look at the code:
var task = Task<bool>.Factory.StartNew(() =>
{
subscriber.RunAsync((T)messagePacket.Body, cancellationToken);
return true;
})
.ContinueWith(
Consider the lambda passed to StartNew: it calls RunAsync, it ignores the Task that it returns, and then it returns true (successfully). So the Task returned by StartNew will always return successfully. This is why the ContinueWith always executes for a successfully-completed task.
What you really want is to await the Task returned by RunAsync. So, something like this:
var task = Task.Run(async () =>
{
await subscriber.RunAsync((T)messagePacket.Body, cancellationToken);
return true;
})
.ContinueWith(
You're still ignoring the return value of RunAsync (the bool it returns is ignored), but you're not ignoring the Task itself (including cancellation/exception information).
P.S. I'm assuming there's a lot of code you're not showing us; using StartNew/Run to just kick off some async work and return a value is very expensive.
P.P.S. Use await Task.Delay instead of Thread.Sleep.

Resources