SendGrid - Loading Exported Contacts - c#

I'm trying to process the resulting URLs from the marketing/contacts/exports/{id} call I used the following code however the data is dataresponse is zipped/encrypted.
SendGridClient client = new SendGridClient(AppConfig.ReadSetting("SENDGRID_API_KEY"));
SingleSendContactList allListsSingleSend = new SingleSendContactList();
var response = await client.RequestAsync(method: SendGridClient.Method.GET, urlPath: "marketing/lists?page_size=500");
allListsSingleSend = JsonConvert.DeserializeObject<SingleSendContactList>(response.Body.ReadAsStringAsync().Result);
SingleSendExportSetup SSExportSetup = new SingleSendExportSetup();
SSExportSetup.file_type = "json";
SSExportSetup.max_file_size = 5000;
// marketing/contacts/exports, POST returns JSON with id as main field
SingleSendExportID ExportContactsSingleSend = new SingleSendExportID();
response = await client.RequestAsync(method: SendGridClient.Method.POST, urlPath: "marketing/contacts/exports", requestBody: JsonConvert.SerializeObject(SSExportSetup));
ExportContactsSingleSend = JsonConvert.DeserializeObject<SingleSendExportID>(response.Body.ReadAsStringAsync().Result);
//Use this id to then call
// marketing/contacts/exports/id, GET returns JSON with urls as a property, use urls[0]
SingleSendExportURL ExportURLSingleSend = new SingleSendExportURL();
response = await client.RequestAsync(method: SendGridClient.Method.GET, urlPath: "marketing/contacts/exports/" + ExportContactsSingleSend.id);
ExportURLSingleSend = JsonConvert.DeserializeObject<SingleSendExportURL>(response.Body.ReadAsStringAsync().Result);
// Call the URL to get the returned JSON
List<SingleSendExportData> ExportDataSingleSend = new List<SingleSendExportData>();
var dataresponse = await client.RequestAsync(method: SendGridClient.Method.GET, urlPath: ExportURLSingleSend.urls[0]);
ExportDataSingleSend = JsonConvert.DeserializeObject<List<SingleSendExportData>>(dataresponse.Body.ReadAsStringAsync().Result);
I can take the URL in ExportURLSingleSend.urls[0] and drop it in a browser and it will force the download of the file and the data is fine. How do I get this data to convert to my class List<SingleSendExportData>?
I posted this question to SendGrid support and they sent me here.
Thanks.
UPDATE:
This post solved my issue:
https://weblog.west-wind.com/posts/2007/jun/29/httpwebrequest-and-gzip-http-responses
However, now I am realizing that the JSON coming from SendGrid is not properly formatted. There is no comma between rows of data.
UPDATE 2:
This post solved my handling of line delimited JSON files;
Line delimited json serializing and de-serializing
Now I am able to read these zipped JSON files without saving them and then handle the JSON format to load into my list List ExportDataSingleSend.

Related

Is there a way to reorder the data sent in a multipart form POST request?

I am making a request to an external API which needs data in a multipart form to be sent in a specific order.
I have two parameters for the request, one is a JsonParameter and the other is a file.
The issue I am having is I need the JsonParameter to come first in the form data request but cannot find a way to do that currently. I have tried simply changing the order I add to the request but this doesn't seem to affect the order when the request is sent.
This is my current code for the request:
var client = new RestClient(baseUrl);
var request = new RestRequest(endpoint, Method.Post);
request.AlwaysMultipartFormData = true;
var json = JsonConvert.SerializeObject(profile);
var jsonParam = new JsonParameter("profile", profile);
request.AddParameter(jsonParam);
var filename = "test.txt";
var bytes = File.ReadAllBytes(filepath);
request.AddFile("file", bytes, filename, "text/plain");
request.AddHeader("X-auth-token", bearerToken);
var res = await client.ExecuteAsync(request);
Is this possible using restsharp so that the JsonParameter will always come first in the request?

Mapping JSON from Yahoo! Finance API to C# objects [duplicate]

