How to receive a response package from GET request for OneNote API - xmlhttprequest

I'm getting a acknowledgement but no response message (details) i.e. list of notebooks from the OneNote API. Below is my code. I am able to receive the header and JSON details from a POST message but not the GET. I have tried to convert the POST code in order to submit a GET request.
private async void getRequestClick(object sender, RoutedEventArgs e)
{
await GetRequests(true, "test");
}
async public Task<StandardResponse> GetRequests(bool debug, string sectionName)
{
Uri PagesEndPoint1 = new Uri("https://www.onenote.com/api/v1.0/notebooks");
var client = new HttpClient();
//// Note: API only supports JSON return type.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//// This allows you to see what happens when an unauthenticated call is made.
if (IsAuthenticated)
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authClient.Session.AccessToken);
}
HttpResponseMessage response;
HttpRequestMessage createMessage = new HttpRequestMessage(HttpMethod.Get, PagesEndPoint1);
response = await client.SendAsync(createMessage);
tbResponse.Text = response.ToString();
return await TranslateResponse(response);
}
private async static Task<StandardResponse> TranslateResponse(HttpResponseMessage response)
{
StandardResponse standardResponse;
if (response.StatusCode == HttpStatusCode.Created)
{
dynamic responseObject = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());
standardResponse = new CreateSuccessResponse
{
StatusCode = response.StatusCode,
OneNoteClientUrl = responseObject.links.oneNoteClientUrl.href,
OneNoteWebUrl = responseObject.links.oneNoteWebUrl.href
};
}
else
{
standardResponse = new StandardErrorResponse
{
StatusCode = response.StatusCode,
Message = await response.Content.ReadAsStringAsync()
};
}
// Extract the correlation id. Apps should log this if they want to collcet the data to diagnose failures with Microsoft support
IEnumerable<string> correlationValues;
if (response.Headers.TryGetValues("X-CorrelationId", out correlationValues))
{
standardResponse.CorrelationId = correlationValues.FirstOrDefault();
}
return standardResponse;
}
My POST messages are working OK. I can create a new page etc.

I think you need to change the expected status code from HttpStatusCode.Created to HttpStatusCode.OK for Get requests, since they return a 200 and not a 201. Try doing that in your TranslateResponse method.

Related

Asp.net Core 2.1 HttpClientFactory: second api call is not waiting for first api call's returned result

