Async calls get stuck at HttpClient.SendAsync() - c#

I am using Microsoft Bot framework (SDK v3) to create a QnA bot. While calling the QnAMaker API, the execution gets stuck at HttpCleint.SendAsync.
I have tried calling ConfigureAwait(false) on all the async calls.
I have tried adding .Result at end of function calls.
Both doesn't seem to work.
[Serializable]
public class QnAMakerService
{
private string qnaServiceHostName;
private string knowledgeBaseId;
private string endpointKey;
public QnAMakerService()
{
qnaServiceHostName = "foo";
knowledgeBaseId = "bar";
endpointKey = "foo";
}
async Task<string> Post(string uri, string body)
{
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
{
request.Method = HttpMethod.Post;
request.RequestUri = new Uri(uri);
request.Content = new StringContent(body, Encoding.UTF8, "application/json");
request.Headers.Add("Authorization", "EndpointKey " + endpointKey);
var response = await client.SendAsync(request);
return await response.Content.ReadAsStringAsync();
}
}
public async Task<string> GetAnswer(string question)
{
string uri = qnaServiceHostName + "/qnamaker/knowledgebases/" + knowledgeBaseId + "/generateAnswer";
string questionJSON = #"{'question': '" + question + "'}";
var response = await Post(uri, questionJSON);
var answers = JsonConvert.DeserializeObject<QnAAnswer>(response);
if (answers.answers.Count > 0)
{
return answers.answers[0].answer;
}
else
{
return "No good match found.";
}
}
}
[BotAuthentication]
public class MessagesController : ApiController
{
/// <summary>
/// POST: api/Messages
/// Receive a message from a user and reply to it
/// </summary>
///
QnAMakerService qna = new QnAMakerService();
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
var q = await qna.GetAnswer(activity.Text);
// return our reply to the user
Activity reply = activity.CreateReply($"{q}");
connector.Conversations.ReplyToActivity(reply);
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
}
The execution stops after the SendAsync call with a 500 internal server error excception.
I think the asynchonous code is getting blocked somewhere, but I don't know where.
EDIT : The same block of code(to call the API) works if I try it in a console application.

Related

Azure Speech API gets into an endless loop when called inside a custom WebAPi

Let me explain the scenario -
I have a custom web API created for an application which has multiple parameters, the user call this api by passing multiple parameters which are concatenated based on some logic and then inside this custom api it calls Azure speech API to convert Text to Speech (in 2 steps - 1. I call the Azure speech service to get the token, 2. I call the Azure speech service to convert the text to speech)
The problem -
When I call the Azure speech service to fetch the token, it stays in a endless loop.
Below is the sample code, any pointers in right direction will be helpful -
public class ConverterController : ApiController
{
/// <summary>
/// default constructor
/// </summary>
public ConverterController()
{
}
[HttpGet]
public HttpResponseMessage ConvertUsingSpeech([FromUri] OutReachMessage outReachMessage)
{
try
{
outReachMessage = new OutReachMessage();
var result = ConvertUsingSpeechApi(outReachMessage);
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StringContent(OutputMp3FilePath);
return response;
}
catch (Exception ex)
{
return new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
}
async Task ConvertUsingSpeechApi(OutReachMessage outReachMessage)
{
var authObj = new Authentication("key");
var token = authObj.GetAccessToken();
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", token);
client.DefaultRequestHeaders.Add("Content-Type", contentType);
client.DefaultRequestHeaders.Add("X-Microsoft-OutputFormat", outputFormat);
UriBuilder uriBuilder = new UriBuilder(fetchSpeechUri);
var content = new StringContent("<speak version='1.0' xml:lang='hi-IN'><voice xml:lang='hi-IN' xml:gender='Female' name = 'hi-IN-SwaraNeural'>" +
"Welcome mahesh to the world of Azure - feeling great. </voice></speak>",
Encoding.UTF8, "text/xml");
var result = await client.PostAsync(uriBuilder.Uri.AbsoluteUri, content);
using (var response = client.PostAsync(uriBuilder.Uri.AbsoluteUri, content).Result)
using (Stream streamToReadFrom = await response.Content.ReadAsStreamAsync())
{
string fileToWriteTo = OutputMp3FilePath;
using (Stream streamToWriteTo = File.Open(fileToWriteTo, FileMode.Create))
{
await streamToReadFrom.CopyToAsync(streamToWriteTo);
}
}
}
}
}
authentication class - which fetchs the token
public class Authentication
{
public static readonly string FetchTokenUri =
"https://centralindia.api.cognitive.microsoft.com/sts/v1.0/issueToken";
private string subscriptionKey;
private string token;
public Authentication(string subscriptionKey)
{
this.subscriptionKey = subscriptionKey;
this.token = FetchTokenAsync(FetchTokenUri, subscriptionKey).Result;
}
public string GetAccessToken()
{
return this.token;
}
private async Task<string> FetchTokenAsync(string fetchUri, string subscriptionKey)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
UriBuilder uriBuilder = new UriBuilder(fetchUri);
var result = await client.PostAsync(uriBuilder.Uri.AbsoluteUri, null);
Console.WriteLine("Token Uri: {0}", uriBuilder.Uri.AbsoluteUri);
return await result.Content.ReadAsStringAsync();
}
}
}
Note - I am able to call the Azure Speech api with postman and also with console application, only when I call the azure service inside my custom webapi it doesnot works.
Change code like below, delete string subscriptionKey. It will work.
public Authentication()
{
this.subscriptionKey = subscriptionKey;
this.token = FetchTokenAsync(FetchTokenUri, subscriptionKey).Result;
}

