No output of hash displayed

Jason Phang

Well-known member
Joined
Aug 13, 2019
Messages
46
Programming Experience
Beginner
I am currently doing a data deduplication program in C# and so far, I am able to upload, download, select and delete files. However, i would want to generate the hash value of the files in the table of my application. However, there is no hash that is displayed, hence I am unsure if I am doing the hashing code right. I just want to show like the MD5 hash of the files in the MD5 column.
C#:
using Google.Apis.Auth.OAuth2;
using Google.Apis.Download;
using Google.Apis.Drive.v3;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Web;
using System.Security.Cryptography;

namespace GoogleDriveRestApi_v3.Models
{
    public class GoogleDriveFilesRepository
    {
        public static string[] Scopes = { DriveService.Scope.Drive };

        //create Drive API service.
        public static DriveService GetService()
        {
            //get Credentials from client_secret.json file
            UserCredential credential;
            using (var stream = new FileStream(@"D:\client_secret.json", FileMode.Open, FileAccess.Read))
            {
                String FolderPath = @"D:\";
                String FilePath = Path.Combine(FolderPath, "DriveServiceCredentials.json");

                credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets,
                    Scopes,
                    "user",
                    CancellationToken.None,
                    new FileDataStore(FilePath, true)).Result;
            }

            //create Drive API service.
            DriveService service = new DriveService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = "GoogleDriveRestAPI-v3",
            });
            return service;
        }

        //get all files from Google Drive.
        public static List<GoogleDriveFiles> GetDriveFiles()
        {
            DriveService service = GetService();

            // define parameters of request.
            FilesResource.ListRequest FileListRequest = service.Files.List();

            //listRequest.PageSize = 10;
            //listRequest.PageToken = 10;
            FileListRequest.Fields = "nextPageToken, files(id, name, size, version, createdTime)";

            //get file list.
            IList<Google.Apis.Drive.v3.Data.File> files = FileListRequest.Execute().Files;
            List<GoogleDriveFiles> FileList = new List<GoogleDriveFiles>();

            if (files != null && files.Count > 0)
            {
                foreach (var file in files)
                {
                    GoogleDriveFiles File = new GoogleDriveFiles
                    {
                        Id = file.Id,
                        Name = file.Name,
                        Size = file.Size,
                        Version = file.Version,
                        CreatedTime = file.CreatedTime,
                        HashFiles = file.Md5Checksum,
                        // HashFile = file.Md5Checksum,
                    };
                    FileList.Add(File);
                }
            }
            return FileList;
        }

        //Get Hash Value

        public static void GenerateHash(HttpPostedFileBase file)
        {
            string directory = Path.Combine(HttpContext.Current.Server.MapPath("~/GoogleDriveFiles"),
                Path.GetFileName(file.FileName));

            using (var md5 = MD5.Create())
            {
                using (var stream = File.OpenRead(directory))
                {
                    var hash = md5.ComputeHash(stream);
                    var data = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();

                }
            }

        }

        //file Upload to the Google Drive.
        public static void FileUpload(HttpPostedFileBase file)
        {
            if (file != null && file.ContentLength > 0)
            {
                DriveService service = GetService();

                string path = Path.Combine(HttpContext.Current.Server.MapPath("~/GoogleDriveFiles"),
                Path.GetFileName(file.FileName));
                file.SaveAs(path);

                var FileMetaData = new Google.Apis.Drive.v3.Data.File();
                FileMetaData.Name = Path.GetFileName(file.FileName);
                FileMetaData.MimeType = MimeMapping.GetMimeMapping(path);

                FilesResource.CreateMediaUpload request;

                using (var stream = new System.IO.FileStream(path, System.IO.FileMode.Open))
                {
                    request = service.Files.Create(FileMetaData, stream, FileMetaData.MimeType);
                    request.Fields = "id";
                    request.Upload();
                }
            }
        }

        //Download file from Google Drive by fileId.
        public static string DownloadGoogleFile(string fileId)
        {
            DriveService service = GetService();

            string FolderPath = System.Web.HttpContext.Current.Server.MapPath("/GoogleDriveFiles/");
            FilesResource.GetRequest request = service.Files.Get(fileId);

            string FileName = request.Execute().Name;
            string FilePath = System.IO.Path.Combine(FolderPath, FileName);

            MemoryStream stream1 = new MemoryStream();

            // Add a handler which will be notified on progress changes.
            // It will notify on each chunk download and when the
            // download is completed or failed.
            request.MediaDownloader.ProgressChanged += (Google.Apis.Download.IDownloadProgress progress) =>
            {
                switch (progress.Status)
                {
                    case DownloadStatus.Downloading:
                        {
                            Console.WriteLine(progress.BytesDownloaded);
                            break;
                        }
                    case DownloadStatus.Completed:
                        {
                            Console.WriteLine("Download complete.");
                            SaveStream(stream1, FilePath);
                            break;
                        }
                    case DownloadStatus.Failed:
                        {
                            Console.WriteLine("Download failed.");
                            break;
                        }
                }
            };
            request.Download(stream1);
            return FilePath;
        }

        // file save to server path
        private static void SaveStream(MemoryStream stream, string FilePath)
        {
            using (System.IO.FileStream file = new FileStream(FilePath, FileMode.Create, FileAccess.ReadWrite))
            {
                stream.WriteTo(file);
            }
        }

        //Delete file from the Google drive
        public static void DeleteFile(GoogleDriveFiles files)
        {
            DriveService service = GetService();
            try
            {
                // Initial validation.
                if (service == null)
                    throw new ArgumentNullException("service");

                if (files == null)
                    throw new ArgumentNullException(files.Id);

                // Make the request.
                service.Files.Delete(files.Id).Execute();
            }
            catch (Exception ex)
            {
                throw new Exception("Request Files.Delete failed.", ex);
            }
        }
    }
}
 
