I've put together some my solution, and I'm finally able to get a response from Zephyr, but it is giving me a 404 response, when I know that it is available. Is anyone else trying to use ZAPI to report test data?
The secret and access key comes from the Jira page that Zephyr adds. The project key comes from Jira. Here is my code and the response it gives me:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Jira.SDK.Domain;
using JWT;
namespace WebPortalUITests.Controllers
{
[TestClass]
public class Reporting
{
static string User = "My.User.Name";
static string Password = "My.Password";
static string jiraBaseUrl = "https://mycompany.atlassian.net/";
static string zephyrBaseUrl = "https://prod-api.zephyr4jiracloud.com/connect";
static string Secret = "P1oihENe5PLUS_THE_REST_OF_MY_SECRET";
static string AccessKey = "amlyYTox_PLUS_THE_REST_OF_MY_KEY";
public async Task<bool> CycleExists(string Name)
{
//connect to Jira to get project and version IDs using the Jira.SDK library
Jira.SDK.Jira jira = new Jira.SDK.Jira();
jira.Connect(jiraBaseUrl, User, Password);
Project webPortal = jira.GetProject("WP");
long id = webPortal.ID;
long version = webPortal.ProjectVersions.Last<ProjectVersion>().ID;
//format the Zephyr request and use it to generate a JWT
string request = "/connect/public/rest/api/1.0/cycles/search?versionId=" + version + "&projectId=" + id;
string finalAPI = zephyrBaseUrl + request;
string token = JsonWebToken.Encode(finalAPI, Secret, JwtHashAlgorithm.HS256);
//put the JWT and the accesskeys in the header and request the info
using (var httpClient = new HttpClient { BaseAddress = new Uri(zephyrBaseUrl)})
{
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("authorization", "JWT "+token);
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("zapiaccesskey", AccessKey);
using (var response = httpClient.GetAsync(string.Format(request)).Result)
{
string responseData = await response.Content.ReadAsStringAsync();
}
return true;
}
}
}
}
response {StatusCode: 404, ReasonPhrase: 'Not Found', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Connection: keep-alive
Date: Thu, 26 Jan 2017 20:34:01 GMT
Server: Apache-Coyote/1.1
Content-Length: 0
}} System.Net.Http.HttpResponseMessage
Related
Can someone please help on this issue, i gets hang and no error is coming.
Seems like ends up with some unknow issue.
I am attaching my code before and after upgrading the restsharp library.
Code in Rest sharp version 106.12.00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RestSharp;
namespace ConsoleApp5
{
class Program
{
static void Main(string[] args)
{
var client = new RestClient("https://shoonyatrade.finvasia.com/NorenWClientTP/QuickAuth");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "text/plain");
var body = #"jData={""apkversion"":""1.0.0"",""uid"":""123456""}";
request.AddParameter("text/plain", body, ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
}
}
}
Code after upgrading to 108.0.1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RestSharp;
namespace ConsoleApp5
{
class Program
{
static void Main(string[] args)
{
var client = new RestClient("https://shoonyatrade.finvasia.com/NorenWClientTP/QuickAuth");
client.Options.MaxTimeout = -1;
var request = new RestRequest("",Method.Post);
request.AddHeader("Content-Type", "text/plain");
var body = #"jData={""apkversion"":""1.0.0"",""uid"":""123456""}";
request.AddParameter("text/plain", body, ParameterType.RequestBody);
RestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
}
}
}
Expected Response
{"stat":"Not_Ok","emsg":"Invalid Input : uid or pwd or factor2 or imei or apkversion or vc or appkey or source is Missing."}
Postman Authorisation
Postman Headers
PostMan Results (Expected)
The docs clearly say that you should not use AddParameter with content-type as the parameter name. It won't work.
Use AddStringBody as described in the docs.
request.AddStringBody(body, "text/plain);
You would spend way less time figuring out what's wrong by sending requests to something like requestbin.com and analysing the actual content of it.
Adding this line solved my issue
System.Net.ServicePointManager.Expect100Continue = false;
I have used fiddler to understand what actual request is going on web.
using RestSharp;
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp5
{
class Program
{
static async Task Main(string[] args)
{
System.Net.ServicePointManager.Expect100Continue = false;
var client = new RestClient("https://shoonyatrade.finvasia.com/NorenWClientTP/QuickAuth");
var request = new RestRequest("",Method.Post);
var body = #"jData={""apkversion"":""1.0.0"",""uid"":""123456""}";
request.AddParameter("text/plain", body, ParameterType.RequestBody);
RestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
}
}
}
I am unable to create Work Item using Azure DevOps REST API as mentioned in Work Items - Create
Request:
https://dev.azure.com/{organization}/MyTestProject/_apis/wit/workitems/$Task?api-version=6.0-preview.3
Request Body:
[
{
"op": "add",
"path": "/fields/System.Title",
"value": "Task2"
}
]
Code to Get Response (Note this code works for all other POST Requests):
using (HttpResponseMessage response = client.SendAsync(requestMessage).Result)
{
response.EnsureSuccessStatusCode();
JsonResponse = await response.Content.ReadAsStringAsync();
}
Response: 400
Can someone please suggest?
It might be helpful to see your full example. However, here is a working example with Newtonsoft.Json (do not forget to create your PAT create personal access token):
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
string PAT = "<personal access token>"; //https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page
string requestUrl = "https://dev.azure.com/<my_org>/<my_project>/_apis/wit/workitems/$Task?api-version=5.0";
try
{
List<Object> flds = new List<Object>
{
new { op = "add", path = "/fields/System.Title", value = "Title" }
};
string json = JsonConvert.SerializeObject(flds);
HttpClientHandler _httpclienthndlr = new HttpClientHandler();
using (HttpClient client = new HttpClient(_httpclienthndlr))
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", "", PAT))));
var request = new HttpRequestMessage(new HttpMethod("PATCH"), requestUrl)
{
Content = new StringContent(json, Encoding.UTF8, "application/json-patch+json")
};
HttpResponseMessage responseMessage = client.SendAsync(request).Result;
}
}
catch (Exception ex)
{
}
}
}
}
Additionally, you can consider to use .NET client libraries for Azure DevOps and TFS. Here is the example: Create a bug in Azure DevOps Services using .NET client libraries
application/json-patch+json is required.
I have an existing and functioning API, which now have to be able to get data from another external API. How do i do that best?
I have tried with using HTTPClient, but i can't seem to get it to work. The error i get:
"No MediaTypeFormatter is available to read an object of type 'IList`1' from content with media type 'text/html'." -> I get this error on line 37. Can you spot it and/or tell me how I can do this differently, taking into account that all i want is the data (From the external API) and not to display it using a view, as this is an API?
Code below. I have also created a Pastebin: https://pastebin.com/MuKjEVys
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net;
namespace API.Controllers
{
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
public class ExternalApiController : Controller
{
private string ExternalApiLink = "https://blablabla.com/api";
private string ExternalApiLinkGet = "/module/1/";
[HttpGet("getdata")]
public ActionResult<ExternalApi> GetDataFromExternal()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(ExternalApiLink);
var requestApi = client.GetAsync(ExternalApiLinkGet);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "XXXX");
requestApi.Wait();
var resultFromApi = requestApi.Result;
if (resultFromApi.IsSuccessStatusCode)
{
var readResponse = resultFromApi.Content.ReadAsAsync<IList<ExternalApi>>();
readResponse.Wait();
var data = readResponse.Result;
return Json(data);
}else
{
return NotFound();
}
}
}
}
}
Your response content seems to be json, while the content-type is text/html. If that is the case, the first thing to do would be to call the party that is exposing the service and have them fix it. In the meantime you could just read the content of the response as a string, and deserialize that string:
// Note that I made this method async.
public async Task<IActionResult> GetDataFromExternal()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(ExternalApiLink);
// note that I moved this line above the GetAsync method.
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "XXXX");
// note that I'm disposing the response
using (var response = await client.GetAsync(ExternalApiLinkGet))
{
if (response.IsSuccessStatusCode)
{
// Since the response content is json, but the content-type
// is text/html, simply read the content as a string.
string content = await response.ReadAsStringAsync();
// You can return the actual received content like below,
// or you may deserialize the content before returning to make
// sure it is correct, using JsonConvert.DeserializeObject<List<ExternalApi>>()
// var data = JsonConvert.DeserializeObject<List<ExternalApi>>(content);
// return Json(data);
return Content(content, "application/json");
}
else
{
return NotFound();
}
}
}
}
I am trying to get the totals for each email statistic metrics for all sub users.
However I am getting an authorized required message:
I cannot figure out what is the issue. I have referenced the sendgrid api online and this should be the correct format.
https://github.com/sendgrid/sendgrid-csharp
Unauthorized {"errors":[{"field":null,"message":"authorization
required"}]} Connection: keep-alive Access-Control-Allow-Methods:
HEAD, GET, PATCH, PUT, POST, OPTIONS, DELETE Access-Control-Max-Age:
21600 Access-Control-Expose-Headers: Link Access-Control-Allow-Origin:
* Access-Control-Allow-Headers: AUTHORIZATION, Content-Type, On-behalf-of, x-sg-elas-acl Content-Security-Policy: default-src
https://api.sendgrid.com; frame-src 'none'; object-src 'none'
X-Content-Type-Options: nosniff Strict-Transport-Security:
max-age=31536000 Date: Wed, 02 Nov 2016 16:25:29 GMT Server: nginx
Here is the code I am using:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SendGrid;
using Newtonsoft.Json; // You can generate your JSON string yourelf or with another library if you prefer
using System.Web.Script.Serialization;
using SendGrid.Helpers.Mail;
namespace SendGridSubStats
{
class Program
{
static void Main(string[] args)
{
Execute().Wait();
}
static async Task Execute()
{
string apiKey = Environment.GetEnvironmentVariable("APIKEY_GOES_HERE", EnvironmentVariableTarget.User);
dynamic sg = new SendGridAPIClient(apiKey);
// Retrieve the totals for each email statistic metric for all subusers.
// GET /subusers/stats/sums
string queryParams = #"{
'aggregated_by': 'day',
'end_date': '2016-04-01',
'limit': 1,
'offset': 1,
'sort_by_direction': 'asc',
'sort_by_metric': 'test_string',
'start_date': '2016-01-01'
}";
dynamic response = await sg.client.subusers.stats.sums.get(queryParams: queryParams);
Console.WriteLine(response.StatusCode);
Console.WriteLine(response.Body.ReadAsStringAsync().Result);
Console.WriteLine(response.Headers.ToString());
Console.ReadLine();
}
}
}
I've asked this on the AWS Forums but getting plenty of views but no comments, I wonder if anyone here can shed any light on it?
Hi,
I've been trying to write a simple c# console application to call the topsites service for two days now and still get issues with the signature generation.
I've tested using a java sample in the gallery and can successfully query using my accesskeyid and secret. I've then used my C# code to prove I can generate the same signature and my code will do so, however when I then craft a request and issue it against the api every single one returns a 403 status - signaturedoesnotmatch - please can someone help me find out what the issue is? I'm tearing my hair out with this.
C# Code:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace ConsoleApplication1
{
class Program
{
private static string baseUrl = ConfigurationManager.AppSettings["baseUrl"];
private static string accessKeyId = ConfigurationManager.AppSettings["accessKeyId"];
private static string accessKey = ConfigurationManager.AppSettings["accessKey"];
private static string serviceVersion = ConfigurationManager.AppSettings["serviceVersion"];
static void Main(string[] args)
{
HttpClient client = new HttpClient();
string requestParameters = "AWSAccessKeyId=" + accessKeyId + "&Action=TopSites&Count=10&CountryCode=&ResponseGroup=Country&SignatureMethod=HmacSHA256&SignatureVersion=2&Start=1001&Timestamp=" + Amazon.Util.AWSSDKUtils.FormattedCurrentTimestampISO8601;
var signature = generateSignature(requestParameters);
var url = "http://" + baseUrl + "?" + requestParameters + "&Signature=" + signature;
HttpResponseMessage message = client.GetAsync(url).Result;
Console.ReadKey();
}
private static string generateSignature(string queryParameters)
{
string stringToSign = "GET\n" + baseUrl + "\n/\n" + queryParameters;
var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);
var secretKeyBytes = Encoding.UTF8.GetBytes(accessKey);
var hmacSha256 = new HMACSHA256(secretKeyBytes);
var hashBytes = hmacSha256.ComputeHash(bytesToSign);
var signature = System.Net.WebUtility.UrlEncode(Convert.ToBase64String(hmacSha256.Hash));
Trace.Write("String to sign:{0}", signature);
return signature;
}
}
}
Request generated (from Fiddler):
GET http://ats.amazonaws.com/?AWSAccessKeyId=REMOVED&Action=TopSites&Count=10&CountryCode=&ResponseGroup=Country&SignatureMethod=HmacSHA256&SignatureVersion=2&Start=1001&Timestamp=2014-11-20T16:57:52.422Z&Signature=vdKOQYRmoJJL3ecY9GAzmGKHAXevoli6rGcEotGFaNY%3D HTTP/1.1
Host: ats.amazonaws.com
Connection: Keep-Alive
Response:
HTTP/1.1 403 Forbidden
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
Date: Thu, 20 Nov 2014 16:57:52 GMT
16d
SignatureDoesNotMatchThe request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.84291dc8-a35e-7dc3-7cc1-56fe20b5b236
0
Based on Darrel's comment and extensive comparisons between requests from the Java app and my sample app I've been able to correctly query the services using a number of requests including the sample one above. It would appear to have been a problem whereby the request string which is signed had an erroneous space character in front of the hostname, for added resiliency I am using the Amazon AWS SDK for .Net to perform the Url Encoding against their requirements to ensure the encoding is correct.
Here's the working sample code:
using System;
using System.Configuration;
using System.Diagnostics;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
private static string baseUrl = ConfigurationManager.AppSettings["AlexaServiceUrl"];
private static string accessKeyId = ConfigurationManager.AppSettings["AlexaAccessKeyId"];
private static string accessKey = ConfigurationManager.AppSettings["AlexaAccessKey"];
private static string serviceVersion = ConfigurationManager.AppSettings["AlexaServiceVersion"];
static void Main(string[] args)
{
HttpClient client = new HttpClient();
string requestParameters = "AWSAccessKeyId=" + accessKeyId + "&Action=TopSites&Count=10&CountryCode=&ResponseGroup=Country&SignatureMethod=HmacSHA256&SignatureVersion=2&Start=1001&Timestamp=" + Amazon.Util.AWSSDKUtils.UrlEncode(Amazon.Util.AWSSDKUtils.FormattedCurrentTimestampISO8601, false);
var signature = generateSignature(requestParameters);
var url = "http://" + baseUrl + "/?" + requestParameters + "&Signature=" + signature;
HttpResponseMessage message = client.GetAsync(url).Result;
Console.ReadKey();
}
private static string generateSignature(string queryParameters)
{
string stringToSign = String.Format("GET{0}{1}{2}/{3}{4}", "\n", baseUrl, "\n", "\n", queryParameters);
var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);
var secretKeyBytes = Encoding.UTF8.GetBytes(accessKey);
var hmacSha256 = new HMACSHA256(secretKeyBytes);
var hashBytes = hmacSha256.ComputeHash(bytesToSign);
var signature = Amazon.Util.AWSSDKUtils.UrlEncode(Convert.ToBase64String(hmacSha256.Hash), false);
Trace.Write("String to sign:{0}", signature);
return signature;
}
}
}
Hope this helps someone else too.