I need to send information to an API, but due to memory limitation, I have to split this data into two parts
My question is, how to send this information separately at the same time?
Example:
I tested it this way and only postTo1 is sent
result = repository.GetAll();
result2 = repository.GetNames();
var jsonString = JsonConvert.SerializeObject(result, Formatting.None);
var jsonString2 = JsonConvert.SerializeObject(result2, Formatting.None);
var postTo1 = HttpPostAsync(Url, "[" +jsonString1 + "]");
var postTo2 = HttpPostAsync(Url, "[" +jsonString2 + "]");
static async Task<HttpResponseMessage> HttpPostAsync(string url, string data)
{
HttpContent content = new StringContent(data);
HttpResponseMessage response = await httpClient.PostAsync(url, content);
response.EnsureSuccessStatusCode();
return response;
}
It depends how you're sending it.
If you sent it via a query parameter or the route, just create an object that holds the two strings. You'll be able to get away with a single API call.
If you are already sending it via the body, you'll need to store the data in something like SQL. Return the primary key in the first API call. Then in your second call, pass the primary key in the route. You'll be able to retrieve the first record.
Related
I'm trying to send json data to an api and it doesn't come trough.
First of all the data is a list of objects. the very first time it works, and that is because the array is empty.
however the second time it tries to send I directly get a 400 without my debugger even coming in the controller.
I suspect that my json data cannot be deserialized form some reason, this is also my second suspect again since my reponse is of type application/problem+json.
However everything might be possible tough.
I have tried to use ['frombody'], I have tried build in json serializer aswell as newtonsoft. I have tried to use formatting.Intended but all witouth luck.
There is one paramater in my object a string that could cause problems as it contains lot of special characters-> this paramater hold a fysical path to a directory so it will contains '/' and '' and space and or other special characters from the directory name.
client:
using (HttpClient client = new HttpClient())
{
var message = new HttpRequestMessage();
message.Content = JsonContent.Create(files, typeof(List<WatchedFile>));
message.RequestUri = new Uri("http://localhost:5245/api/fileagent");
message.Method = HttpMethod.Post;
var response = await client.SendAsync(message);
if (!response.IsSuccessStatusCode)
{
logger.LogError($"Sending to api was not successful {(int)response.StatusCode}");
}
}
This still needs to be refactored to inject the hhtpclient rather thatn the using statement
controller:
[HttpPost]
public async Task<ActionResult> AddMessages([FromBody]List<WatchedFile> messages)
{
messages.ForEach(x => x.Ipaddress = HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString());
//send to repository
await context.WatchedFiles.AddRangeAsync(messages);
await context.SaveChangesAsync();
return Ok();
}
I would make sure the JSON is actually a valid JSON.
Then you try to send it with Postman to your endpoint to see if you get the intended result.
That would at least help you eliminate some of the places where it could go wrong.
When I post to my API (written in .NET core and hosted on Linux) from Postman, everything works as expected. When I do the same from code (using HttpClient), the parameters do not get sent. Below my code:
var content = new FormUrlEncodedContent(new []
{
new KeyValuePair<string, string>(nameof(userName), userName),
new KeyValuePair<string, string>(nameof(serialNumber), serialNumber)
});
var result = await _httpClient.PostAsync(_uri, content).ConfigureAwait(false);
var json = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
return JsonConvert.DeserializeObject<Response>(json);
In my opinion content should get sent and everything should be alright. I see significant differences between the calls in Wireshark.
Working POST from Postman:
POST from HttpClient that does not work:
.
What can I do to make sure that my HttpClient.PostAsync sends the data correctly?
The Postman version doesn't have a body, but it has userName and serialNumber encoded into the url as query parameters.
In order to achieve the same using HttpClient, you need to add those parameters to the url.
var uriBuilder = new UriBuilder(_uri);
// If you already have query parameters, this code will preserve them.
// Otherwise you can just create a new NameValueCollection instance.
var parameters = HttpUtility.ParseQueryString(uriBuilder.Query);
parameters[nameof(userName)] = userName;
parameters[nameof(serialNumber)] = serialNumber;
uriBuilder.Query = parameters.ToString();
// Pass null as HttpContent to make HttpClient send an empty body
var result = await _httpClient.PostAsync(uriBuilder.ToString(), null).ConfigureAwait(false);
I've this function :
public string GetSecurityCrumb()
{
string uri = $"{Url}/crumbIssuer/api/xml";// URL where the XML is available
var client = new RestClient(uri); // define it as the actual client
var request = new RestRequest(Method.GET);
byte[] ua = Encoding.ASCII.GetBytes(Username + ":" + ApiToken); // Encoding username and token in base 64
request.AddHeader("authorization", "Basic " + Convert.ToBase64String(ua));// adding header to get the xml
IRestResponse response = client.Execute(request);
XDocument document = XDocument.Parse(response.Content);// parsing the content of the response in a document
var crumb = document.Root.Element("crumb").Value;// retrieve the content of the crumb only
return crumb;
}
I tried a lot of things to do this aynchronous, but I just don't see how I can return string value if I change my Rest call to an aynschronous one.
Maybe somebody already got this kind of problem and could help me.
EDIT 1
I tried this :
public async Task<string> GetSecurityCrumb()
{
string uri = $"{Url}/crumbIssuer/api/xml";// URL where the XML is available
var client = new RestClient(uri); // define it as the actual client
var request = new RestRequest(Method.GET);
byte[] ua = Encoding.ASCII.GetBytes(Username + ":" + ApiToken); // Encoding username and token in base 64
request.AddHeader("authorization", "Basic " + Convert.ToBase64String(ua));// adding header to get the xml
IRestResponse response = await client.ExecuteTaskAsync(request);
XDocument document = XDocument.Parse(response.Content);// parsing the content of the response in a document
var crumb = document.Root.Element("crumb").Value;// retrieve the content of the crumb only
return crumb;
}
but it seems like I need to put await before all my calls on this method and use GetSecurityCrumb().Result to get the real content. I don't know if it's the best way because I've totally 0 error handlers at the moment. A lot of my methods depend of this one so I prefer having the best solution
it seems like I need to put await before all my calls on this method and use GetSecurityCrumb().Result to get the real content
You shouldn't call .Result - that would block on the asynchronous method, removing all the benefits of asynchronous code in the first place.
It's normal to await the task returned from GetSecurityCrumb(). And using that await means that the calling method should also be marked async and return a task. Which means that its callers should use await, so they should be made async, etc. This is all perfectly normal and is the correct way to use async/await.
I'm trying to use an Azure function to forward an Outlook email using its ID.
var url = "https://graph.microsoft.com/v1.0/users('<blah>')/messages/" + ID + "/forward";
var content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
var response = await client.PostAsJsonAsync(url, content);
log.Info(response.Content.ReadAsStringAsync().Result);
The result I'm getting is The value of the parameter 'ToRecipients' is empty. Specify 'ToRecipients' either in the message object or in the action.
The data variable I'm passing in is {"message":{"ToRecipients":[{"emailAddress":{"address":"<blah>"}}]}}.
What am I doing wrong? How do I successfully post a data JSON object? I feel like I've tried every example I can find online and I haven't had any luck.
FYI, token has already been attached to headers, I'm just not showing that part.
You appear to be double serializing the data to be sent.
First when you manually serialize
...JsonConvert.SerializeObject(data)...
and second when you call PostAsJsonAsync
client.PostAsJsonAsync(url, content);
which would serialize the provided object to JSON before posting.
If calling PostAsJsonAsync then no need for you to create the content manually
//...
var url = "https://graph.microsoft.com/v1.0/users('<blah>')/messages/" + ID + "/forward";
var response = await client.PostAsJsonAsync(url, data);
var result = await response.Content.ReadAsStringAsync();
log.Info(result);
//...
I am attempting to speed up the process of my local software sync. Right now we send a GET requested for each individual record that we need and the API sends back a JSON string containing that records data, which is then inserted into the local database. This all works, however it can be tediously slow. I am trying to speed this up, and was hoping a good way to do so would be to send a JSON of List<Dictionary<string, string>>. This would make it so that I can request much more data in one shot on the API side, add it to the list, and pass it back as JSON to the local machine.
Right now on the local side I have:
Encoding enc = System.Text.Encoding.GetEncoding(1252);
using (HttpClient client = new HttpClient())
{
string basicAuth = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", usr, pwd)));
client.BaseAddress = new Uri(baseUrl);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", basicAuth);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
string requested = JsonConvert.SerializeObject(tableList);
HttpResponseMessage response = client.GetAsync(syncUrl + hash + "/" + requested).Result;
if (!response.IsSuccessStatusCode)
{
// get the error
StreamReader errorStream = new StreamReader(response.Content.ReadAsStreamAsync().Result, enc);
throw new Exception(errorStream.ReadToEnd());
}
}
My Controller call looks like this:
[System.Web.Http.AcceptVerbs("GET")]
[Route("getRecords/{hash}/{requested}")]
public HttpResponseMessage getRecords(string hash, string requested)
Whenever I make this call it gives me an error that it cannot find the URI and I don't even hit my breakpoint on my API. How do I get this to work, or is there a better way to accomplish what I'm doing?
You need to urlencode the data, if there is any special url chars (like ampersand or slash) it will render unusable the data, so you must urlencode it to be rightly formatted.
Use something like...
string requested = Uri.EscapeDataString(JsonConvert.SerializeObject(tableList));
This will encode the special chars so them can be transferred securely on the URL.