C# HTTP Request using MongoDB - c#

I am having trouble inserting data into a MongoDB from a windows form application through a rest API. Below is what I have so far.
ProductController (API)
[HttpPost]
public JsonResult Post(Product item)
{
MongoClient dbClient = new MongoClient(_configuration.GetConnectionString("AppConString"));
dbClient.GetDatabase("motopartsdb").GetCollection<Product>("products").InsertOne(item);
return new JsonResult("Added Successfully");
}
WindowsApplication
async private void createProduct()
{
var values = new Dictionary<string, string>
{
{ "name", ProductNameInput.Text },
{ "category", category},
{ "type", "New" },
{ "supplier", SupplierInput.Text },
{ "quantity", QuantityInput.Text },
{ "price", PriceInput.Text },
{ "condition", "" },
{ "description", DescriptionInput.Text }
};
HttpClient client = new HttpClient();
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("https://localhost:57501/api/product", content);
var responseString = await response.Content.ReadAsStringAsync();
}
When I run the code I get error 415 from the rest API, I tried possible fixes but cant seem to figure it out.
Any help is appreciated, many thanks.

I would recommend that you don't send a Dictionary<string, string> but a Product object.
Below is an untested example, I am guessing your Product object properties.
EDITED
I have edited the below code to Serialize the product and generated StringContent to send.
async private void createProduct()
{
Product prod = new Product()
{
Name = ProductNameInput.Text,
Category = category,
Type = "New" ,
Supplier = SupplierInput.Text ,
Quantity = QuantityInput.Text ,
Price = PriceInput.Text ,
Condition = "" ,
Description = DescriptionInput.Text
};
HttpClient client = new HttpClient();
StringContent stringContent = null;
if (prod != null)
{
//serialize object to string in Json format
string content = JsonConvert.SerializeObject(prod, _jsonSerializerSettings);
//create content
stringContent = new StringContent(content, Encoding.UTF8, "application/json");
stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
}
var response = await client.PostAsync("https://localhost:57501/api/product", stringContent);
var responseString = await response.Content.ReadAsStringAsync();
}
In addition you may need to
add a JSON request header to your HttpClient
set your Mongo DB Convention. For example I use Camel Case.
//clear accept headers
client.DefaultRequestHeaders.Accept.Clear();
//add accept json
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//an example C# object
public class MyExample
{
//camel case in mongoDB saved as firstName
public string FirstName {get; set;}
}
//on Mongo DB create
var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() };
ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);

Related

How to post silent notification using onesignal rest api C#

I am beginner in using this api and it's services. I have tried lots of thing but nothing worked for me, Just wanted to push silent notification. Any suggestion will be appreciated and Thanks in advance.
private static readonly string oneSignalUrl = "https://onesignal.com/api/v1/notifications";
public async Task<HttpResponseMessage> SendNotification(string playerId, string notificationAppId, string notificationSecretKey)
{
var client = new HttpClient();
client.BaseAddress = new Uri(oneSignalUrl);
client.DefaultRequestHeaders.Add("authorization", "Basic " + notificationSecretKey);
var model = new DictionaryDTO { aps = new Dictionary<string, int>() { { "content-available", 1 } }, acme1 = "logout" };
var content = GetContent(notificationAppId, model, playerId);
var response = await client.PostAsync(oneSignalUrl, content);
return response;
}
public StringContent GetContent(string notificationAppId, DictionaryDTO model, string playerId)
{
var content = new StringContent(JsonConvert.SerializeObject(new
{
app_id = notificationAppId,
contents = new
{
en = "Testing the push notification functionality",
model
},
include_player_ids = new string[] { playerId }
}), Encoding.UTF8, "application/json");
return content;
}

How to store API result set for different response types using C#.Net

