The format of value 'XXX.yyyyy' is invalid - c#

I am trying to set up if-match header as following and making use of HttpClient available in System.Net.Http:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var adobeRequest = new HttpRequestMessage(HttpMethod.Put, new Uri(url))
{
Content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json")
};
if (!string.IsNullOrEmpty(Etag))
adobeRequest.Headers.Add("If-Match", Etag);
var response = client.SendAsync(adobeRequest);
Etag I received from adobe in previous(Get) call is :
64E8BBA87ACFD0C2C84AF6E1193A3761.5334C3A18AB5A054FF3DBC33AFBDF6C
So when I try to add the same for Put request, it gives me following error:
The format of value
'64E8BBA87ACFD0C2C84AF6E1193A3761.5334C3A18AB5A054FF3DBC33AFBDF6C' is
invalid.
How to resolve this issue? It clearly says format is not valid, however I believe Adobe's api is being used by million others. So somehow Its something from my end.
Link for Adobe api

Use adobeRequest.Headers.TryAddWithoutValidation instead.

Related

How to replicate Postman POST request in C#

I'm fairly new to .NET's HTTPClient class, hence kindly excuse if I sounded noob. I'm tryin to replicate Postman's POST request in C# .Net and written following code. However I'm not getting any response but StatusCode: 404. Could someone assist understanding where I'm going wrong?
Also I'd like to understand, how do set Body in following code.
var httpClient = new HttpClient
{
BaseAddress = new Uri("https://testURL.com"),
Timeout = TimeSpan.FromMinutes(10)
};
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("audio/wav"));
httpClient.DefaultRequestHeaders.Add("Authorization", "Basic ldjfdljfdlfjdsjfdsl");
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("model", "Test"),
});
var result = httpClient.PostAsync("api/v1/recognize", content).Result;
Here is what I'm doing in Postman and it works:
"Params" in Postman refers to query parameters which are appended to the URL. You'll see that the URL in Postman contains the parameters you added in the "Params" tab:
However, it seems those are just dummy values you've entered so perhaps you don't need them? In any case, the way you add query parameters to the request for HttpClient is a little different as it needs to be added to the URL.
After that you also need to add the audio file as content to your request. At the moment you're setting the "Accept" header to "audio/wav" but you probably want to set the "Content-Type" header instead (or are you expecting a WAV file to be returned in the response too?).
As far as I can see this is what you're missing:
using (var httpClient = new HttpClient())
{
httpClient.Timeout = TimeSpan.FromMinutes(10);
// Set request headers
httpClient.DefaultRequestHeaders.Add("Authorization", "Basic ldjfdljfdlfjdsjfdsl");
// Set query parameters
var uriBuilder = new UriBuilder("https://testURL.com/api/v1/recognize");
uriBuilder.Query = "model=Test";
// Build request body
// Read bytes from the file being uploaded
var fileBytes = File.ReadAllBytes(wavFilePath);
// Create request content with metadata/headers to tell the
// backend which type of data (media type) is being uploaded
var byteArrayContent = new ByteArrayContent(fileBytes);
byteArrayContent.Headers.ContentType = MediaTypeHeaderValue.Parse("audio/wav");
// Wrap/encode the content as "multipart/form-data"
// See example of how the output/request looks here:
// https://dotnetfiddle.net/qDMwFh
var requestContent = new MultipartFormDataContent
{
{byteArrayContent, "audio", "filename.wav"}
};
var response = await httpClient.PostAsync(uriBuilder.Uri, requestContent);
}
I haven't tested this of course against your application, but it should be something along the lines of this. It might be that the backend doesn't expect "multipart/form-data" and just needs the "audio/wav". I can't see the output headers in your Postman screenshots, but if so, you can use byteArrayContent directly instead of wrapping it in MultipartFormDataContent.
Note: Don't use httpClient.PostAsync(...).Result. If you want to use the asynchronous method, you should await it. Depending on your code, using Result might give you problems if you're not careful. And remember to dispose the HttpClient after use (easiest solution is to use a using statement). If you plan on reusing the HttpClient for more requests, you can avoid disposing it until you're done.

GET Request return 400 bad response

It's a generic question, but I need help with my specific case.
I have a simple GET endpoint (see image) which I've tested with Postman and it works
It takes two id tokens in the header and thats it.
I've put breakpoints in the code and copied the exact instance of the ids into Postman and the request works, but executing from code, I get a 400 response
using (HttpClient client = new HttpClient())
{
var request = new HttpRequestMessage()
{
RequestUri = new Uri("https://*******.execute-api.ap-southeast-2.amazonaws.com/dev/uploads/image.jpg"),
Method = HttpMethod.Get,
};
var idToken = Application.Current.Properties["id_token"].ToString();
var accessToken = Application.Current.Properties["access_token"].ToString();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Add("Id-Token", idToken);
request.Headers.Add("Access-Token", accessToken);
var response = await client.SendAsync(request);
}
I've tried with and without the content-type header and makes no difference. Also doesn't matter if it's present in Postman
This is a Xamarin project which is where Application.Current.Properties comes from. I'm utilising other endpoints in the application are there are no issues with accessing the tokens like this.

Rest calls in c#