This question already has answers here:
Deserialize JSON data with C#
(4 answers)
Closed 1 year ago.
I am a student working on a project. I am trying to use the Yahoo! Finance API as a source for my data https://www.yahoofinanceapi.com . I can use HttpWebRequests to call the API and get the "OK" code, see the code below on how I did it:
string BaseURL = "https://yfapi.net/v6/finance/quote?symbols=AAPL";
string addSymbol = "%2C";
string URL = BaseURL;
foreach (string stock in stocks)
{
URL += addSymbol + stock;
}
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Headers.Add("X-API-KEY", "[My API key]");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Console.WriteLine(response.ContentType);
Console.WriteLine(response.StatusCode);
response.ContentType gives back "application/json".
response.StatusCode gives back "OK".
Since the response is a JSON I tried to parse it into a string using .ToString() but this obviously doesn't work. When I print it, it just says "System.Net.HttpWebResponse" instead of the showing the actual data in the JSON.
After that I tried to deserialize it using newtonsoft
Results result = JsonConvert.DeserializeObject<Results>(request.GetResponse().ToString());
where Results is a class I made where there is a list of stocks, Stock is also a class I made with some variables in it with the same names of variables in the JSON response.
I got a JSON response from PostMan when I tested the API, opened the response to see what kind of data it contained.
When I ran my code I got the following error message:
Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered while parsing value: S. Path '', line 0, position 0.'
This was as far as I got, I tested a few other methods trying to get this working but this one worked the "best".
My biggest issue at the moment is mapping the response into a c# object.
Anything that can help me understand is appreciated :D
You're trying to serialise the HttpWebResponse object into Results, which means deserialisation won't work.
The data is still wrapped & won't be in the format of the Results object.
The GetResponseStream() method can be used to get the contents of the HTTP response as a stream, which can then be deserialised directly, in this case, using Json.NET.
Replace this section:
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Console.WriteLine(response.ContentType);
Console.WriteLine(response.StatusCode);
With this:
var serializer = new JsonSerializer();
using (var response = (HttpWebResponse)request.GetResponse())
{
var encoding = Encoding.GetEncoding(response.CharacterSet);
using var responseStream = response.GetResponseStream();
using var reader = new StreamReader(responseStream, encoding);
using (var jsonTextReader = new JsonTextReader(reader))
{
Console.WriteLine(response.ContentType);
Console.WriteLine(response.StatusCode);
Results result = serializer.Deserialize<Results>(jsonTextReader);
}
}
Alternatively, a much better solution if you're using .NET 4.5 <= would be to use HttpClient like below:
private static readonly HttpClient httpClient = new HttpClient();
...
string BaseURL = "https://yfapi.net/v6/finance/quote?symbols=AAPL";
string addSymbol = "%2C";
string URL = BaseURL;
foreach(string stock in stocks) {
URL += addSymbol + stock;
}
client.DefaultRequestHeaders.Add("X-API-KEY", "[My API key]");
var data = await httpClient.GetStringAsync(address);
Results result = JsonConvert.DeserializeObject<Results>(data);

Sending a POST request with FILE using in XAMARIN C#

