how to pass the following JSON to a C# patch method w or w/o Javascript serializer - c#

I am working on a program to access the REST API for Visual Studio Team Services (was Visual Studio Online). I am following https://www.visualstudio.com/integrate/api/wit/work-items
I was able to query the work item by passing the correct Id using this code snippet:
var uri = new Uri("https://{instance}.visualstudio.com/DefaultCollection/_apis/wit/workitems/7?api-version=1.0");
GetWorkItem(uri);
public static async void GetWorkItem(Uri uri)
{
try
{
var username = "my username";
var password = " my pass word";
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(
ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", username, password))));
using (HttpResponseMessage response = client.GetAsync(uri)
.Result)
{
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
}
Console.Read();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.Read();
}
}
It correctly returns a JSON as specified here https://www.visualstudio.com/integrate/api/wit/work-items#GetalistofworkitemsByIDs
Now I am trying to update the work item by modifying its title .
https://www.visualstudio.com/integrate/api/wit/work-items#UpdateworkitemsUpdateafield
For this I wrote a method :
public static async void UpdateWorkItemStatus(Uri requestUri, HttpContent iContent)
{
{
var method = new HttpMethod("PATCH");
var request = new HttpRequestMessage(method, requestUri)
{
Content = iContent
};
HttpResponseMessage response;
try
{
using (HttpClient client = new HttpClient())
{
var username = "my username";
var password = "my password";
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(
ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", username, password))));
response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
Console.WriteLine(response);
Console.Read();
}
}
catch (TaskCanceledException e)
{
Console.WriteLine("ERROR: " + e.ToString());
Console.Read();
}
}
}
I am calling this method by passing my json :
var uri = new Uri("https://{instance}.visualstudio.com/DefaultCollection/_apis/wit/workitems/7?api-version=1.0");
string json = new JavaScriptSerializer().Serialize(new
{
op="replace",
path="fields/System.Title",
value=" 123 New Title"
});
HttpContent httpContent = new StringContent(json, Encoding.UTF8, "application/json-patch+json");
UpdateWorkItemStatus(uri, httpContent);
This is in accordance with the information in https://www.visualstudio.com/integrate/api/wit/work-items#Updateworkitems
They don't have any code samples so I used JavascriptSerializer
But this doesn't do anything . The code runs but gives no output and my work item is also not edited. I am not sure if it is incorrect in format due to using JavascriptSerializer but I have used this class before and it has worked well.
Basically I need to pass this JSON :
[
{
"op": "replace",
"path": "fields/System.Title",
"value":"New Title"
}
]
Any help on how to get this running and pass the JSON in a right format would be appreciated even if without using the JS Serializer class.
Eventually the idea is to convert this to an interpreted script that can run on Unix, like curl, Python or Perl. Any pointers or recommendations on that would also be appreciated.

I usually pass the content strings directly and it works:
string json = "[{\"op\":\"replace\",\"path\":\"/fields/System.Title\",\"value\":\"Title\"}]";
The string json you generated by JavaScriptSerializer is missing "[" and "]".
By the way, with the code you provided, if you run GetWorkItem(uri) before UpdateWorkItemStatus(uri, httpContent), UpdateWorkItemStatus() won't run since the app exit after GetWorkItem().

Related

Re-generating Postman request from C#

I'm having an issue creating a POST request from C# to generate a token. There's nothing wrong with the service because I can consume it using Postman.
Can someone help my out.
Following my coding. Every time I get a 403 error.
public async Task<string> LoginAsync(string userName, string password)
{
try
{
var keyValues = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "client_credentials")
};
var request = new HttpRequestMessage(HttpMethod.Post, login_url);
request.Content = new FormUrlEncodedContent(keyValues);
var client = new HttpClient();
var authenticationBytes = System.Text.Encoding.ASCII.GetBytes("----------username-------- : ----------pwd----------");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(authenticationBytes));
//request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(authenticationBytes));
var response = await client.SendAsync(request);
var jwtResponse = await response.Content.ReadAsStringAsync(); // contains access token
JObject jwtDynamic = JsonConvert.DeserializeObject<dynamic>(jwtResponse);
accessToken = jwtDynamic.Value<string>("access_token");
Debug.WriteLine(jwtResponse);
}
catch (Exception e)
{
Console.WriteLine(e);
}
return accessToken;
}
Following are the screenshots of Postman.
Thanks a lot.
you can use generating code from postman using RestSharp Library for .Net as you can see by clicking on code button below in the picture .
best regards