Last edited by a moderator:

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
3,917
Location
Sydney, Australia
Programming Experience
10+
What's up with posting every line of code you have? You need to post ONLY relevant code. You also need to debug your code, i.e. set a breakpoint and step through it line by line and examine the state as you go. You can then tell us exactly where and how the actual behaviour differs from your expectation. Posting loads of code and expecting us to wade through it to find the relevant part and determine what it's actually supposed to do is expecting a bit much. We're here to help but you need to do as much as you can to help us do that.
 

NoUserHere

Well-known member
Joined
Sep 5, 2018
Messages
2,138
Programming Experience
10+
I am not reading all that either. lol
We have things to do too ya know. You are best posting the code you doubt, or the code you want to question us about. Whacking a whole namespace in there and expecting us to wade through it is something I'm not prepared to do given how little time I have to spare lately. You need to simplify and trim it down for us. So instead, I'll give you a quick example of using md5hash ::
C#:
        private string Xfile => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "CFile.txt");
        private void Button1_Click(object sender, EventArgs e)
        {
            var FilePath = Path.GetFullPath(Xfile);
            Console.WriteLine($"FilePath returns '{FilePath}' which when passed to the GetMD5 will be the actual path of the file, which you need.");
            var getmd5return = GetMD5(FilePath);
            /* You can use bit converter to convert it to hex */
            var getasstring = bitCon(getmd5return);
            Console.WriteLine($"The md5 returns type {getmd5return} as {getmd5return.Length} chars \nAnd the bitconvert returns a hex representation as string {getasstring}");
        }
        private byte[] GetMD5(string file)
        {
            using (var md5 = MD5.Create())
            {
                using (var data = File.OpenRead(file))
                {
                   byte[] mdsum = md5.ComputeHash(data); /* Computes the hash from the file */
                    Console.WriteLine($"Computes the hash from the file to {mdsum.Length} bytes");
                    return mdsum; /* This will return 16 bytes */
                }
            }
        }
        private string bitCon(byte[] hash)
        {
             return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); /* This will return a string representation in hex */
        }
Coneole output:
GetFileName returns 'C:\Users\user\Desktop\CFile.txt' which when passed to the GetMD5 will be the actual path of the file, which you need.
Computes the hash from the file to 16 bytes
The md5 returns type System.Byte[] as 16 chars
And the bitconvert returns a hex representation as string c1b2469efa04bc14fa3cb808bcb8a78a
If you need any more info, there is a whole documentation section here to feast your eyes on : MD5 Class (System.Security.Cryptography)