why await does not wait untill httpclient postasync complets?

Im creating http client for consume some api.
Here is my client method calling to api endpoint.
public async Task<HttpResponseMessage> SendRequestAsync()
{
string adaptiveUri = "https://some-api/api/Authentication/AuthenticateThirdPartyUserAsync";
using (HttpClient httpClient = new HttpClient())
{
var json = JsonConvert.SerializeObject(new { userName = "uname", password = "123", applicantCode = "hello" });
var payload = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage responseMessage = null;
try
{
responseMessage = await httpClient.PostAsync(adaptiveUri, payload);
}
catch (Exception ex)
{
if (responseMessage == null)
{
responseMessage = new HttpResponseMessage();
}
responseMessage.StatusCode = HttpStatusCode.InternalServerError;
responseMessage.ReasonPhrase = string.Format("RestHttpClient.SendRequest failed: {0}", ex);
}
return responseMessage;
}
}
calling method is as follows
public async Task<IBaseStatus> Handle(InspectionAddedEvent domainEvent)
{
var tk = await _iAClient.SendRequestAsync();
return something;
}
but await does not wait untill postasync completes.
but when i use
httpClient.PostAsync(adaptiveUri, payload).GetAwaiter().GetResult()
it waits until post is complets.
can anyone have idea about this?
Thanks.
await _iAClient.SendRequestAsync(); definitely waits for the PostAsync.
I think the problem is that your are receiving an exception in SendRequestAsync and confuse the result.
Remove completely the try/carch block
public async Task<HttpResponseMessage> SendRequestAsync()
{
string adaptiveUri ="https://someapi/api/Authentication/AuthenticateThirdPartyUserAsync";
using (HttpClient httpClient = new HttpClient())
{
var json = JsonConvert.SerializeObject(new { userName = "uname", password = "123", applicantCode = "hello" });
var payload = new StringContent(json, Encoding.UTF8, "application/json");
return await httpClient.PostAsync(adaptiveUri, payload);
}
}
And try to catch it in the caller:
public async Task<IBaseStatus> Handle(InspectionAddedEvent domainEvent)
{
try
{
var tk = await _iAClient.SendRequestAsync();
return something;
}
catch(Exception ex)
{
//Probably return some IBaseStatus
}
}

