Send request as Json on UWP - c#

I have deployed an AzureML published experiment with deployed web service. I tried to use the sample code provided in the configuration page, but universal apps do not implement Http.Formatting yet, thus I couldn't use postasjsonasync.
I tried to follow the sample code as much as possible, but I'm getting statuscode of 415 "Unsupported Media Type", What's the mistake I'm doing?
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
// client.BaseAddress = uri;
var scoreRequest = new
{
Inputs = new Dictionary<string, StringTable>() {
{
"dataInput",
new StringTable()
{
ColumnNames = new [] {"Direction", "meanX", "meanY", "meanZ"},
Values = new [,] { { "", x.ToString(), y.ToString(), z.ToString() }, }
}
},
},
GlobalParameters = new Dictionary<string, string>() { }
};
var stringContent = new StringContent(scoreRequest.ToString());
HttpResponseMessage response = await client.PostAsync(uri, stringContent);
Many Thanks

You'll need to serialize the object to a JSON string (I recommend using NewtonSoft.Json to make it easier) and set the content type accordingly. Here's an implementation I'm using in my UWP apps (note that _client is an HttpClient):
public async Task<HttpResponseMessage> PostAsJsonAsync<T>(Uri uri, T item)
{
var itemAsJson = JsonConvert.SerializeObject(item);
var content = new StringContent(itemAsJson);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
return await _client.PostAsync(uri, content);
}

Related

Postman form-data: How to program it inside a HttpRequestMessage?

I am doing a request through postman to a specific url but I set the form-data type in order to get data to the site like this:
Now I want to program this request inside C# but everything I tried so far is returning a 400 Bad Request response. This is what I tried:
public async Task<CheckAccessTokenModel> CheckAccessTokenAsync(string accessToken)
{
string uriString = "someurl";
var uri = new Uri(uriString);
try
{
using(var httpClient = new HttpClient())
{
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = uri
};
var ClientId = ConfigurationAccessor.Configuration["WebCredentials:ClientId"];
var Secret = ConfigurationAccessor.Configuration["WebCredentials:Secret"];
var authString = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{ClientId}:{Secret}"));
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authString);
MultipartFormDataContent content = new MultipartFormDataContent();
content.Add(new StringContent("token"), accessToken);
request.Content = content;
var response = await httpClient.SendAsync(request);
var checkTokenResponseData = await response.Content.ReadAsStringAsync();
//return new CheckAccessTokenModel { Active = true, Exp = 1647431224233 };
return JsonConvert.DeserializeObject<CheckAccessTokenModel>(checkTokenResponseData);
}
}
catch
{
return null;
}
}
I am doing it with the MultipartFormDataContent Object as suggested by many others here but it still won't work.
What can be the problem here?
EDIT: Wrong picture replaced
You can simply
request.Content = new StringContent($"token={accessToken}");
With form data I think it's something like this:
var data = new Dictionary<string, string>
{
{"token", acccessToken}
};
using var content = new FormUrlEncodedContent(data);
request.Content = content;

Send SMS Nexmo from Azure Function got error

