Need to store the image from a private git repository to a blob using C#. Tried with below code but getting 404 errors.
I am using the below code from
C# example of downloading GitHub private repo programmatically
var githubToken = "[token]";
var url =
"https://github.com/[username]/[repository]/archive/[sha1|tag].zip";
var path = #"[local path]";
using (var client = new System.Net.Http.HttpClient())
{
var credentials = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}:", githubToken);
credentials = Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(credentials));
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", credentials);
var contents = client.GetByteArrayAsync(url).Result;
System.IO.File.WriteAllBytes(path, contents);
}
Note: Able to fetch from the public repository
How to fix :
The URL is changed to GET /repos/:owner/:repo/:archive_format/:ref. See https://developer.github.com/v3/repos/contents/#get-archive-link
For private repositories, these links are temporary and expire after five minutes.
GET /repos/:owner/:repo/:archive_format/:ref
You should not pass the credentials using basic authentication. Instead, you should create a token by following the official docs. see https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line
Finally, you need pass an extra User-Agent header. It is required by GitHub API. See https://developer.github.com/v3/#user-agent-required :
All API requests MUST include a valid User-Agent header.
Demo
public class GitHubRepoApi{
public string EndPoint {get;} = "https://api.github.com/repos";
public async Task DownloadArchieveAsync(string saveAs, string owner, string token, string repo,string #ref="master",string format="zipball")
{
var url = this.GetArchieveUrl(owner, repo, #ref, format);
var req = this.BuildRequestMessage(url,token);
using( var httpClient = new HttpClient()){
var resp = await httpClient.SendAsync(req);
if(resp.StatusCode != System.Net.HttpStatusCode.OK){
throw new Exception($"error happens when downloading the {req.RequestUri}, statusCode={resp.StatusCode}");
}
using(var fs = File.OpenWrite(saveAs) ){
await resp.Content.CopyToAsync(fs);
}
}
}
private string GetArchieveUrl(string owner, string repo, string #ref = "master", string format="zipball")
{
return $"{this.EndPoint}/{owner}/{repo}/{format}/{#ref}"; // See https://developer.github.com/v3/repos/contents/#get-archive-link
}
private HttpRequestMessage BuildRequestMessage(string url, string token)
{
var uriBuilder = new UriBuilder(url);
uriBuilder.Query = $"access_token={token}"; // See https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line
var req = new HttpRequestMessage();
req.RequestUri = uriBuilder.Uri;
req.Headers.Add("User-Agent","My C# Client"); // required, See https://developer.github.com/v3/#user-agent-required
return req;
}
}
Test :
var api = new GitHubRepoApi();
var saveAs= Path.Combine(Directory.GetCurrentDirectory(),"abc.zip");
var owner = "newbienewbie";
var token = "------your-----token--------";
var repo = "your-repo";
var #ref = "6883a92222759d574a724b5b8952bc475f580fe0"; // will be "master" by default
api.DownloadArchieveAsync(saveAs, owner,token,repo,#ref).Wait();
According to the message you provide, you use the wrong url to download. Regarding how to get the download url, please refer to the following steps:
Use the following url to get the download url
Method: GET
URL: https://api.github.com/repos/:owner/:repo/contents/:path?ref:<The name of the commit/branch/tag>
Header:
Authorization: token <personal access token>
The repose body will tell you the download url
For example :
Download file
For more details, please refer to https://developer.github.com/v3/repos/contents/#get-contents.
Related
In UI, the input type for SourceOfWealthOrIncome is a checkbox. In the front-end Razor page, I am using Flurl to issue a POST request.
var baseUrl = configuration.GetSection("xxx").GetValue<string>("Url");
string endPoint = "/Api/test/";
string url = string.Format("{0}{1}{2}", baseUrl, endPoint, ecddClientId);
var response = await url.SetQueryParams(new { id = ecddClientId, dealerCode })
.PostMultipartAsync(mp =>
{
mp = mp.AddString("SourceOfWealthOrIncome", postData.SourceOfWealthOrIncome);
foreach (var doc in postData.SupportingDocs)
{
mp = mp.AddFile("SupportingDocs", doc.FileContent, doc.FileName);
}
});
Troubleshoot: If I changed from SourceOfWealthOrIncome[] to SourceOfWealthOrIncome, I can see the values of the checkbox for example "value1, value2". But I can't change the endpoint code. This is the code for endpoint in C# in .NET Framework 4.x.
[HttpPost]
public async Task<IHttpActionResult> PutEnhancedCdd(int id, string dealerCode)
{
string root = Path.GetTempPath();
var provider = new MultipartFormDataStreamProvider(root);
await Request.Content.ReadAsMultipartAsync(provider);
var sourceOfWealthOrIncome = provider.FormData["SourceOfWealthOrIncome[]"];
return Ok();
}
How do I change my front-end code using Flurl so that I can send a string object over to this current endpoint?
I am developing a web API to handle realtime updates (Lead information) from Facebook to integrate with my CRM.
In the WEB API POST request, I am able to capture the leadID but the problem comes when I get leadinfo by invoking FB.Get(LeadID). To make a Graph API GET request(for lead information) I need to have a user access token and this is where i have been struggling for quite sometime. I have looked up several posts online but havent got any solution for my problem.
In my sample implementation, GetLoginUrl(parameters) returns a uri and when when I request the uri in a browser, I see that the access token gets generated in the redirected Uri. But how to do this programatically ? I have tried the following
string FBAccessUrl = "https://graph.facebook.com/oauth/authorize?client_id=XXXXXXXXXXXX&response_type=token&redirect_uri=https://www.facebook.com/connect/login_success.html";
var accessTokenRequest = System.Net.HttpWebRequest.Create(FBAccessUrl);
HttpWebResponse response = (HttpWebResponse)accessTokenRequest.GetResponse();
but then i get this ResponseUri = {https://www.facebook.com/unsupportedbrowser} which is not what I want.
Can someone help me with how the user access token can be generated using C# in the Web API (without the facebook login dialog)
[HttpPost]
[ActionName("Complex")]
public void PostComplex(RootObject root)
{
FacebookClient fb = new FacebookClient();
// Get leadID from the inital HTTP POST request
long leadgen_id = root.entry[0].changes[0].value.leadgen_id;
string leadID = leadgen_id.ToString();
// to get user access token
dynamic parameters = new ExpandoObject();
parameters.client_id = "XXXXXXXXXXXXXXX";
parameters.redirect_uri = "https://www.facebook.com/connect/login_success.html";
parameters.response_type = "token";
// generate the login url
Uri uri = fb.GetLoginUrl(parameters);
// reuest the uri in browser and uri2 is the redirected uri
Uri uri2 = "****************"
string accesstoken = "";
FacebookOAuthResult oauthResult;
if (fb.TryParseOAuthCallbackUrl(uri, out oauthResult))
{
if (oauthResult.IsSuccess)
{
accesstoken = oauthResult.AccessToken;
}
else
{
var errorDescription = oauthResult.ErrorDescription;
var errorReason = oauthResult.ErrorReason;
}
}
fb.AccessToken = accesstoken;
string me = fb.Get(leadID).ToString();
// Then fetch required lead information
}
I am using the code below to fetch user from the azure AD using the graph API, but somehow I am getting the token access issue while doing so.
static async void MakeRequest()
{
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
/* OAuth2 is required to access this API. For more information visit:
https://msdn.microsoft.com/en-us/office/office365/howto/common-app-authentication-tasks */
// Specify values for the following required parameters
queryString["api-version"] = "1.6";
// Specify values for path parameters (shown as {...})
// var uri = "https://graph.windows.net/microsoft.onmicrosoft.com/users/{v-sidmis#microsoft.com}?" + queryString;
var uri = "https://graph.windows.net/72f988bf-86f1-41af-91ab-2d7cd011db47/users?api-version=1.6";
var response = await client.GetAsync(uri);
if (response.Content != null)
{
var responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseString);
}
}
This code is taken up from TechNet.
It depends on how you want to acquire the token. There are lots of scenario to integrate the application with Azure AD. You can refer it from here.
For example, if you want to use the Azure AD Graph in a daemon or service application, we can use the Client Credential flow.
1 . First we need to register an web application on the portal( detail steps refer here) and grant the permission to read the directory data like figure below:
2 . And then we can get the clientId, secret, tenantId from the portal and use the code below to acquire token(need to install the Active Directory Authentication Library)
string authority = "https://login.microsoftonline.com/{tenantId}";
string clientId = "";
string secret = "";
string resrouce = "https://graph.windows.net";
var credential = new ClientCredential(clientId, secret);
AuthenticationContext authContext = new AuthenticationContext(authority);
var token = authContext.AcquireTokenAsync(resrouce, credential).Result.AccessToken;
Console.WriteLine(token);
3 . Then we can use this token to call the Azure AD Graph REST directly or we can use the graph client library for Azure AD to retrieve the users. Here is the code samples for your reference:
//use the Azure AD client library
string accessToken = "";
string tenantId = "";
string graphResourceId = "https://graph.windows.net";
Uri servicePointUri = new Uri(graphResourceId);
Uri serviceRoot = new Uri(servicePointUri, tenantId);
ActiveDirectoryClient client = new ActiveDirectoryClient(serviceRoot, async () => await Task.FromResult(accessToken));
foreach(var user in client.Users.ExecuteAsync().Result.CurrentPage)
Console.WriteLine(user.DisplayName);
//using the HTTP request
var client = new HttpClient();
var tenantId = "";
var uri = $"https://graph.windows.net/{tenantId}/users?api-version=1.6";
var token = "";
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", token);
var response = client.GetAsync(uri).Result;
var result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(result);
Update
The secrecy is available for the web application/web API when you create an application. Then you can generate the key by keys section like figure below. After you save the app, you can copy the secrect now.
We have set the Azure AD as a identity provider in our application. We want to display profile picture that should come from Azure AD, in the application.
In order to test, I have added one Windows Live Id account (which has a profile picture) in the Azure AD. We then tried it using Graph Explorer, but no luck.
How do we get the profile picture from Azure AD?
You can use Azure Active Directory Graph Client to get user thumbnail photo
var servicePoint = new Uri("https://graph.windows.net");
var serviceRoot = new Uri(servicePoint, "<your tenant>"); //e.g. xxx.onmicrosoft.com
const string clientId = "<clientId>";
const string secretKey = "<secretKey>";// ClientID and SecretKey are defined when you register application with Azure AD
var authContext = new AuthenticationContext("https://login.windows.net/<tenant>/oauth2/token");
var credential = new ClientCredential(clientId, secretKey);
ActiveDirectoryClient directoryClient = new ActiveDirectoryClient(serviceRoot, async () =>
{
var result = await authContext.AcquireTokenAsync("https://graph.windows.net/", credential);
return result.AccessToken;
});
var user = await directoryClient.Users.Where(x => x.UserPrincipalName == "<username>").ExecuteSingleAsync();
DataServiceStreamResponse photo = await user.ThumbnailPhoto.DownloadAsync();
using (MemoryStream s = new MemoryStream())
{
photo.Stream.CopyTo(s);
var encodedImage = Convert.ToBase64String(s.ToArray());
}
Azure AD returns user's photo in binary format, you need to convert to Base64 string
Getting photos through Graph Explorer is not supported. Assuming that "signedInUser" already contains the signed in user entity, then this code snippet using the client library should work for you...
#region get signed in user's photo
if (signedInUser.ObjectId != null)
{
IUser sUser = (IUser)signedInUser;
IStreamFetcher photo = (IStreamFetcher)sUser.ThumbnailPhoto;
try
{
DataServiceStreamResponse response =
photo.DownloadAsync().Result;
Console.WriteLine("\nUser {0} GOT thumbnailphoto", signedInUser.DisplayName);
}
catch (Exception e)
{
Console.WriteLine("\nError getting the user's photo - may not exist {0} {1}", e.Message,
e.InnerException != null ? e.InnerException.Message : "");
}
}
#endregion
Alternatively you can do this through REST and it should look like this:
GET https://graph.windows.net/myorganization/users//thumbnailPhoto?api-version=1.5
Hope this helps,
According to the Azure AD Graph API Docs, Microsoft recommends transitioning to Microsoft Graph, as the Azure AD Graph API is being phased out.
However, to easily grab the photo via Azure AD, for now, use this URL template:
https://graph.windows.net/myorganization/users/{user_id}/thumbnailPhoto?api-version={version}
For example (this is a fake user id):
https://graph.windows.net/myorganization/users/abc1d234-01ab-1a23-12ab-abc0d123e456/thumbnailPhoto?api-version=1.6
The code below assumes you already have an authenticated user, with a token. This is a simplistic example; you'll want to change the return value to suit your needs, add error checking, etc.
const string ThumbUrl = "https://graph.windows.net/myorganization/users/{0}/thumbnailPhoto?api-version=1.6";
// Attempts to retrieve the thumbnail image for the specified user, with fallback.
// Returns: Fully formatted string for supplying as the src attribute value of an img tag.
private string GetUserThumbnail(string userId)
{
string thumbnail = "some base64 encoded fallback image";
string mediaType = "image/jpg"; // whatever your fallback image type is
string requestUrl = string.Format(ThumbUrl, userId);
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", GetToken());
HttpResponseMessage response = client.GetAsync(requestUrl).Result;
if (response.IsSuccessStatusCode)
{
// Read the response as a byte array
var responseBody = response.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult();
// The headers will contain information on the image type returned
mediaType = response.Content.Headers.ContentType.MediaType;
// Encode the image string
thumbnail = Convert.ToBase64String(responseBody);
}
return $"data:{mediaType};base64,{thumbnail}";
}
// Factored out for use with other calls which may need the token
private string GetToken()
{
return HttpContext.Current.Session["Token"] == null ? string.Empty : HttpContext.Current.Session["Token"].ToString();
}
So I am just trying to list the tables in the storage account to test the authorization using the Query Tables method. I tried using the SDK, but the SDK was trying to reference DLLs that aren't available in RT. Decided to try out the REST API. but am having trouble with the authentication from this spec http://msdn.microsoft.com/en-us/library/windowsazure/dd179428.aspx
public async Task ExecuteAsync()
{
try
{
HttpClient client = new HttpClient();
Dictionary<string, string> headers = GetHeaders("/Tables");
client.DefaultRequestHeaders.Date = DateTimeOffset.Parse(headers["Date"]);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("SharedKey", headers["Authorization"]);
const string url = "http://account-name.table.core.windows.net/Tables";
XmlReader reader = XmlReader.Create(await client.GetStreamAsync(url));
//
// Do some stuff with the reader here
//
}
catch (Exception e)
{
// handle exception
}
}
public Dictionary<string, string> GetHeaders(string resource)
{
Dictionary<string, string> headers = new Dictionary<string, string>();
headers["Date"] = DateTime.Now.ToString("R");
headers["Authorization"] = GetAuthorizationHeader(resource, headers["Date"]);
return headers;
}
public string GetAuthorizationHeader(string resource, string date)
{
const string key = PRIMARY_KEY;
const string accountName = ACCOUNT_NAME;
string signee = string.Join("\n", new List<string> { "GET", "", "", date, resource });
// make the signature
MacAlgorithmProvider hmac = MacAlgorithmProvider.OpenAlgorithm("HMAC_SHA256");
IBuffer keyMaterial = CryptographicBuffer.ConvertStringToBinary(key, BinaryStringEncoding.Utf8);
CryptographicKey hmacKey = hmac.CreateKey(keyMaterial);
IBuffer data = CryptographicBuffer.ConvertStringToBinary(signee, BinaryStringEncoding.Utf8);
IBuffer hash = CryptographicEngine.Sign(hmacKey, data);
string signature = CryptographicBuffer.EncodeToBase64String(hash);
return string.Format("{0}:{1}", accountName, signature);
}
Obviously I am missing something as I continue to get 403's. See any problems looking through this code?
A few comments:
There's a storage client library for Windows RT as well. Please take a look at my answer here: Working with Azure in Winrt with Rest API, trouble with signature.
Coming to your problem, can you try changing the following line of code:
headers["Date"] = DateTime.Now.ToString("R");
to
headers["Date"] = DateTime.UtcNow.ToString("R");
and see if that helps.
UPDATE
I also noticed that you're using CryptographicBuffer.ConvertStringToBinary to convert Base64 encoded key to bytes. Please try using CryptographicBuffer.DecodeFromBase64String (http://msdn.microsoft.com/en-us/library/windows/apps/windows.security.cryptography.cryptographicbuffer.decodefrombase64string.aspx) instead.