I am trying to call two API's and store their response.
Below is the API response type:
API1 response:
{
"Name": "Apple",
"Expiry": "2008-12-28T00:00:00",
"Price": 3.99,
"Sizes": [
"Small",
"Medium",
"Large"
]
}
API2 Response:
["Name=xyz, Id=1, Version=1","Name=abc, Id=1, Version=2","Name=hgf, Id=1, Version=3","Name=utgds, Id=1, Version=4","Name=kfgf, Id=2, Version=1"]
below is the code to call an API and get the result set.
var jsonObj = Get<SomeClass>("API_URL1");
var jsonObj2 = Get<Test>("API_URL2");
public T Get<T>(string requestUri)
{
T response = default(T);
using (var handler = new HttpClientHandler { Credentials = CredentialCache.DefaultNetworkCredentials })
{
using (var httpClient = CreateNewRequest(handler))
{
var httpTask = httpClient.GetAsync(requestUri);
var response = task.Result;
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
var res = JsonConvert.DeserializeObject<T>(result);
}
}
}
return res;
}
private HttpClient CreateNewRequest(HttpClientHandler handler)
{
HttpClient client = new HttpClient(handler);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
public class Test
{
public string Name { get; set; }
public int Id { get; set; }
public int Version { get; set; }
}
Similarly i have created a class to hold the API1 response.
I am able to store API1 Response however while storing API2 response i am getting this error message.
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type
because the type requires a JSON object (e.g. {"name":"value"}) to
deserialize correctly. To fix this error either change the JSON to a
JSON object (e.g. {"name":"value"}) or change the deserialized type to
an array or a type that implements a collection interface..
any idea/hints on this?
Thanks!
I tested what i said in comment. Second response is JSON array of strings. You should deserialize it as array of string (string[]) or collection of strings (List<string>). Following works as expected:
var response = "[\"Name=xyz, Id=1, Version=1\", \"Name=abc, Id=1, Version=2\", \"Name=hgf, Id=1, Version=3\", \"Name=utgds, Id=1, Version=4\", \"Name=kfgf, Id=2, Version=1\"]";
var result = JsonConvert.DeserializeObject<string[]>(response);
To summarise: instead of Get<Test> use Get<string[]>. You just have to parse strings, but this seems to be another problem.
Full demo below (url invocations intentionally mocked):
class Program
{
static void Main(string[] args)
{
var invoker = new JsonMockInvoker();
var jsonObj = invoker.Get<SomeClass>("API_URL1");
var jsonObj2 = invoker.Get<string[]>("API_URL2");
}
}
class SomeClass
{
public string Name { get; set; }
//other properties
}
public class JsonMockInvoker:JsonInvoker
{
public override string InvokeRest(string url)
{
if (url == "API_URL1")
return "{\"Name\": \"Apple\",\"Expiry\": \"2008-12-28T00:00:00\",\"Price\": 3.99,\"Sizes\": [\"Small\",\"Medium\",\"Large\"]}";
if (url == "API_URL2")
return "[\"Name=xyz, Id=1, Version=1\", \"Name=abc, Id=1, Version=2\", \"Name=hgf, Id=1, Version=3\", \"Name=utgds, Id=1, Version=4\", \"Name=kfgf, Id=2, Version=1\"]";
throw new NotImplementedException();
}
}
public class JsonInvoker
{
public T Get<T>(string requestUri)
{
var result = InvokeRest(requestUri);
return result != null ? JsonConvert.DeserializeObject<T>(result) : default(T);
}
public virtual string InvokeRest(string url)
{
using (var handler = new HttpClientHandler { Credentials = CredentialCache.DefaultNetworkCredentials })
using (var httpClient = CreateNewRequest(handler))
{
var httpTask = httpClient.GetAsync(url);
var response = httpTask.Result;
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
return response.Content.ReadAsStringAsync().Result;
}
}
return null;
}
private HttpClient CreateNewRequest(HttpClientHandler handler)
{
HttpClient client = new HttpClient(handler);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return client;
}
}
String values are not in JSON format - you have to parse them manually:
//parse to typed object
var parsedObject = jsonObj2.Select(a => new
{
Id = Regex.Match(a, "(?<=Id=)[^,]*").Value,
Name = Regex.Match(a, "(?<=Name=)[^,]*").Value
});
//parse to dictionary
var regex = new Regex("([\\s]|^)(?<key>[^=]+)=(?<value>[^,]*)");
var parsed = jsonObj2.Select(a =>
{
var dictionary = new Dictionary<string, string>();
foreach (Match match in regex.Matches(a))
dictionary[match.Groups["key"].Value] = match.Groups["value"].Value;
return dictionary;
});

C# Api controller not receiving json parameter

