In one of the previous post, I have explained how you can upload file to google drive in MVC using OAuth but in this article, I will explain, how you can upload file to google drive using Service account. Using Service account, you do not have to prompt user for google credentials, it can be helpful to use Service Account, when you want to upload files to google drive using  background jobs in MVC or without user intervention.

In this post, I will also enable domain wide delegation, as when using Service account, we can upload files without delegation, but it won't be visible, so it is of no use, unless we use delegation (basically, adding it into some user's google drive ) to impersonate user.

Create service account in Google Developer console

First of all you need to create service account in your google developer console and get .p12 file of your project.

  1. Go to https://console.developers.google.com/iam-admin/serviceaccounts
  2. Select your project (From the top-left) and click on "Create Service Account" to create a new service account
    service-account-drive-mvc-c-sharp-min.png
  3. Follow the steps to create service account
  4. Once you have created Service account, You will need a key now, so click on three vertical dots , and Select "Create Key", Select "JSON" and click "Create", extract Key from this JSON file, which we will use later.
  5. Save the downloaded file and copy it into root folder of your project.
  6. Enable "Domain wide delegation" for this service account, click on the Service account , then "Enable G-Suite Domain wide validation" and save changes ( This step is required if you are using some company account like test@example.com)
    site-wide-delegation-min.png
  7. A new column, Domain-wide delegation, can be seen. Click View Client ID, to obtain and make a note of the client ID.

Note: In the above process, I am considering you have already created project in Google Developer console, here we have created Service account for that Google developer console project. If you haven't create

Get site wide delegation to Service Account

We have enabled Service account in above step and also enabled domain wide delegation for service account, but we still need to give permission to that particular Service account from main GSuite admin account.

So, follow these steps as explained below

  1. Go to your G Suite domain’s Admin console.
  2. Select Security from the list of controls. If you don't see Security listed, select More controls from the gray bar at the bottom of the page, then select Security from the list of controls.
  3. Select Advanced settings from the list of options.
  4. Select Manage API client access in the Authentication section.
    select-manage-api-google-admin.png
  5. In the Client name field, enter the client ID obtained from the service account creation steps above.
    In the One or More API Scopes field enter the scopes required for your application (for a list of possible scopes, see Authorize requests).
    For example, if you require domain-wide access to Users and Groups enter:
    https://www.googleapis.com/auth/drive,  https://www.googleapis.com/auth/drive.appfolder,https://www.googleapis.com/auth/drive.file,https://www.googleapis.com/auth/drive.install, https://www.googleapis.com/auth/drive.readonly
    manage-api-authorize-min.png
  6. Click the Authorize button.

Your service account now has domain-wide access to the Google Drive API and can be used with impersonation

C# code for uploading file on google drive in MVC application

We are almost done, now we need to write code using Service account details to upload file on Google drive using it's API.

Install Google Drive API using Nuget, so , navigate to "Tools"-> "Nuget Package Manager" -> "Manage Nuget Packages for solution" -> Select "Browse" -> Search for "Google Drive API

google-drive-upload-file-service-account-mvc

Once you have Google Drive API installed, navigate to your Controller and use the C# code as shown below

   public static DriveService GetService()
        {
            string[] scopes = new string[] { DriveService.Scope.Drive };


           //"SERVICE_ACCOUNT_EMAIL_HERE";
            String serviceAccountEmail = "test-417@elated-graph-261115.iam.gserviceaccount.com";

            // Scope and user email id which you want to impersonate
            var initializer = new ServiceAccountCredential.Initializer(serviceAccountEmail)
            {
                Scopes = scopes,
                User = "yourEmail@domain.com"
            };

            //get private key, from .JSON file
            var credential = new ServiceAccountCredential(initializer.FromPrivateKey("-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCkHeAicu6uFQn0\n7KUVTjgZ68nQui8+c8NmKW8aW8vhkBIKfdewXFECiUlTMPyI+HXbubsCK5Dl2xBS\nnphLq6YyE0xEQxNFLYHwfUKuzGQ2rV+qObcZ0mLZjCaf+pw3YiRVuU6OtslLJKJH\n-----END PRIVATE KEY-----\n"));


            // Create the service.
            var service = new DriveService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = "DriveAPI",
            });



            service.HttpClient.Timeout = TimeSpan.FromMinutes(100);
            return service;
        }
        //file Upload to the Google Drive root folder.
        public void UplaodFileOnDrive(HttpPostedFileBase file)
        {
            if (file != null && file.ContentLength > 0)
            {
                //create service
                DriveService service = GetService();
                string path = Path.Combine(Server.MapPath("~/"),
                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();
                }



            }
        }

 so your Complete HomeController.cs code will look like this