I encountered an issue using HttpClientFactory. I need to call two web methods from one third party web api.
getOrderNumber.
getShippingLabelFile.
Call #2 depends on #1's result since it needs to pass orderNumber to it e.g.:
await _client.getAsync("http://xxx/api/getLabel?orderNumber=[returnedOrderNumber]&fileType=1")
When I set break-point and debug, it works as expected. Without debugging mode, #2 web method always failed. I have done investigation. If I pass static query parameter like:
http://xxx/api/getLabel?orderNumber=123&fileType=1
it works fine. It seems #2 evaluates the query string and execute api call before orderNumber gives to it. It is very frustrating, can you please shed on some light on this issue?
On Controller:
private readonly ISite1AuthHttpClient _site1HttpClient;
public OrderShippingOrdersController(site1AuthHttpClient)
{
_site1HttpClient=site1AuthHttpClient
}
[HttpGet("{id}")]
public async Task<IActionResult> GetShippingLabel(int id)
{
string token=await _site1HttpClient.GetToken(username.ToString(),password);
string orderNumber=await _site1HttpClient.CreateOrder(Order,token);
if (orderNumber!=null && orderNumber!="")
{
//this API call always failed during runtime. It works on debugging mode.
var streamFile=(MemoryStream)(await _site1HttpClient.getShippingLabel(orderNumber,token));
}
}
HttpClient Type Class:
public interface ISite1HttpClient
{
Task<string> CreateOrder(AueCreateOrder order,string token);
Task<Stream> GetShippingLabel(string orderNumber,string token);
}
public class Site1HttpClient:ISite1HttpClient
{
private readonly HttpClient _client;
public Site1HttpClient(HttpClient httpClient)
{
httpClient.BaseAddress = new Uri("http://abcapi.Site1.com/");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
_client = httpClient;
}
public async Task<string> CreateOrder(AbcCreateOrder order,string token)
{
var jsonInString=JsonConvert.SerializeObject(order);
jsonInString="[ " + jsonInString + " ]";
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",token);
HttpResponseMessage response = await _client.PostAsync(
"api/AgentShipmentOrder/Create", new StringContent(jsonInString, Encoding.UTF8, "application/json"));
if (response.IsSuccessStatusCode)
{
var contents = await response.Content.ReadAsStringAsync();
AbcOrderCreateResponse abcRes = JsonConvert.DeserializeObject<AbcOrderCreateResponse>(contents);
return abcRes.Message;
}
else
{
var errorResponse = await response.Content.ReadAsStringAsync();
throw new Exception(errorResponse);
}
}
public async Task<Stream> GetShippingLabel(string orderNumber,string token)
{
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",token);
HttpResponseMessage response = await _client.GetAsync("api/GetOrderLabel?orderId="+orderNumber+"&fileType=1");
if (response.IsSuccessStatusCode)
{
Stream streamFile= await response.Content.ReadAsStreamAsync();
return streamFile;
}
else
{
throw new Exception("failed to get label.");
}
}
}
string token = _site1HttpClient.GetToken(username.ToString(),password);
string orderNumber = await _site1HttpClient.CreateOrder(Order,token);
I guess the problem occurs because of first await keyword. When you use await for the first function call (calling an async function), you declare that your program does not need to hold on for the response. So the token variable is used in the second function when it is not set. As you can see above, you should be good to go without the first await for the token variable.

Asp.Net Core - Making API calls from backend

I have an application which is calling API's from a backend cs class, using IHostedService. With basic API calls ("http://httpbin.org/ip") it is working fine and returning the correct value, however I now need to call a Siemens API which requires me to set an Authorization header, and place "grant_type=client_credentials" in the body.
public async Task<string> GetResult()
{
string data = "";
string baseUrl = "https://<space-name>.mindsphere.io/oauth/token";
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", {ServiceCredentialID: ServiceCredentialSecret});
using (HttpResponseMessage res = await client.GetAsync(baseUrl))
{
using (HttpContent content = res.Content)
{
data = await content.ReadAsStringAsync();
}
}
}
I think I have the header set up correctly but I won't know for sure until the full request gets formatted. Is it even possible to set the the body of the request to "grant_type=client_credentials"?
As far as I can see from Siemens API documentation they expect Form data, so it should be like:
public async Task<string> GetResult()
{
string data = "";
string baseUrl = "https://<space-name>.mindsphere.io/oauth/token";
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", {ServiceCredentialID: ServiceCredentialSecret});
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "client_credentials")
});
using (HttpResponseMessage res = await client.PostAsync(baseUrl, formContent))
{
using (HttpContent content = res.Content)
{
data = await content.ReadAsStringAsync();
}
}
}
}

Azure web api Unauthorized 401