I am trying to create a basic test web api, and use a standard controller to test call it.
When I run it, by putting
http://localhost:55144/home/testapi
it'll run the catcher function and completely ignore the parameter.
Then, the catcher will happily return a value, which can be seen in the calling code.
I have tried various combinations of putting [FromBody], changing the type of the parameter in TestApiMethod, and seeing if making a list or array makes any difference.
I've noticed a couple of weird things:
- I'm not using the parameter in the code of TestApiMethod, but Visual Studio is not giving me an unused variable warning.
- If I make the type of the parameter testString a string or even an int, the code below will route to the catcher. If I make it some variation of a model or a Jobject, it will not. It gets as far as running
HttpResponseMessage response = await client.PostAsJsonAsync("api/activity", sendData);
then just returns to the web page.
Here's the code:
Models
public class testStringModel
{
public string testString { get; set; }
}
public class apiResponse
{
public string response { get; set; }
}
Home controller calling Api:
public void TestApi()
{
Task myTask = testApiCall();
}
private async Task<string> testApiCall()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:55144");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
testStringModel data = new testStringModel { testString = "cheese" };
string jsonData = JsonConvert.SerializeObject(data);
var sendData = new StringContent(jsonData, Encoding.UTF8, "application/json");
//var sendData = new Dictionary<string, string>
//{
// {"testString", "cheese"}
//};
HttpResponseMessage response = await client.PostAsJsonAsync("api/activity", sendData);
string responseBodyAsText = await response.Content.ReadAsStringAsync();
dynamic stuff = JObject.Parse(responseBodyAsText);
string finalResponse = stuff.response;
return finalResponse;
}
}
The api:
namespace ApplicationActivity
{
public class ActivityController : ApiController
{
[System.Web.Http.HttpPost]
public HttpResponseMessage Catcher()
{
apiResponse apiResponseObject = new apiResponse();
apiResponseObject.response = "You have somehow wound up in the catcher";
string json = JsonConvert.SerializeObject(apiResponseObject);
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, "value");
response.Content = new StringContent(json, Encoding.Unicode, "application/json");
response.Headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromMinutes(20)
};
return response;
}
[System.Web.Http.HttpPost]
public HttpResponseMessage TestApiMethod(string testString)
{
apiResponse apiResponseObject = new apiResponse();
apiResponseObject.response = "OK from test";
string json = JsonConvert.SerializeObject(apiResponseObject);
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, "value");
response.Content = new StringContent(json, Encoding.Unicode, "application/json");
response.Headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromMinutes(20)
};
return response;
}
}
}
Please will you tell me what I'm doing wrong with my code, how to fix it and what is happening when the code doesn't get to the catcher?
Thanks.
It turns out that I was using an older version of visual studio and as a result the whole thing got really confused with whether is was running .net core or not.
Upgrading to the latest and making sure the latest .net core is installed solved most of my troubles

Patching to TFS API with JSON gives 400 error (Bad Request)

