I have the following code;
var httpClientHandler = new HttpClientHandler()
{
UseDefaultCredentials = true,
PreAuthenticate = false,
};
var webclient = new HttpClient(httpClientHandler);
webclient.BaseAddress = new Uri("http://localhost");
webclient.Timeout = new TimeSpan(1);
var res = webclient.PostAsync("http://localhost/test", "'test'", new JsonMediaTypeFormatter()).Result; //.ContinueWith(x => ProcessResult(x));
The .Result blocks the thread and hangs the application. If I replace it with the continuation, it is never executed.
If I increase the timeout, the code works, so it seems to be the failing timeout.
I've solved it by using another task to timeout but would like to understand better;
if (await Task.WhenAny(task, Task.Delay(new TimeSpan(0, 0, 0, 20))) == task)
{
//success
}
else
{
//failure
}
Related
I am using a library for communicate with a crypto api.
In Console Application every thing is ok about async post.
But in webforms it goes to sleep and nothing happens!
Just loading mode.
Here is the method :
private async Task<WebCallResult<T>> PostAsync<T>(string url, object obj = null, CancellationToken cancellationToken = default(CancellationToken))
{
using (var client = GetHttpClient())
{
var data = JsonConvert.SerializeObject(obj ?? new object());
var response = await client.PostAsync($"{url}", new StringContent(data, Encoding.UTF8, "application/json"), cancellationToken);
var content = await response.Content.ReadAsStringAsync();
// Return
return this.EvaluateResponse<T>(response, content);
}
}
private HttpClient GetHttpClient()
{
var handler = new HttpClientHandler()
{
AllowAutoRedirect = false
};
var client = new HttpClient(handler);
client.BaseAddress = new Uri(this.EndpointUrl);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
In line var response = web site goes to loading mode.
No error - Nothing - Just Loading.
How can i fix this problem in webforms?
In Console Application it is working fine.
Maybe i should change something in Web.config!!!
Here is the library
May I know what is the proper way of disposing Handler? or should I really need to dispose it?
Because Microsoft is also diposing the Handler https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclienthandler?view=netcore-3.1
Here is my static Handler.
private static HttpClientHandler handlerWithProxy = new HttpClientHandler
{
UseCookies = false,
UseDefaultCredentials = true,
DefaultProxyCredentials = CredentialCache.DefaultCredentials,
Proxy = new WebProxy($"{MyProxy.ProxyHost}:{MyProxy.ProxyPort}", false),
UseProxy = true,
SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls,
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; }
};
And here where I'm calling the dispose. Is it correct?
private static async Task<JsonDocument> ResponseMessage(HttpRequestMessage request, CancellationToken token)
{
HttpCompletionOption option = HttpCompletionOption.ResponseHeadersRead;
using (HttpResponseMessage response = MyProxy.UseProxy ? await clientWithProxy.SendAsync(request, option, token).ConfigureAwait(false)
: await client.SendAsync(request, option, token).ConfigureAwait(false))
{
token.ThrowIfCancellationRequested();
HttpStatusCode status = response.StatusCode;
using (Stream stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
{
if (stream == null || stream.CanRead == false) { return default; }
var options = new JsonDocumentOptions { AllowTrailingCommas = true };
var json = await JsonDocument.ParseAsync(stream, options).ConfigureAwait(false);
if (!response.IsSuccessStatusCode) { throw new InvalidDataException($"Error occured: {ParseError(uri, json, status)}"); }
//is this right of calling the dispose if it is already null?
if (handler == null) { handler.Dispose(); }
return json;
}
}
}
This answer will be short, but sweet:
Handlers are tied to the HttpClient at creation. You don't dispose of those. Just create your HttpClient with it and forget about it. That example on MS's site is not a typical usage scenario.
Make sure that when you create your HttpClient you make it static and in the class scope:
private static readonly HttpClient clientWithProxy = new HttpClient(handlerWithProxy);
You should use reuse the same HttpClient throughout the lifetime of your application for all HTTP requests.
The example shown on the following page doesn't work:
Using c# ClientWebSocket with streams
It hangs on the following line:
await ws.ConnectAsync(serverUri, CancellationToken.None);
It appears the connection is not made.
Please indicate the simplest modification to make the following code work. I do not wish to use any 3rd party tools or libraries.
private static async Task DoClientWebSocket()
{
using (ClientWebSocket ws = new ClientWebSocket())
{
Uri serverUri = new Uri("wss://echo.websocket.org/");
await ws.ConnectAsync(serverUri, CancellationToken.None);
while (ws.State == WebSocketState.Open)
{
string msg = "hello123";
ArraySegment<byte> bytesToSend = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msg));
await ws.SendAsync(bytesToSend, WebSocketMessageType.Text, true, CancellationToken.None);
ArraySegment<byte> bytesReceived = new ArraySegment<byte>(new byte[1024]);
WebSocketReceiveResult result = await ws.ReceiveAsync(bytesReceived, CancellationToken.None);
Console.WriteLine(Encoding.UTF8.GetString(bytesReceived.Array, 0, result.Count));
}
}
}
You are correct. You don't need to add any header in order to use wss://echo.websocket.org/. Your code run just fine at my end. But I'll suggest one improvement to include timeout for your ConnectAsync, SendAsync and ReceiveAsync calls so that it do not get stuck for long.
I have restricted code to call SendAsync to just 5 times so that its easier to verify output.
[Edited:] Include logic to receive complete response by calling `ReceiveAsync multiple times.
private static async Task DoClientWebSocket()
{
using (ClientWebSocket ws = new ClientWebSocket())
{
Uri serverUri = new Uri("wss://echo.websocket.org/");
//Implementation of timeout of 5000 ms
var source = new CancellationTokenSource();
source.CancelAfter(5000);
await ws.ConnectAsync(serverUri, source.Token);
var iterationNo = 0;
// restricted to 5 iteration only
while (ws.State == WebSocketState.Open && iterationNo++ < 5)
{
string msg = "hello0123456789123456789123456789123456789123456789123456789";
ArraySegment<byte> bytesToSend =
new ArraySegment<byte>(Encoding.UTF8.GetBytes(msg));
await ws.SendAsync(bytesToSend, WebSocketMessageType.Text,
true, source.Token);
//Receive buffer
var receiveBuffer = new byte[200];
//Multipacket response
var offset = 0;
var dataPerPacket = 10; //Just for example
while (true)
{
ArraySegment<byte> bytesReceived =
new ArraySegment<byte>(receiveBuffer, offset, dataPerPacket);
WebSocketReceiveResult result = await ws.ReceiveAsync(bytesReceived,
source.Token);
//Partial data received
Console.WriteLine("Data:{0}",
Encoding.UTF8.GetString(receiveBuffer, offset,
result.Count));
offset += result.Count;
if (result.EndOfMessage)
break;
}
Console.WriteLine("Complete response: {0}",
Encoding.UTF8.GetString(receiveBuffer, 0,
offset));
}
}
}
static void Main(string[] args)
{
var taskWebConnect = Task.Run(() => DoClientWebSocket());
taskWebConnect.Wait();
}
Output on command prompt:
Data:hello01234
Data:5678912345
Data:6789123456
Data:7891234567
Data:8912345678
Data:9123456789
Complete response: hello0123456789123456789123456789123456789123456789123456789
I have followed the example here and here to handle timeouts successfully with the C# HttpClient but I just can't make it work!
var urls = new List<string> { "/success", "/willtimeout", "/success" };
var baseAddress = "http://endpoint";
var httpClient = new HttpClient();
httpClient.Timeout = new TimeSpan(0, 0, 30);
httpClient.BaseAddress = new Uri(baseAddress);
foreach (var url in urls)
{
try
{
var cs = CancellationTokenSource.CreateLinkedTokenSource(CancellationToken.None);
cs.CancelAfter(new TimeSpan(0, 0, 3));
var result = await httpClient.GetAsync(urls, cs.Token);
Console.WriteLine("Success");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
This code will print
Success
A task was canceled.
A task was canceled.
How can I make this work properly without creating a new HttpClient every time?
CreateLinkedTokenSource Creates a CancellationTokenSource that will be in the canceled state when any of the source tokens are in the canceled state.
So I guess this is the problem, just create new token source every time and don't link it to anything:
try
{
var cs = new CancellationTokenSource();
// ...
I want to get data from this wss://ws-feed.gdax.com
I don't know anything about websocket. I am reading some tutorials and it uses terms like websocket server, TCP, etc which I have no idea about. Can anyone please advice how should I proceed, how to write a c# code to get data from the above.
This is the document which I reading to fetch real time data - https://docs.gdax.com/#websocket-feed
Started by creating a window app. Read here that the WebSocketSharp library can be used to connect WebSockets so installed it and so far written this code:
using (var ws = new WebSocket("wss://ws-feed.gdax.com"))
{
ws.Connect();
string json = "{\"type\": \"subscribe\", \"product_ids\": [\"BTC-USD\"]}";
ws.Send(json); //gives error -Function evaluation disabled because a previous function evaluation timed out. You must continue execution to reenable function evaluation.
}
Any help would be much appreciated.
ClientWebSocket socket = new ClientWebSocket();
Task task = socket.ConnectAsync(new Uri("wss://ws-feed.gdax.com"), CancellationToken.None);
task.Wait();
Thread readThread = new Thread(
delegate(object obj)
{
byte[] recBytes = new byte[1024];
while (true) {
ArraySegment<byte> t = new ArraySegment<byte>(recBytes);
Task<WebSocketReceiveResult> receiveAsync = socket.ReceiveAsync(t, CancellationToken.None);
receiveAsync.Wait();
string jsonString = Encoding.UTF8.GetString(recBytes);
Console.Out.WriteLine("jsonString = {0}", jsonString);
recBytes = new byte[1024];
}
});
readThread.Start();
string json = "{\"product_ids\":[\"btc-usd\"],\"type\":\"subscribe\"}";
byte[] bytes = Encoding.UTF8.GetBytes(json);
ArraySegment<byte> subscriptionMessageBuffer = new ArraySegment<byte>(bytes);
socket.SendAsync(subscriptionMessageBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
Console.ReadLine();
Basically, what you do is in the right direction. Just check websocket state before you read the message.
The below example is from https://github.com/sefbkn/gdax.netcore, with little modification
var webSocketClient = new ClientWebSocket();
var cancellationToken = new CancellationToken();
await webSocketClient.ConnectAsync(new Uri("wss://ws-feed.gdax.com"), cancellationToken).ConfigureAwait(false);
if (webSocketClient.State == WebSocketState.Open)
{
var requestString = JsonConvert.SerializeObject(new {
type = "subscribe",
product_ids = new[]{"ETH-EUR"},
channels = new[]{"ticker"}
});
var requestBytes = UTF8Encoding.UTF8.GetBytes(requestString);
var subscribeRequest = new ArraySegment<byte>(requestBytes);
var sendCancellationToken = new CancellationToken();
await webSocketClient.SendAsync(subscribeRequest, WebSocketMessageType.Text, true, sendCancellationToken).ConfigureAwait(false);
while (webSocketClient.State == WebSocketState.Open)
{
var receiveCancellationToken = new CancellationToken();
using(var stream = new MemoryStream(1024))
{
var receiveBuffer = new ArraySegment<byte>(new byte[1024*8]);
WebSocketReceiveResult webSocketReceiveResult;
do
{
webSocketReceiveResult = await webSocketClient.ReceiveAsync(receiveBuffer, receiveCancellationToken).ConfigureAwait(false);
await stream.WriteAsync(receiveBuffer.Array, receiveBuffer.Offset, receiveBuffer.Count);
} while(!webSocketReceiveResult.EndOfMessage);
var message = stream.ToArray().Where(b => b != 0).ToArray();
messageReceived(Encoding.ASCII.GetString(message, 0, message.Length));
}
}
}