Async/Await blocking on Task.WhenAll is called in Sitecore MVC project - asp.net-mvc

I have to call a restsharp ExecuteTaskAsync, I have used await while executing the API and await to complete all tasks since it runs in loop, as soon as it hits await System.Threading.Tasks.Task.WhenAll(tasksList), then no it's blocked, no response in it.
Calling Async code:
Task<IEnumerable<AsyncResponse>> responseList = AddPAsync(id, id1);
To Execute Restsharp's ExecuteTaskAsync:
public static async Task<AsyncResponse> ExecuteApiAsync(RestRequest request, string url, dynamic identifier)
{
var restClient = new RestClient(url);
var cancellationTokenSource = new CancellationTokenSource();
var restResponse = await restClient.ExecuteTaskAsync(request);
return new AsyncResponse{ RestResponse = restResponse, Identifier = identifier };
}
Preparing request and calling RestSharp's ExecuteTaskAsync:
private async Task<IEnumerable<AsyncResponse>> AddPAsync(List<Participant> participantInfo, string registrationId)
{
foreach (var p in pinfo)
{
try
{
var request = new RestRequest(Constants.API_VERSION + Uri, Method.POST);
request.AddHeader("Authorization", string.Format("Bearer {0}", accessToken));
request.AddParameter(Constants.APP_JSON, JsonConvert.SerializeObject(p), ParameterType.RequestBody);
var response = Util.ExecuteApiAsync(request, Constants.END_POINT_URL_NAME, p.Identifier);
tasksList.Add(response);
}
catch (Exception ex)
{
}
}
await System.Threading.Tasks.Task.WhenAll(tasksList);
}
When it hits await Task.WhenAll then no response.
I have already tried:
`ConfigureAwait(false) - it is not working.
It is ASP.Net MVC application in sitecore.

Adding AsyncContext from Nito.AsyncEx worked.

Related

Headers already sent in .net 5

We have middleware in a web API, which we use to filter the resposne body from a controller
After updating our service to .net 5, replacing the output fails with
System.InvalidOperationException: Headers already sent.
at Microsoft.AspNetCore.Server.HttpSys.Response.CheckResponseStarted()
at Microsoft.AspNetCore.Server.HttpSys.FeatureContext.ConsiderEnablingResponseCache()
at Microsoft.AspNetCore.Server.HttpSys.FeatureContext.OnResponseStart()
at Microsoft.AspNetCore.Server.HttpSys.FeatureContext.CompleteAsync()
at Microsoft.AspNetCore.Server.HttpSys.RequestContext.Execute()
at Microsoft.AspNetCore.Server.HttpSys.RequestContext.Execute()
Our middleware to filter the output looks something like this
internal class FilterOutput : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var originalBodyStream = context.Response.Body;
var tempResponseBody = new MemoryStream();
context.Response.Body = tempResponseBody;
context.Response.OnStarting(async state =>
{
await FilterResponse(context, tempResponseBody, originalBodyStream);
}, context);
await next(context);
}
private async Task FilterResponse(HttpContext context, MemoryStream tempResponseBody, Stream originalBodyStream)
{
if (context.Response.StatusCode == 200)
{
var output = Encoding.UTF8.GetString(tempResponseBody.GetBuffer());
var newOutput = output.Filter(null);
var updatedStream = GenerateStreamFromString(newOutput);
await updatedStream.CopyToAsync(originalBodyStream);
context.Response.Body = originalBodyStream;
return;
}
await tempResponseBody.CopyToAsync(originalBodyStream);
}
public static Stream GenerateStreamFromString(string s)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
}
I realize net 5 is propably more asynchronous and sends headers earlier
Is there a way to stop that, so I can modify the output body in middleware?

Integration testing for ChangeEmailAsync in .net core 3.1

I am trying to write Integration test case for change EmailID.
cshtml.cs file
var token = await _userManager.GenerateChangeEmailTokenAsync(user, Input.Email);
var changeEmailResult = await _userManager.ChangeEmailAsync(user, Input.Email, token);
[Fact]
public async Task OnPostUpdateEmailAsync_WithValidInput_ShouldReturnSuccessMessage()
{
await _client.LoginAsync("test1#test.com", TestData.AlicePassword);
var response = await _client.SubmitAsync("./OnPostUpdateEmailAsync", new
{
Email = "testemail#test.com",
Password_ChangeEmail = "Password1"
});
response.AssertOnPage("./ChangeEmailPassword/UpdateEmail");
response.EnsureSuccessStatusCode();
var document = await response.GetDocument();
document.QuerySelectorAll(".alert-success")
.AssertCount(1)
.AssertHasTextEqual(
$"The email address has been changed successfully.");
}
[Fact]
public async Task OnPostResetPasswordAsync_WithWrongConfirmPassword_ShouldReturnErrorMessage()
{
await _client.LoginAsync(TestData.AliceEmail, TestData.AlicePassword);
var response = await _client.SubmitAsync("./ChangeEmailPassword/OnPostResetPasswordAsync", new
{
OldPassword = "OldPassword1",
Password = "NewPassword1",
ConfirmPassword = "NewPassword1"
});
response.AssertOnPage("./ChangeEmailPassword/ResetPassword");
response.EnsureSuccessStatusCode();
var document = await response.GetDocument();
document.QuerySelectorAll(".alert-danger")
.AssertCount(1)
.AssertHasTextEqual($"Error: The passwords do not match.");
}
It is working fine but after executing this, all other test case is getting failed. As i can assume we are changing email id here but for others it still look for old email id. May be i am wrong here. Requesting you all, please help me in this.

Bad state: Stream has already been listened to Flutter error

I am calling an api. I am getting a streamed response after sending the request. But i cannot parse the response and convert it to String/JSON. This is where I am calling the api.
static Future<String> callDeviceListFetchApi() async {
Completer completer = new Completer();
String jsonResponse;
String url = Constants.BASE_URL + Constants.DEVICE_REGISTER_URL;
var client = new http.Client();
var request = new http.Request('GET', Uri.parse(url));
request.headers[HttpHeaders.CONTENT_TYPE] = 'application/json';
request.headers[HttpHeaders.AUTHORIZATION] = '<auth code>';
await client.send(request).then((response) {
response.stream.bytesToString().then((value) {
print(value.toString());
jsonResponse = value.toString();
completer.complete(jsonResponse);
});
}).catchError((error) {
print(error.toString());
});
return completer.future;
}
I am getting the error,
Bad state: Stream has already been listened to Flutter error. Any idea why this is happening?
There's a couple of things wrong with your code. I think you have a slight misunderstanding about how Async and Futures work in dart - you should re-read the docs and this tutorial (part 1 and part 2).
Basically, the problem is that you were returning a 'Future' from an async function. If you return a future from an async function, it has issues (I don't know why the analyzer doesn't catch that).
Future<String> callDeviceListFetchApi() async {
Completer completer = new Completer();
String url = "<url>";
var client = new http.Client();
var request = new http.Request('GET', Uri.parse(url));
request.headers[HttpHeaders.CONTENT_TYPE] = 'application/json';
request.headers[HttpHeaders.AUTHORIZATION] =
'<auth string>';
var response = await client.send(request);
String jsonResponse;
try {
var value = await response.stream.bytesToString();
print(value.toString());
jsonResponse = value.toString();
} catch (error) {
print(error.toString());
}
return completer.complete(jsonResponse);
}
Or not async:
Future<String> callDeviceListFetchApiNotAsync() {
String url = "<url>";
var client = new http.Client();
var request = new http.Request('GET', Uri.parse(url));
request.headers[HttpHeaders.CONTENT_TYPE] = 'application/json';
request.headers[HttpHeaders.AUTHORIZATION] =
'<auth string>';
Completer completer = new Completer();
return client.send(request).then((response) {
return response.stream.bytesToString();
}).then((value) {
print(value.toString());
return value.toString();
}).catchError((error) {
print(error.toString());
// if you use catchError, whatever you return from it
// is the value you'll get wherever you resolve the future.
return null;
});
}
But unless you're trying to do something I'm not seeing, there's a way easier way to do this (assuming all you want to do is get a string from a server):
Future<String> getList() async {
var response = await http.get("<url>", headers: {
HttpHeaders.CONTENT_TYPE: 'application/json',
HttpHeaders.AUTHORIZATION: '<auth string>',
});
if (response.statusCode == 200) {
return response.body;
} else {
throw Error();
}
}

Pass through the HTTP response to the client in MVC 6

I am new to Web API and HTTP.
I am using the MVC 6 (beta version). I have a proxy service (Web API) which has a POST method to get response from another service with XML content returned. I need to return the response content to the client since the client can't call the service directly.
// In my proxy service
public HttpResponseMessage Post(String content)
{
using ( HttpClient client = new HttpClient() ) {
.......
HttpResponseMessage response = client.PostAsync(uri, content).Result;
// I get everything I need in the "response".
// How to return the response or it body to the client.
// return response;
}
}
II need to return the "response" to the client with no or minimum changes. I tried "return response", or create a new HttpResponseMessage, but I only got something like
{"Headers":[{"Key":"Content-Type","Value":["text/xml"]}]}
in the body.
So is there a simple way to pass the response back to the client? Thanks.
The ASP.NET team is currently working on a "proxy middleware" that does exactly what you're looking for: https://github.com/aspnet/Proxy
Here's how it works internally:
public async Task Invoke(HttpContext context)
{
var requestMessage = new HttpRequestMessage();
if (string.Equals(context.Request.Method, "POST", StringComparison.OrdinalIgnoreCase))
{
var streamContent = new StreamContent(context.Request.Body);
requestMessage.Content = streamContent;
}
// Copy the request headers
foreach (var header in context.Request.Headers)
{
if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value) && requestMessage.Content != null)
{
requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
}
requestMessage.Headers.Host = _options.Host + ":" + _options.Port;
var uriString = $"{_options.Scheme}://{_options.Host}:{_options.Port}{context.Request.PathBase}{context.Request.Path}{context.Request.QueryString}";
requestMessage.RequestUri = new Uri(uriString);
requestMessage.Method = new HttpMethod(context.Request.Method);
using (var responseMessage = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
{
context.Response.StatusCode = (int)responseMessage.StatusCode;
foreach (var header in responseMessage.Headers)
{
context.Response.Headers.SetValues(header.Key, header.Value.ToArray());
}
foreach (var header in responseMessage.Content.Headers)
{
context.Response.Headers.SetValues(header.Key, header.Value.ToArray());
}
// SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
context.Response.Headers.Remove("transfer-encoding");
await responseMessage.Content.CopyToAsync(context.Response.Body);
}
}
https://github.com/aspnet/Proxy/blob/dev/src/Microsoft.AspNet.Proxy/ProxyMiddleware.cs

How to ensure UploadStringCompletedEventHandler event has been executed successfully?

How to ensure UploadStringCompletedEventHandler event has been executed successfully ? in following code you can see i am calling function UploadMyPOST with my lastreads parameter having some data. Now you can see i am saving a variable named response into the MyClassXYZ varialbe. in the extreme last you can see there is a event which invoked by the method UploadMyPost() is filling the server response into the response variable. Now here issue is UploadMyPost(lastreads) executes successfully but its invoked event does not executes. Even cursor do not go on that event by which i am not able to fill server response into the response variable. So Anyone know any approach by which i can wait until that event successfully execute and i could able to save server response ?
private async void MyMethod(MyClassXYZ lastreads)
{
await UploadMyPOST(lastreads);
MyClassXYZ serverResponse = response;
if (serverResponse.Book == null)
{
//Do Something.
}
}
private void UploadMyPOST(MyClassXYZ lastreads)
{
apiData = new MyClassXYZApi()
{
AccessToken = thisApp.currentUser.AccessToken,
Book = lastreads.Book,
Page = lastreads.Page,
Device = lastreads.Device
};
//jsondata is my global variable of MyClassXYZ class.
jsondata = Newtonsoft.Json.JsonConvert.SerializeObject(apiData);
MyClassXYZ responsedData = new MyClassXYZ();
Uri lastread_url = new Uri(string.Format("{0}lastread", url_rootPath));
WebClient wc = new WebClient();
wc.Headers["Content-Type"] = "application/json;charset=utf-8";
wc.UploadStringCompleted += new UploadStringCompletedEventHandler(MyUploadStringCompleted);
wc.UploadStringAsync(lastread_url, "POST", jsondata);
}
private void MyUploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
try
{
if (e.Error == null)
{
string resutls = e.Result;
DataContractJsonSerializer json = new DataContractJsonSerializer(typeof(MyClassXYZ));
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(resutls));
response = (MyClassXYZ)json.ReadObject(ms);
}
else
{
string sx = e.Error.ToString();
}
}
catch(Exception exe)
{
}
}
//After Stephen suggession i used the HttpClient so i have written new code with the help of HttpClient. Code is building successfully but at run time cursor goes out from this method to the parent method where from its calling.
private async Task<string> UploadMyPOST(MyClassXYZ lastreads)
{
string value = "";
try
{
apiData = new LastReadAPI()
{
AccessToken = thisApp.currentUser.AccessToken,
Book = lastreads.Book,
Page = lastreads.Page,
Device = lastreads.Device
};
jsondata = Newtonsoft.Json.JsonConvert.SerializeObject(apiData);
LastRead responsedData = new LastRead();
Uri lastread_url = new Uri(string.Format("{0}lastread", url_rootPath));
HttpClient hc = new HttpClient();
//After following line cursor go back to main Method.
var res = await hc.PostAsync(lastread_url, new StringContent(jsondata));
res.EnsureSuccessStatusCode();
Stream content = await res.Content.ReadAsStreamAsync();
return await Task.Run(() => Newtonsoft.Json.JsonConvert.SerializeObject(content));
value = "kd";
}
catch
{ }
return value;
}
I recommend that you use HttpClient or wrap the UploadStringAsync/UploadStringCompleted pair into a Task-based method. Then you can use await like you want to in MyMethod.
Thank you Stephen Clear you leaded me in a right direction and i did POST my request successfully using HttpClient.
HttpClient hc = new HttpClient();
hc.BaseAddress = new Uri(annotation_url.ToString());
HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Post, myUrl);
HttpContent myContent = req.Content = new StringContent(myJsonData, Encoding.UTF8, "application/json");
var response = await hc.PostAsync(myUrl, myContent);
//Following line for pull out the value of content key value which has the actual resposne.
string resutlContetnt = response.Content.ReadAsStringAsync().Result;
DataContractJsonSerializer deserializer_Json = new DataContractJsonSerializer(typeof(MyWrapperClass));
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(resutlContetnt.ToString()));
AnnotateResponse = deserializer_Json.ReadObject(ms) as Annotation;

Resources