Download "Visual Studio Team Services" Charts via WebRequest - c#

I need to upgrade an old TFS 2013 class for Visual Studio Team Services.
To get the Burndown-Chart I used to download the image via HttpWebRequest direcly from the url.
Somehow Iam not able to do this in VSTS. I always get the error message "invalid parameters". Everything else works fine. (I had to setup the Alternate authentication credentials in my profile to get it working for my application)
Here my code:
public Image GetChart(string uri)
{
HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(uri);
httpWebRequest.Credentials = new NetworkCredential("MyUserNameForApplication", "MyPWForApplication");
using (HttpWebResponse httpWebReponse = (HttpWebResponse)httpWebRequest.GetResponse())
{
using (Stream stream = httpWebReponse.GetResponseStream())
{
return Image.FromStream(stream); //Error occourse
}
}
}
The url which gets passed as a parameter usally looks like this:
https://YourVSName.visualstudio.com/DefaultCollection/a5d2310b-d3f8-4365-b693-3826ab60e939/_api/_teamChart/Burndown?chartOptions={%22Width%22%3A1248%2C%22Height%22%3A161%2C%22ShowDetails%22%3Atrue%2C%22Title%22%3A%22%22}&counter=1&iterationPath=Developing\Sprint+1&__v=5
What I think the problem is:
First I thought this might be a security issue, because this code is able to download normal google images. And when I try to get the content of the url It returns a lot of code with a message in it:
Microsoft Internet Explorer's Enhanced Security Configuration is currently enabled on your environment. This enhanced level of security prevents our web integration experiences from displaying or performing correctly. To continue with your operation please disable this configuration or contact your administrator
I set my Internet security settings to the lowest level and still the same result.
Another reason why this might not working is, because the url linking to the burndown-chart doesnt contain an Image extension. Iam not quite shure here this effects the result.
Or that the parameters which are getting past in the url are incorrect...
What I have tried so far:
I have used bunch of other code to get the image from that link. For example using WebClient or tried to upload cookies (credentials) to the tfs and than tried to connect.
My Question
Is it possible to get that image from the chart via url, and if so, how?
Thanks for any kind of help :).
EDIT
Currently Iam using this code (Thanks to #Eddie - MSFT):
public static async void GetChart(string uri,string username, string password)
{
try
{
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", username, password))));
using (HttpResponseMessage response = client.GetAsync(uri).Result)
{
response.EnsureSuccessStatusCode();
var responseStream = await response.Content.ReadAsStreamAsync();
var img = Image.FromStream(responseStream);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
static void Main(string[] args)
{
string uri = "https://Name.visualstudio.com/DefaultCollection/a5d2310b-d3f8-4365-b693-3826ab60e939/_api/_teamChart/Burndown?chartOptions=%7B%22Width%22%3A1248%2C%22Height%22%3A636%2C%22ShowDetails%22%3Atrue%2C%22Title%22%3A%22%22%7D&counter=1&iterationPath=Developing%5CSprint+1&__v=5";
TFSHelper.TFSHelper.GetChart(uri, username,pw)
}

I use "httpclient" with alternative credential to do this:
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Net.Http;
using System.Net.Http.Headers;
using System.IO;
namespace GetImageA
{
class Program
{
static void Main(string[] args)
{
Uri uri = new Uri("your image uri");
GetImage(uri);
}
public static void GetImage(Uri uri)
{
var username = "username";
var password = "password";
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))));
Stream str = client.GetStreamAsync(uri).Result;
Image im = Image.FromStream(str);
im.Save("E:\\image.png");
}
}
}
}

Did you try the authentication with your personal access token instead of username and password, something like this?
I am using the below code to download the attachments, inline images of the Work items from VSTS.
try
{
var personalaccesstoken = "Your_VSTS_Personal_Access_Token";
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", "", personalaccesstoken))));
using (HttpResponseMessage response = client.GetAsync(uri).Result)
{
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}

Related

How can I execute an url call from C# code on a ASP website on a ASCX page?

I need to call a Custom protocol (something like: "custom:signDocs?param1=value?param2=value") that is registered on a client.
I have a working one that is executed via JavaScript on a button click.
But I need to call the url to execute the program I have on the clients pc.
The program is for signing documents and sending them back to the server, and, in the code I have a 15min timer that waits for the status of the documents to change to signed then it shows the documents to the user.
I also tried using webrequest:
//Method that uses the webrequest
{
System.Net.WebRequest.RegisterPrefix("customProtocolName", new PrototipoIDPTRequestCreator());
System.Net.WebRequest req = System.Net.WebRequest.Create(protocolUrlWithParams);
var aux = req.GetResponse();
}
internal class CustomRequestCreator : System.Net.IWebRequestCreate
{
public WebRequest Create(Uri uri)
{
return new CustomWebRequest(uri);
}
}
class CustomWebRequest: WebRequest
{
public override Uri RequestUri { get; }
public CustomWebRequest(Uri uri)
{
RequestUri = uri;
}
}
But this does nothing, I do not know it its even the right path...
Does anyone know of a way to accomplish this?
You can use HttpClient from System.Net.Http like the following example.
Simple get call from a test api endpoint.
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("YOUR_BASE_URL"); //https://localhost:8000
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("api/test"); //api uri
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
}
Note: For more details refer, HttpClient Doc

