I am trying to connect to an api, that returns GZip encoded JSON, from a WCF service (WCF service to WCF service). I am using the HTTPClient to connect to the API and have been able to return the JSON object as a string. However I need to be able to store this returned data in a database and as such I figured the best way would be to return and store the JSON object in an array or byte or something along those lines.
What I am having trouble with specifically is the decompressing of the GZip encoding and have been trying lots of different example but still cant get it.
The below code is how I am establishing my connection and getting a response, this is the code that returns a string from the API.
public string getData(string foo)
{
string url = "";
HttpClient client = new HttpClient();
HttpResponseMessage response;
string responseJsonContent;
try
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
response = client.GetAsync(url + foo).Result;
responseJsonContent = response.Content.ReadAsStringAsync().Result;
return responseJsonContent;
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return "";
}
}
I have been following a few different examples like these StackExchange API, MSDN, and a couple on stackoverflow, but I haven't been able to get any of these to work for me.
What is the best way to accomplish this, am I even on the right track?
Thanks guys.
Just instantiate HttpClient like this:
HttpClientHandler handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
using (var client = new HttpClient(handler)) //see update below
{
// your code
}
Update June 19, 2020:
It's not recommended to use httpclient in a 'using' block as it might cause port exhaustion.
private static HttpClient client = null;
ContructorMethod()
{
if(client == null)
{
HttpClientHandler handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
client = new HttpClient(handler);
}
// your code
}
If using .Net Core 2.1+, consider using IHttpClientFactory and injecting like this in your startup code.
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(60));
services.AddHttpClient<XApiClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
}).AddPolicyHandler(request => timeout);
I used code from below link to decompress GZip stream.Then used the decompressed byte array to get the required JSON object. Hope it may help some one.
var readTask = result.Content.ReadAsByteArrayAsync().Result;
var decompressedData = Decompress(readTask);
string jsonString = System.Text.Encoding.UTF8.GetString(decompressedData, 0, decompressedData.Length);
ResponseObjectClass responseObject = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponseObjectClass>(jsonString);
https://www.dotnetperls.com/decompress
static byte[] Decompress(byte[] gzip)
{
using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress))
{
const int size = 4096;
byte[] buffer = new byte[size];
using (MemoryStream memory = new MemoryStream())
{
int count = 0;
do
{
count = stream.Read(buffer, 0, size);
if (count > 0)
{
memory.Write(buffer, 0, count);
}
}
while (count > 0);
return memory.ToArray();
}
}
}
Ok so I eventually solved my problem. If there are better ways please let me know :-)
public DataSet getData(string strFoo)
{
string url = "foo";
HttpClient client = new HttpClient();
HttpResponseMessage response;
DataSet dsTable = new DataSet();
try
{
//Gets the headers that should be sent with each request
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Returned JSON
response = client.GetAsync(url).Result;
//converts JSON to string
string responseJSONContent = response.Content.ReadAsStringAsync().Result;
//deserializes string to list
var jsonList = DeSerializeJsonString(responseJSONContent);
//converts list to dataset. Bad name I know.
dsTable = Foo_ConnectAPI.ExtentsionHelpers.ToDataSet<RootObject>(jsonList);
//Returns the dataset
return dsTable;
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return null;
}
}
//deserializes the string to a list. Utilizes JSON.net. RootObject is a class that contains the get and set for the JSON elements
public List<RootObject> DeSerializeJsonString(string jsonString)
{
//Initialized the List
List<RootObject> list = new List<RootObject>();
//json.net deserializes string
list = (List<RootObject>)JsonConvert.DeserializeObject<List<RootObject>>(jsonString);
return list;
}
The RootObject contains the get set that will get the values of the JSON.
public class RootObject
{
//These string will be set to the elements within the JSON. Each one is directly mapped to the JSON elements.
//This only takes into account a JSON that doesn't contain nested arrays
public string EntityID { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Address3 { get; set; }
}
The easiest way to create the above class(es) is to use json2charp which will format it accordingly and also provide the correct datatypes.
The following is from another answer on Stackoverflow
again it does not take into account nested JSON.
internal static class ExtentsionHelpers
{
public static DataSet ToDataSet<T>(this List<RootObject> list)
{
try
{
Type elementType = typeof(RootObject);
DataSet ds = new DataSet();
DataTable t = new DataTable();
ds.Tables.Add(t);
try
{
//add a column to table for each public property on T
foreach (var propInfo in elementType.GetProperties())
{
try
{
Type ColType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType;
t.Columns.Add(propInfo.Name, ColType);
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
try
{
//go through each property on T and add each value to the table
foreach (RootObject item in list)
{
DataRow row = t.NewRow();
foreach (var propInfo in elementType.GetProperties())
{
row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value;
}
t.Rows.Add(row);
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
insert.insertCategories(t);
return ds.
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return null;
}
}
};
Then finally to insert the above dataset into a table with columns that were mapped to the JSON I utilized SQL bulk copy and the following class
public class insert
{
public static string insertCategories(DataTable table)
{
SqlConnection objConnection = new SqlConnection();
//As specified in the App.config/web.config file
objConnection.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["foo"].ToString();
try
{
objConnection.Open();
var bulkCopy = new SqlBulkCopy(objConnection.ConnectionString);
bulkCopy.DestinationTableName = "dbo.foo";
bulkCopy.BulkCopyTimeout = 600;
bulkCopy.WriteToServer(table);
return "";
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return "";
}
finally
{
objConnection.Close();
}
}
};
So the above works to insert JSON from a webAPI into a database. This is something that I get to work. But by no means do I expect it to be perfect. If you have any improvements then please update it accordingly.
Sooner or later your code might brake if your server use another compression scheme like 'Brotli' with content-type: br
I have made a video to handle decompression in httpClient with the clientHandler:
compression algos handled by httpClientHandler
Related
I am trying to connect to an api, that returns GZip encoded JSON, from a WCF service (WCF service to WCF service). I am using the HTTPClient to connect to the API and have been able to return the JSON object as a string. However I need to be able to store this returned data in a database and as such I figured the best way would be to return and store the JSON object in an array or byte or something along those lines.
What I am having trouble with specifically is the decompressing of the GZip encoding and have been trying lots of different example but still cant get it.
The below code is how I am establishing my connection and getting a response, this is the code that returns a string from the API.
public string getData(string foo)
{
string url = "";
HttpClient client = new HttpClient();
HttpResponseMessage response;
string responseJsonContent;
try
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
response = client.GetAsync(url + foo).Result;
responseJsonContent = response.Content.ReadAsStringAsync().Result;
return responseJsonContent;
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return "";
}
}
I have been following a few different examples like these StackExchange API, MSDN, and a couple on stackoverflow, but I haven't been able to get any of these to work for me.
What is the best way to accomplish this, am I even on the right track?
Thanks guys.
Just instantiate HttpClient like this:
HttpClientHandler handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
using (var client = new HttpClient(handler)) //see update below
{
// your code
}
Update June 19, 2020:
It's not recommended to use httpclient in a 'using' block as it might cause port exhaustion.
private static HttpClient client = null;
ContructorMethod()
{
if(client == null)
{
HttpClientHandler handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
client = new HttpClient(handler);
}
// your code
}
If using .Net Core 2.1+, consider using IHttpClientFactory and injecting like this in your startup code.
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(60));
services.AddHttpClient<XApiClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
}).AddPolicyHandler(request => timeout);
I used code from below link to decompress GZip stream.Then used the decompressed byte array to get the required JSON object. Hope it may help some one.
var readTask = result.Content.ReadAsByteArrayAsync().Result;
var decompressedData = Decompress(readTask);
string jsonString = System.Text.Encoding.UTF8.GetString(decompressedData, 0, decompressedData.Length);
ResponseObjectClass responseObject = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponseObjectClass>(jsonString);
https://www.dotnetperls.com/decompress
static byte[] Decompress(byte[] gzip)
{
using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress))
{
const int size = 4096;
byte[] buffer = new byte[size];
using (MemoryStream memory = new MemoryStream())
{
int count = 0;
do
{
count = stream.Read(buffer, 0, size);
if (count > 0)
{
memory.Write(buffer, 0, count);
}
}
while (count > 0);
return memory.ToArray();
}
}
}
Ok so I eventually solved my problem. If there are better ways please let me know :-)
public DataSet getData(string strFoo)
{
string url = "foo";
HttpClient client = new HttpClient();
HttpResponseMessage response;
DataSet dsTable = new DataSet();
try
{
//Gets the headers that should be sent with each request
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Returned JSON
response = client.GetAsync(url).Result;
//converts JSON to string
string responseJSONContent = response.Content.ReadAsStringAsync().Result;
//deserializes string to list
var jsonList = DeSerializeJsonString(responseJSONContent);
//converts list to dataset. Bad name I know.
dsTable = Foo_ConnectAPI.ExtentsionHelpers.ToDataSet<RootObject>(jsonList);
//Returns the dataset
return dsTable;
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return null;
}
}
//deserializes the string to a list. Utilizes JSON.net. RootObject is a class that contains the get and set for the JSON elements
public List<RootObject> DeSerializeJsonString(string jsonString)
{
//Initialized the List
List<RootObject> list = new List<RootObject>();
//json.net deserializes string
list = (List<RootObject>)JsonConvert.DeserializeObject<List<RootObject>>(jsonString);
return list;
}
The RootObject contains the get set that will get the values of the JSON.
public class RootObject
{
//These string will be set to the elements within the JSON. Each one is directly mapped to the JSON elements.
//This only takes into account a JSON that doesn't contain nested arrays
public string EntityID { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Address3 { get; set; }
}
The easiest way to create the above class(es) is to use json2charp which will format it accordingly and also provide the correct datatypes.
The following is from another answer on Stackoverflow
again it does not take into account nested JSON.
internal static class ExtentsionHelpers
{
public static DataSet ToDataSet<T>(this List<RootObject> list)
{
try
{
Type elementType = typeof(RootObject);
DataSet ds = new DataSet();
DataTable t = new DataTable();
ds.Tables.Add(t);
try
{
//add a column to table for each public property on T
foreach (var propInfo in elementType.GetProperties())
{
try
{
Type ColType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType;
t.Columns.Add(propInfo.Name, ColType);
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
try
{
//go through each property on T and add each value to the table
foreach (RootObject item in list)
{
DataRow row = t.NewRow();
foreach (var propInfo in elementType.GetProperties())
{
row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value;
}
t.Rows.Add(row);
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
insert.insertCategories(t);
return ds.
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return null;
}
}
};
Then finally to insert the above dataset into a table with columns that were mapped to the JSON I utilized SQL bulk copy and the following class
public class insert
{
public static string insertCategories(DataTable table)
{
SqlConnection objConnection = new SqlConnection();
//As specified in the App.config/web.config file
objConnection.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["foo"].ToString();
try
{
objConnection.Open();
var bulkCopy = new SqlBulkCopy(objConnection.ConnectionString);
bulkCopy.DestinationTableName = "dbo.foo";
bulkCopy.BulkCopyTimeout = 600;
bulkCopy.WriteToServer(table);
return "";
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return "";
}
finally
{
objConnection.Close();
}
}
};
So the above works to insert JSON from a webAPI into a database. This is something that I get to work. But by no means do I expect it to be perfect. If you have any improvements then please update it accordingly.
Sooner or later your code might brake if your server use another compression scheme like 'Brotli' with content-type: br
I have made a video to handle decompression in httpClient with the clientHandler:
compression algos handled by httpClientHandler
I am trying to connect to an api, that returns GZip encoded JSON, from a WCF service (WCF service to WCF service). I am using the HTTPClient to connect to the API and have been able to return the JSON object as a string. However I need to be able to store this returned data in a database and as such I figured the best way would be to return and store the JSON object in an array or byte or something along those lines.
What I am having trouble with specifically is the decompressing of the GZip encoding and have been trying lots of different example but still cant get it.
The below code is how I am establishing my connection and getting a response, this is the code that returns a string from the API.
public string getData(string foo)
{
string url = "";
HttpClient client = new HttpClient();
HttpResponseMessage response;
string responseJsonContent;
try
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
response = client.GetAsync(url + foo).Result;
responseJsonContent = response.Content.ReadAsStringAsync().Result;
return responseJsonContent;
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return "";
}
}
I have been following a few different examples like these StackExchange API, MSDN, and a couple on stackoverflow, but I haven't been able to get any of these to work for me.
What is the best way to accomplish this, am I even on the right track?
Thanks guys.
Just instantiate HttpClient like this:
HttpClientHandler handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
using (var client = new HttpClient(handler)) //see update below
{
// your code
}
Update June 19, 2020:
It's not recommended to use httpclient in a 'using' block as it might cause port exhaustion.
private static HttpClient client = null;
ContructorMethod()
{
if(client == null)
{
HttpClientHandler handler = new HttpClientHandler()
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
client = new HttpClient(handler);
}
// your code
}
If using .Net Core 2.1+, consider using IHttpClientFactory and injecting like this in your startup code.
var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
TimeSpan.FromSeconds(60));
services.AddHttpClient<XApiClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
}).AddPolicyHandler(request => timeout);
I used code from below link to decompress GZip stream.Then used the decompressed byte array to get the required JSON object. Hope it may help some one.
var readTask = result.Content.ReadAsByteArrayAsync().Result;
var decompressedData = Decompress(readTask);
string jsonString = System.Text.Encoding.UTF8.GetString(decompressedData, 0, decompressedData.Length);
ResponseObjectClass responseObject = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponseObjectClass>(jsonString);
https://www.dotnetperls.com/decompress
static byte[] Decompress(byte[] gzip)
{
using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress))
{
const int size = 4096;
byte[] buffer = new byte[size];
using (MemoryStream memory = new MemoryStream())
{
int count = 0;
do
{
count = stream.Read(buffer, 0, size);
if (count > 0)
{
memory.Write(buffer, 0, count);
}
}
while (count > 0);
return memory.ToArray();
}
}
}
Ok so I eventually solved my problem. If there are better ways please let me know :-)
public DataSet getData(string strFoo)
{
string url = "foo";
HttpClient client = new HttpClient();
HttpResponseMessage response;
DataSet dsTable = new DataSet();
try
{
//Gets the headers that should be sent with each request
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Returned JSON
response = client.GetAsync(url).Result;
//converts JSON to string
string responseJSONContent = response.Content.ReadAsStringAsync().Result;
//deserializes string to list
var jsonList = DeSerializeJsonString(responseJSONContent);
//converts list to dataset. Bad name I know.
dsTable = Foo_ConnectAPI.ExtentsionHelpers.ToDataSet<RootObject>(jsonList);
//Returns the dataset
return dsTable;
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return null;
}
}
//deserializes the string to a list. Utilizes JSON.net. RootObject is a class that contains the get and set for the JSON elements
public List<RootObject> DeSerializeJsonString(string jsonString)
{
//Initialized the List
List<RootObject> list = new List<RootObject>();
//json.net deserializes string
list = (List<RootObject>)JsonConvert.DeserializeObject<List<RootObject>>(jsonString);
return list;
}
The RootObject contains the get set that will get the values of the JSON.
public class RootObject
{
//These string will be set to the elements within the JSON. Each one is directly mapped to the JSON elements.
//This only takes into account a JSON that doesn't contain nested arrays
public string EntityID { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Address3 { get; set; }
}
The easiest way to create the above class(es) is to use json2charp which will format it accordingly and also provide the correct datatypes.
The following is from another answer on Stackoverflow
again it does not take into account nested JSON.
internal static class ExtentsionHelpers
{
public static DataSet ToDataSet<T>(this List<RootObject> list)
{
try
{
Type elementType = typeof(RootObject);
DataSet ds = new DataSet();
DataTable t = new DataTable();
ds.Tables.Add(t);
try
{
//add a column to table for each public property on T
foreach (var propInfo in elementType.GetProperties())
{
try
{
Type ColType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType;
t.Columns.Add(propInfo.Name, ColType);
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
try
{
//go through each property on T and add each value to the table
foreach (RootObject item in list)
{
DataRow row = t.NewRow();
foreach (var propInfo in elementType.GetProperties())
{
row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value;
}
t.Rows.Add(row);
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
insert.insertCategories(t);
return ds.
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return null;
}
}
};
Then finally to insert the above dataset into a table with columns that were mapped to the JSON I utilized SQL bulk copy and the following class
public class insert
{
public static string insertCategories(DataTable table)
{
SqlConnection objConnection = new SqlConnection();
//As specified in the App.config/web.config file
objConnection.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["foo"].ToString();
try
{
objConnection.Open();
var bulkCopy = new SqlBulkCopy(objConnection.ConnectionString);
bulkCopy.DestinationTableName = "dbo.foo";
bulkCopy.BulkCopyTimeout = 600;
bulkCopy.WriteToServer(table);
return "";
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return "";
}
finally
{
objConnection.Close();
}
}
};
So the above works to insert JSON from a webAPI into a database. This is something that I get to work. But by no means do I expect it to be perfect. If you have any improvements then please update it accordingly.
Sooner or later your code might brake if your server use another compression scheme like 'Brotli' with content-type: br
I have made a video to handle decompression in httpClient with the clientHandler:
compression algos handled by httpClientHandler
I am using RestSharp to post an object to asp.net Web API action. For JSON format, my client side codes work OK with server side
that provides Web API post action. For XML format, my other client side codes do not work; debugging on server side Web API action,
the object binding is always null; the input paramenter "analyticsLogs" is recevied as null for XML format (see codes below). Please help.
The following is my asp.net web API POST action on server side:
[HttpPost]
public HttpResponseMessage PostAnalyticsLogs([FromBody] AnalyticsLogs analyticsLogs)
{
_logger.Info(analyticsLogs);
bool status = _analyticService.CreateAnalyticsLogs(analyticsLogs);
HttpResponseMessage response = new HttpResponseMessage();
if(status)
{
response = Request.CreateResponse<AnalyticsLogs>(HttpStatusCode.OK, analyticsLogs);
}
else
{
response = Request.CreateResponse<AnalyticsLogs>(HttpStatusCode.InternalServerError, analyticsLogs);
}
return response;
}
The client codes for JSON format works OK:
private void buttonPostAnalyticsLogsDTO_Click(object sender, EventArgs e)
{
try
{
string pingMessage = string.Empty;
clearDataGridViewLinqToExcel();
if (!isWebAPISiteRunning(out pingMessage))
{
MessageBox.Show(pingMessage);
_logger.Error(pingMessage);
return;
}
// POST
AnalyticsLogs analyticsLogs = new AnalyticsLogs();
Analytics analytics = new Analytics();
analytics.Action = "Action test JSON";
analytics.Category = "Category test JSON";
analytics.Label = "Label test";
analytics.Value = 2147483647;
analytics.Timestamp = DateTime.Now;
analyticsLogs.Add(analytics);
// REST SHARP
var client = new RestClient(_webApiBaseUrl);
var request = new RestRequest();
request.Method = Method.POST;
request.RequestFormat = DataFormat.Json; // JSON ***************
request.Resource = "Analytic";
request.AddBody(analyticsLogs);
var response = client.Execute<AnalyticsLogs>(request);
if (response.ResponseStatus == ResponseStatus.Error)
{
_logger.Error(response.ErrorMessage);
MessageBox.Show(response.ErrorMessage);
return;
}
dataGridViewLocalDMSWebAPIForDataAggregator.DataSource = response.Data;
}
catch(Exception ex)
{
_logger.Error(ex);
MessageBox.Show(ex.Message);
}
}
The client codes for XMLformat do not work:
private void buttonPostAnalyticsLogsDTO_XML_Click(object sender, EventArgs e)
{
try
{
string pingMessage = string.Empty;
clearDataGridViewLinqToExcel();
if (!isWebAPISiteRunning(out pingMessage))
{
MessageBox.Show(pingMessage);
_logger.Error(pingMessage);
return;
}
// POST
AnalyticsLogs analyticsLogs = new AnalyticsLogs();
Analytics analytics = new Analytics();
analytics.Action = "Action test XML";
analytics.Category = "Category test XML";
analytics.Label = "Label test";
analytics.Value = 47950494;
analytics.Timestamp = DateTime.Now;
analyticsLogs.Add(analytics);
// REST SHARP
var client = new RestClient(_webApiBaseUrl);
var request = new RestRequest();
request.Method = Method.POST;
request.RequestFormat = DataFormat.Xml; // XML *****************
request.Resource = "Analytic";
request.AddBody(analyticsLogs);
var response = client.Execute<AnalyticsLogs>(request);
if (response.ResponseStatus == ResponseStatus.Error)
{
_logger.Error(response.ErrorMessage);
MessageBox.Show(response.ErrorMessage);
return;
}
dataGridViewLocalDMSWebAPIForDataAggregator.DataSource = response.Data;
}
catch (Exception ex)
{
_logger.Error(ex);
MessageBox.Show(ex.Message);
}
}
My custom DTO classes:
public class Analytics
{
public DateTime Timestamp { get; set; }
public long UserExpId { get; set; }
public string UserExpStatus { get; set; }
public string Category { get; set; }
public string Action { get; set; }
public string Label { get; set; }
public int Value { get; set; }
}
public class AnalyticsLogs : List<Analytics>
{
}
Debugging the problem with XML client codes gives me some information:
(new System.Collections.Generic.Mscorlib_CollectionDebugView<RestSharp.Parameter>(request.Parameters)).Items[0] :RequestBody
+ [0] {text/xml=<AnalyticsLogs>
<Analytics>
<Timestamp>9/9/2014 9:15:58 AM</Timestamp>
<UserExpId>0</UserExpId>
<Category>Category test XML</Category>
<Action>Action test XML</Action>
<Label>Label test</Label>
<Value>47950494</Value>
</Analytics>
</AnalyticsLogs>} RestSharp.Parameter
request.RootElement : null
I've found the problem. The RestSharp Serializer is not comaptible with the DataContractSerializer or XmlSerializer. Both are used from Web API (Default: DataContractSerializer).
RestSharp produces clean XML but the DataContractSerializer need some extra information (aka xmlns:i and xmlns attributes).
You can reproduce your problem within an console application with this code:
(It will throw an detailed exception within the deserialization process)
AnalyticsLogs analyticsLogs = new AnalyticsLogs();
Analytics analytics = new Analytics();
analytics.Action = "Action test XML";
analytics.Category = "Category test XML";
analytics.Label = "Label test";
analytics.Value = 47950494;
analytics.Timestamp = DateTime.Now;
analyticsLogs.Add(analytics);
var serializer = new RestSharp.Serializers.XmlSerializer();
var xml = serializer.Serialize(analyticsLogs);
var obj = Deserialize<AnalyticsLogs>(xml);
static string Serialize<T>(T value) {
XmlMediaTypeFormatter formatter = new XmlMediaTypeFormatter();
// formatter.UseXmlSerializer = true;
// Create a dummy HTTP Content.
Stream stream = new MemoryStream();
var content = new StreamContent(stream);
/// Serialize the object.
formatter.WriteToStreamAsync(typeof(T), value, stream, content, null).Wait();
// Read the serialized string.
stream.Position = 0;
return content.ReadAsStringAsync().Result;
}
static T Deserialize<T>(string str) where T : class {
XmlMediaTypeFormatter formatter = new XmlMediaTypeFormatter();
// formatter.UseXmlSerializer = true;
// Write the serialized string to a memory stream.
Stream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(str);
writer.Flush();
stream.Position = 0;
// Deserialize to an object of type T
return formatter.ReadFromStreamAsync(typeof(T), stream, null, null).Result as T;
}
The Methods are from Web API Tutorial and you have to install Web API in your console app.
I've found no solution to get them both work together - sry :(
In our programming environment at work we have both Java and C# developers. I have a web service I created In C# that the Java developers are trying to consume. I have been writing the Java to consume this web service and while I am getting a json result, it is in the wrong format.
Here is what I have on the c# side:
[WebMethod]
public static LinkedList<string> GetInfo(string InfoID, string Username, string Password)
{
LinkedList<string> Result = new LinkedList<string>();
try
{
// Do some stuff I can't show you to get the information...
foreach (Result from data operations)
{
Result.AddLast(sample1);
Result.AddLast(sample2);
Result.AddLast(sample3);
Result.AddLast(BD));
Result.AddLast(CN);
Result.AddLast(Name);
Result.AddLast("###");
}
}catch(Exception exc)
{
Result.AddLast(exc.ToString());
return Result;
}
return Result;
}
Then this is the Java Side:
try {
String uri = "http://example.com/service.asmx/GetInfo";
URL url = new URL(uri);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// Setup Connection Properties
connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("charset", "utf-8");
connection.setRequestProperty("Accept", "application/json");
connection.setChunkedStreamingMode(0);
connection.connect();
// Create the JSON Going out
byte[] parameters = "{'InfoID':'123456789','Username':'usernametoken','Password':'passwordtoken'}".getBytes("UTF-8");
// Start doing stuff
DataOutputStream os = new DataOutputStream(connection.getOutputStream());
os.write(parameters);
os.close();
InputStream response;
// Check for error , if none store response
if(connection.getResponseCode() == 200){response = connection.getInputStream();}
else{response = connection.getErrorStream();}
InputStreamReader isr = new InputStreamReader(response);
StringBuilder sb = new StringBuilder();
BufferedReader br = new BufferedReader(isr);
String read = br.readLine();
while(read != null){
sb.append(read);
read = br.readLine();
}
// Print the String
System.out.println(sb.toString());
// Creat JSON off of String
JSONObject token = new JSONObject(sb.toString());
// print JSON
System.out.println("Tokener: " + token.toString());
response.close();
} catch(IOException exc) {
System.out.println("There was an error creating the HTTP Call: " + exc.toString());
}
And the response I get is in this form...
{"d":["Sample1","Sample2","Sample3","BD","CN","Name","###","Sample1","Sample2","Sample3","BD","CN","Name","###","Sample1","Sample2","Sample3","BD","CN","Name","###"]}
I was wondering if there was a better way to send the response such that the JSON would look like this:
{"1":["Sample1","Sample2","Sample3","BD","CN","Name","###"],"2":["Sample1","Sample2","Sample3","BD","CN","Name","###"],"3":["Sample1","Sample2","Sample3","BD","CN","Name","###"],"4":["Sample1","Sample2","Sample3","BD","CN","Name","###"]}
Ok I think I see your problem here. You want your data to be serialized as
{"1":["Sample1","Sample2","Sample3","BD","CN","Name","###"],"2":["Sample1","Sample2","Sample3","BD","CN","Name","###"],"3":["Sample1","Sample2","Sample3","BD","CN","Name","###"] ... etc
Yet the data structure you are serializing is a single linked list, which is why it is serialized as a single long list. What you need to do is change the data structure. A Dictionary would be perfect, since it is easily serializable as JSON.
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
[WebMethod]
public static Dictionary<int,LinkedList<string>> GetInfo(string InfoID, string Username, string Password)
{
var Result = new Dictionary<int,LinkedList<string>>();
try
{
// Do some stuff I can't show you to get the information...
foreach (Result from data operations)
{
var newList = new LinkedList<string>();
newList.AddLast(sample1);
newList.AddLast(sample2);
newList.AddLast(sample3);
newList.AddLast(BD));
newList.AddLast(CN);
newList.AddLast(Name);
newList.AddLast("###");
int number = something //the number before the list
Result.add( number, newList);
}
}catch(Exception exc)
{
.
.
.
}
return Result;
}
I need to use "HTTP Post" with WebClient to post some data to a specific URL I have.
Now, I know this can be accomplished with WebRequest but for some reasons I want to use WebClient instead. Is that possible? If so, can someone show me some example or point me to the right direction?
I just found the solution and yea it was easier than I thought :)
so here is the solution:
string URI = "http://www.myurl.com/post.php";
string myParameters = "param1=value1¶m2=value2¶m3=value3";
using (WebClient wc = new WebClient())
{
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
string HtmlResult = wc.UploadString(URI, myParameters);
}
it works like charm :)
There is a built in method called UploadValues that can send HTTP POST (or any kind of HTTP methods) AND handles the construction of request body (concatenating parameters with "&" and escaping characters by url encoding) in proper form data format:
using(WebClient client = new WebClient())
{
var reqparm = new System.Collections.Specialized.NameValueCollection();
reqparm.Add("param1", "<any> kinds & of = ? strings");
reqparm.Add("param2", "escaping is already handled");
byte[] responsebytes = client.UploadValues("http://localhost", "POST", reqparm);
string responsebody = Encoding.UTF8.GetString(responsebytes);
}
Using WebClient.UploadString or WebClient.UploadData you can POST data to the server easily. I’ll show an example using UploadData, since UploadString is used in the same manner as DownloadString.
byte[] bret = client.UploadData("http://www.website.com/post.php", "POST",
System.Text.Encoding.ASCII.GetBytes("field1=value1&field2=value2") );
string sret = System.Text.Encoding.ASCII.GetString(bret);
More: http://www.daveamenta.com/2008-05/c-webclient-usage/
string URI = "site.com/mail.php";
using (WebClient client = new WebClient())
{
System.Collections.Specialized.NameValueCollection postData =
new System.Collections.Specialized.NameValueCollection()
{
{ "to", emailTo },
{ "subject", currentSubject },
{ "body", currentBody }
};
string pagesource = Encoding.UTF8.GetString(client.UploadValues(URI, postData));
}
//Making a POST request using WebClient.
Function()
{
WebClient wc = new WebClient();
var URI = new Uri("http://your_uri_goes_here");
//If any encoding is needed.
wc.Headers["Content-Type"] = "application/x-www-form-urlencoded";
//Or any other encoding type.
//If any key needed
wc.Headers["KEY"] = "Your_Key_Goes_Here";
wc.UploadStringCompleted +=
new UploadStringCompletedEventHandler(wc_UploadStringCompleted);
wc.UploadStringAsync(URI,"POST","Data_To_Be_sent");
}
void wc__UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
try
{
MessageBox.Show(e.Result);
//e.result fetches you the response against your POST request.
}
catch(Exception exc)
{
MessageBox.Show(exc.ToString());
}
}
Using simple client.UploadString(adress, content); normally works fine but I think it should be remembered that a WebException will be thrown if not a HTTP successful status code is returned. I usually handle it like this to print any exception message the remote server is returning:
try
{
postResult = client.UploadString(address, content);
}
catch (WebException ex)
{
String responseFromServer = ex.Message.ToString() + " ";
if (ex.Response != null)
{
using (WebResponse response = ex.Response)
{
Stream dataRs = response.GetResponseStream();
using (StreamReader reader = new StreamReader(dataRs))
{
responseFromServer += reader.ReadToEnd();
_log.Error("Server Response: " + responseFromServer);
}
}
}
throw;
}
Using webapiclient with model send serialize json parameter request.
PostModel.cs
public string Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public int Age { get; set; }
WebApiClient.cs
internal class WebApiClient : IDisposable
{
private bool _isDispose;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose(bool disposing)
{
if (!_isDispose)
{
if (disposing)
{
}
}
_isDispose = true;
}
private void SetHeaderParameters(WebClient client)
{
client.Headers.Clear();
client.Headers.Add("Content-Type", "application/json");
client.Encoding = Encoding.UTF8;
}
public async Task<T> PostJsonWithModelAsync<T>(string address, string data,)
{
using (var client = new WebClient())
{
SetHeaderParameters(client);
string result = await client.UploadStringTaskAsync(address, data); // method:
//The HTTP method used to send the file to the resource. If null, the default is POST
return JsonConvert.DeserializeObject<T>(result);
}
}
}
Business caller method
public async Task<ResultDTO> GetResultAsync(PostModel model)
{
try
{
using (var client = new WebApiClient())
{
var serializeModel= JsonConvert.SerializeObject(model);// using Newtonsoft.Json;
var response = await client.PostJsonWithModelAsync<ResultDTO>("http://www.website.com/api/create", serializeModel);
return response;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
Most of the answers are old. Just wanted to share what worked for me. In the interest of doing things asynchronously i.e. to post data to specific URL using WebClient asynchronously in .NET 6.0 Preview 7, .NET Core and other versions can be done using WebClient.UploadStringTaskAsync Method.
Use namespace System.Net; and for a class ResponseType to capture the response from the server, we can use this method to POST data to a specific URL. Make sure to use the await keyword while calling this method
public async Task<ResponseType> MyAsyncServiceCall()
{
try
{
var uri = new Uri("http://your_uri");
var body= "param1=value1¶m2=value2¶m3=value3";
using (var wc = new WebClient())
{
wc.Headers[HttpRequestHeader.Authorization] = "yourKey"; // Can be Bearer token, API Key etc.....
wc.Headers[HttpRequestHeader.ContentType] = "application/json"; // Is about the payload/content of the current request or response. Do not use it if the request doesn't have a payload/ body.
wc.Headers[HttpRequestHeader.Accept] = "application/json"; // Tells the server the kind of response the client will accept.
wc.Headers[HttpRequestHeader.UserAgent] = "PostmanRuntime/7.28.3";
string result = await wc.UploadStringTaskAsync(uri, body);
return JsonConvert.DeserializeObject<ResponseType>(result);
}
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
Here is the crisp answer:
public String sendSMS(String phone, String token) {
WebClient webClient = WebClient.create(smsServiceUrl);
SMSRequest smsRequest = new SMSRequest();
smsRequest.setMessage(token);
smsRequest.setPhoneNo(phone);
smsRequest.setTokenId(smsServiceTokenId);
Mono<String> response = webClient.post()
.uri(smsServiceEndpoint)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.body(Mono.just(smsRequest), SMSRequest.class)
.retrieve().bodyToMono(String.class);
String deliveryResponse = response.block();
if (deliveryResponse.equalsIgnoreCase("success")) {
return deliveryResponse;
}
return null;
}