0

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

KyleMit
  • 30,350
  • 66
  • 462
  • 664
Ramakrishna Reddy
  • 347
  • 1
  • 2
  • 18
  • Getting a 404 shows that a resource (image in this case) isn't at the location specified by the URL. Can you post or check your URL to see if it is correct? If it is correct but (for example) the authentication failed it should give you something else than 404 – MindSwipe Oct 21 '19 at 13:14
  • I am using a Personal access token to fetch the image. Image URL is correct(with the same URL i am able to fetch image if i make repository as public) I doubt authentication is not happening with the token. but i gave all permissions to that token in github – Ramakrishna Reddy Oct 21 '19 at 13:27
  • The link you provided is just a stackoverflow question with multiple snippets of code. What's the actual code you are running? And is the repo owned by the same account the access tokens were created for? github gives a 404 if you don't have permission to access the private repo – LampToast Oct 21 '19 at 13:41
  • 1
    As LampToast pointed out, I wrongly assumed that GitHub returns a 401 when unauthorized, while it actually returns a 404. Can you give us your linked anonymized (replace your GitHub name with something like YourName). Also [edit] your question to add the code you are using – MindSwipe Oct 21 '19 at 13:47
  • the link I am using "https://github.com/ramakrishnareddy2108/FileAccessTest/blob/master/Test.jpg" which is in private repository – Ramakrishna Reddy Oct 21 '19 at 16:28

2 Answers2

2

How to fix :

  1. 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

  2. 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

  3. 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();
itminus
  • 23,772
  • 2
  • 53
  • 88
1

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:

  1. 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 : enter image description here

  1. Download file enter image description here

For more details, please refer to https://developer.github.com/v3/repos/contents/#get-contents.

Jim Xu
  • 21,610
  • 2
  • 19
  • 39
  • @RamakrishnaReddy If your issue has been resolved, could you please accept the answer? It may help more persons who have similar issue. – Jim Xu Oct 22 '19 at 06:30