How to Retrieve file from URL which Requires Authentication?

I'm making a tool in Unity to retrieve data from a server. The server's interface can provide URLs that we can later click on which will return an XML or CSV file with the results of that query from that server. But, it requires Basic Authentication. When clicking the links, it simply pops up a login screen before giving me the results. If I try what I [think] I know in Unity (starting with WebRequest.GetResponse()) it simply fails and says I am not authorized. It does not show the popup for authentication. So how do I let that login popup appear when accessing with Unity and await the login results to get the file? Or is there some standardized way to provide that info in the link itself?
Here is some code that should you get started. Just fill in the request link and username, password. please see the comments in the code to see what it does.
//try just in case something went wrong whith calling the api
try
{
//Use using so that if the code end the client disposes it self
using (HttpClient client = new HttpClient())
{
//Setup authentication information
string yourusername = "username";
string yourpwd = "password";
//this is when you expect json to return from the api
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//add the authentication to the request
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes($"{yourusername}:{yourpwd}")));
//api link used to make the call
var requestLink = $"apiLink";
using (HttpResponseMessage response = client.GetAsync(requestLink).Result)
{
//Make sure the request was successfull before proceding
response.EnsureSuccessStatusCode();
//Get response from website and convert to a string
string responseBody = response.Content.ReadAsStringAsync().Result;
//now you have the results
}
}
}
//Catch the exception if something went from and show it!
catch (Exception)
{
throw;
}
This is what I ended up going with after looking at the comments above. Let me know if I'm doing anything terribly inefficient!
String username = "Superman"; // Obviously handled secretly
String pw = "ILoveLex4evar!"; // Obviously handled secretly
String url = "https://www.SuperSecretServer.com/123&stuff=?uhh";
String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + pw));
CookieContainer myContainer = new CookieContainer();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.Add("Authorization", "Basic " + encoded);
try
{
using (WebResponse response = request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
using (FileStream xml = File.Create("filepath/filename.xml"))
{
byte[] buffer = new byte[BufferSize];
int read;
while ((read = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
xml.Write(buffer, 0, read);
}
}
}
}
}

Connect to TFS programmatically from vs 2017

I am using TFS 15.x. package.
Error:
Microsoft.TeamFoundation.TeamFoundationServerUnauthorizedException:
'TF30063: You are not authorized to access
"https://myproject.visualstudio.com/RpaCodeReview'
Uri Repurl = new Uri("https://myproject.visualstudio.com/RpaCodeReview");
NetworkCredential netCred = new NetworkCredential(username, password);
VssBasicCredential basicCred = new VssBasicCredential(netCred);
VssCredentials tfsCred = new VssCredentials(basicCred);
TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(Repurl, tfsCred);
tpc.EnsureAuthenticated();
It depends on the version of your TFS. However, if you're trying to connect to TFS2015, or TFS2017, this will do;
using Microsoft.TeamFoundation.Client;
using Microsoft.VisualStudio.Services.Common;
using System;
using System.Net;
namespace TFSConsoleApp
{
class Program
{
static void Main(string[] args)
{
NetworkCredential networkCredentials = new NetworkCredential(#"Domain\Account", #"Password");
Microsoft.VisualStudio.Services.Common.WindowsCredential windowsCredentials = new Microsoft.VisualStudio.Services.Common.WindowsCredential(networkCredentials);
VssCredentials basicCredentials = new VssCredentials(windowsCredentials);
TfsTeamProjectCollection tfsColl = new TfsTeamProjectCollection(
new Uri("http://XXX:8080/tfs/DefaultCollection"),
basicCredentials);
tfsColl.Authenticate(); // make sure it is authenticate
}
}
}
I cannot stress enough to ensure the credentials are a-okay! This error has occured to me a couple times too.
There is also another solution if the above doesn't work.
Close Visual Studio and go to Control Panel
User Accounts --> Manage your Credentials (on the left column)
Select "Windows Credentials"
Scroll down to the "Generic Credentials" section and look for
your TFS server connection
Expand the pull down and click "Edit"
Enter in your network password
Restart Visual Studio and retry the code
Along with all the comments on credentials I have found basic authentication blocked on some repositories.
I have found it best to create Personal Access Token (PAT) in the repository. Then use that in you connections to access the APIs.
Example to read what projects are in the default collection of a tfs/devops repo:
string PAT = "Put PAT String Here";
string RepoStore = "https://url of repo here";
string responseBody = "";
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", "", PAT))));
using (HttpResponseMessage response = client.GetAsync(
RepoStore + "/_apis/projects").Result)
{
response.EnsureSuccessStatusCode();
responseBody = await response.Content.ReadAsStringAsync();
}
Console.WriteLine(responseBody);
}
Console.ReadKey();

