I am using REST call, the code is like:
public bool restfunc(string id)
{
var result = Task.Factory.StartNew(() => RunAsync(id)).Result; //RunAsync(id).Wait();
return true;
}
public static Task RunAsync(string id)
{
try
{
dynamic result = null;
string pathValue = WebConfigurationManager.AppSettings["R2G2APIUrl"];
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(pathValue);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.Timeout = TimeSpan.FromMinutes(5);
Task responsetask = null;
var jobid = id.Split('_')[1];
client.GetAsync("OnTranscriptionStarted/" + jobid).ContinueWith((requesttask) =>
{
responsetask = requesttask;
HttpResponseMessage resp = requesttask.Result; //HERE ERR OCCUR
resp.EnsureSuccessStatusCode();
resp.Content.ReadAsStringAsync().ContinueWith((readtask) =>
{
result = JsonConvert.DeserializeObject(readtask.Result);
});
});
}
return result;
Doubt:
I have API in pathvalue..I have to write pathvalue in
GetAsync() or function name and id which I want to call?
Help me out from this problem please..
You can use UriBuilder for that:
var builder = new UriBuilder(
"http", pathValue, 80, string.Format("OnTranscriptionStarted/{0}", jobId));
client.GetAsync(builder.Uri.ToString());
Related
I have designed the following method to call api within the loop. I was wondering if there is any other better way (performance) of calling APIs multiple times?
private List<ClientInfo> populateDetails(List<ClientInfo> lstClientDetails)
{
using (var client = new HttpClient())
{
client.BaseAddress = EndpointAddress;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string Uri = "";
ClientInfo clientInfo;
foreach (var record in lstClientDetails)
{
Uri = string.Format("{0}", record.id);
var postResponse = client.GetAsync(Uri).Result;
if (postResponse.IsSuccessStatusCode)
{
string result = postResponse.Content.ReadAsStringAsync().Result;
clientInfo = JsonConvert.DeserializeObject<ClientInfo>(result);
if (clientInfo != null)
record.email = clientInfo.email;
}
}
return lstClientDetails;
}
}
Maybe you can change your code to use async/await pattern
private async Task populateDetails(List<ClientInfo> lstClientDetails)
{
using (var client = new HttpClient())
{
client.BaseAddress = EndpointAddress;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string Uri = "";
ClientInfo clientInfo;
foreach (var record in lstClientDetails)
{
Uri = string.Format("{0}", record.id);
var postResponse = await client.GetAsync(Uri);
if (postResponse.IsSuccessStatusCode)
{
string result = await postResponse.Content.ReadAsStringAsync();
clientInfo = JsonConvert.DeserializeObject<ClientInfo>(result);
if (clientInfo != null)
record.email = clientInfo.email;
}
}
}
}
And as you can see it doesn't make senso to return the same List which is passed as a paramters: the code will change the underlyne objects
Reference Microsoft Docs Parallel Library
sample code:
public class ParallelClient
{
private async Task ParallelRequest(List<string> requests)
{
var responses = new ConcurrentBag<HttpResponseMessage>();
using (var client = new HttpClient())
{
Parallel.ForEach(requests, new ParallelOptions { MaxDegreeOfParallelism = 10 }, async r =>
{
var requestMessage = new HttpRequestMessage();
requestMessage.Method = HttpMethod.Post;
requestMessage.Content = new StringContent(r, Encoding.UTF8, "application/json");
var response = await client.SendAsync(requestMessage);
responses.Add(response);
});
}
}
}
Wanted to verify if HttpCLient instance should be created outside method passed to polly for ExecuteAsync, or in?
My current usage varies between the two options and I am not sure which is the correct one?
Also, if it incurs some drawbacks, or possible memory leaks, etc. ?
Get:
var client = new HttpClient(new NativeMessageHandler()) { Timeout = new TimeSpan(0, 0, TimeOutSec) };
var httpResponse = await AuthenticationOnUnauthorizePolicy.ExecuteAsync(async () =>
{
UpdateClientHeader(client, correlationId);
return await client.GetAsync(url, token);
});
Post:
var httpResponse = await AuthenticationOnUnauthorizePolicy.ExecuteAsync(async () =>
{
using (var client = new HttpClient(new NativeMessageHandler()) { Timeout = new TimeSpan(0, 0, TimeOutSec) })
{
UpdateClientHeader(client, correlationId);
WriteNetworkAccessStatusToLog();
return await client.PostAsync(url, content);
}
});
The policy used here:
AuthenticationOnUnauthorizePolicy = Policy
.HandleResult<HttpResponseMessage>(reposnse => reposnse.StatusCode == HttpStatusCode.Unauthorized)
.RetryAsync(1, onRetryAsync:
async (response, count, context) =>
{
_logger.Info("Unauthorized Response! Retrying Authentication...");
await Authenticate();
});
Appreciates any comments on the code above.
Is there a correct way?
Do I need to use the Context to get the client again, or is my usage okay?
Update:
Authenticate method:
public virtual async Task Authenticate()
{
// lock it - only one request can request token
if (Interlocked.CompareExchange(ref _isAuthenticated, 1, 0) == 0)
{
var result = new WebResult();
var loginModel = new LoginModel
{
email = _settingService.Email,
password = _settingService.Password
};
var url = ......
var correlationId = Guid.NewGuid().ToString();
try
{
var stringObj = JsonHelper.SerializeObject(loginModel);
HttpContent content = new StringContent(stringObj, Encoding.UTF8, HttpConsts.JsonMediaType);
using (var client = new HttpClient(new NativeMessageHandler()) { Timeout = new TimeSpan(0, 0, TimeOutSec) }
)
{
UpdateClientHeader(client, correlationId, useToken: false); // not token, we need new one
using (var httpResponse = await client.PostAsync(url, content))
{
var sReader = await httpResponse.Content.ReadAsStringAsync();
await HandleRequest(result, sReader, httpResponse, correlationId, url, "result");
}
}
if (result != null && !result.HasError)
{
_loginToken = result.Token;
}
}
catch (Exception ex)
{
// Log error
}
finally
{
_isAuthenticated = 0;
}
}
}
Update client headr method:
if (_loginToken != null &&
!client.DefaultRequestHeaders.Contains("Token"))
{
client.DefaultRequestHeaders.Add("Token", _loginToken );
}
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(HttpConsts.JsonMediaType));
I have only one method for Api Request as follow
private async Task<Site> getSiteAsync(string siteId)
{
Site site = null;
var response = await httpClient.SendAsync(
new HttpRequestMessage(HttpMethod.Get, httpClient.BaseAddress + $"api/sites/{siteId}"));
if (response.IsSuccessStatusCode)
{
var stream = await response.Content.ReadAsStreamAsync();
site = await JsonSerializer.DeserializeAsync<Site>(stream, serializerOptions);
}
return site;
}
When I try to call it from my MainClass the first call (a) works fine, but the b,c and d they all return me the Status = WaitingForActivation.
private readonly HttpClient httpClient = new HttpClient();
private readonly JsonSerializerOptions serializerOptions = new JsonSerializerOptions();
public MainWindow()
{
httpClient.BaseAddress = new Uri($"http://localhost:5000/MyApi/");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
serializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
var a = getSiteAsync("0001"); << I only get the value of this call.
var b = getSiteAsync("0002");
var c = getSiteAsync("0003");
var d = getSiteAsync("0004");
InitializeComponent();
}
How can I get the Result of b,c and d ?
You should await the calls and since you can only do this in an async method and not in a constructor, you should move your code to a method or an event handler:
public MainWindow()
{
httpClient.BaseAddress = new Uri($"http://localhost:5000/MyApi/");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
serializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
Loaded += async (s, e) =>
{
var a = await getSiteAsync("0001");
var b = await getSiteAsync("0002");
var c = await getSiteAsync("0003");
var d = await getSiteAsync("0004");
};
InitializeComponent();
}
I have uploaded a file to SharePoint and found out what id it has. Now I need to update some of the other columns on that listitem. The problem is that System.Net.Http.HttpMethod.Patch doesn't exist.
public static async Task<string> UpdateFileData()
{
var (authResult, message) = await Authentication.AquireTokenAsync();
string updateurl = MainPage.rooturl + "lists/edd49389-7edb-41db-80bd-c8493234eafa/items/" + fileID + "/";
var httpClient = new HttpClient();
HttpResponseMessage response;
try
{
var root = new
{
fields = new Dictionary<string, string>
{
{ "IBX", App.IBX }, //column to update
{ "Year", App.Year}, //column to update
{ "Month", App.Month} //column to update
}
};
var s = new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat };
var content = JsonConvert.SerializeObject(root, s);
var request = new HttpRequestMessage(HttpMethod.Put, updateurl);
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authResult.AccessToken);
request.Content = new StringContent(content, Encoding.UTF8, "application/json");
response = await httpClient.SendAsync(request);
var responseString = await response.Content.ReadAsStringAsync();
return responseString;
}
catch (Exception ex)
{
return ex.ToString();
}
}
Modify the code as below.
public static async Task<string> UpdateFileData()
{
var (authResult, message) = await Authentication.AquireTokenAsync();
string updateurl = MainPage.rooturl + "lists/edd49389-7edb-41db-80bd-c8493234eafa/items/" + fileID + "/";
var httpClient = new HttpClient();
HttpResponseMessage response;
try
{
var root = new
{
fields = new Dictionary<string, string>
{
{ "IBX", App.IBX }, //column to update
{ "Year", App.Year}, //column to update
{ "Month", App.Month} //column to update
}
};
var s = new JsonSerializerSettings { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat };
var content = JsonConvert.SerializeObject(root, s);
var request = new HttpRequestMessage(new HttpMethod("PATCH"), updateurl);
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authResult.AccessToken);
request.Content = new StringContent(content, System.Text.Encoding.UTF8, "application/json;odata=verbose");
response = await httpClient.SendAsync(request);
var responseString = await response.Content.ReadAsStringAsync();
return responseString;
}
catch (Exception ex)
{
return ex.ToString();
}
}
Or we can also use REST API to update list item by ID.
Refer to: SharePoint 2013 REST Services using C# and the HttpClient
It dependents whether .NET Core or .NET Framework is utilized, in case of `.NET Core HttpClient.PatchAsync Method could be utilized.
In case of .NET Framework ListItem could be updated like this:
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client.BaseAddress = new Uri("https://graph.microsoft.com");
var listItemPayload = new Dictionary<string, object>
{
{"Color", "Fuchsia"},
{"Quantity", 934}
};
var requestContent = new StringContent(JsonConvert.SerializeObject(listItemPayload));
requestContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
var response = await client.PatchAsync(new Uri($"https://graph.microsoft.com/v1.0/sites/{siteId}/lists/{listId}/items/{itemId}/fields"), requestContent);
var data = response.Content.ReadAsStringAsync().Result.ToString();
}
where PatchAsync is the extension method for HttpClient class:
public static class HttpClientExtensions
{
public static async Task<HttpResponseMessage> PatchAsync(this HttpClient client, Uri requestUri, HttpContent iContent)
{
var method = new HttpMethod("PATCH");
var request = new HttpRequestMessage(method, requestUri)
{
Content = iContent
};
HttpResponseMessage response = new HttpResponseMessage();
try
{
response = await client.SendAsync(request);
}
catch (TaskCanceledException e)
{
Debug.WriteLine("ERROR: " + e.ToString());
}
return response;
}
}
All the credits for extension method go to the author of this answer
Can't you just use the HttpMethod class constructor?
new HttpMethod("PATCH");
Source: https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpmethod.-ctor?view=netframework-4.7.2#System_Net_Http_HttpMethod__ctor_System_String_
Given that I have the following web api method in my controller
public HttpResponseMessage PostGrantAccess(GrantAccessRequest grantAccessRequest)
{
var deviceId = grantAccessRequest.DeviceId;
var grantAccessResponse = new GrantAccessResponse()
{
Status = "OK"
};
var response = Request.CreateResponse<GrantAccessResponse>(HttpStatusCode.OK, grantAccessResponse);
return response;
}
Client calling code:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:55208/");
var request = new GrantAccessRequest { DeviceId = "bla" };
var response = client.PostAsJsonAsync("api/accesspanel", request).Result;
if (response.IsSuccessStatusCode)
{
var uri = response.Headers.Location;
}
}
How do I get back GrantAccessResponse at the client?
response.Content.ReadAsAsync<GrantAccessResponse>()