If that's not enough, ask a specific question about a specific part of your code that's not delivering results as expected.
Simpler version:
        private string Xfile => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "CFile.txt");
        private void Button1_Click(object sender, EventArgs e)
        {
            string FilePath = Path.GetFullPath(Xfile);
            Console.WriteLine($"FilePath returns '{FilePath}' which when passed to the GetMD5 will be the actual path of the file, which you need.");
            byte[] getmd5return = GetMD5(FilePath);
            /* You can use bit converter to convert it to hex */
            string getasstring = bitCon(getmd5return);
            Console.WriteLine($"The md5 returns type {getmd5return} as {getmd5return.Length} chars \nAnd the bitconvert returns a hex representation as string {getasstring}");
        }
        private byte[] GetMD5(string file)
        {
            using (MD5 md5 = MD5.Create())
            {
                using (FileStream data = File.OpenRead(file))
                {
                   byte[] mdsum = md5.ComputeHash(data); /* Computes the hash from the file */
                    Console.WriteLine($"Computes the hash from the file to {mdsum.Length} bytes");
                    return mdsum; /* This will return 16 bytes */
                }
            }
        }
        private string bitCon(byte[] hash)
        {
             return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); /* This will return a string representation in hex */
        }
Edited out a typo
 
Last edited:

Jason Phang

Well-known member
Joined
Aug 13, 2019
Messages
46
Programming Experience
Beginner
Okay, apologies for the length post. I will breakdown the problem here. Firstly, the hash that i want to generate for the files in the Google Drive is not displaying, hence I was not sure whether it is because of my hash code problem.

Hash Class (To generate MD5 hash of files in google drive):
 //Get Hash Value

        public static void GenerateHash(HttpPostedFileBase file)
        {
            string directory = Path.Combine(HttpContext.Current.Server.MapPath("~/GoogleDriveFiles"),
                Path.GetFileName(file.FileName));

            using (var md5 = MD5.Create())
            {
                using (var stream = File.OpenRead(directory))
                {
                    var hash = md5.ComputeHash(stream);
                    var data = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();

                }
            }

        }

But I was not sure how can I link that code of hash to the .cshtml file where I will display the output.

GetGoogleDrive.cshtml:
  <table class="table" border="1">
        <tr id="header">
            <th>
                @Html.DisplayNameFor(model => model.Name)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Size)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Version)
            </th>

            <th>
                @Html.DisplayNameFor(model => model.CreatedTime)
            </th>

            <th>
                @Html.DisplayNameFor(model => model.md5Checksum)
            </th>

This belonged to the main model class of my application

Main model:
public class GoogleDriveFiles
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public long? Size { get; set; }
        public long? Version { get; set; }
        public DateTime? CreatedTime { get; set; }
       public string md5Checksum { get; set; }

    }

hasherror.PNG


This is my main problem for I am unsure whether the hash code that I did was necessary. Based on the hash code that I have seen mostly, it is basically getting the hash for files that we set from the codes. WHat i am trying to achieve is to get the hash of the files in the drive.

table.PNG


I just want to be able to display the hash in that column so that i know that i am able to generate the hash of those files in the google drive.
 

NoUserHere

Well-known member
Joined
Sep 5, 2018
Messages
2,138
Programming Experience
10+
It's my understanding that List of Google.Apis.Drive.v3.Data.File will only return meta data and not actual files and its not like iterating files on a PC. If you want a file from the returned meta data response, you will need to get the id of that file and call to download that file through the api and read it into memory preferably from webclient download file. The file will need to be downloaded before you can work some md5 magic on her.
 

NoUserHere

Well-known member
Joined
Sep 5, 2018
Messages
2,138
Programming Experience
10+
For example, here is what returns on my account when checking my drivespace, minus some filtration of IDS etc
C#:
{
 "kind": "drive#fileList",
 "incompleteSearch": false,
 "files": [
  {
   "kind": "drive#file",
   "id": "1-ny8************h1Bek",
   "name": "Long-term Assistance",
   "mimeType": "application/vnd.google-apps.document"
  },
  {
   "kind": "drive#file",
   "id": "16ff************BhYD",
   "name": "Php************.rar",
   "mimeType": "application/rar"
  }
 ]
}
 

Jason Phang