looking on the web, I saw a little bit how to POST a 'file' and therefore, I wrote my code in this way:
var upfilebytes = File.ReadAllBytes((string)fPath);
//create new HttpClient and MultipartFormDataContent and add our file, and StudentId
HttpClient client = new HttpClient();
MultipartFormDataContent content = new MultipartFormDataContent();
ByteArrayContent baContent = new ByteArrayContent(upfilebytes);
content.Add(baContent, "img", fPath);
StringContent emailText = new StringContent(lbl_email.Text);
content.Add(emailText, "email");
string url = "http://192.168.178.77/TestLoginURL/api/updateUserImage.php";
//upload MultipartFormDataContent content async and store response in response var
var response =
await client.PostAsync(url, content);
//read response result as a string async into json var
var responsestr = response.Content.ReadAsStringAsync().Result;
now the problem is another ... this is my API code:
<?php
$response = array();
if($_SERVER['REQUEST_METHOD']=='POST'){
//getting values
$img = $_FILES['img']['name'];
$email = $_POST['email'];
//including the db operation file
require_once '../includes/DbOperation.php';
$db = new DbOperation();
$target = "/Applications/XAMPP/xamppfiles/htdocs/TestLoginURL/images/".basename($img);
//inserting values
if($db->updateImage((String)basename($img),$email)){
$response['error']=false;
$response['message']='Image added successfully - test fileName = '.(String)basename($img);
}else{
$response['error']=true;
$response['message']='Could not add image';
}
if(move_uploaded_file($_FILES['img']['tmp_name'], $target)) {
/*$response['error']=false;
$response = "Image uploaded successfully";*/
}else{
$response['error']=true;
$response = "Failed to upload image";
}
}else{
$response['error']=true;
$response['message']='You are not authorized';
}
echo json_encode($response);
With Postman it works perfectly, updates the name of the image in the database and physically inserts the image in the designated path and the response message for example is this: {"error": false, "message": "Image added successfully - test fileName = trollolollo.png"}
Now, the app saves the file in the right repository but does NOT UPDATE the name of the 'image' in the database ... BUT strangely, the "response" message in the debugger also correctly shows the name of the FILE ... So I just don't understand where I'm wrong ... Could someone help me with the code please? Thanks
OFF_TOPIC: usually, when I have to send only strings, I send a post request written in this way
string url = "http://192.168.178.77/TestLoginURL/api/insertUser.php";
FormUrlEncodedContent formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("nickname", nickname),
new KeyValuePair<string, string>("password", password1),
new KeyValuePair<string, string>("email", email)
});
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
try
{
CancellationTokenSource cts = new CancellationTokenSource();
var responseMessage = httpClient.PostAsync(url, formContent).Result;
}
catch (Exception ex)
{
ex.Message.ToString();
throw;
}
but now, being a file and having no experience about it I am having difficulties...
thanks again, I hope someone can help me with the code
Are you sure that you are handling update query correctly ?
Update query will only return false on a failure if you messed up the SQL query or anything like that. So you have to use mysqli_stmt_affected_rows to see if a row has been updated in your PHP code.
If postman can do it HttpClient must be able to do it too, with the proper configuration.
Try to use all the headers postman is using you are probably missing something, maybe the filename is causing the DB query to fail.
By the way is there any difference between how you handle jpg and png in your server ? you can check that too.

Post JSON data to Microsoft Graph API Azure Function

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);
//...

AWS sagemaker invokeEndpoint model internal error

I am trying to send a request on a model on sagemaker using .NET. The code I am using is:
var data = File.ReadAllBytes(#"C:\path\file.csv");
var credentials = new Amazon.Runtime.BasicAWSCredentials("","");
var awsClient = new AmazonSageMakerRuntimeClient(credentials, RegionEndpoint.EUCentral1);
var request = new Amazon.SageMakerRuntime.Model.InvokeEndpointRequest
{
EndpointName = "EndpointName",
ContentType = "text/csv",
Body = new MemoryStream(data),
};
var response = awsClient.InvokeEndpoint(request);
var predictions = Encoding.UTF8.GetString(response.Body.ToArray());
the error that I am getting on awsClient.InvokeEndpoint(request)
is:
Amazon.SageMakerRuntime.Model.ModelErrorException: 'The service
returned an error with Error Code ModelError and HTTP Body:
{"ErrorCode":"INTERNAL_FAILURE_FROM_MODEL","LogStreamArn":"arn:aws:logs:eu-central-1:xxxxxxxx:log-group:/aws/sagemaker/Endpoints/myEndpoint","Message":"Received
server error (500) from model with message \"\". See
"https:// url_to_logs_on_amazon"
in account xxxxxxxxxxx for more
information.","OriginalMessage":"","OriginalStatusCode":500}'
the url that the error message suggests for more information does not help at all.
I believe that it is a data format issue but I was not able to find a solution.
Does anyone has encountered this behavior before?
The problem relied on the data format as suspected. In my case all I had to do is send the data as a json serialized string array and use ContentType = application/json because the python function running on the endpoint which is responsible for sending the data to the predictor was only accepting json strings.
Another way to solve this issues is to modify the python function which is responsible for the input handling to accept all content types and modify the data in a way that the predictor will understand.
example of working code for my case:
var data = new string[] { "this movie was extremely good .", "the plot was very boring ." };
var serializedData = JsonConvert.SerializeObject(data);
var credentials = new Amazon.Runtime.BasicAWSCredentials("","");
var awsClient = new AmazonSageMakerRuntimeClient(credentials, RegionEndpoint.EUCentral1);
var request = new Amazon.SageMakerRuntime.Model.InvokeEndpointRequest
{
EndpointName = "endpoint",
ContentType = "application/json",
Body = new MemoryStream(Encoding.ASCII.GetBytes(serializedData)),
};
var response = awsClient.InvokeEndpoint(request);
var predictions = Encoding.UTF8.GetString(response.Body.ToArray());

Categories

Resources