using Google.Apis.Auth.OAuth2;

using Google.Apis.Services;
using Google.Apis.Drive.v3;
using System;
using System.IO;
using System.Web;
using System.Web.Mvc;

namespace UploadFilesToGoogleDrive.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            
            return View();
        }

        [HttpPost]
        public ActionResult Index(HttpPostedFileBase file)
        {
            UplaodFileOnDrive(file);
            ViewBag.Success = "File Uploaded on Google Drive";
            return View();
        }


        public static DriveService GetService()
        {
            string[] scopes = new string[] { DriveService.Scope.Drive };


           //"SERVICE_ACCOUNT_EMAIL_HERE";
            String serviceAccountEmail = "test-417@elated-graph-261115.iam.gserviceaccount.com";

            // Scope and user email id which you want to impersonate
            var initializer = new ServiceAccountCredential.Initializer(serviceAccountEmail)
            {
                Scopes = scopes,
                User = "yourEmail@domain.com"
            };

            //get private key, from .JSON file
            var credential = new ServiceAccountCredential(initializer.FromPrivateKey("-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCkHeAicu6uFQn0\n7KUVTjgZ68nQui8+c8NmKW8aW8vhkBIKfdewXFECiUlTMPyI+HXbubsCK5Dl2xBS\nnphLq6YyE0xEQxNFLYHwfUKuzGQ2rV+qObcZ0mLZjCaf+pw3YiRVuU6OtslLJKJH\nAtcyB97ZaPP4x+vaFaVdf8OiWDYKwLtOJ2wSsp6VktIHLqBDd6OF688AElFarO/2\nbHeALFiaEFOkqUaba0Jbzs2pHGj0Q35HuiapohCGaZpbAzPOOQ55SK42ZaJxH5FK\nJ3kBmfRhNP5sqw7cVGWUMTWB7R4LsHKULQZuju4iQ35KbKuXI6gLU2oT5kX9rSb5\nWjXJG2e/AgMBAAECggEABcnV93EVUQeF7+EO24cEPInP9vAyLWI44JgShpv5P23s\n7PjOTDadVtkPwILoTU5yHbtZyLRPqoPE+h0E4xpdRMPge0HgYp69yAUq/m5QFIud\n5auedScx/FlQnXDh5KQuAuYDys3QoLlcjeOgQm/7oLBudnZar7j2uasBc+7njQ57\n-----END PRIVATE KEY-----\n"));


            // Create the service.
            var service = new DriveService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = "DriveAPI",
            });



            service.HttpClient.Timeout = TimeSpan.FromMinutes(100);
            return service;
        }
        //file Upload to the Google Drive root folder.
        public void UplaodFileOnDrive(HttpPostedFileBase file)
        {
            if (file != null && file.ContentLength > 0)
            {
                //create service
                DriveService service = GetService();
                string path = Path.Combine(Server.MapPath("~/"),
                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();
                }



            }
        }
    }
}

That's it, we are done with C# code for uploading file on Google Drive, just create Index.cshtml page to browse local file and pass it to Controller.

@{
    ViewBag.Title = "Home Page";
}

@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <div class="row" style="margin-top:10px;margin-bottom:10px;">
        <div class="col-md-2"><label for="file">Upload file on drive:</label></div>
        <div class="col-md-10">
            <input type="file" name="file" id="file" />
        </div>
        <div class="col-md-2">
            <br />
            <input type="submit" class="btn btn-success" value="Upload" />
        </div>
    </div>
}

@ViewBag.Success

We are done, build and try to upload file on Server, you will see it on your Google Drive, without user intervention.

Note: Uploading file on Google drive has same C# code, as it was in article, which uploads file using OAuth, just the difference is while creating Google Drive service, we are adding a user, which has site-wide delegation rights and using JSON file private key of Service Account.

Also, In the above sample, I am showing Private key, please read it directly from .p12 or JSON file, it is not recommended to use private key as plain text inside C# Code.

You might also like to read:

File Upload in ASP.NET MVC (Single and Multiple files upload example)

Aggregate Functions in SQL Server (SUM, AVG, COUNT, MIN, MAX)