Well-known member
Joined
Aug 13, 2019
Messages
46
Programming Experience
Beginner
Okay, so I managed to get the hash values of the files as desired.
Code for hash md5:
  public static List<GoogleDriveFiles> GetDriveFiles()
        {
            DriveService service = GetService();

            // define parameters of request.
            FilesResource.ListRequest FileListRequest = service.Files.List();

            //listRequest.PageSize = 10;
            //listRequest.PageToken = 10;
            FileListRequest.Fields = "nextPageToken, files(id, name, size, createdTime, md5Checksum)";

            //get file list.
            IList<Google.Apis.Drive.v3.Data.File> files = FileListRequest.Execute().Files;
            List<GoogleDriveFiles> FileList = new List<GoogleDriveFiles>();

            //get hash


            if (files != null && files.Count > 0)
            {
                foreach (var file in files)
                {
                    GoogleDriveFiles File = new GoogleDriveFiles
                    {
                        Id = file.Id,
                        Name = file.Name,
                        Size = file.Size,
                        CreatedTime = file.CreatedTime,
                        MD5hash = file.Md5Checksum,

                };
                    FileList.Add(File);
                  
                }
            }
            return FileList;



        }

Now, I want to insert those hash values of the files in like a hashset. I tried to declare the hashset under the return file list and add the MD5hash into the hashset but it does not allow. Should I declare another hashset function or I can call it in the same block as above,
 

Jason Phang

Well-known member
Joined
Aug 13, 2019
Messages
46
Programming Experience
Beginner
This hashtable would contain the key pair and its values. So for my context, the key pair would be the filename and the value would be the hash? And this hashtable should it be in this block of code?

Get File List From Google Drive:
 //get file list.
            IList<Google.Apis.Drive.v3.Data.File> files = FileListRequest.Execute().Files;
            List<GoogleDriveFiles> FileList = new List<GoogleDriveFiles>();

            if (files != null && files.Count > 0)
            {
                foreach (var file in files)
                {
                    GoogleDriveFiles File = new GoogleDriveFiles
                    {
                        Id = file.Id,
                        Name = file.Name,
                        Size = file.Size,
                        CreatedTime = file.CreatedTime,
                        MD5hash = file.Md5Checksum,

                };
                    FileList.Add(File);

                    
                }
            }
            return FileList;

        }

Or should i put inside here?
Upload file to google drive:
        //file Upload to the Google Drive.
        public static void FileUpload(HttpPostedFileBase file)
        {
            if (file != null && file.ContentLength > 0)
            {
                DriveService service = GetService();

                string path = Path.Combine(HttpContext.Current.Server.MapPath("~/GoogleDriveFiles"),
                Path.GetFileName(file.FileName));
                file.SaveAs(path);

                var FileMetaData = new Google.Apis.Drive.v3.Data.File();
                FileMetaData.Name = Path.GetFileName(file.FileName);
                FileMetaData.MimeType = MimeMapping.GetMimeMapping(path);

                FilesResource.CreateMediaUpload request;

                  using (var stream = new System.IO.FileStream(path, System.IO.FileMode.Open))
                {
                    request = service.Files.Create(FileMetaData, stream, FileMetaData.MimeType);
                    request.Fields = "id";
                    request.Upload();
                }
            }
        }

I am unsure on this hashtable where I should like put it in which block. Or I should build like a new function?
 

Jason Phang

Well-known member
Joined
Aug 13, 2019
Messages
46
Programming Experience
Beginner
Hashtable:
//get file list.
            IList<Google.Apis.Drive.v3.Data.File> files = FileListRequest.Execute().Files;
            List<GoogleDriveFiles> FileList = new List<GoogleDriveFiles>();

            if (files != null && files.Count > 0)
            {
                foreach (var file in files)
                {
                    GoogleDriveFiles File = new GoogleDriveFiles
                    {
                        Id = file.Id,
                        Name = file.Name,
                        Size = file.Size,
                        CreatedTime = file.CreatedTime,
                        MD5hash = file.Md5Checksum,

                };
                    FileList.Add(File);

                    Hashtable HashedFiles = new Hashtable();
                    HashedFiles.Add(file.Id, file.Md5Checksum);
                    
                }
            }
            return FileList;

        }