500 Error when calling an API in C# with having ID in URL

I need to Call a API using C# to this URL: I changed the URL so not working here but it is working in postman)
https://uattest.com/api/leads/28/comments
This is the object to post:
{
"code":"22535345454-263663",
"text":"This is a test"
}
This is working fine when I post via postman, but when I post using my C# code I am getting 500 error. This is my C# code:
Controller:
[HttpPost]
[Route("AddNote")]
public Task<NoteReturnModel> AddNote(int LeadId, Comments note)
{
return Repository.AddNote(LeadId, note);
}
Repository
public async Task<NoteReturnModel> AddNote(int LeadId, Comments note)
{
using (GetWSObject<NoteReturnModel> addObjectInt = new GetWSObject<NoteReturnModel>())
{
string URL = string.Format("/api/leads/" + LeadId+ "/comments");
return await addObjectInt.PostWSObjectModel(URL, note);
}
}
and this is PostWSObjectModel Method:
public async Task<T> PostWSObjectModel(string uriActionString, Object model)
{
T returnValue = default(T);
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(WebConfigurationManager.AppSettings["URL"]);
var content = new StringContent(JsonConvert.SerializeObject(model));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage response = await client.PostAsync(uriActionString, content);
response.EnsureSuccessStatusCode();
returnValue = JsonConvert.DeserializeObject<T>(((HttpResponseMessage)response).Content.ReadAsStringAsync().Result);
}
return returnValue;
}
catch (Exception e)
{
throw (e);
}
}
I am checking all the URLs are correct, in this line that calling HttpResponseMessage response = await client.PostAsync(uriActionString, content); giving error.

Executing POST request for Microsoft Graph API to add members to an AD group