I have some code that used to call Azure Scheduler to get a token, then using that token, make restful calls. Works a treat.
So i decided to adopt the code into a new app but this time call my own web api hosted on azure. The API is registered in Active directory I have created a secret key etc. When i initiliaze my static httpclient it fetches a token succesfully.
But when i make a call to the API using the token for auth, the response is a 401 "unauthorized", below is the code.
public static class SchedulerHttpClient
{
const string SPNPayload = "resource={0}&client_id={1}&grant_type=client_credentials&client_secret={2}";
private static Lazy<Task<HttpClient>> _Client = new Lazy<Task<HttpClient>>(async () =>
{
string baseAddress = ConfigurationManager.AppSettings["BaseAddress"];
var client = new HttpClient();
client.BaseAddress = new Uri(baseAddress);
await MainAsync(client).ConfigureAwait(false);
return client;
});
public static Task<HttpClient> ClientTask => _Client.Value;
private static async Task MainAsync(HttpClient client)
{
string tenantId = ConfigurationManager.AppSettings["AzureTenantId"];
string clientId = ConfigurationManager.AppSettings["AzureClientId"];
string clientSecret = ConfigurationManager.AppSettings["AzureClientSecret"];
string token = await AcquireTokenBySPN(client, tenantId, clientId, clientSecret).ConfigureAwait(false);
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); //TODO ssmith: const or localization
}
private static async Task<string> AcquireTokenBySPN(HttpClient client, string tenantId, string clientId, string clientSecret)
{
var payload = String.Format(SPNPayload,
WebUtility.UrlEncode(ConfigurationManager.AppSettings["ARMResource"]),
WebUtility.UrlEncode(clientId),
WebUtility.UrlEncode(clientSecret));
var body = await HttpPost(client, tenantId, payload).ConfigureAwait(false);
return body.access_token;
}
private static async Task<dynamic> HttpPost(HttpClient client, string tenantId, string payload)
{
var address = String.Format(ConfigurationManager.AppSettings["TokenEndpoint"], tenantId);
var content = new StringContent(payload, Encoding.UTF8, "application/x-www-form-urlencoded");
using (var response = await client.PostAsync(address, content).ConfigureAwait(false))
{
if (!response.IsSuccessStatusCode)
{
Console.WriteLine("Status: {0}", response.StatusCode);
Console.WriteLine("Content: {0}", await response.Content.ReadAsStringAsync().ConfigureAwait(false));
}//TODO: start removing tests
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsAsync<dynamic>().ConfigureAwait(false);
}
}
}
The above code is the class that creates a httpclient and gets its authorization.
public virtual async Task<T> GetAsync(string apiURL)
{
try
{
_client = await SchedulerHttpClient.ClientTask;
var response = await _client.GetAsync(apiURL);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsAsync<T>().ConfigureAwait(false);
return responseContent;
}
catch (Exception e)
{
return default(T);
}
}
The above code is a quick lift of my old code simply to test if i can get any results. but as stated it returns a 401.
My question is, is my old code to get authorization incorrect?
<add key="ARMResource" value="https://management.core.windows.net/" />
<add key="TokenEndpoint" value="https://login.windows.net/{0}/oauth2/token" />
<add key="BaseAddress" value="https://mysite.azurewebsites.net" />
As suspected, This particular issue was cause by the incorrect "ARMresource" in the case of a web api it required me to change it to the client id.
Source of answer
Seems my issue was the same, however i suspect i may be able to omit the resource entirely from my SPNPayload string.

MVC aynchronous method

I am working on a MVC project that submits a request via a third party.
In my controller, I have a SubmitClaims() action that receive ajax request and then calls RunAsync(). RunAsync submits a request by using HttpClient.
I am not sure if I did a right thing here.
Also I have two version of SubmitClaims(), both work. But I don't know which version is better.
version 1
[HttpPost]
public async Task<string> SubmitClaims()
{
string result = "";
result = await RunAsync();
return result;
}
version 2 learn from Cannot implicitly convert type 'string' to 'System.Threading.Tasks.Task<string>'
[HttpPost]
public async Task<string> SubmitClaims()
{
return await Task.Run(() =>
{
return RunAsync();
});
}
static async Task<string> RunAsync()
{
string result = "Failed.";
using (var client = new HttpClient())
{
try
{
client.BaseAddress = new Uri("http://peter:8001/internal/uickpost");
client.DefaultRequestHeaders.Add("contenttype", "application/xml");
client.DefaultRequestHeaders.Add("hiconline.protocol.content.role", "REQUEST");
client.DefaultRequestHeaders.Add("hiconline.protocol.content.transactionid", "asdfsdf");
client.DefaultRequestHeaders.Add("hiconline.protocol.remote.contenttype", "TestDataType");
client.DefaultRequestHeaders.Add("hiconline.protocol.remote.mode", "P");
client.DefaultRequestHeaders.Host = "peter:8001";
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
string opv = "Test Data";
HttpContent _content = new StringContent(opv);
_content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
_content.Headers.Add("contenttype", "TestDataType");
HttpResponseMessage response1 = await client.PostAsync(client.BaseAddress, _content);
if (response1.IsSuccessStatusCode)
{
Uri gizmoUrl = response1.Headers.Location;
result = response1.Content.ReadAsStringAsync().Result;
}
}
catch (Exception ex)
{
result = ex.Message;
}
return result;
}
}
Option 1 is better. RunAsync() already returns a task, so why create another one?
Even better would be return await RunAsync();. Even better would just be calling RunAsync directly, since the wrapper doesn't add anything.