Is the way of doing the hashtable something like this? If so, based on that hashtable, is it possible that I can remove the files that have the same hash?
 

NoUserHere

Well-known member
Joined
Sep 5, 2018
Messages
2,138
Programming Experience
10+
The key would be the checksum and not the file. Switch them. The key would be unique (MD5) and I think it would be better to be able to reference the filename if you need to get them from the table later on, so the hash table suits for such usage.

Since you are uploading the files I would extend this public static void FileUpload(HttpPostedFileBase file) to include an extra parameter to be passed in, which would be your whole hash table. Or make a static hashtable property/field you can return where you need it. Since it would be static, you could do this from any part of your application.
 
Last edited:

Jason Phang

Well-known member
Joined
Aug 13, 2019
Messages
46
Programming Experience
Beginner
The hashtable should be inserted in which block? The file upload or the retrieving file list? Based on your statement that an extra parameter should be inserted in the upload file, I beleive that the hashtable should be like this then?

Hashtable:
 if (files != null && files.Count > 0)
            {
                foreach (var file in files)
                {
                    GoogleDriveFiles File = new GoogleDriveFiles
                    {
                        Id = file.Id,
                        Name = file.Name,
                        Size = file.Size,
                        CreatedTime = file.CreatedTime,
                        MD5hash = file.Md5Checksum,

                };
                    FileList.Add(File);

                    Hashtable HashedFiles = new Hashtable();
                    HashedFiles.Add(file.Md5Checksum, file.Id);

                }
            }

Upload file to google drive:
     //file Upload to the Google Drive.
        public static void FileUpload(HttpPostedFileBase file, Hashtable HashedFiles)
        {
            if (file != null && file.ContentLength > 0)
            {
                DriveService service = GetService();

                string path = Path.Combine(HttpContext.Current.Server.MapPath("~/GoogleDriveFiles"),
                Path.GetFileName(file.FileName));
                file.SaveAs(path);

                var FileMetaData = new Google.Apis.Drive.v3.Data.File();
                FileMetaData.Name = Path.GetFileName(file.FileName);
                FileMetaData.MimeType = MimeMapping.GetMimeMapping(path);

                FilesResource.CreateMediaUpload request;

                  using (var stream = new System.IO.FileStream(path, System.IO.FileMode.Open))
                {
                    request = service.Files.Create(FileMetaData, stream, FileMetaData.MimeType);
                    request.Fields = "id";
                    request.Upload();
                }
            }
        }

When you mean by make a static hashtable property, do you mean like declaring the hashtable on its own? Like a function by itself for the hashtable?
 

NoUserHere

Well-known member
Joined
Sep 5, 2018
Messages
2,138
Programming Experience
10+
I would say insert it in neither. The whole point would be to have a public property or field. Depending on however you want to implement it. You would then pass it around... Declare at constructor level
C#:
    public Hashtable HashTableX { get; set; } = new Hashtable();
    public static Hashtable HashTableY;
Then with this pseudo sample you can interact with it
C#:
methodA()
{
           I am getting your meta data
           While getting data, I add said data to hashtable
           Got the data? Great, send it to methodB
           methodB(someParam, HashTableX or so)
}

methodB (upload param, hash param)
{
          I am waiting for hashtable data from methodA to be passed here
          Do work with md5 data
}
 

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
3,917
Location
Sydney, Australia
Programming Experience
10+
Okay, apologies for the length post. I will breakdown the problem here. Firstly, the hash that i want to generate for the files in the Google Drive is not displaying, hence I was not sure whether it is because of my hash code problem.

Hash Class (To generate MD5 hash of files in google drive):
 //Get Hash Value

        public static void GenerateHash(HttpPostedFileBase file)
        {
            string directory = Path.Combine(HttpContext.Current.Server.MapPath("~/GoogleDriveFiles"),
                Path.GetFileName(file.FileName));

            using (var md5 = MD5.Create())
            {
                using (var stream = File.OpenRead(directory))
                {
                    var hash = md5.ComputeHash(stream);
                    var data = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();

                }
            }

        }
Why would you expect that to display anything to begin with? The method is declared void so it's not going to return anything and, within the method, you are assigning only to local variables. Even if data contains the correct hash, you never do anything useful with it.
 
Top Bottom