I try to send the SMS from Azure Function, it show the error. But if i do in Web or console app the sms succesfully sent. The error is this:
System.TypeInitializationException:'The type initializer for 'Nexmo.Api.Configuration' threw an exception.'
MissingMethodException:
Method not found: 'Microsoft.Extensions.Configuration.IConfigurationBuilder Microsoft.Extensions.Configuration.MemoryConfigurationBuilderExtensions.AddInMemoryCollection(Microsoft.Extensions.Configuration.IConfigurationBuilder, System.Collections.Generic.IEnumerable1<System.Collections.Generic.KeyValuePair2>)'.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var client = new Nexmo.Api.Client(creds: new Credentials(Api_KEY, Api_Secret));
var results = client.SMS.Send(request: new SMS.SMSRequest()
{
from = nexmo.Sender,
text = nexmo.Msg,
to = nexmo.Receiver
});
I faced the same problem, it seems that the Nexmo.Csharp.Client package does not work correctly on Azure Functions. This could be because one of the assemblies is not compatible with Azure (not all are) or some configuration setting that is not supported on Azure Functions.
I was surprised by how many references/assemblies are installed by:
Install-Package Nexmo.Csharp.Client
So I gave up on trying to identify what is the cause. Instead a much simpler solution is to create your own HttpClient and use the REST API directly (that is probably what the weighty package does anyhow).
var client = new HttpClient();
var requestContent = new FormUrlEncodedContent(new[] {
new KeyValuePair<string, string>("api_key", "YOURKEY"),
new KeyValuePair<string, string>("api_secret", "YOURSECRET"),
new KeyValuePair<string, string>("to", "TO!!!"),
new KeyValuePair<string, string>("from", "MisterCook"),
new KeyValuePair<string, string>("text", "MisterCook Says Hi")
});
HttpResponseMessage response = await client.PostAsync(
"https://rest.nexmo.com/sms/json",
requestContent);
HttpContent responseContent = response.Content;
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
// If you need it...
}
This will spare you from deploying the bulky Nexmo.Csharp.Client package deployment and works in Azure Functions.
I realise this is an old question, but I noticed it's still not had an answer accepted.
I've just used the latest version of the .Net SDK (5.9.0) with Functions v1, v3 and v4 using the below code and had no issues
using Vonage;
using Vonage.Request;
using Vonage.Messaging;
var credentials = Credentials.FromApiKeyAndSecret("abcd123efg", "abcdefgfgfgfgf");
var VonageClient = new VonageClient(credentials);
var response = VonageClient.SmsClient.SendAnSms(new SendSmsRequest()
{
To = "0123456789",
From = "Vonage APIs",
Text = "A text message sent using the Vonage SMS API"
});
If it works locally or in another context, then the code is correct. For Azure Functions in particular I would check that the dependencies are installed as you expect, and that the variables like API key have the values you expect (add some logging to test this) - these work differently in the serverless context. Hope that helps!
I also was able to get the new WhatsApp API running with Mister Cook's approach.
public bool Send(Message msg)
{
var task = SendAsync(msg);
task.Wait();
return task.Result;
}
public async Task<bool> SendAsync(Message msg)
{
var requestJson = CreateJson(msg);
Console.WriteLine(requestJson);
var content = new StringContent(requestJson);
content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
var client = new HttpClient();
try
{
HttpResponseMessage response = await client.PostAsync("https://messages-sandbox.nexmo.com/v0.1/messages", content);
string responseJson = await response.Content.ReadAsStringAsync();
return MessageSucceeded(responseJson);
}
catch
{
return false;
}
}
private string CreateJson(Message msg)
{
JObject request = new JObject();
JObject from = new JObject();
from.Add("type", "whatsapp");
from.Add("number", "14157386170");
request.Add("from", from);
JObject to = new JObject();
to.Add("type", "whatsapp");
to.Add("number", ConnectionData);
request.Add("to", to);
JObject message = new JObject();
JObject content = new JObject();
content.Add("type", "text");
content.Add("text", msg.Text);
message.Add("content", content);
request.Add("message", message);
return request.ToString();
}
private bool MessageSucceeded(string json)
{
var obj = JObject.Parse(json);
JToken token;
return obj.TryGetValue("message_uuid", out token);
}
The RequestJson for Sandbox Testing is:
{
"from": { "type": "whatsapp", "number": "14157386170" },
"to": { "type": "whatsapp", "number": "YOUR_WHITELIST_NUMBER" },
"message": {
"content": { "type": "text", "text": "Test succeeded. Congrats" }
}
}
If the Request succeeded, the ResponseJson will contain a message_uuid. I only check wether it is contained or not
{"message_uuid": "e6859d67-1a94-44c4-bf09-a3e3fa7f8691"}

Getting unauthorised access in YouTube API [Xamarin.Forms (Portable)]

I am trying to upload the Video from Xamarin.Forms (Portable) to YouTube, I have tried to use the Google APIs but the Google APIs are not compatible with the Xamarin.Forms (Portable) at this stage. So, I compulsory have to upload it via HttpClient but I am getting Unauthorised in StatusCode
public async Task UploadVideoAsync(Stream stream)
{
//var token = flow.LoadTokenAsync("", CancellationToken.None).Result;
string json = #"{
""snippet"": {
""title"": ""using API"",
""description"": ""This is a description of my video"",
""tags"": [""cool"", ""video"", ""more keywords""],
""categoryId"": ""21"",
},
""status"": {
""privacyStatus"": ""public"",
""embeddable"": true,
""license"": ""youtube""
}
}";
var JsonReqMsg = new StringContent(json);
JsonReqMsg.Headers.ContentType = new MediaTypeHeaderValue("application/json")
{
CharSet = "UTF-8"
};
var request = new HttpRequestMessage
(HttpMethod.Post, new Uri("https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status"));
request.Headers.Add("X-Upload-Content-Length", stream.Length.ToString());
request.Headers.Add("x-upload-content-type", "video/*");
request.Content = JsonReqMsg;
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Authorization", Constants.API.Google.AccessTokenType + " " + Constants.API.Google.AccessToken);
var UploadReq = await httpClient.SendAsync(request);
if (UploadReq.IsSuccessStatusCode)
{
IEnumerable<string> _VideoUrl = null;
var res = await UploadReq.Content.ReadAsStringAsync();
UploadReq.Headers.TryGetValues("Location", out _VideoUrl);
var binaryContent = new StreamContent(stream);
var UploadReq_ = await httpClient.PutAsync(new Uri(_VideoUrl.ToString()), binaryContent);
if (UploadReq_.IsSuccessStatusCode)
{
var res_ = await UploadReq_.Content.ReadAsStringAsync();
}
}
}
Is there anything wrong in the code?
You're authorization is incorrect. You should be using "bearer" or a developer key. Here is the YouTube documentation: https://developers.google.com/youtube/2.0/developers_guide_protocol#OAuth2_Calling_a_Google_API

