I'm using the WebClient class. I've had some luck with the OpenReadTaskAsync method with a GET, but right now, I want to call a POST, or PUT REST method. I figured that I should use UploadStringTaskAsync. But, when I call this method on a working REST service, I get this error:
System.Net.WebException: An exception occurred during a WebClient request. ---> System.NotSupportedException: Specified method is not supported on this request.
at System.Net.Browser.BrowserHttpWebRequest.set_Method(String value)
at System.Net.WebClient.GetWebRequest(Uri address)
at System.Net.WebClient.UploadStringAsync(Uri address, String method, String data, Object userToken)
--- End of inner exception stack trace ---
at Microsoft.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccess(Task task)
at Microsoft.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at CF.RESTClientDotNet.Silverlight.Sample.MainPage.d__3.MoveNext()
This is the code
var webClient = new WebClient();
var returnValue = await webClient.UploadStringTaskAsync(uri.AbsoluteUri, "POST", bodyString);
I ended up completely redesigning my library. There are samples here:
https://bitbucket.org/MelbourneDeveloper/restclient-.net/src/master/
NuGet: Install-Package RESTClient.NET
Related
I'm trying to delete a blob snapshot - I don't want to delete anything other than the snapshot for which I have the reference.
await snapshotBlob.DeleteAsync(DeleteSnapshotsOption.None,
acc,
new BlobRequestOptions(),
new OperationContext());
I've tried different DeleteSnapshotsOption but the exception tells me that only DeleteSnapshotsOption.None can be used when deleting a snapshot.
The AccessCondition (acc) has only the LeaseID set.
I don't have BlobRequestOptions or OperationContext preferences; I've also tried passing null for those two properties but it makes no difference.
The method call throws "The remote server returned an error: (400) Bad Request."
Stack trace:
Microsoft.WindowsAzure.Storage.StorageException at
Microsoft.WindowsAzure.Storage.Core.Executor.Executor.EndExecuteAsync[T](IAsyncResult
result) at
Microsoft.WindowsAzure.Storage.Blob.CloudBlob.EndDelete(IAsyncResult
asyncResult) at
Microsoft.WindowsAzure.Storage.Core.Util.AsyncExtensions.<>c__DisplayClass4.b__3(IAsyncResult
ar)
--- End of stack trace from previous location where exception was thrown --- at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task) at
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task) at
System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at StorageHooks.StorageBackup.d__0.MoveNext() in [line in my
code]
Can anyone explain what's wrong with the way I'm calling the method?
Also, in case it has an influence, I'm calling this method in an Azure Function. Furthermore, the code is copying existing blobs into another container, and the code works for creating a snapshot, creating the new blob, uploading to the other container, copying metadata, obtaining a lease... The only part which fails is deleting the snapshot.
I tried your code and traced the request/response through Fiddler. When I specified the lease id in the access condition, I got the 400 error. When I looked up the details, this is what the error message told me:
<?xml version="1.0" encoding="utf-8"?>
<Error>
<Code>InvalidQueryParameterValue</Code>
<Message>
Value for one of the query parameters specified in the request URI is invalid.
RequestId:cb8bcb1d-001e-004a-4811-991d8e000000
Time:2018-01-29T15:00:02.6030417Z
</Message>
<QueryParameterName>snapshot</QueryParameterName>
<QueryParameterValue>2018-01-29T14:55:27.3537780Z</QueryParameterValue>
<Reason>Leases are not allowed with snapshots.</Reason>
</Error>
Please try your request by removing the access condition from your request. When I did that, the request went just fine. So your code would be:
await snapshotBlob.DeleteAsync(DeleteSnapshotsOption.None)
I'm building a web application that connects to a Predix Timeseries instance to ingest data through a websocket. When I attempt to create the socket, I get this exception:
System.Net.WebSockets.WebSocketException: 'Unable to connect to the
remote server'
I'm using this code to create my websocket, with my error being thrown on the ConnectAsync call:
public async Task openWebSocket()
{
_socket = new ClientWebSocket();
_socket.Options.SetRequestHeader(headerName: "predix-zone-id", headerValue: PREDIX_ZONE_ID_HERE);
_socket.Options.SetRequestHeader(headerName: "authorization", headerValue: "Bearer " + AUTH_TOKEN_HERE);
_socket.Options.SetRequestHeader(headerName: "content-type", headerValue: "application/json");
CancellationToken token = new CancellationToken();
var uri = new Uri(uriString: "wss://gateway-predix-data-services.run.aws-usw02-pr.ice.predix.io/v1/stream/messages");
await _socket.ConnectAsync(uri: uri, cancellationToken: token);
}
and here is my exception's stack trace:
System.Net.WebSockets.WebSocketException occurred
HResult=0x80004005
Message=Unable to connect to the remote server
Source=<Cannot evaluate the exception source>
StackTrace:
at System.Net.WebSockets.WebSocketHandle.<ConnectAsyncCore>d__20.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Net.WebSockets.ClientWebSocket.<ConnectAsyncCore>d__16.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PROJECTNAME.Services.TimeseriesService.<openWebSocket>d__6.MoveNext() in %PROJECTLOCATION%\Services\%SERVICENAME%.cs:line 34
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PROJECTNAME.Services.TimeseriesService.<Initialize>d__5.MoveNext() in %PROJECTLOCATION%\Services\%SERVICENAME%.cs:line 21
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at PROJECTNAME.Program.<Initialize>d__1.MoveNext() in %PROJECTLOCATION%\Program.cs:line 52
Inner Exception 1:
WebSocketException: Unable to connect to the remote server
The inner exception stack track has little more information, but noting the ThrowOnInvalidConnectState() that might be useful:
at System.Net.WebSockets.WinHttpWebSocket.ThrowOnInvalidConnectState()
at System.Net.WebSockets.WinHttpWebSocket.<ConnectAsync>d__18.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Net.WebSockets.WebSocketHandle.<ConnectAsyncCore>d__20.MoveNext()
I'm not sure what else to try - lots of other posts on SO at least have some useful information in the inner exception.
I've also attempted to use Fiddler. I can see message for other services, including my auth token retrieval from UAA, but nothing from this service.
Am I missing some configuration steps somewhere? Any help or guidance would be appreciated.
I figured out the issue. The three required headers for the Predix Timeseries are:
Predix-Zone-Id: zone_id_here
Authorization: Bearer auth_token_here
Origin: "https:// hostname_here
My problem is that I tried the Origin header, but the Predix VCAP_APPLCIATION environmental variable for the application_uris doesn't include the "https://". Once I added it manually ("https://" + uri) it worked fine.
I haven't done this in C#, but "Unable to connect" sounds like it could be a network issue. Can you open a websocket to another server? Maybe this one?
https://www.websocket.org/echo.html
Could be a proxy server issue? Can you try from a different network?
I'm trying to return a 304 Not Modified status code in my ASP.Net Core application when a file is accessed via my middleware.
I try setting the HTTP Status Code and sending the response back like so:
context.Response.StatusCode = 304;
await context.Response.WriteAsync("Not Modified");
But I get this exception:
System.InvalidOperationException occurred HResult=-2146233079
Message=Write to non-body 304 response.
Source=Microsoft.AspNetCore.Server.Kestrel StackTrace:
at Microsoft.AspNetCore.Server.Kestrel.Internal.Http.Frame.HandleNonBodyResponseWrite()
at Microsoft.AspNetCore.Server.Kestrel.Internal.Http.Frame.d__183.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at Adapt.REST.ServeStaticFilesMiddleware.d__8.MoveNext() in
C:\AdaptSource\Xivic\Adapt.Services\ServeStaticFilesMiddleware.cs:line
113 InnerException:
So obviously I can't use WriteAsync or SendFileAsync because they both send a response that contains a body.
How do I send a 304 back to the client without a body?
Simply doing nothing after setting the status code causes the intended functionality.
context.Response.StatusCode = 304;
return;
I was having a WebClient that was requesting an URL. I wanted to do the same thing within a UWP application, and I saw that I had to import Microsoft.Net.Http and use HttpClient.
So I replaced this(that was in a Class library):
WebClient client = new WebClient();
client.Headers[HttpRequestHeader.UserAgent] = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/15.0.874.121 Safari/535.2";
string content = client.DownloadString(url);
By this in a PCL library:
HttpClient client = new HttpClient();
string content = await client.GetStringAsync(url);
And now I got this exception:
System.Net.Http.HttpRequestException occurred
HResult=-2147012867
Message=An error occurred while sending the request.
Source=System.Net.Http
StackTrace:
at System.Net.Http.HttpClientHandler.<SendAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at XXXX.YYYY.MHDJ.ZZZZ.<ParsePage>d__4.MoveNext()
InnerException:
ErrorCode=-2147012867
HResult=-2147012867
Message=Le texte associé à ce code d’erreur est introuvable.
Impossible d'établir une connexion avec le serveur
Source=""
StackTrace:
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Net.Http.HttpHandlerToFilter.<SendAsync>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Net.Http.HttpClientHandler.<SendAsync>d__1.MoveNext()
InnerException:
I don't think the issue is the Headers, so what is?
The HRESULT code -2147012867 in hex is 0x80072EFD. The 0x8007 prefix means it's actually an HRESULT wrapper around a Win32 error code. The original Win32 error code is 0x2EFD.
The Win32 error code list tells us that values 0x2EE0 through 0x2F8F are ERROR_INTERNET_* error codes, which sounds like the right kind of error. After following the link to the Win32 ERROR_INTERNET_* error code listing, we can convert our error code 0x2EFD back to decimal (12029) and discover it is error ERROR_INTERNET_CANNOT_CONNECT:
The attempt to connect to the server failed.
Rather generic, and not much help.
I'd recommend trying the connection again, ensuring that your application has appropriate permissions and the device actually has a working Internet connection. If that doesn't work, try adding the UserAgent header back in; it's possible that the networking stack on your device insists on it.
Update: Tracking down the error code meaning was rather tedious, so I wrote an app to do it.
Experienced the 0x80072efd problem. Has cost me hours if not days to solve. The solution that worked for me was the following command from an admin command prompt:
netsh winhttp reset proxy
There are so many ways to do things, and I'm not suggesting that this is the best way, but this is how I construct my methods. This example is what I use to return a list of U.S. State objects that are provided in JSON format. One important note... this is in a Universal Windows class library, not a PCL... but I do not believe it uses anything that a PCL does not have access to.
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using System.Threading.Tasks;
//IStateInfo is my model class interface
public async Task<IList<IStateInfo>> GetAllStatesAsync()
{
List<IStateInfo> states = new List<IStateInfo>();
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://YourBaseApiHere");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string url = "lookup/usstates";
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
//deserialize into client class Newtonsoft JSON used here
var lst = JsonConvert.DeserializeObject<List<StateInfo>>(json);
states.AddRange(lst);
}
else
{
//notify of failed web call here
}
}
}
catch (Exception e)
{
//notify of error
}
return states;
}
I am working on a Windows Runtime Component which makes API calls. Until earlier today I used the HttpClient and related models from System.Net but switched over to Windows.Web instead to leverage the WinRT streams.
Aside from changing the using statements, swapping HttpContent to IHttpContent and using the WindowsRuntimeExtensions to change my IInputStream to Stream for JSON.NET, I didn't have to do anything special. However suddenly 3 out of my 16 tests fail whereas previously everything worked.
All 3 (integration) tests validate that I receive an error response when logging in with invalid credentials. There are other tests that include logging in as well (but with valid credentials) and they work just fine. The given error message is of type AggregateException and has as message
System.AggregateException: One or more errors occurred. ---> System.Exception: Element not found.
A dialog cannot be displayed because the parent window handle has not been set.
The exception contains HRESULT values. The outerexception has value -2146233088 which corresponds to 0x80131500 while the innerexception has -2147023728 which corresponds to 0x80070490. Neither of those are a known error code on the MSDN page.
Following investigation:
0x80131500 corresponds to COR_E_EXCEPTION
0x80070490 corresponds to ERROR_NOT_FOUND
Stacktrace:
Result StackTrace:
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at xx.Models.Requests.GetRequest.<ExecuteRequestAsync>d__0.MoveNext() in c:\Users\jeroen\Github\Windows-app\xx\xx\Models\Requests\Request.cs:line 17
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at xx.ApiDispatcher.<ExecuteAsync>d__0`2.MoveNext() in c:\Users\jeroen\Github\Windows-app\xx\xx\ApiDispatcher.cs:line 40
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at System.Threading.Tasks.Task`1.get_Result()
at xx.ApiDispatcher.Execute[TCallResult,TResponseObject](ApiCall`2 call) in c:\Users\jeroen\Github\Windows-app\xx\xx\ApiDispatcher.cs:line 22
Originally my question was worded somewhat differently because the actual problem seemed to be hidden. I have found out that the GET request by the HttpClient returns back to the caller instead of awaiting the result of the call (and executing the rest of the method).
In my project, executing the line var data = await myHttpClient.GetAsync(url); will return to the calling method with a non-constructed object and subsequent lines that come after the GetAsync() call are simply not executed.
Adding .ConfigureAwait(false) to stop it from going back did not make a difference.
The AggregateException is thrown when a user tries to login with invalid credentials. For some reason the HttpClient decides to throw an exception then without giving me a return value I could use. The problem here is that it does not tell me what kind of exception: catching COMException, TaskCanceledException, AggregateException and Exception only trigger the latter.
I have also found out that asynchronous integration tests do not work well with the multithreaded MSTest environment, so that explains several other failed tests that I had (but worked just fine individually)
I also, finally, have an example that demonstrates the problem (but I can't provide a webservice that takes basic auth)!
[TestMethod]
public void TestMethod3()
{
Assert.IsTrue(new Test().Do().AsTask().Result);
}
public sealed class Test
{
public IAsyncOperation<bool> Do()
{
return DoSomething().AsAsyncOperation();
}
private async Task<bool> DoSomething()
{
var client = new HttpClient();
var info = "jeroen.vannevel#something.com:nopass";
var token = Convert.ToBase64String(Encoding.UTF8.GetBytes(info));
client.DefaultRequestHeaders.Authorization = new HttpCredentialsHeaderValue("Basic", token);
var data = await client.GetAsync(new Uri("https://mytestdomain/v2/apikey?format=Json"));
return true;
}
}
Executing this code with a valid password will return true while an invalid password will throw an AggregateException.
Right now I am working around the problem by catching a general Exception around the call to GetAsync() but this is very rudimentary and I'd like to know why this incomplete exception is thrown in the first place.
After reconstructing your example and playing around, I figured out what happens.
var data = await client.GetAsync(new Uri("https://mytestdomain/v2/apikey?format=Json"));
The GetAsync method invokes the HTTP request with invalid credentials. What happens is that the returned request tries to look for a window where you can enter the correct credentials, but doesn't find one. Hence it throws an Element Not Found while searching for that window.
This can be fixed by creating a HttpBaseProtocolFilter and setting the AllowUI property to false and then passing it to the HttpClient:
private async Task<bool> DoSomething()
{
var httpBaseFilter = new HttpBaseProtocolFilter
{
AllowUI = false
};
var client = new HttpClient(httpBaseFilter);
var info = "jeroen.vannevel#something.com:nopass";
var token = Convert.ToBase64String(Encoding.UTF8.GetBytes(info));
client.DefaultRequestHeaders.Authorization = new HttpCredentialsHeaderValue("Basic", token);
var data = await client.GetAsync(new Uri("https://mytestdomain/v2/apikey?format=Json"));
return true;
}
Setting AllowUI on HttpBaseProtocolFilter to false will stop this error.
If however you do want a dialog box to display, allowing the user to enter credentials, then the web request needs to be started on the UI thread.
I think the problem is that the exception is actually thrown by your call to EnsureSuccessStatusCode.
Did you try adding HttpResponseMessage class EnsureSuccessStatusCode() method and check.
http://msdn.microsoft.com/en-us/library/system.net.http.httpresponsemessage.ensuresuccessstatuscode.aspx
After this line:
var data = await client.GetAsync(new Uri("https://mytestdomain/v2/apikey?format=Json"));
date.EnsureSuccessStatusCode();