BenchmarkDotNet with async task - c#

I'm trying to run this code :
public class Parsing
{
private const string Url ="blabla";
private static HttpClient client = new HttpClient();
private static Task<string> newton = ParseNewton();
private static Task<string> servicestack = ParseServiceStack();
[Benchmark]
private static async Task<string> ParseNewton()
{
var response = client.GetAsync(Url).Result;
var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
var serializer = new Newtonsoft.Json.JsonSerializer();
using (var sr = new StreamReader(stream))
using (var jsonTextReader = new JsonTextReader(sr))
{
return serializer.Deserialize<string>(jsonTextReader);
}
}
[Benchmark]
private static async Task<string> ParseServiceStack()
{
var response = client.GetAsync(Url).Result;
var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
return ServiceStack.Text.JsonSerializer.DeserializeFromStream<string>(stream);
}
}
And the call is
internal class Program
{
public static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<Parsing>();
Console.ReadKey();
}
}
I'm pretty sure I did many things wrong (since it doesn't work) ; I always get the message No Benchmark found and from the samples I found I could not find how to make it work.
I'd like to deserialise like 1000 times the same response from the url given with both NewtonSoft & ServiceStack and get a good benchmark from it. How can I make this code work and what did I do wrong ?

Both the class and the methods need to be public and can not be static. The class must also not be sealed.

Related

Consume a Web Service in C#: Remove Task.Wait()

I am trying to consume a web service. It's an XML based service. I mean response in XML format. The code is working fine. However, I do not want to use task.Wait(). Please let me know how I can replace it with async/await.
Below is my code :
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace ConsoleApp6
{
class Program
{
static void Main(string[] args)
{
Program obj = new Program();
var result = obj.GetData().Result;
}
public async Task<string> GetData()
{
string url =
"https://test.net/info.php?akey=abcd&skey=xyz";
HttpClient client = new HttpClient();
HttpResponseMessage response = client.GetAsync(url).Result;
var responseValue = string.Empty;
if (response != null)
{
Task task = response.Content.ReadAsStreamAsync().ContinueWith(t =>
{
var stream = t.Result;
using (var reader = new StreamReader(stream))
{
responseValue = reader.ReadToEnd();
}
});
task.Wait(); // How I can replace it and use await
}
return responseValue;
}
}
[XmlRoot(ElementName = "Info")]
public class Test
{
[XmlAttribute(AttributeName = "att")]
public string SomeAttribute{ get; set; }
[XmlText]
public string SomeText{ get; set; }
}
}
You already are in an async context, so just use await:
var stream = await response.Content.ReadAsStreamAsync();
using (var reader = new StreamReader(stream))
{
responseValue = reader.ReadToEnd();
}
That said, you should check all your calls:
HttpResponseMessage response = await client.GetAsync(url);
and make your main async, too and while we are at it make the method static:
public static async Task Main)
{
var result = await GetData();
}
where your method signature is:
public static async Task<string> GetData()
The static isn't required, but you will find parallel and/or asynchronous programming is a lot easier if you have as little side effects as possible.
You can make Main method async as well and await GetData
static async Task Main(string[] args)
{
Program obj = new Program();
var result = await obj.GetData();
}

Calling Delete Method of API Controller Does Not Work

The Get and Post methods work fine, but when I try to call the Delete endpoint, it seems like it is never executed.
UserController.cs
[HttpDelete]
[MapToApiVersion("1.0")]
public async Task<IActionResult> Delete([FromForm] string userName)
{
return await RemoveUser(userName);
}
I am using the HttpClientto perform the request as follows:
using (Client = new HttpClient())
{
Client.BaseAddress = new Uri("https://localhost:44332/");
var result = await Client.DeleteAsync(new Uri($"/api/v{Version}/User" +"/xxx"));
return result.ToString();
}
I have created a console application to test the API:
Program.cs
public class Program
{
private static readonly HttpClient Client = new HttpClient { BaseAddress = new Uri("https://localhost:44332/") };
public static void Main(string[] args)
{
Task.Run(() => RunAsync(args));
Console.ReadLine();
}
private static async Task RunAsync(IReadOnlyList<string> args)
{
var result = await Client.DeleteAsync(new Uri($"/api/v1/user/gareth"));
Console.WriteLine(result.ToString());
}
}
When I call the same endpoint using Postman it works, what am I doing wrong?
You are trying to parse the username from the request body ([FromBody]), but you are not providing any payload to the HTTP client, instead you are specifying the parameter within the URL. Therefore, your API method should look something like this:
UserController.cs
[HttpDelete("{userName}")]
public async Task<IActionResult> Delete(string userName)
{
return await RemoveUser(userName);
}
The code below will issue a DELETE request against the UserController and pass john-doe as the userName parameter.
Program.cs
private static void Main(string[] args)
{
var httpClient = new HttpClient { BaseAddress = new Uri("https://localhost:44332") };
httpClient.DeleteAsync(new Uri("/api/v1/user/john-doe", UriKind.Relative)).Wait();
}

