I writing a Windows 8 app. I have a code :
public async Task<string> readweb()
{
var uri = new Uri(#"http://stackoverflow.com/");
var httpClient = new HttpClient();
var data = await httpClient.GetStringAsync(uri);
string text = data;
return text;
}
i want to get web-data by string data = readweb(); but it error "cannot convert task to string". Help me! Thanks!
Do like this,
public async Task<string> readweb()
{
var uri = new Uri(#"http://stackoverflow.com/");
var httpClient = new HttpClient();
var data = await httpClient.GetStringAsync(uri);
string text = data;
return text;
}
private async void Something()
{
var data = await readweb();
}
Related
I'm new to working with API's so bare with me. I'm trying to load 3 images into picture boxes by using the Bing Image Search API but I'm having trouble with my async method. From my POV everything looks like it should be working just fine. (I used this documentation for my code https://learn.microsoft.com/en-us/bing/search-apis/bing-image-search/quickstarts/sdk/image-search-client-library-csharp). Any advice would be greatly appreciated.
private static string _subscriptionKey = "MY_API_KEY";
private static string _baseUri = "https://api.bing.microsoft.com/v7.0/images/search";
private static string searchString = "car";
private static string _clientIdHeader = null;
private const string QUERY_PARAMETER = "?q="; // Required
private const string MKT_PARAMETER = "&mkt="; // Strongly suggested
private void searchButton_Click(object sender, EventArgs e)
{
RunAsync().Wait();
static async Task RunAsync()
{
try
{
// Remember to encode the q query parameter.
var queryString = QUERY_PARAMETER + Uri.EscapeDataString(searchString);
queryString += MKT_PARAMETER + "en-us";
HttpResponseMessage response = await MakeRequestAsync(queryString);
_clientIdHeader = response.Headers.GetValues("X-MSEdge-ClientID").FirstOrDefault();
// This example uses dictionaries instead of objects to access the response data.
var contentString = await response.Content.ReadAsStringAsync();
Dictionary<string, object> searchResponse = JsonConvert.DeserializeObject<Dictionary<string, object>>(contentString);
if (response.IsSuccessStatusCode)
{
PrintImages(searchResponse);
}
}
catch (Exception)
{
}
async Task<HttpResponseMessage> MakeRequestAsync(string queryString)
{
string count = "3";
string offset = "0";
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", _subscriptionKey);
return await client.GetAsync(string.Format("{0}q={1}&count={1}", _baseUri + queryString, count, offset));
}
void PrintImages(Dictionary<string, object> response)
{
var images = response["value"] as Newtonsoft.Json.Linq.JToken;
foreach (Newtonsoft.Json.Linq.JToken image in images)
{
string imagePic = (image["contentUrl"]).ToString();
optionOnePicture.ImageLocation = imagePic;
optionTwoPicture.ImageLocation = imagePic;
optionThreePicture.ImageLocation = imagePic;
}
}
}
Don't block on async code. Instead, use await:
private async void searchButton_Click(object sender, EventArgs e)
{
await RunAsync();
...
}
Side note: this code is using async void because the method is an event handler. Normally, you would want to avoid async void.
I apologize in advance for the bad editing skills, I'm new at posting questions
I'm trying to call my c# api from an angular app, however the request is stuck on pending. I don't think theres a mistake in my typescript code but I'm new to c# so it might be something to do with the api, possibly because of the asyncs.
Here's the api code
{
private static readonly string Tenant = "https://login.microsoftonline.com/{azure.tenant}/";
private static readonly string Resource = "https://analysis.windows.net/powerbi/api";
private string getToken()
{
var authContext = new AuthenticationContext(Tenant);
var clientCredential = new ClientCredential(AppId, AppSecret);
var token = authContext.AcquireTokenAsync(Resource, clientCredential);
return token.Result.AccessToken;
}
private PowerBIClient getPBIClient()
{
var token = new TokenCredentials(getToken(), "Bearer");
return new PowerBIClient(new Uri("https://api.powerbi.com/"), token);
}
public async Task<ODataResponseListReport> getReportsAsync(string ws)
{
PowerBIClient pbiClient = getPBIClient();
var reports = await pbiClient.Reports.GetReportsInGroupAsync(ws);
return reports;
}
public async Task<ReportEmbeddingData> getReportEmbeddingDataAsync(string ws, string rep)
{
PowerBIClient pbiClient = getPBIClient();
var report = await pbiClient.Reports.GetReportInGroupAsync(ws, rep);
var embedUrl = report.EmbedUrl;
var reportName = report.Name;
GenerateTokenRequest genTokenReqParam = new GenerateTokenRequest(accessLevel: "view");
string embedToken = (await pbiClient.Reports.GenerateTokenInGroupAsync(ws, rep, genTokenReqParam)).Token;
return new ReportEmbeddingData {
reportId = rep,
reportName = reportName,
embedUrl = embedUrl,
accessToken = embedToken
};
}
}
And here is my angular call that's being done on ngOnInit
getReports(){
this.http.get("http://localhost:44391/api/Auth?ws="+this.workspaceId)
.subscribe((response) => {
this.reportArray = response;
console.log(this.reportArray);
});
}
I am looking for how to cache a request in ASP.NET Core 2.x?
I have API proxy which always return a different response using the same request (synonyms composition using an AI, hence that's why I am not looking for caching the response).
And I would like to cache the request since it's always the same (always the same basic auth and parameters to poke the other API that I am proxy-ing).
Since the request use a file input.xml for the parameters, I am wondering where I can cache that one as well
My controller:
[Route("api/v1/[controller]")]
public class CompositionController : Controller
{
[HttpGet]
public async Task<string> Get(string transformation = "xml")
{
var httpClient = new HttpClient();
const string authScheme = #"Basic";
const string name = #"myUserName";
const string password = #"myPassword";
var authBytes = Encoding.ASCII.GetBytes($#"{name}:{password}");
var auth64BaseString = Convert.ToBase64String(authBytes);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authScheme, auth64BaseString);
const string fileName = #"input.xml";
var inputBytes = File.ReadAllBytes(fileName);
var byteArrayContent = new ByteArrayContent(inputBytes);
const string formDataKey = #"""file""";
const string formDataValue = #"""input.xml""";
var multipartFormDataContent = new MultipartFormDataContent()
{
{ byteArrayContent, formDataKey, formDataValue }
};
const string url = #"http://baseurl:port/my/resource/is/there.do?transformation=" + transformation;
var response = await httpClient.PostAsync(url, multipartFormDataContent);
return await response.Content.ReadAsStringAsync();
}
}
You really shouldn't be constructing an HttpClient every time the endpoint is called.
This is what I would do:
//create a service that caches HttpClient based on url
public interface IHttpClientService
{
IHttpClient GetClient(string baseHref);
void AddClient(HttpClient client, string baseHref);
}
//implement your interface
public class HttpClientService : IHttpClientService
{
private readonly ConcurrentDictionary<string, IHttpClient> _httpClients;
public HttpClientService()
{
_httpClients = new ConcurrentDictionary<string, IHttpClient>();
}
public void AddClient(HttpClient client, string baseHref)
{
_httpClients.
.AddOrUpdate(baseHref, client, (key, existingHttpClient) => existingHttpClient);
}
public IHttpClient GetClient(string baseHref)
{
if (_httpClients.TryGetValue(baseHref, out var client))
return client;
return null;
}
}
//register as singleton Startup.cs
services.AddSingleton<IHttpClientService, HttpClientService>();
//inject into Controller
[HttpGet]
public async Task<string> Get(string transformation = "xml")
{
const string url = #"http://baseurl:port/my/resource/is/there.do?transformation=" + transformation;
var httpClient = _httpService.GetClient(url);
if(httpClient == null)
{
httpClient = new HttpClient(url);
const string authScheme = #"Basic";
const string name = #"myUserName";
const string password = #"myPassword";
var authBytes = Encoding.ASCII.GetBytes($#"{name}:{password}");
var auth64BaseString = Convert.ToBase64String(authBytes);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authScheme, auth64BaseString);
const string fileName = #"input.xml";
var inputBytes = File.ReadAllBytes(fileName);
var byteArrayContent = new ByteArrayContent(inputBytes);
const string formDataKey = #"""file""";
const string formDataValue = #"""input.xml""";
var multipartFormDataContent = new MultipartFormDataContent()
{
{ byteArrayContent, formDataKey, formDataValue }
};
_httpClient.AddClient(httpClient, url);
}
else
{
//You can cache your MultipartFormDataContent in MemoryCache or same cache as HttpClient
//Get MultipartFormDataContent from cache and
}
var response = await httpClient.PostAsync(url, multipartFormDataContent);
return await response.Content.ReadAsStringAsync();
}
So I am working on writing an extension class for my project using HttpClient since I am moving over from HttpWebRequest.
When doing the POST request, how do I send a normal string as a parameter? No json or anything just a simple string.
And this is what it looks like so far.
static class HttpClientExtension
{
static HttpClient client = new HttpClient();
public static string GetHttpResponse(string URL)
{
string fail = "Fail";
client.BaseAddress = new Uri(URL);
HttpResponseMessage Response = client.GetAsync(URL).GetAwaiter().GetResult();
if (Response.IsSuccessStatusCode)
return Response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
else
return fail;
}
public static string PostRequest(string URI, string PostParams)
{
client.PostAsync(URI, new StringContent(PostParams));
HttpResponseMessage response = client.GetAsync(URI).GetAwaiter().GetResult();
string content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
return content;
}
}
If you look at this like
client.PostAsync(URI, new StringContent(PostParams));
You can see that I just tried creating new StringContent and passing a string into it and the response returned 404 page not found.
How do I properly use Post.Async(); do I send a string or byte array? Because with HttpWebRequest you would do it like this
public static void SetPost(this HttpWebRequest request, string postdata)
{
request.Method = "POST";
byte[] bytes = Encoding.UTF8.GetBytes(postdata);
using (Stream requestStream = request.GetRequestStream())
requestStream.Write(bytes, 0, bytes.Length);
}
In the PostRequest the following is done..
client.PostAsync(URI, new StringContent(PostParams));
HttpResponseMessage response = client.GetAsync(URI).GetAwaiter().GetResult();
Which does not capture the response of the POST.
Refactor to
public static string PostRequest(string URI, string PostParams) {
var response = client.PostAsync(URI, new StringContent(PostParams)).GetAwaiter().GetResult();
var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
return content;
}
HttpClient is primarily meant to be used async so consider refactoring to
public static async Task<string> PostRequestAsync(string URI, string PostParams) {
var response = await client.PostAsync(URI, new StringContent(PostParams));
var content = await response.Content.ReadAsStringAsync();
return content;
}
You need prepare object and then you will serialize the object using Newtonsoft.Json. After that you will prepare byte content from the buffer. We are using api url api/auth/login and it is not full api url as we used dependency injection and configure base address in startup, see the second code.
public async void Login(string username, string password)
{
LoginDTO login = new LoginDTO();
login.Email = username;
login.Password = password;
var myContent = JsonConvert.SerializeObject(login);
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await httpClient.PostAsync("api/auth/login", byteContent);
var contents = await response.Content.ReadAsStringAsync();
}
services.AddHttpClient<IAuthService, AuthService>(client =>
{
client.BaseAddress = new Uri("https://localhost:44354/");
});
.NET 5 Solution
In .NET 5, There is new class JsonContent and you can implement this easily
LoginDTO login = new LoginDTO();
login.Email = username;
login.Password = password;
JsonContent content = JsonContent.Create(login);
var url = "http://...";
HttpResponseMessage response = await httpClient.PostAsync(url, content);
I have worked the following (using the package Ngonzalez.ImageProcessorCore).
Query (ASP.NET Core 2 Controller):
async Task<byte[]> CreateImage(IFormFile file)
{
using (var memoryStream = new MemoryStream())
{
await file.CopyToAsync(memoryStream);
var image = new Image(memoryStream);
var height = image.Height < 150 ? image.Height : 150;
image.Resize((int)(image.Width * height / image.Height), height).Save(memoryStream);
return memoryStream.ToArray();
}
}
[HttpPost, ValidateAntiForgeryToken]
public async Task<IActionResult> ImageAdd(ImageAddVm vm)
{
byte[] image = null;
if (vm.File != null && vm.File.Length > 0)
image = await CreateImage(vm.File);
if (image != null)
{
var json = JsonConvert.SerializeObject(new { vm.ObjectId, image });
var content = new StringContent(json, Encoding.UTF8, "application/json");
var client= new HttpClient();
await client.PostAsync($"{ApiUrl}/SaveImage", content);
}
return RedirectToAction("ReturnAction");
}
Api (ASP.NET Core 2 Controller):
public class ObjectImage
{
public int ObjectId { get; set; }
public byte[] Image { get; set; }
}
[HttpPost("SaveImage")]
public void SaveImage([FromBody]object content)
{
var obj = JsonConvert.DeserializeObject<ObjectImage>(content.ToString());
_db.Images.Find(obj.ObjectId).Image = obj.Image;
_db.SaveChanges();
}
I am using Moq in .net core(1.1) and having a bit of torrid time understanding this behavior as all the examples on interweb points to the fact the this should work with no issues.
I have already tried with:
Returns(Task.FromResult(...)
Returns(Task.FromResult(...)
ReturnsAsync(...)
Mocking a IHttpClient interface to wrap PostAsync, PutAsync and GetAsync. All of these return an ApiResponse object.
var mockClient = new Mock<IHttpClient>();
Does not work:
mockClient.Setup(x => x.PostAsync(url, JsonConvert.SerializeObject(body), null))
.Returns(Task.FromResult(new ApiResponse()));
PostSync definition:
public async Task<ApiResponse> PostAsync(string url, string body, string authToken = null)
Does work:
mockClient.Setup(x => x.PostAsync(url, JsonConvert.SerializeObject(body), null))
.Returns(Task.FromResult(bool));
PostSync definition:
public async Task<bool> PostAsync(string url, string body, string authToken = null)
Usage:
var api = new ApiService(mockClient.Object);
var response = api.LoginAsync(body.Username, body.Password);
UPDATE
[Fact]
public async void TestLogin()
{
var mockClient = new Mock<IHttpClient>();
mockClient.Setup(x => x.PostAsync(url, JsonConvert.SerializeObject(body), null)).Returns(Task.FromResult(new ApiResponse()));
var api = new ApiService(mockClient.Object);
var response = await api.LoginAsync(body.Username, body.Password);
Assert.IsTrue(response);
}
Return Type:
public class ApiResponse
{
public string Content { get; set; }
public HttpStatusCode StatusCode { get; set; }
public string Reason { get; set; }
}
LoginAsync:
public async Task<bool> LoginAsync(string user, string password)
{
var body = new { Username = user, Password = password };
try
{
var response = await _http.PostAsync(_login_url, JsonConvert.SerializeObject(body), null);
return response .State == 1;
}
catch (Exception ex)
{
Logger.Error(ex);
return false;
}
}
PostAsync:
public async Task<object> PostAsync(string url, string body, string authToken = null)
{
var client = new HttpClient();
var content = new StringContent(body, Encoding.UTF8, "application/json");
var response = await client.PostAsync(new Uri(url), content);
var resp = await response.Result.Content.ReadAsStringAsync();
return new ApiResponse
{
Content = resp,
StatusCode = response.Result.StatusCode,
Reason = response.Result.ReasonPhrase
};
}
Assuming a simple method under test like this based on minimal example provided above.
public class ApiService {
private IHttpClient _http;
private string _login_url;
public ApiService(IHttpClient httpClient) {
this._http = httpClient;
}
public async Task<bool> LoginAsync(string user, string password) {
var body = new { Username = user, Password = password };
try {
var response = await _http.PostAsync(_login_url, JsonConvert.SerializeObject(body), null);
return response.StatusCode == HttpStatusCode.OK;
} catch (Exception ex) {
//Logger.Error(ex);
return false;
}
}
}
The following test works when configured correctly
[Fact]
public async Task Login_Should_Return_True() { //<-- note the Task and not void
//Arrange
var mockClient = new Mock<IHttpClient>();
mockClient
.Setup(x => x.PostAsync(It.IsAny<string>(), It.IsAny<string>(), null))
.ReturnsAsync(new ApiResponse() { StatusCode = HttpStatusCode.OK });
var api = new ApiService(mockClient.Object);
//Act
var response = await api.LoginAsync("", "");
//Assert
Assert.IsTrue(response);
}
The above is just for demonstrative purposes only to show that it can work provided the test is configured properly and exercised based on the expected behavior.
Take some time and review the Moq quick start to get a better understanding of how to use the framework.