I am struggling with Rest call. Here is my code and it is working for basic authentication.
public async Task RunAsync(string name, string value)
{
using (var handler = new HttpClientHandler { UseDefaultCredentials = true })
using (var client = new HttpClient(handler))
{
var byteArray = Encoding.ASCII.GetBytes("username:password");
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
var urlRestGet = HomeController.url;
client.BaseAddress = new Uri(urlRestGet + "?name=" + name + "&value=" + value + "");
client.DefaultRequestHeaders.Accept.Clear();
**1. if(HomeController.contentType.ToLower()=="xml"){
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
}**
else if (HomeController.contentType.ToLower() == "json")
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
HttpResponseMessage response = await client.GetAsync(urlRestGet + "?name=" + name + "&value=" + value + "");
if (response.IsSuccessStatusCode)
{
//Get the response
loginJsonString = await response.Content.ReadAsStringAsync();
//Converting to xml
using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(loginJsonString)))
{
var output = new XmlDictionaryReaderQuotas();
xmlResult = XDocument.Load(JsonReaderWriterFactory.CreateJsonReader(stream, output)).ToString();
}
}
}
}
1) If the content type is application/xml am I correct to use line 1 part in the code.
2) How can I make this code more generic. (when the authentication type is different eg: tokenized or cookiebased how can I change this.)
There are a couple of things about your code I do not understand.
What is HomeController.contentType all about? The name "HomeController" suggests you're writing an ASP.NET MVC Controller (serverside). Though you seem to be writing something intended to be used as a HTTP client. But I could be mistaken or mislead here.
You are reading a Json response, then loading it as a Xml document?
I'll try to answer anyway.
1) If the content type is application/xml am I correct to use line 1 part in the code.
The Accept header sent by the client (you) tells the server that you accept the given content type. If you send Accept application/xml you tell the server you prefer if the response is Xml.
Your code seem to assume the response's content type is always Json.
You could include both application/xml and application/json as Accept headers in your request. The server should honor that request and pick the first supported content type for it's response.
When processing the response you should check the actual content type and handle the response content appropriately.
Remember that Accept only tells the server that you prefer those content types. The server may decide not to honor your whishes and can return any content type it desires.
2) How can I make this code more generic. (when the authentication type is different eg: tokenized or cookiebased how can I change this.)
If you mean tokenized as in a query parameter you should probably handle your query parameters as a collection rather than a hardcoded formatted string.
Check out the NameValueCollection class and this SO question on NameValueCollection to query string.
To handle cookies, you basically need to copy/re-use the cookie collection returned in a response in the next request.
See this SO question on how to inject cookies when you create a new HttpClient.
... but it's much easier to use a library
As you already discovered, making a robust REST/HTTP client is not a easy task.
And as #Mafii and #Fildor already pointed out in comments there are already numerous libraries available. RestSharp (https://restsharp.org) being one very popular.

Using http client to send header and content via post

I'm making a really simple call to an API to receive some data. I need to send headers to get authorized also I need to send some content on the body. This is what I came up with :
public async Task<List<LoremIpsum>> LoremIpsumJson()
{
LoremIpsum1 data = null;
try
{
var client = new HttpClient();
//now lets add headers . 1.method, 2.token
client.DefaultRequestHeaders.Add("Method", "LoremIpsumExample");
client.DefaultRequestHeaders.Add("Token", "sometoken");
HttpContent content = new StringContent("{\"Name\":\"John\",\"Surname\":\"Doe\",\"Example\":\"SomeNumber\"}", Encoding.UTF8, "application/json");
// ==edit==
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.PostAsync("www.theUrlToTheApi", content);
response.EnsureSuccessStatusCode();
string json = await response.Content.ReadAsStringAsync();
data = JsonConvert.DeserializeObject<QueueInfo>(json);
}
catch(Exception ex)
{
Debug.WriteLine(ex.Message.ToString());
}
return data.data;
Debug.WriteLine(data.data);
}
The app breaks after response.EnsureSuccessStatusCode(); because the request obviously is not successful.
I think I'm really missing something really simple here. How can I do this call?
The error is
StatusCode: 406, ReasonPhrase: 'Not Acceptable'
There could be many reasons for this not working. For instance: keyvalues.ToString() is most likely not putting in the value you want. Seems like you might need to serialize to json rather than just calling .ToString().
Use a tool like postman first and get it working there so you have a working example then try and recreate in C#. It will make your life a lot easier.
For everyone coming here to find a solution.
HttpContent cannot take a header much o less a content-type. There was a typo on adding the content-type which was supposed to be added in HttpClient in this way:
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

No mediatype formatter found

I'm trying to call this method
[HttpGet]
[Route("api/Trinity/GetDirectoryAndTask/{modelTemplateId}/{taskName}")]
public KeyValuePair<string, string> GetDirectoryAndTask(int modelTemplateId, string taskName)
with the url http://localhost:46789/api/Trinity/GetDirectoryAndTask/9/AG33%2f34 but am getting a "MediaTypeFormatter is available to read an object of type 'KeyValuePair`2' from content with media type 'text/html'" exception.
because of using / or %2f in route values, I suspect that the main problem at server side should be:
HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
And to solve it you can change routing to this:
api/Trinity/GetDirectoryAndTask/{modelTemplateId}/{*taskName}
To test if the server side is OK, paste the url in browser and get the result.
But for your client the error is related to the way you read data from that api. I use this code and it reads data after I changed the route:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(" http://localhost:46789/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("api/Trinity/GetDirectoryAndTask/9/AG33%2f34");
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<KeyValuePair<string, string>>();
//The result is a valid key/value pair
}
}

Categories