Cannot call method from another class without static field

I have interface with this code
interface IHttpRequest
{
Task<string> GetCountries();
}
That I inherit in class like this
public class GettingCountries: IHttpRequest
{
public async Task<string> GetCountries()
{
var client = new RestClient("http://api.xplorpal.com");
var request = new RestRequest("/countries", Method.POST);
var response = await client.ExecuteTaskAsync(request);
var content = response.Content;
var responseCountries = JsonConvert.DeserializeObject<IEnumerable<GettingCountry.RootObjectCountries>>(content);
GettingCountry.CountriesList.Clear();
GettingCountry.ListOfCountriesRoot.Clear();
foreach (var country in responseCountries)
{
GettingCountry.CountriesList.Add(country.nicename);
GettingCountry.ListOfCountriesRoot.Add(new GettingCountry.RootObjectCountries(country.id, country.nicename));
}
return content;
}
}
After this I need to call method of this class somewhere, like this for example var countries_list = await GettingCountries.GetCountries();
But now I have error.
How I can solve it? I can make it static, but is this ok? Maybe smth other?

Why do two (almost) similar methods(using c#) of uploading a file to Slack cause different outcomes?

so this question baffels me. I'll post quite abit of code to explain this one. First, I have and "old" version of code(c#), which I used to post messages and files to Slack. And this code works fine for me! The method of interest is the following:
public class PostMessage
{
private string _token = "xoxp-MyToken";
public string token { get { return _token; } }
public string channel { get; set; }
public string text { get; set; }
public MultipartFormDataContent UploadFile()
{
var requestContent = new MultipartFormDataContent();
var fileContent = new StreamContent(GetFile.ReadFile());
requestContent.Add(new StringContent(token), "token");
requestContent.Add(new StringContent(channel), "channels");
requestContent.Add(fileContent, "file", Path.GetFileName(GetFile.path));
return requestContent;
}
public static class GetFile
{
public static string path = #"C:\Users\f.held\Desktop\Held-Docs\Download.jpg";
public static FileStream ReadFile()
{
FileInfo fileInfo = new FileInfo(path);
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
return fs;
}
}
Here is my client:
public class SlackClient
{
public Uri _method { get; set; }
private readonly HttpClient _httpClient = new HttpClient {};
public SlackClient(Uri webhookUrl)
{
_method = webhookUrl;
}
public async Task<HttpResponseMessage> UploadFileAsync(MultipartFormDataContent requestContent)
{
var response = await _httpClient.PostAsync(_method, requestContent);
return response;
}
}
And I call all of this in this Main:
public static void Main(string[] args)
{
Task.WaitAll(TalkToSlackAsync());
private static async Task TalkToSlackAsync()
{
var webhookUrl = new Uri("https://slack.com/api/files.upload");
var slackClient = new SlackClient(webhookUrl);
PostMessage PM = new PostMessage();
PM.channel = "DCW21NBHD";
var cont = PM.UploadFile();
var response = await slackClient.UploadFileAsync(cont);
string content = await response.Content.ReadAsStringAsync();
}
}
So far, so good! But now it gets interesting. I build a similar version, in which I use Newtonsoft's Json NuGet-package
Now, first the code:
the client:
public async Task<HttpResponseMessage> SendFileAsync(MultipartFormDataContent requestContent)
{
_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "xoxp-MyToken");
var response = await _httpClient.PostAsync(UriMethod, requestContent);
return response;
}
the same Filestram-method for reading the file:
public class Message
{
public class GetFile // Just pass a path here as parameter!
{
public static string path = #"C:\Users\f.held\Desktop\Held-Docs\Download.jpg";
public static FileStream ReadFile()
{
FileInfo fileInfo = new FileInfo(path);
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
return fs;
}
}
the Json-class which I serialize:
public class JsonObject
{
[JsonProperty("file")]
public string file { get; set; }
[JsonProperty("channels")]
public string channels { get; set; }
}
And the Main:
class MainArea
{
public static void Main( string[] args)
{
try
{
Task.WaitAll(SendMessage());
}
catch(Exception dudd)
{
Console.WriteLine(dudd);
Console.ReadKey();
}
}
private static async Task SendMessage()
{
var client = new BpsHttpClient("https://slack.com/api/files.upload");
JsonObject JO = new JsonObject();
JO.channels = "DCW21NBHD";
var Json = JsonConvert.SerializeObject(JO, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
var StringJson = new StringContent(Json, Encoding.UTF8, "multipart/form-data");
var DeSon = JsonConvert.DeserializeObject(Json);
Console.WriteLine(DeSon);
Console.ReadKey();
var requestContent = new MultipartFormDataContent();
var fileContent = new StreamContent(Message.GetFile.ReadFile());
requestContent.Add(fileContent, "file", Path.GetFileName(Message.GetFile.path));
requestContent.Add(StringJson);
var ResponseFile = await client.SendFileAsync(requestContent);
Console.WriteLine(ResponseFile);
Console.ReadKey();
}
}
So, both SEEM to work. But the latter of these methods does NOT post the file to the declared channel - it merely uploads it to Slack. Which would be fine, because I could then work with the 'public_url' to publicise it on any channel. BUT - BIG BUT - with the first method, it immediately loads it to my channel! And it tells me so in the response I get from Slack. The responses are in both exactly the same - except for the timestamps and file_id etc. obviously. But the ending is different!
Here is the ending of the response from the old version:
"shares":{"private":{"DCW21NBHD":[{"reply_users":[],"reply_users_count":0,"reply_count":0,"ts":"1544025773.001700"}]}},"channels":[],"groups":[],"ims":["DCW21NBHD"]}}
and here is the answer from the new version:
"shares":{},"channels":[],"groups":[],"ims":[]}}
Okay now, why on god's green earth does one method do that and the other one does not? :D
Thanks to anybody who has some insight and knowledge on this specific "issue" and is willing to share!
As stated in the documentation for files.upload:
Present arguments as parameters in application/x-www-form-urlencoded
querystring or POST body. This method does not currently accept
application/json.
So the reason this does not work is that you are trying to provide the API parameters like channels as JSON, when this method does not support JSON. The result is that those properties are ignore, which is why the image is uploaded, but not shared in the designated channel.
To fix it simply provide your parameters as application/x-www-form-urlencoded querystring as you did in your 1st example.
Note that in general only a subset of the Slack API methods support using JSON for providing the parameters as listed here. If you want to use JSON, please double-check if the API method supports it, or stick with x-www-form-urlencoded (which is the standard for POST) to be on the safe side.