.NETCore HttpWebRequest - Old Way isn't Working

Before I upgraded to the newest .NetCore I was able to run the HttpWebRequest, add the headers and content Type and pull the stream of the JSON file from Twitch. Since the upgrade this is not working. I receive a Web Exception each time I go to get the response Stream. Nothing has changed with twitch because it still works with the old Bot. The old code is below:
private const string Url = "https://api.twitch.tv/kraken/streams/channelname";
HttpWebRequest request;
try
{
request = (HttpWebRequest)WebRequest.Create(Url);
}
request.Method = "Get";
request.Timeout = 12000;
request.ContentType = "application/vnd.twitchtv.v5+json";
request.Headers.Add("Client-ID", "ID");
try
{
using (var s = request.GetResponse().GetResponseStream())
{
if (s != null)
using (var sr = new StreamReader(s))
{
}
}
}
I have done some research and found that I may need to start using either an HttpClient or HttpRequestMessage. I have tried going about this but when adding headers content type the program halts and exits. after the first line here: (when using HttpsRequestMessage)
request.Content.Headers.ContentType.MediaType = "application/vnd.twitchtv.v5+json";
request.Content.Headers.Add("Client-ID", "rbp1au0xk85ej6wac9b8s1a1amlsi5");
You are trying to add a ContentType header, but what you really want is to add an Accept header (your request is a GET and ContentType is used only on requests which contain a body, e.g. POST or PUT).
In .NET Core you need to use HttpClient, but remember that to correctly use it you need to leverage the use of async and await.
Here it is an example:
using System.Net.Http;
using System.Net.Http.Headers;
private const string Url = "https://api.twitch.tv/kraken/streams/channelname";
public static async Task<string> GetResponseFromTwitch()
{
using(var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.twitchtv.v5+json"));
client.DefaultRequestHeaders.Add("Client-ID", "MyId");
using(var response = await client.GetAsync(Url))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync(); // here we return the json response, you may parse it
}
}
}

Using RESTapi to connect to TFS online from code

I am trying to get access to my projects in TFS online from my C# code in order to get all the data about builds, tasks, projects etc. with the RESTapi, I have been following the documentation available online to do so (http://www.visualstudio.com/en-us/integrate/get-started/get-started-rest-basics-vsi), however, when I want to get the Json response from the url, I always get: HTTP code 203: Non-Authoritative Information, and therefore I am not able to get the Json data. If I try to get the response using POSTMAN (chrome extension) I get an HTTP code 200 and the data I need.
This is my code:
public static async void GetBuilds()
{
try
{
var username = "userTest";
var password = "PassTest";
using (HttpClient client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(
System.Text.ASCIIEncoding.ASCII.GetBytes(
string.Format("{0}:{1}", username, password))));
using (HttpResponseMessage response = client.GetAsync(
"https://myproject.visualstudio.com/DefaultCollection/_apis/build/builds?api-version=1.0-preview.1").Result)
{
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseBody);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
I always get in the response a high amount of HTML but nothing close to what I need, what am I doing wrong?
Many thanks in advance for your time.
Your code seems correct to me. Have you enabled alternate credentials for your VSO account? It won't work without it. Here's the link explaining how to do it.
You can also check out my project on the codeplex: https://vsorest.codeplex.com/ It shows how to use some of the VSO REST APIs using C#

Categories

Resources