C# Web API Sending Body Data in HTTP Post REST Client

I need to send this HTTP Post Request:
POST https://webapi.com/baseurl/login
Content-Type: application/json
{"Password":"password",
"AppVersion":"1",
"AppComments":"",
"UserName":"username",
"AppKey":"dakey"
}
It works great in RestClient and PostMan just like above.
I need to have this pro-grammatically and am not sure if to use
WebClient, HTTPRequest or WebRequest to accomplish this.
The problem is how to format the Body Content and send it above with the request.
Here is where I am with example code for WebClient...
private static void Main(string[] args)
{
RunPostAsync();
}
static HttpClient client = new HttpClient();
private static void RunPostAsync(){
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
Inputs inputs = new Inputs();
inputs.Password = "pw";
inputs.AppVersion = "apv";
inputs.AppComments = "apc";
inputs.UserName = "user";
inputs.AppKey = "apk";
var res = client.PostAsync("https://baseuriplus", new StringContent(JsonConvert.SerializeObject(inputs)));
try
{
res.Result.EnsureSuccessStatusCode();
Console.WriteLine("Response " + res.Result.Content.ReadAsStringAsync().Result + Environment.NewLine);
}
catch (Exception ex)
{
Console.WriteLine("Error " + res + " Error " +
ex.ToString());
}
Console.WriteLine("Response: {0}", result);
}
public class Inputs
{
public string Password;
public string AppVersion;
public string AppComments;
public string UserName;
public string AppKey;
}
This DOES NOW WORK and responses with a (200) OK Server and Response
Why are you generating you own json?
Use JSONConvert from JsonNewtonsoft.
Your json object string values need " " quotes and ,
I'd use http client for Posting, not webclient.
using (var client = new HttpClient())
{
var res = client.PostAsync("YOUR URL",
new StringContent(JsonConvert.SerializeObject(
new { OBJECT DEF HERE },
Encoding.UTF8, "application/json")
);
try
{
res.Result.EnsureSuccessStatusCode();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
You are not properly serializing your values to JSON before sending. Instead of trying to build the string yourself, you should use a library like JSON.Net.
You could get the correct string doing something like this:
var message = JsonConvert.SerializeObject(new {Password = pw, AppVersion = apv, AppComments = acm, UserName = user, AppKey = apk});
Console.WriteLine(message); //Output: {"Password":"password","AppVersion":"10","AppComments":"","UserName":"username","AppKey":"dakey"}
var client = new RestClient("Your URL");
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/json");
request.AddHeader("apk-key", apk);
//Serialize to JSON body.
JObject jObjectbody = new JObject();
jObjectbody.Add("employeeName", data.name);
jObjectbody.Add("designation", data.designation);
request.AddParameter("application/json", jObjectbody, ParameterType.RequestBody);
try
{
var clientValue= client.Execute<Response>(request);
return RequestResponse<Response>.Create(ResponseCode.OK, "", clientValue.Data);
}
catch (Exception exception)
{
throw exception;
}
I made a tools to do it quick and easy:
Install-Package AdvancedRestHandler
or
dotnet add package AdvancedRestHandler
AdvancedRestHandler arh = new AdvancedRestHandler("https://webapi.com/baseurl");
var result = await arh.PostDataAsync<MyLoginResponse, MyLoginRequest>("/login", new MyLoginRequest{
Password = "password",
AppVersion = "1",
AppComments = "",
UserName = "username",
AppKey = "dakey"
});
public class MyLoginRequest{
public string Password{get;set;}
public string AppVersion{get;set;}
public string AppComments{get;set;}
public string UserName{get;set;}
public string AppKey{get;set;}
}
public class MyLoginResponse {
public string Token{get;set;}
}
Extra:
One other thing you can do is to use ArhResponse:
Either this way, in the class definition:
public class MyLoginResponse: ArhResponse
{
...
}
Or this way, in the API call:
var result = await arh.PostDataAsync<ArhResponse<MyLoginResponse>, MyLoginRequest> (...)
and instead of try or cache, check your API call state using simple if statements:
// check service response status:
if(result.ResponseStatusCode == HttpStatusCode.OK) { /* api receive success response data */ }
// check Exceptions that may occur due to implementation change, or model errors
if(result.Exception!=null) { /* mostly serializer failed due to model mismatch */ }
// have a copy of request and response, in case the service provider need your request response and they think you are hand writing the service and believe you are wrong
_logger.Warning(result.ResponseText);
_logger.Warning(result.RequestText);
// Get deserialized verion of, one of the fallback models, in case the provider uses more than one type of data in same property of the model
var fallbackData = (MyFallbackResponse)result.FallbackModel;
Header Possible Issue
There are cases that the Server does not accept C# request due to the header that the HttpClient generates.
It is because HttpClient by default uses the value of application/json; charset=utf-8 for Content-Type...
For sending only application/json part as Content-Type and ignore the ; charset=utf-8 part, you can do as following:
For HttpClient you can fix it by looking into this thread: How do you set the Content-Type header for an HttpClient request?
As for (AdvancedRestHandler) ARH, I fixed it due to integration with some company, but I don't remember fully... I did it, either through options like of requests or through resetting the header value.
we will use HttpPost with HttpClient PostAsync for the issue.
using System.Net.Http;
static async Task<string> PostURI(Uri u, HttpContent c)
{
var response = string.Empty;
using (var client = new HttpClient())
{
HttpResponseMessage result = await client.PostAsync(u, c);
if (result.IsSuccessStatusCode)
{
response = result.StatusCode.ToString();
}
}
return response;
}
We will call it by creating a string that we will use to post:
Uri u = new Uri("http://localhost:31404/Api/Customers");
var payload = "{\"CustomerId\": 5,\"CustomerName\": \"Pepsi\"}";
HttpContent c = new StringContent(payload, Encoding.UTF8, "application/json");
var t = Task.Run(() => PostURI(u, c));
t.Wait();
Console.WriteLine(t.Result);
Console.ReadLine();

Jira Rest API login error in JIRA SERVER using C#

I want connect to jira server using C# Rest api
https://jira.myserver.co.kr/rest/auth/1/session
enter code here
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.ContentType = "application/json";
request.Method = method;
... more
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
the remote server returned an error (404)
I tried different work arounds but all went in vain. May I know why this error is coming? What could be the resolution of this error?
You can search for a reason of this error in different ways:
by looking at logs of JIRA server, there might be some messages/stacktraces there (for example, atlasian-jira.log);
by using some tool to perform/debug/test REST calls (for example, postman), and when it's start working in tool you can write code to do it programmatically. JIRA can return description of error in the response, and tool can show it to you.
When you get this information it can give you exact reason why it is not working. Once I got 403 error and it was because threshold of unsuccessful login attempts was exceeded, I logged into JIRA server using web browser (and entered captcha), and after that I was able to obtain session through application code.
I can successfully obtain session from JIRA in the following way using postman:
Request type: POST
URL: https://myjiraserver.com/rest/auth/1/session
Body: {"username":"myusername","password":"mypassword"}
Headers: Content-Type:application/json
you can do something like this:
namespace YOUR_NAME_SPACE
{
public class jira
{
public static string createTicket(string url, string data)
{
try
{
var client = new System.Net.Http.HttpClient();
string base64Credentials = GetEncodedCredentials();
var header = new AuthenticationHeaderValue("Basic", base64Credentials);
client.DefaultRequestHeaders.Authorization = header;
var content = new StringContent(data, Encoding.UTF8, "application/json");
var result = client.PostAsync(url, content).Result;
var response = result.Content.ReadAsStringAsync().Result;
// You can call putIssue if you want
return response;
}
catch (System.Net.WebException ex)
{
Console.WriteLine("Exception Occurred" + " : {0}", ex.Message);
throw;
}
}
private static string GetEncodedCredentials()
{
string mergedCredentials = string.Format("{0}:{1}", "LOGIN", "PASSWD");
byte[] byteCredentials = UTF8Encoding.UTF8.GetBytes(mergedCredentials);
return Convert.ToBase64String(byteCredentials);
}
public static string jiraSerialise(string project, string summary, string description, string issutype, string author)
{
JObject valuesToJson =
new JObject(
new JProperty("fields",
new JObject(
new JProperty("project",
new JObject(new JProperty("key", project))),
new JProperty("summary", summary),
new JProperty("description", description),
new JProperty("issuetype",
new JObject(new JProperty("name", issutype))),
new JProperty("assignee",
new JObject(new JProperty("name", author))))));
return valuesToJson.ToString();
}
public static string putSerialize(string key, string value)
{
JObject valueToJson =
new JObject(
new JProperty(key, value));
return valueToJson.ToString();
}
public static string putIssue(string response, string author, System.Net.Http.HttpClient client)
{
JObject jsonResponse = JObject.Parse(response);
Dictionary<string, string> dictResponse = jsonResponse.ToObject<Dictionary<string, string>>();
string issueUrl = dictResponse.Last().Value;
string issueAssignee = issueUrl + "/assignee";
var authorContent = new StringContent(author, Encoding.UTF8, "application/json");
var authorResult = client.PutAsync(issueAssignee, authorContent).Result;
var authorResponse = authorResult.Content.ReadAsStringAsync().Result;
Console.WriteLine(authorResponse);
return authorResponse;
}
}
}
And now you can call this class like that:
string data = jira.jiraSerialise("lala", "nameVulnerabilty", "descriptionField", "Bug", "author");
string url = "http://YOUR_URL/rest/api/2/issue/";
Console.WriteLine(jira.createTicket(url, data));
Hope it helps :)

HttpClient: The uri string is too long

Given the following attempt to post data to a web service that generates PDF files, PDF rocket (which is awesome by the way).
I get the error Invalid URI: The uri string is too long
Why would anyone impose an arbitrary limit on POSTed data?
using (var client = new HttpClient())
{
// Build the conversion options
var options = new Dictionary<string, string>
{
{ "value", html },
{ "apikey", ConfigurationManager.AppSettings["pdf:key"] },
{ "MarginLeft", "10" },
{ "MarginRight", "10" }
};
// THIS LINE RAISES THE EXCEPTION
var content = new FormUrlEncodedContent(options);
var response = await client.PostAsync("https://api.html2pdfrocket.com/pdf", content);
var result = await response.Content.ReadAsByteArrayAsync();
return result;
}
I receive this rediculous error.
{System.UriFormatException: Invalid URI: The Uri string is too long.
at System.UriHelper.EscapeString
at System.Uri.EscapeDataString
at System.Net.Http.FormUrlEncodedContent.Encode
at System.Net.Http.FormUrlEncodedContent.GetContentByteArray
This reminds me of 640k ought to be enough... I mean really?
If, like me, you're faced with some wonky 3rd party web service that will only accept form content, you can work around the problem like this:
// Let's assume you've got your key-value pairs organised into a nice Dictionary<string, string> called formData
var encodedItems = formData.Select(i => WebUtility.UrlEncode(i.Key) + "=" + WebUtility.UrlEncode(i.Value));
var encodedContent = new StringContent(String.Join("&", encodedItems), null, "application/x-www-form-urlencoded");
// Post away!
var response = await client.PostAsync(url, encodedContent);
With a post can include the content in the http message instead of the URI. A uri has a max length of 2083 characters. You could send it as JSON in the http message instead of the URI which is the recommended way to send larger chunks of data in an HttpPost/HttpPut. I altered your code to make use of it. This assumes that your service you are contacting can work with JSON (.net Web Api out of the box should have no problem with this).
using (var client = new HttpClient())
{
// Build the conversion options
var options = new
{
value = html,
apikey = ConfigurationManager.AppSettings["pdf:key"],
MarginLeft = "10",
MarginRight = "10"
};
// Serialize our concrete class into a JSON String
var stringPayload = JsonConvert.SerializeObject(options);
var content = new StringContent(stringPayload, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://api.html2pdfrocket.com/pdf", content);
var result = await response.Content.ReadAsByteArrayAsync();
return result;
}
Make sure to install newtonsoft json.
I just solved a similar problem. For me I was integrating with a backend I didn't control and had to POST file along with form data (eg customerID) as form variables. So switching to JSON or Multipart would break the backend I didn't control. The problem was that large files would cause the FormUrlEncodedContent to throw an error saying "The uri string is too long".
This is the code that solved it for me after two days of effort (note still needs to be tweaked to be ASYNC).
private string UploadFile(string filename, int CustomerID, byte[] ImageData) {
string Base64String = "data:image/jpeg;base64," + Convert.ToBase64String(ImageData, 0, ImageData.Length);
var baseAddress = new Uri("[PUT URL HERE]");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { AllowAutoRedirect = true, UseCookies = true, CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
try {
//ENCODE THE FORM VARIABLES DIRECTLY INTO A STRING rather than using a FormUrlEncodedContent type which has a limit on its size.
string FormStuff = string.Format("name={0}&file={1}&id={2}", filename, HttpUtility.UrlEncode(Base64String), CustomerID.ToString());
//THEN USE THIS STRING TO CREATE A NEW STRINGCONTENT WHICH TAKES A PARAMETER WHICH WILL FormURLEncode IT AND DOES NOT SEEM TO THROW THE SIZE ERROR
StringContent content = new StringContent(FormStuff, Encoding.UTF8, "application/x-www-form-urlencoded");
//UPLOAD
string url = string.Format("/ajax/customer_image_upload.php");
response = client.PostAsync(url, content).Result;
return response.Content.ToString();
}
catch (Exception ex) {
return ex.ToString();
}
}
}
#Mick Byrne :
Thanks - your solution worked like a charme!
Here is my complete code:
public async Task DateienSendenAsync (string PfadUndDatei, string Dateiname, String VRPinGUID, String ProjektGUID, String VRPinX, String VRPinY, String VRPinZ)
{
var client = new HttpClient();
// Create the HttpContent for the form to be posted.
var requestContent = new[] {
new KeyValuePair<string, string>("dateiname", Dateiname),
new KeyValuePair<string, string>("bild", Convert.ToBase64String(File.ReadAllBytes(PfadUndDatei))),
new KeyValuePair<string, string>("VRPinGUID", VRPinGUID),
new KeyValuePair<string, string>("ProjektGUID", ProjektGUID),
new KeyValuePair<string, string>("ebene", "ebene"),
new KeyValuePair<string, string>("raumnummer", "raumnummer"),
new KeyValuePair<string, string>("ansichtsname", "ansichtsname"),
new KeyValuePair<string, string>("VRPinX", VRPinX),
new KeyValuePair<string, string>("VRPinY", VRPinY),
new KeyValuePair<string, string>("VRPinZ", VRPinZ),
};
String url = "http://yourhomepage/path/upload.php";
var encodedItems = requestContent.Select(i => WebUtility.UrlEncode(i.Key) + "=" + WebUtility.UrlEncode(i.Value));
var encodedContent = new StringContent(String.Join("&", encodedItems), null, "application/x-www-form-urlencoded");
// Post away!
var response = await client.PostAsync(url, encodedContent);
}

REST API Request constantly returning HTML instead of JSON

For the last few hours, I've been trying to write a separate project for consuming an API. Documentation/examples for it are here.
Sadly, I can't get an "application/json" response from it, even with example values from documentation. Here's the code for my method with example values (which is copy/pasted from the documentation). I've tried a few modifications but I don't even know where to start digging.
public async void SendOrder()
{
using (var httpClient = new HttpClient { BaseAddress = baseAddress })
{
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("authorization", "Bearer 3e5cac39-7e38-4139-8fd6-30adc06a61bd");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (var content = new StringContent("{ \"notifyUrl\": \"https://your.eshop.com/notify\", \"customerIp\": \"127.0.0.1\", \"merchantPosId\": \"145227\", \"description\": \"RTV market\", \"currencyCode\": \"PLN\", \"totalAmount\": \"21000\", \"products\": [ { \"name\": \"Wireless mouse\", \"unitPrice\": \"15000\", \"quantity\": \"1\" }, { \"name\": \"HDMI cable\", \"unitPrice\": \"6000\", \"quantity\": \"1\" } ]}", Encoding.UTF8, "application/json"))
{
using (var response = await httpClient.PostAsync("api/v2_1/orders/", content/*, null, "application/json"*/))
{
string responseData = await response.Content.ReadAsStringAsync();
}
}
}
}
responseData value - http://pastebin.com/t3EYyP8w
I would give RestSharp a try, can install it via Nuget. Has a easy way of doing it. http://restsharp.org/
var client = new RestClient("https://Whatever.com/api/");
client.Authenticator = new HttpBasicAuthenticator("Bearer", "YourToken");
//Add the Method you are executing from API
var request = new RestRequest("resource/{id}", Method.POST);
//Add your paramers like this
request.AddParameter("name", "value");
//Json
request.RequestFormat = DataFormat.Json;
//Execute Post
var response = client.execute(request);
//If you want to turn Json into Model
var responseModel = JsonConvert.DeserializeObject<YourObject>(response.Content);

Categories

Resources