I am trying to add members to an AD groups invoking Microsoft Graph API through an Azure Function
It is very easy and straightforward to execute GET requests through Graph API's, but I can't find any examples how I could execute post requests for the Graph API
I do have an example of a post request for the Graph API which is
POST https://graph.microsoft.com/v1.0/groups/{id}/members/$ref
Content-type: application/json
Content-length: 30
{
"#odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/{id}"
}
Here is the code I successfully use to retrieve the Graph response
public static async Task<HttpResponseMessage> GetDirectoryUsers(string graphToken, TraceWriter log, string displayName)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", graphToken);
string requestUrl = "https://graph.microsoft.com/v1.0/groups?$top=2&$filter=displayName eq '" + displayName + "'&$expand=Members";
var request = new HttpRequestMessage(new HttpMethod("GET"), requestUrl);
var response = await client.SendAsync(request);
return response;
}
However, I am completely lost how I could execute the request through a C# code within the Azure function to ADD the retrieved users to another AD. How can construct the request URL? How should I handle the odata id within that request URL?
If anyone could help me in any way, I would greatly appreciate it
A reuse method for add sub-group/member to group(O365 doesn't support add sub-group to group now)
/// <param name="graphClient"></param>
/// <param name="groupId"></param>
/// <param name="memberId">memberId/sub-group id</param>
/// <returns></returns>
public static async Task AddGroupMember1(GraphServiceClient
graphClient, string groupId, string memberId)
{
User memberToAdd = new User { Id = memberId };
//Group memberToAdd= new Group { Id = memberId };
await graphClient.Groups[groupId].Members.References.Request().AddAsync(memberToAdd);
}
Here is the answer that worked for me
public static async Task<string> AddGroupMember(string accessToken, string groupId, string memberId)
{
var status = string.Empty;
try
{
string endpoint = "https://graph.microsoft.com/v1.0/groups/" + groupId + "/members/$ref";
string queryParameter = "";
// pass body data
var keyOdataId = "#odata.id";
var valueODataId = "https://graph.microsoft.com/v1.0/directoryObjects/" + memberId;
var values = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(keyOdataId, valueODataId)
};
var jsonData = $#"{{ ""{keyOdataId}"": ""{valueODataId}"" }}";
var body = new StringContent(jsonData, Encoding.UTF8, "application/json");
using (var client = new HttpClient())
{
using (var request = new HttpRequestMessage(HttpMethod.Post, endpoint + queryParameter))
{
request.Content = body;
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
using (var response = await client.SendAsync(request))
{
if (response.StatusCode == HttpStatusCode.NoContent)
status = "Member added to Group";
else
status = $"Unable to add Member to Group: {response.StatusCode}";
}
}
}
}
catch (Exception ex)
{
status = $"Error adding Member to Group: {ex.Message}";
}
return status;
}
I'm using graph api for sending email. The code in below
public async Task<dynamic> SendMail(string accessToken, MailWrapper mail)
{
try
{
GraphServiceClient graphClient = SDKHelper.GetMicrosoftAuthenticatedClient(accessToken);
Message message = await BuildEmailMessage(graphClient, mail);
await graphClient.Me.SendMail(message, true).Request().PostAsync(CancellationToken.None);
var response = await graphClient.Me.MailFolders.SentItems.Messages.Request()
.OrderBy(sendDateTimeDesc)
.Top(1)
.GetAsync();
return await Task.FromResult(response);
}
catch (ServiceException ex)
{
throw ex;
}
}
Assembly Microsoft.Graph, Version=1.9.0.0
That's what worked for me
public void AddUserToGroup(string groupId)
{
var requestUri = $"{_graphApiUrl}/v1.0/groups/{groupId}/members/$ref";
var id = "user_id";
var OdataId = "#odata.id";
var ODataValue = $"https://graph.microsoft.com/v1.0/users/{id}";
var content = $#"{{ ""{OdataId}"": ""{ODataValue}"" }}";
using (var httpClient = new HttpClient())
using (var httpRequest = CreateHttpRequest(HttpMethod.Post, requestUri, content))
{
var response = httpClient.SendAsync(httpRequest).GetAwaiter().GetResult();
if (!response.IsSuccessStatusCode)
{
var reason = $"Status code: {(int)response.StatusCode}, Reason: {response.StatusCode}";
throw new Exception(reason);
}
}
}
And important thing was when creating a request to use:
request.Content = new StringContent(content, Encoding.UTF8, "application/json");
it didn't work with:
request.Content = new StringContent(content);
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json;odata=verbose");

System.Net.Http.HttpClient in [Universal Windows Platform] not working properly

I wrote simple method for getting data from (online) REST Service:
public async Task<Object> GetTask()
{
try
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("http://111.111.111.111:8080/");
HttpResponseMessage result = await client.GetAsync("ABC/CDE/getsomeinfo");
if (result.IsSuccessStatusCode)
{
//Deserialize
}
}
}
catch (Exception ex)
{
Debug.WriteLine("Error" + ex);
}
return null;
}
Whenever i run this on UWP i'm getting catch exception:
The text associated with this error code could not be found.
A connection with the server could not be established
HResult 2147012867
Im trying to connect my client with restapi in internal network. In forms same code is working properly.
Try this
HttpResponseMessage response;
public async Task<string> webserviceResponse(string HttpMethod)
{
// check internet connection is available or not
if (NetworkInterface.GetIsNetworkAvailable() == true)
{
// CancellationTokenSource cts = new CancellationTokenSource(2000); // 2 seconds
HttpClient client = new HttpClient();
MultipartFormDataContent mfdc = new MultipartFormDataContent();
mfdc.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data");
string GenrateUrl = "your url";
if (HttpMethod == "POST")
{
response = await client.PostAsync(GenrateUrl, mfdc);
}
else if (HttpMethod == "PUT")
{
response = await client.PutAsync(GenrateUrl, mfdc);
}
else if (HttpMethod == "GET")
{
response = await client.GetAsync(GenrateUrl);
}
var respon = await response.Content.ReadAsStringAsync();
string convert_response = respon.ToString();
return convert_response;
}
else
{
return "0";
}
}

Categories

Resources