Supplying api key in HttpClient's headers not working

I'm trying to get data from https://ndb.nal.usda.gov, basing on instructions provided here https://ndb.nal.usda.gov/ndb/doc/apilist/API-FOOD-REPORT.md
I'm using HttpClient as follows, but can't seem to be able to pass the api_key correctly. Shouldn't I be adding it to headers? I tried
public static async Task<string> DownloadItemData(string itemName)
{
using (HttpClient client = new HttpClient())
{
HttpContent requestContent =
new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("api_key", "myKey"),
new KeyValuePair<string, string>("ndbno", "01009"),
new KeyValuePair<string, string>("type", "f")
});
requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage response = await client.PostAsync("http://api.nal.usda.gov/ndb/reports", requestContent);
using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync()))
{
// Write the output.
string result = await reader.ReadToEndAsync();
return result;
}
}
But all I'm getting is:
{
"error": {
"code": "API_KEY_MISSING",
"message": "No api_key was supplied. Get one at http://api.nal.usda.gov"
}
}
I also tried this, but with the same result:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("api_key", "myKey");
Any ideas how to pass the api_key correctly? Thanks in advance!

Post byte array to Web API server using HttpClient

I want to post this data to Web API server:
public sealed class SomePostRequest
{
public int Id { get; set; }
public byte[] Content { get; set; }
}
Using this code for server:
[Route("Incoming")]
[ValidateModel]
public async Task<IHttpActionResult> PostIncomingData(SomePostRequest requestData)
{
// POST logic here
}
and this - for client:
var client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:25001/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var content = new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "id", "1" },
{ "content", "123" }
});
var result = await client.PostAsync("api/SomeData/Incoming", content);
result.EnsureSuccessStatusCode();
everything works fine (at least, debugger stops at breakpoint in PostIncomingData).
Since there is a byte array, I don't want to serialize it as JSON, and want to post it as binary data to decrease network traffic (something like application/octet-stream).
How this can be achieved?
I've tried to play with MultipartFormDataContent, but looks like I just can't understand, how MultipartFormDataContent will match signature of controller's method.
E.g., replacing content to this:
var content = new MultipartFormDataContent();
content.Add(new FormUrlEncodedContent(new Dictionary<string, string> { { "id", "1" } }));
var binaryContent = new ByteArrayContent(new byte[] { 1, 2, 3 });
binaryContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
content.Add(binaryContent, "content");
var result = await client.PostAsync("api/SomeData/Incoming", content);
result.EnsureSuccessStatusCode();
leads to error 415 ("Unsupported media type").
WebAPI v2.1 and beyond supports BSON (Binary JSON) out of the box, and even has a MediaTypeFormatter included for it. This means you can post your entire message in binary format.
If you want to use it, you'll need to set it in WebApiConfig:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Formatters.Add(new BsonMediaTypeFormatter());
}
}
Now, you an use the same BsonMediaTypeFormatter at the client side to serialize your request:
public async Task SendRequestAsync()
{
var client = new HttpClient
{
BaseAddress = new Uri("http://www.yourserviceaddress.com");
};
// Set the Accept header for BSON.
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/bson"));
var request = new SomePostRequest
{
Id = 20,
Content = new byte[] { 2, 5, 7, 10 }
};
// POST using the BSON formatter.
MediaTypeFormatter bsonFormatter = new BsonMediaTypeFormatter();
var result = await client.PostAsync("api/SomeData/Incoming", request, bsonFormatter);
result.EnsureSuccessStatusCode();
}
Or, you can use Json.NET to serialize your class to BSON. Then, specify you want to use "application/bson" as your "Content-Type":
public async Task SendRequestAsync()
{
using (var stream = new MemoryStream())
using (var bson = new BsonWriter(stream))
{
var jsonSerializer = new JsonSerializer();
var request = new SomePostRequest
{
Id = 20,
Content = new byte[] { 2, 5, 7, 10 }
};
jsonSerializer.Serialize(bson, request);
var client = new HttpClient
{
BaseAddress = new Uri("http://www.yourservicelocation.com")
};
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/bson"));
var byteArrayContent = new ByteArrayContent(stream.ToArray());
byteArrayContent.Headers.ContentType = new MediaTypeHeaderValue("application/bson");
var result = await client.PostAsync(
"api/SomeData/Incoming", byteArrayContent);
result.EnsureSuccessStatusCode();
}
}
I convert Byte Array into Base64 String to post:
await client.PostAsJsonAsync( apiUrl,
new {
message = "",
content = Convert.ToBase64String(yourByteArray),
}
);
and receiver can convert the Base64 String back to Byte Array by:
string base64Str = (string)postBody.content;
byte[] fileBytes = Convert.FromBase64String(base64Str);
I have created this generic and cross platform method to support the BSON format using the Json.NET library so we can reuse it easier later. It works fine in Xamarin platform as well.
public static async HttpResponseMessage PostBsonAsync<T>(string url, T data)
{
using (var client = new HttpClient())
{
//Specifiy 'Accept' header As BSON: to ask server to return data as BSON format
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/bson"));
//Specify 'Content-Type' header: to tell server which format of the data will be posted
//Post data will be as Bson format
var bSonData = HttpExtensions.SerializeBson<T>(data);
var byteArrayContent = new ByteArrayContent(bSonData);
byteArrayContent.Headers.ContentType = new MediaTypeHeaderValue("application/bson");
var response = await client.PostAsync(url, byteArrayContent);
response.EnsureSuccessStatusCode();
return response;
}
}
The method to help to serialise data to BSON format:
public static byte[] SerializeBson<T>(T obj)
{
using (MemoryStream ms = new MemoryStream())
{
using (BsonWriter writer = new BsonWriter(ms))
{
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(writer, obj);
}
return ms.ToArray();
}
}
Then you can use the Post method like this:
var response = await PostBsonAsync<SamplePostRequest>("api/SomeData/Incoming", requestData);
Fyi, for protobuf serialization to request body posts
LoginRequest loginRequest = new LoginRequest()
{
Code = "UserId",
Password = "myPass",
CMToken = "eIFt4lYTKGU:APA91bFZPe3XCDL2r1JUJuEQLlN3FoeFw9ULpw8ljEavNdo9Lc_-Qua4w9pTqdOFLTb92Kf03vyWBqkcvbBfYEno4NQIvp21kN9sldDt40eUOdy0NgMRXf2Asjp6FhOD1Kmubx1Hq7pc",
};
byte[] rawBytes = ProtoBufSerializer.ProtoSerialize<LoginRequest>(loginRequest);
var client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:9000/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/x-protobuf"));
//var bSonData = HttpExtensions.SerializeBson<T>(data);
var byteArrayContent = new ByteArrayContent(rawBytes);
byteArrayContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-protobuf");
var result = client.PostAsync("Api/Login", byteArrayContent).Result;
Console.WriteLine(result.IsSuccessStatusCode);
I wanted to send it truly binary like I did with WebClient before not make it multipart.
Using inspiration from this question I got it working this way:
HttpClient InternalHttpClient = new HttpClient();
HttpContent BinaryContent = new ByteArrayContent(new byte[] { 1, 2, 3 });
byte[] ReceivedData = new byte[0];
using (HttpResponseMessage ResponseMessage = InternalHttpClient.PostAsync("apiurl/binarycomms.aspx", BinaryContent).Result)
{
using (HttpContent ResponseBytes = ResponseMessage.Content)
{
ReceivedData = ResponseBytes.ReadAsByteArrayAsync().Result;
}
}
On the server side the code is also fully binary:
protected void Page_Load(object sender, EventArgs e)
{
Page.Response.ContentType = "application/octet-stream";
byte[] Challenge = Page.Request.BinaryRead(Request.TotalBytes);
Page.Response.BinaryWrite(new byte[] { 10, 20, 30 });
}
You can easily add compression to this communication to make the bandwidth usage even smaller.
Love to hear comments should I have missed something or if this is off topic, but it works like a charm for me.

Categories