How to Seriailize an c# object into Json, while using httpClient?

I have a little program which should communicate with "Slack". In an older Version I used "Dictionary<string, string>" and then put them into UrlEncodedContent - which worked fine.
Now I am trying to create a Json-object, using Newtonsoft's Nuget-package and (in my opinion) formatting my object the way they say on their website.
Problem is, when I try to make a simple request, my program just runs to one specific line in the code(var response = await _httpClient.SendAsync(request);) and then it just ends. It doesn't throw an exception or display any kind of message, it simply ends on this line. I went through my code step by step while debugging, that's how I know it ends on exactly this line. And I just don't know why!
Now my code:
First, my object...
namespace BPS.Slack
{
public class JsonObject
{
//generally needed parameters
[JsonProperty("ok")]
public bool ok { get; set; }
[JsonProperty("error")]
public string error { get; set; }
[JsonProperty("channel")]
public string channel { get; set; }
[JsonProperty("token")]
private string token = "xoxp-MyToken";
[JsonProperty("as_user")]
public bool as_user = false;
[JsonProperty("username")]
public string username { get;set; }
//--------------------------------
//only needed for textmessages
[JsonProperty("text")]
public string text { get; set; }
//--------------------------------
//for posting messages with data attached
[JsonProperty("initial_comment")]
public string initial_comment { get; set; }
[JsonProperty("file")]
public string file { get; set; }
[JsonProperty("channels")]
public string channels { get; set; }
//--------------------------------
//for getting the latest message from a channel
[JsonProperty("count")]
public string count = "1";
[JsonProperty("unreads")]
public bool unreads = true;
}
}
now the client:
namespace BPS.Slack
{
public class BpsHttpClient
{
private readonly HttpClient _httpClient = new HttpClient { };
public Uri UriMethod { get; set; }
public BpsHttpClient(string webhookUrl)
{
UriMethod = new Uri(webhookUrl);
}
public async Task<HttpResponseMessage> UploadFileAsync(MultipartFormDataContent requestContent)
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, UriMethod);
request.Content = requestContent;
var response = await _httpClient.SendAsync(request);
return response;
}
}
}
and the main
namespace TestArea
{
class MainArea
{
public static void Main( string[] args)
{
try
{
Task.WhenAll(SendMessage());
}
catch(Exception ass)
{
Console.WriteLine(ass);
Console.ReadKey();
}
}
private static async Task SendMessage()
{
var client = new BpsHttpClient("https://slack.com/api/im.history");
JsonObject JO = new JsonObject();
JO.channel = "DCW21NBHD";
var Json = JsonConvert.SerializeObject(JO);
var StringJson = new StringContent(Json, Encoding.UTF8);
MultipartFormDataContent content = new MultipartFormDataContent();
content.Add(StringJson);
var Response = await client.UploadFileAsync(content);
string AnswerContent = await Response.Content.ReadAsStringAsync();
Console.WriteLine(AnswerContent);
Console.ReadKey();
}
}
}
I had the same problem in my older version, BUT only as I wanted to DEserialize an answer I got from Slack. It had to do with my object I tried do deserialize the answer into. But this time I can not figure out what's wrong. But, as I said, I do not have any experience with using serialized objects as Json-property to send requests... anyone has an idea what is wrong with my code?
EDIT: This problem is kinda solved. But there is a follow up problem.
Okay, I found out that the reason for the abprubt termination was the
Task.WhenAll(SendMessage());
it should be
Task.WaitAll(SendMessage()); Why??? Somebody said I should use WhenAll, but obviously it doesn't work properly in this case...
Now I get a response from Slack, but now a different problem has arisen. When I use this method:
public async Task<HttpResponseMessage> UploadFileAsync(MultipartFormDataContent requestContent)
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, UriMethod);
request.Content = requestContent;
var response = await _httpClient.SendAsync(request);
return response;
}
I allways get the answer:
{"ok":false,"error":"invalid_form_data"}
so I tried to explicitly tell it the 'mediaType', I tried "application/json" and others, but with all of them I get the same error. Here is the full method that calls the upper mehtod:
private static async Task SendMessage()
{
var client = new BpsHttpClient("https://slack.com/api/chat.postMessage");
JsonObject JO = new JsonObject();
JO.channel = "DCW21NBHD";
JO.text = "This is so much fun :D !";
var Json = JsonConvert.SerializeObject(JO, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
var StringJson = new StringContent(Json, Encoding.UTF8, "application/json");
var requestContent = new MultipartFormDataContent();
requestContent.Add(StringJson);
var Response = await client.UploadFileAsync(requestContent);
string AnswerContent = await Response.Content.ReadAsStringAsync();
}
When I use this method:
public async Task<HttpResponseMessage> SendMessageAsync(FormUrlEncodedContent content)
{
var response = await _httpClient.PostAsync(UriMethod, content);
return response;
}
so bascially I am passing "FormUrlEncodedContent" instead of "MultipartFormDataContent" in this, and then I get the response I want and can work wiht it. BUT this i of little use to me since I have to use "MultipartFormDataContent" to be able to send files with my requests.
Anyone have an idea what is failing here? Why does it not like the one content-type but the other one? I'd be gratefull for tipps and ideas!
You are serializing your object to Json and then adding it to a Multipart body, that's quite strange. Unless you're uploading binary data (eg Files), there is no need to use MultipartFormDataContent.
You are can directly post your JsonObject serialized as JSON:
public async Task<HttpResponseMessage> PostJsonAsync(StringContent content)
{
var response = await client.PostAsync(url, content);
return response;
}
var client = new BpsHttpClient("https://slack.com/api/im.history");
JsonObject JO = new JsonObject();
JO.channel = "DCW21NBHD";
var Json = JsonConvert.SerializeObject(JO);
var StringJson = new StringContent(Json, Encoding.UTF8);
var Response = await client.PostJsonAsync(content);
Also this is should be POST on the UploadFileAsync function.
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, UriMethod);
so I figured out that in the Main() the problem was this:
Task.WhenAll(SendMessage());
I should instead use:
Task.WaitAll(SendMessage());
Anyone who has more knowledge on this, please elaborate why!

Categories