Saving data in windows phone received from WCF/web service .

Saving data in windows phone received from WCF/web service .
The response may be received after sometime so how to handle this situation.
Saving data is no problem but How to handel if data is received late
You can use this code (show the code from my project):
public void sendPost(string postData, Action<MyResponse, Exception> callback, CreateResponse creater)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(UrlRequest);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Accept = "application/json";
webRequest.AllowAutoRedirect = true;
webRequest.BeginGetRequestStream(new AsyncCallback(getRequestStreamCallback), new Request()
{
HttpRequest = webRequest,
PostData = postData,
Url = UrlRequest,
CallBack = callback,
Creater = creater
});
}
private void getRequestStreamCallback(IAsyncResult asynchronousResult)
{
var request = (Request)asynchronousResult.AsyncState;
// End the stream request operation
Stream postStream = request.HttpRequest.EndGetRequestStream(asynchronousResult);
byte[] byteArray = Encoding.UTF8.GetBytes(request.PostData);
// Add the post data to the web request
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
// Start the web request
request.HttpRequest.BeginGetResponse(new AsyncCallback(getResponseCallback), request);
}
private void getResponseCallback(IAsyncResult asynchronousResult)
{
var request = (Request)asynchronousResult.AsyncState;
try
{
HttpWebResponse response;
// End the get response operation
response = (HttpWebResponse)request.HttpRequest.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamReader = new StreamReader(streamResponse);
var myResponse = streamReader.ReadToEnd();
streamResponse.Close();
streamReader.Close();
response.Close();
MyResponse response_obj = request.Creater.CreateResponseObj();
using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(myResponse)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(response_obj.GetType());
response_obj = (GYResponse)serializer.ReadObject(stream);
if (request.CallBack != null)
{
request.CallBack.Invoke(response_obj, null);
}
}
}
catch (WebException e)
{
if (request.CallBack != null)
{
request.CallBack.Invoke(null, e);
}
}
}
public void getInfo(string uid, Action<MyResponse, Exception> callback)
{
CreateResponse creater = new CreateResponseGetInfo();
string model = "User";
string method = "getInfo";
Params parametrs = new Params();
parametrs.Uid = uid;
//create yor request
string request = getRequestString(model, method, parametrs, Atoken);
sendPost(request, callback, creater);
}
So, you call method, which send request to web service postRequester.getInfo(uid, ResponseHandler) and use delegate for processing result.
private void ResponseHandler(MyResponse result, Exception error)
{
if (error != null)
{
string err = error.Message;
return;
}
else
{
var infoResponse = result as ResponseGetInfo;
if (infoResponse != null)
{
//result processing..
}
}
}
All the web requests you make in a Windows Phone app are Asynchronous. That means, you make a web request from your app and attach a handler to handle the response when it comes. In the response handler, you will have to take care of the response and do whatever you want with it.
Check this link Using WebClient and HttpWebRequest