I'm trying to do a patch http request to change one of the fields in TFS through the TFS REST API. I've tried several approaches, but I always end up with 400 error. Here is what I have right now:
public void SetFieldValue(string value, string path, int id)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(PatchwebAPIUrl("wit/workitems", id.ToString()));
httpWebRequest.ContentType = "application/json-patch+json";
httpWebRequest.Method = "PATCH";
httpWebRequest.Headers["Authorization"] = "Basic" + Base64authorizationToken();
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = "[{\"op\":\"replace\"," +
$"\"path\":\"{path}\"," +
$"\"value\":\"{value}\"}}]";
streamWriter.Write(JsonConvert.SerializeObject(json));
streamWriter.Flush();
streamWriter.Close();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
}
And the test method that calls this method:
[TestMethod()]
public void setFieldValue()
{
TFSWebAPIImplementation webAPI = new TFSWebAPIImplementation();
webAPI.SetFieldValue("654321", "/fields/Custom.Tracking", 61949);
}
The PatchwebAPIUrl("...") Method is fine, and returns a good URL, when I navigate to it I get the JSON data that I want to edit. I'm not 100% on the path variable but it's used the same as the example provided from Microsoft. The authorization works, just based on the fact that when I mess with it I get a 401 instead.
This is my sample code:
Class for work item:
public class WorkItemAtrr
{
[JsonProperty("id")]
public int id;
[JsonProperty("rev")]
public int rev;
[JsonProperty("fields")]
public Dictionary<string, string> fields;
[JsonProperty("_links")]
public Dictionary<string, Link> _links;
[JsonProperty("relations")]
public List<Relation> relations;
[JsonProperty("url")]
public string url;
}
public class Link
{
[JsonProperty("href")]
public string href;
}
public class Relation
{
[JsonProperty("rel")]
public string rel;
[JsonProperty("url")]
public string url;
[JsonProperty("attributes")]
public RelationAttribute attributes;
}
public class RelationAttribute
{
[JsonProperty("comment")]
public string comment = "";
[JsonProperty("isLocked")]
public bool isLocked;
}
Class for new and updated fields:
public class NewField
{
[JsonProperty("op")]
public string op = "add";
[JsonProperty("path")]
public string path;
[JsonProperty("value")]
public object value;
}
Class for exceptions:
public class RestApiExceptionContainer
{
[JsonProperty("id")]
public int id;
[JsonProperty("innerException")]
public string innerException;
[JsonProperty("message")]
public string message;
[JsonProperty("typeName")]
public string typeName;
[JsonProperty("typeKey")]
public string typeKey;
[JsonProperty("errorCode")]
public int errorCode;
[JsonProperty("evenId")]
public int eventId;
}
Method for update a work item:
private static WorkItemAtrr UpdateWorkItemRest()
{
Dictionary<string, string> _fields = new Dictionary<string, string>();
_fields.Add("REFERENCE_NAME", "VALUE");
var _updatedWi = UpdateWorkItem("ID", _fields).Result;
}
Method for preparing request:
public async Task<WorkItemAtrr> UpdatedWorkItem(int pId, Dictionary<String, String> pFields)
{
//PATCH https://{instance}/DefaultCollection/_apis/wit/workitems/{id}?api-version={version}
string _query_url = String.Format("https://YOUR_SERVER/DefaultCollection/_apis/wit/workitems/{id}?api-version=1.0", pId);
List<Object> flds = new List<Object>();
foreach (var _key in pFields.Keys)
flds.Add(new NewField { op = "add", path = "/fields/" + _key, value = pFields[_key] });
HttpResponseMessage _response = await DoRequest(_query_url, JsonConvert.SerializeObject(flds), ClientMethod.PATCH);
return JsonConvert.DeserializeObject<WorkItemAtrr>(await ProcessResponse(_response));
}
Universal method for request:
private async Task<HttpResponseMessage> DoRequest(string pRequest, string pBody, ClientMethod pClientMethod)
{
try
{
HttpClientHandler _httpclienthndlr = new HttpClientHandler();
//update for your auth
if (UseDefaultCredentials) _httpclienthndlr.Credentials = CredentialCache.DefaultCredentials;
else if (TFSDomain == "") _httpclienthndlr.Credentials = new NetworkCredential(TFSUserName, TFSPassword);
else _httpclienthndlr.Credentials = new NetworkCredential(TFSUserName, TFSPassword, TFSDomain);
using (HttpClient _httpClient = new HttpClient(_httpclienthndlr))
{
switch (pClientMethod)
{
case ClientMethod.GET:
return await _httpClient.GetAsync(pRequest);
case ClientMethod.POST:
return await _httpClient.PostAsync(pRequest, new StringContent(pBody, Encoding.UTF8, "application/json"));
case ClientMethod.PATCH:
var _request = new HttpRequestMessage(new HttpMethod("PATCH"), pRequest);
_request.Content = new StringContent(pBody, Encoding.UTF8, "application/json-patch+json");
return await _httpClient.SendAsync(_request);
default:
return null;
}
}
}
catch (Exception _ex)
{
throw new Exception("Http Request Error", _ex);
}
}
Universal method for response:
public async Task<string> ProcessResponse(HttpResponseMessage pResponse)
{
string _responseStr = "";
if (pResponse != null)
{
if (pResponse.IsSuccessStatusCode)
_responseStr = await pResponse.Content.ReadAsStringAsync();
else
{
_responseStr = await pResponse.Content.ReadAsStringAsync();
var _error = JsonConvert.DeserializeObject<RestApiExceptionContainer>(_responseStr);
throw new RestApiException(_error);
}
}
return _responseStr;
}
A 400 means that the request was malformed. In other words, the data stream sent by the client to the server didn't follow the rules.
In the case of a REST API with a JSON payload, 400's are typically, used to indicate that the JSON is invalid in some way according to the API specification for the service.
So, the issue is caused by the JSON body.
Just try it like below:
string json = "[{\"op\":\"replace\",\"path\":\"/fields/System.Title\",\"value\":\"Title\"}]";
You can also use below sample to update the fields with PATCH method via the REST API, it works for me:
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Newtonsoft.Json;
namespace UpdateWorkItemFiled0411
{
class Program
{
static void Main(string[] args)
{
string password = "xxxx";
string credentials = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "username", password )));
Object[] patchDocument = new Object[1];
patchDocument[0] = new { op = "replace", path = "/relations/attributes/comment", value = "Adding traceability to dependencies" };
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);
var patchValue = new StringContent(JsonConvert.SerializeObject(patchDocument), Encoding.UTF8, "application/json-patch+json");
var method = new HttpMethod("PATCH");
var request = new HttpRequestMessage(method, "http://server:8080/tfs/DefaultCollection/_apis/wit/workitems/21?api-version=1.0") { Content = patchValue };
var response = client.SendAsync(request).Result;
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
}
}
}
}
}
Also you may use nugate package Microsoft.TeamFoundationServer.Client.
Connect to team project from here:
using Microsoft.TeamFoundation.Core.WebApi;
using Microsoft.VisualStudio.Services.Common;
...
//create uri and VssBasicCredential variables
Uri uri = new Uri(url);
VssBasicCredential credentials = new VssBasicCredential("", personalAccessToken);
using (ProjectHttpClient projectHttpClient = new ProjectHttpClient(uri, credentials))
{
IEnumerable<TeamProjectReference> projects = projectHttpClient.GetProjects().Result;
}
my code to add comments:
JsonPatchDocument PatchDocument = new JsonPatchDocument();
PatchDocument.Add(
new JsonPatchOperation()
{
Operation = Operation.Add,
Path = "/fields/System.History",
Value = "Changes from script"
}
);
VssCredentials Cred = new VssCredentials(true);
WorkItemTrackingHttpClient WIClient = new WorkItemTrackingHttpClient(new Uri("http://YOUR_SERVER/tfs/DefaultCollection"), Cred);
WorkItem result = WIClient.UpdateWorkItemAsync(PatchDocument, id).Result;
Okay guys, so unfortunately none of your solutions worked, and I think it's because there was always an extra set of curly brackets on the outside that the TFS API didn't like. Here is my solution that solved my problem:
public void SetFieldValue(string value, string path, int id)
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Base64authorizationToken());
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
using (JsonWriter writer = new JsonTextWriter(sw))
{
writer.Formatting = Formatting.Indented;
writer.WriteStartArray(); // [
writer.WriteStartObject(); // {
writer.WritePropertyName("op"); // "Product:"
writer.WriteValue("replace");
writer.WritePropertyName("path");
writer.WriteValue(path);
writer.WritePropertyName("value");
writer.WriteValue(value);
writer.WriteEndObject(); //}
writer.WriteEnd(); // ]
}
var method = new HttpMethod("PATCH");
var request = new HttpRequestMessage(method, PatchwebAPIUrl("wit/workitems", id.ToString())) { Content = new StringContent(sb.ToString().Trim(new char[] {'{','}'}), Encoding.UTF8, "application/json-patch+json") };
var response = client.SendAsync(request).Result;
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
}
}
}

pass integer to FormUrlEncodedContent

i use asp.net mvc and c#,
i my bank setion project i use this code for banking
var requestContent = new FormUrlEncodedContent(new[] {
new KeyValuePair<string, string>("amount", payment.Amount), //i want change this section for <string,int>
new KeyValuePair<string, string>("transid", "id"),
new KeyValuePair<string, string>("pin","pin" )
});
var client = new HttpClient();
HttpResponseMessage response = await client.PostAsync("http://address.com/api/verify/", requestContent);
HttpContent responseContent = response.Content;
string result = "";
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
result = await reader.ReadToEndAsync();
}
now my bank scenario is change and i should pass integer for amount,how i can do i from mycode?
because FormUrlEncodedContent accept <string,string>
thank you for your help
Try this, It is working for me.
public class PaymentActionsRequest
{
[JsonProperty("payment_intent")]
public string PaymentIntent { get; set; }
[JsonProperty("amount")]
public long Amount { get; set; }
}
var keyValueContent = PaymentActionsRequest.ToKeyValue();
var formUrlEncodedContent = new FormUrlEncodedContent(keyValueContent);
You need to use something like Amount.ToString() as this content would eventually be string/encoded as part of POST body.

Categories