I'm using json to write data that the user enters. I want this to be done with SerializeAsync. But how can I best do this based on this code?
This is my code without SerializeAsync
public static bool TempFileExists()
{
return File.Exists(TempJsonPath());
}
public static async Task WriteToTempJsonAsync(DeclarationJoined declaration)
{
if (TempFileExists())
{
var json = JsonSerializer.Serialize(declaration);
File.WriteAllText(PaymentCardListPath(), json);
}
}
And this is what I have tried
public static async Task WriteToTempJsonAsync(DeclarationJoined declaration)
{
if (TempFileExists())
{
Stream writer = new FileStream(TempJsonPath(), FileMode.Append);
await JsonSerializer.SerializeAsync(writer, declaration);
}
}
Every time I do this SerializeAsync I got a sharing violation. How can I do this asynchronously?
Related
I'm trying to extend the HttpClient with an EventHandler.
Is this possible?
I have an Extension on HttpClient as follows:
public static class HttpClientExtensions
{
public async static Task<T> GetSomthingSpecialAsync<T>(this HttpClient client, string url)
{
using var response = await client.GetAsync(url);
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
//I have an error and want to raise the HttpClientEventError
HttpClientErrorEvent(null, new HttpClientErrorEventArgs()
{
StatusCode = response.StatusCode,
Message = $"{response.StatusCode } {(int)response.StatusCode } "
});
return default(T);
}
response.EnsureSuccessStatusCode();
[... ]
}
}
public class HttpClientErrorEventArgs : EventArgs
{
public System.Net.HttpStatusCode StatusCode { get; set; }
public string Message { get; set; }
}
But how do I define the HttpClientErrorEvent?
I tried the following but it is not an extension to a specific HttpClient:
public static event EventHandler<HttpClientErrorEventArgs> HttpClientErrorEvent = delegate { };
Don't use an event to return errors. For starters, how are you going to identify which request raised which error? You'd have to register and unregister event handlers around each call but how would you handle concurrent calls? How would you compose multiple such calls?
Errors aren't events anyway. At best, you'd have to handle the event as if it was a callback - in which case why not use an actual callback?
public async static Task<T> GetSomethingSpecialAsync<T>(this HttpClient client, string url,Action<(HttpStatusCode Status,string Message)> onError)
{
...
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
onError(response.Status,....);
return default;
}
}
...
var value=await client.GetSomethingSpesialAsync(url,
(status,msg)=>{Console.WriteLine($"Calling {url} Failed with {status}:{msg}");}
);
async/await was created so people can get rid of callbacks and events though. It's almost impossible to compose multiple async calls with events, and hard enough to do so with callbacks. That's why a lot of languages (C#, JavaScript, Dart, even C++ in a way ) introduced promises and async/await to get rid of both the success and error callback.
Instead of calling a callback you can actually return either a result or an error from your function. This is a functional way embedded in eg F#, Rust and Go (through tuples). There are a lot of ways to do this in C#:
Return a tuple with the value and error, eg (T? value, string? error)
Create a record with the value and error
Create separate Success and Error classes that share a common IResult<T> interface
Pattern matching can be used with any option to retrieve either the error or value without a ton of if statements.
Let's say we have a specific error type, HttpError.:
record HttpError(HttpStatusCode Status,string Message);
Using tuples, the method becomes:
public async static Task<(T value,HttpError error> GetSomethingSpecialAsync<T>(this HttpClient client,string url)
{
...
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
return (default,new HttpError(response.Status,....);
}
}
And called :
var (value,error)=await client.GetSomethingSpecialAsync(url);
if(error!=null)
{
var (status,msg)=error;
Console.WriteLine($"Calling {url} Failed with {status}:{msg}");
...
}
Instead of a tuple, we can create a Result record:
record Result<T>(T? Value,HttpError? Error);
Or separate classes:
interface IResult<T>
{
bool IsSuccess{get;}
}
record Success<T>(T Value):IResult<T>
{
public bool IsSuccess=>true;
}
record Error<T>(HttpError Error):IResult<T>
{
public bool IsSuccess => false;
}
public async static Task<IResult<T>> GetSomethingSpecialAsync<T>(this HttpClient client,string url){...}
var result=await client.GetSomethingSpecialAsync(url);
In all cases pattern matching can be used to simplify handling the result, eg:
var result=await client.GetSomethingSpecialAsync<T>(url);
switch (result)
{
case Error<T> (status,message):
Console.WriteLine($"Calling {url} Failed with {Status}:{Message}");
break;
case Success<T> (value):
...
break;
}
Having a specific Result<T> or IResult<T> type makes it easy to write generic methods to handle success, errors or compose a chain of functions. For example, the following could be used to call the "next" function if the previous one succeeded, otherwise just propagate the "error" :
IResult<T> ThenIfOk(this IResult<T> previous,Func<T,IResult<T>> func)
{
return previous switch
{
Error<T> error=>error,
Success<T> ok=>func(ok.Value)
}
}
This would allow creating a pipeline of calls :
var finalResult=doSomething(url)
.ThenIfOk(value=>somethingElse(value))
.ThenIfOk(....);
This style is called Railway oriented programming and is very common in functional and dataflow (pipeline) programming
You could store the handlers in your extension class and do something like this ? Please note this code is not thread safe and need to be synchronized around dictionary and list access !
public static class HttpClientExtensions
{
private static Dictionary<HttpClient, List<Action<HttpClientErrorEventArgs>>> Handlers { get; set; }
static HttpClientExtensions()
{
Handlers = new Dictionary<HttpClient, List<Action<HttpClientErrorEventArgs>>>();
}
public async static Task<T> GetSomthingSpecialAsync<T>(this HttpClient client, string url)
{
////code ....
//I have an error and want to raise the HttpClientEventError
HttpClientErrorEventArgs args = null;
client.RaiseEvent(args);
return default(T);
////code
}
public static void AddHandler(this HttpClient client, Action<HttpClientErrorEventArgs> handler)
{
var found = Handlers.TryGetValue(client, out var handlers);
if (!found)
{
handlers = new List<Action<HttpClientErrorEventArgs>>();
Handlers[client] = handlers;
}
handlers.Add(handler);
}
public static void RemoveHandler(this HttpClient client, Action<HttpClientErrorEventArgs> handler)
{
var found = Handlers.TryGetValue(client, out var handlers);
if (found)
{
handlers.Remove(handler);
if (handlers.Count == 0)
{
Handlers.Remove(client);
}
}
}
private static void RaiseEvent(this HttpClient client, HttpClientErrorEventArgs args)
{
var found = Handlers.TryGetValue(client, out var handlers);
if (found)
{
foreach (var handler in handlers)
{
handler.Invoke(args);
}
}
}
}
I am writing a program to interact with the Spotify API via a command line.
I have some code here to take a command, and then execute the relevant function to retrieve data from Spotify.
This code shows the problem, I have left out irrelevant code.
public class CommandHandler
{
public async void HandleCommands()
{
var spotifyCommand = GetCommand();
if (spotifyCommand == SpotifyCommand.Current)
{
WriteCurrentSong(await new PlayerController().GetCurrentlyPlayingAsync());
}
if (spotifyCommand == SpotifyCommand.NextTrack)
{
WriteCurrentSong(await new PlayerController().NextTrackAsync());
}
Console.ReadLine();
//end of program
}
}
public class PlayerController
{
public async Task<SpotifyCurrentlyPlaying> NextTrackAsync()
{
using (var httpClient = new HttpClient())
{
//removed code to set headers etc
//Skip Track
var response = await httpClient.PostAsync("https://api.spotify.com/v1/me/player/next", null);
if (response.StatusCode != HttpStatusCode.NoContent)
{
//code to handle this case, not important
}
return await GetCurrentlyPlayingAsync();
}
}
public async Task<SpotifyCurrentlyPlaying> GetCurrentlyPlayingAsync()
{
using (var httpClient = new HttpClient())
{
//removed code to set headers etc
var response = await httpClient.GetAsync("https://api.spotify.com/v1/me/player/currently-playing");
response.EnsureSuccessStatusCode();
return JsonSerializer.Deserialize<SpotifyCurrentlyPlaying>(await response.Content.ReadAsStringAsync());
}
}
}
The two if statements in HandleCommands() call into PlayerController and await the result of the method. For some reason if I use await PlayerController.MethodCall() the call is made, however, the result does not return before the program finishes executing.
Strangely, this is not an issue if I use PlayerController.MethodCall().Result.
Any help will be greatly appreciated, as I would really rather not use .Result. Thanks!
Signature of the HandleCommands is an issue
public async void HandleCommands()
{
// ...
}
You are not showing how this method is called, but I assume it is something like below:
var handler = new CommandHandler();
handler.HandleCommands();
Because of async void method doesn't return Task and caller can not "observe" it's completion.
So application finishes without waiting for task to complete.
To fix - change method signature to below and await for task to complete
public async Task HandleCommands()
{
// ...
}
var handler = new CommandHandler();
await handler.HandleCommands();
I am trying get a JSON response from a web API.
I am able to retrive response in Console application with similar code, however in UWP await httpClient.GetAsync(uri); does not work as expected.
public static async Task<double> GetJson()
{
using (var httpClient = new HttpClient())
{
Uri uri= new Uri("https://api.cryptonator.com/api/ticker/btc-usd");
HttpResponseMessage response = await httpClient.GetAsync(uri);
//Below code is not relevent since code is failing on await
var result = response.Content.ReadAsStringAsync();
var jsonResponse = Json.ToObjectAsync<ExchangeRate>(result);//
jsonResponse.Wait();//
ExchangeRate exchangeRateObj = jsonResponse.Result;//
return 1.2;//
}
}
Code behind:
private void Button_Click(object sender,RoutedEventArgs e){
var ROC__ = MyClass.GetJson();
ROC__.Wait();
currency_.ROC = ROC__.Result;
}
What is does not work here means?
It is supposed to connect to URL and fetch the response and response should be assigned some value. Instead on debug with either step into or Continue the control exits the current line skips subsequent lines too.
(I have put debug on next lines too),The app just freezes.
I refereed similar codes for JSON parsing with HTTPClient on Stackoverflow and other blogs , its suggested to use System.Net.Http or Windows.Web.Http
Related Question : how-to-get-a-json-string-from-url
I think tasks are run and its going on forever wait mode , which seems strange as debug mode doesnt show code being run , it just show ready . There is no exception as well.
Am I doing something wrong or missing some Nuget reference?
Please suggest.
PS : Its the same case with httpClient.GetStringAsync method too.
On Console app this line works but not on UWP
var json = new WebClient().DownloadString("https://api.cryptonator.com/api/ticker/btc-usd");
Not duplicate of httpclient-getasync-never-returns-on-xamarin-android
Its not Xamarin , even though it is C# based , my code is different , its not WebApiClient or GetInformationAsync method which I am concerned about.
There're several errors with the code specified that needs to be cured. First, mark your event handler async:
private async void Button_Click(object sender, RoutedEventArgs e)
Second, await GetJson and since this is an asynchronous method, it is a better convention to add the suffix "Async" to it's name; therefore, await GetJsonAsync:
currency_.ROC = await MyClass.GetJsonAsync();
Now, back to GetJsonAsync itself, ReadAsStringAsync and ToObjectAsync should be awaited too:
private static async Task<double> GetJsonAsync()
{
using (var httpClient = new HttpClient())
{
Uri uri = new Uri("https://api.cryptonator.com/api/ticker/btc-usd");
HttpResponseMessage response = await httpClient.GetAsync(uri);
string result = await response.Content.ReadAsStringAsync();
//Below code is not relevent since code is failing on await
ExchangeRate exchangeRateObj = await Json.ToObjectAsync<ExchangeRate>(result);
return 1.2;//
}
}
The reason it wasn't working before is that there was a deadlock caused by the context switch between the await call and the synchronous block of .Wait(). Find more about that here.
Your code works fine. I regenerated it here below. Just get rid of that wonky wait call you're doing.
Do this. Create a new uwp app, paste in the below code and put a breakpoint on the return and see that it gets executed.
It will work regardless if you make your button handler async or not. If you don't make it asnyc though then the request won't be executed asynchronously
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
SomeClass.GetJson();
}
}
public class SomeClass
{
public static async Task<double> GetJson()
{
using (var httpClient = new HttpClient())
{
Uri uri = new Uri("https://api.cryptonator.com/api/ticker/btc-usd");
HttpResponseMessage response = await httpClient.GetAsync(uri);
return 1.2;
}
}
}
Might I take this moment for a shameless plug of my UWP lib. It does this work for you.
https://github.com/DotNetRussell/UWPLibrary
In the BasecodeRequestManager.cs file there's a BeginRequest function that does this work async for you. The lib has many many other features as well.
So I tried this by myself. Unfortunately your informations where not complete so a little header:
For the Json-Handling I used Newtonsoft, because I didnt found the Json.ToObjectAsync in my UWP environment.
To create the ExchangeRate- class I used Json2CSharp.
Here are the ExchangeRate classes:
public class ExchangeRate
{
public string Error { get; set; }
public bool Success { get; set; }
public Ticker Ticker { get; set; }
public int Timestamp { get; set; }
}
public class Ticker
{
public string #Base { get; set; }
public string Change { get; set; }
public string Price { get; set; }
public string Target { get; set; }
public string Volume { get; set; }
}
I changed the Button_Click-Method to an async void. Normally its not recommend to have an async void instead of a async Task. But because it is a Handler from a UI-Element its not a problem, because the source will not wait anyway and you shouldn't call this methode directly from your code-behind.
The Button_Click-Method:
private async void Button_Click(object sender, RoutedEventArgs e)
{
var ROC__ = await MyClass.GetJson();
//Do whatever you want with the result.
//Its a double, maybe you want to return an ExchangeRate objcet insted
}
Inside of your GetJson-Method, you need to add an await for your async operations, or add the .Wait() directly after the method and not in a new line. You need to do this, because the Task automatically starts to run, when you call the async operation and the .Wait() comes to late. So your GetJson-Method looks like this:
public static async Task<Double> GetJson()
{
using (var httpClient = new HttpClient())
{
Uri uri = new Uri("https://api.cryptonator.com/api/ticker/btc-usd");
HttpResponseMessage response = await httpClient.GetAsync(uri);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var result = await response.Content.ReadAsStringAsync();
ExchangeRate rate = JsonConvert.DeserializeObject<ExchangeRate>(result); //Newtonsoft
return 1.2;
}
else
{
return -1; //Example value
}
}
}
In addition I added a check, if the Request was successful, to be sure, that we have a response. How I said before: I think you should return a ExchangeRate-object instead of a double, but this depends on your context.
I'm still having trouble understanding how to use Async methods. I have the following code in a controller.
[HttpPost]
public async Task<IActionResult> ManualUpload([Bind("MktRpt")] ManualMktRptFileUpload itemFileUpload)
{
var manager = new RecyclableMemoryStreamManager();
using (var stream = manager.GetStream())
{
await itemFileUpload.MktRpt.CopyToAsync(stream);
await _azureStorageService.saveBlob(stream, Path.GetFileName(itemFileUpload.MktRpt.FileName));
}
itemFileUpload.status = "Success";
return View(itemFileUpload);
}
my service method is simple too:
public async Task saveBlob(MemoryStream stream, string filename)
{
var blockBlob = _container.GetBlockBlobReference(filename);
await blockBlob.UploadFromStreamAsync(stream);
}
along with a simple model class:
public class ManualMktRptFileUpload
{
[Required]
[Display(Name = "Manual Report")]
public IFormFile MktRpt { get; set; }
public string status { get; set; } = "Constructed";
}
When I check my Blob Container in Azure, the file is there BUT, it's zero bytes.
I believe this is because I am not correctly waiting for the stream to transfer, but I don't know how to fix it.
I doubt that this has anything to do with async really. Currently you're copying one stream into a MemoryStream, but then leaving the "cursor" at the end of the MemoryStream... anything trying to read from it won't see the new data.
The fix is really simple: just "rewind" the stream before you call your saveBlob method:
using (var stream = manager.GetStream())
{
await itemFileUpload.MktRpt.CopyToAsync(stream);
stream.Position = 0;
await _azureStorageService.saveBlob(stream, Path.GetFileName(itemFileUpload.MktRpt.FileName));
}
Alternatively, avoid the copying into the MemoryStream entirely:
using (var stream = itemFileUpload.MktRpt.OpenReadStream())
{
await _azureStorageService.saveBlob(stream, Path.GetFileName(itemFileUpload.MktRpt.FileName));
}
I am trying to use the concept of async and await in my program. The program abruptly exits. I am trying to get the content length from few random urls and process it and display the size in bytes of each url.
Code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
namespace TestProgram
{
public class asyncclass
{
public async void MainCall() {
await SumPageSizes();
}
public async Task SumPageSizes(){
List<string> urllist = GetUrlList();
foreach (var url in urllist)
{
byte[] content = await GetContent(url);
Displayurl(content, url);
}
}
private void Displayurl(byte[] content, string url)
{
var length = content.Length;
Console.WriteLine("The bytes length for the url response " + url + " is of :" +length );
}
private async Task<byte[]> GetContent(string url)
{
var content = new MemoryStream();
try
{
var obj = (HttpWebRequest)WebRequest.Create(url);
WebResponse response = obj.GetResponse();
using (Stream stream = response.GetResponseStream())
{
await stream.CopyToAsync(content);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
return content.ToArray();
}
private List<string> GetUrlList()
{
var urllist = new List<string>(){
"http://msdn.microsoft.com/library/windows/apps/br211380.aspx",
"http://msdn.microsoft.com",
"http://msdn.microsoft.com/en-us/library/hh290136.aspx",
"http://msdn.microsoft.com/en-us/library/ee256749.aspx",
"http://msdn.microsoft.com/en-us/library/hh290138.aspx",
"http://msdn.microsoft.com/en-us/library/hh290140.aspx",
"http://msdn.microsoft.com/en-us/library/dd470362.aspx",
"http://msdn.microsoft.com/en-us/library/aa578028.aspx",
"http://msdn.microsoft.com/en-us/library/ms404677.aspx",
"http://msdn.microsoft.com/en-us/library/ff730837.aspx"
};
return urllist;
}
}
}
Main
public static void Main(string[] args)
{
asyncclass asyncdemo = new asyncclass();
asyncdemo.MainCall();
}
MainCall returns an uncompleted task and no other line of code is present beyond that, so your program ends
To wait for it use:
asyncdemo.MainCall().Wait();
You need to avoid async void and change MainCall to async Task in order to be able to wait for it from the caller.
Since this seems to be a console application, you can't use the await and async for the Main method using the current version of the compiler (I think the feature is being discussed for upcoming implementation in C# 7).
The problem is that you don't await an asynchron method and therefore you application exits before the method ended.
In c# 7 you could create an async entry point which lets you use the await keyword.
public static async Task Main(string[] args)
{
asyncclass asyncdemo = new asyncclass();
await asyncdemo.MainCall();
}
If you want to bubble your exceptions from MainCall you need to change the return type to Task.
public async Task MainCall()
{
await SumPageSizes();
}
If you wanted to run your code async before c# 7 you could do the following.
public static void Main(string[] args)
{
asyncclass asyncdemo = new asyncclass();
asyncdemo.MainCall().Wait();
// or the following line if `MainCall` doesn't return a `Task`
//Task.Run(() => MainCall()).Wait();
}
You have to be very careful when using async void methods. Those will not be awaited. One normal example of an async void is when you are calling an awaitable method inside a button click:
private async void Button_Click(object sender, RoutedEventArgs e)
{
// run task here
}
This way the UI won't be stuck waiting for the button click to complete.
On most custom methods you will almost always want to return a Task so that you are able to know when your method is finished.