download file from google drive using asp.net - asp.net

I am trying download file from google drive using the code below:
public static Boolean downloadFile(string downloadurl, string _saveTo)
{
if (!String.IsNullOrEmpty(downloadurl))
{
try
{
var x = service.HttpClient.GetByteArrayAsync(downloadurl);
byte[] arrBytes = x.Result;
System.IO.File.WriteAllBytes(_saveTo, arrBytes);
return true;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
return false;
}
}
else
{
// The file doesn't have any content stored on Drive.
return false;
}
}
On debugging the above code throwing exception as below:
?service.HttpClient.GetByteArrayAsync(downloadurl)
Id = 10, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"
AsyncState: null
CancellationPending: false
CreationOptions: None
Exception: null
Id: 10
Result: null
Status: WaitingForActivation
I am trying to do it from my Service account created using Google API Console.
and the exception detail is as follows:
System.NullReferenceException was caught
HResult=-2147467261
Message=Object reference not set to an instance of an object.
Source=System.Net.Http
StackTrace:
at System.Net.Http.Headers.HttpRequestHeaders.AddHeaders(HttpHeaders sourceHeaders)
at System.Net.Http.HttpClient.PrepareRequestMessage(HttpRequestMessage request)
at System.Net.Http.HttpClient.SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.GetContentAsync[T](Uri requestUri, HttpCompletionOption completionOption, T defaultValue, Func`2 readAs)
at System.Net.Http.HttpClient.GetByteArrayAsync(Uri requestUri)
at System.Net.Http.HttpClient.GetByteArrayAsync(String requestUri)

You can try this.
link
using Google.Apis.Authentication;
using Google.Apis.Drive.v2;
using Google.Apis.Drive.v2.Data;
using System.Net;
public class MyClass {
public static System.IO.Stream DownloadFile(
IAuthenticator authenticator, File file) {
if (!String.IsNullOrEmpty(file.DownloadUrl)) {
try {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
new Uri(file.DownloadUrl));
authenticator.ApplyAuthenticationToRequest(request);
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK) {
return response.GetResponseStream();
} else {
Console.WriteLine(
"An error occurred: " + response.StatusDescription);
return null;
}
} catch (Exception e) {
Console.WriteLine("An error occurred: " + e.Message);
return null;
}
} else {
// The file doesn't have any content stored on Drive.
return null;
}
}
}

Code using the Google .net client library
Service account:
string[] scopes = new string[] {DriveService.Scope.Drive}; // Full access
var keyFilePath = #"c:\file.p12" ; // Downloaded from https://console.developers.google.com
var serviceAccountEmail = "xx#developer.gserviceaccount.com"; // found https://console.developers.google.com
//loading the Key file
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential( new ServiceAccountCredential.Initializer(serviceAccountEmail) {
Scopes = scopes}.FromCertificate(certificate));
create drive service
var service = new DriveService(new BaseClientService.Initializer() {HttpClientInitializer = credential,
ApplicationName = "Drive API Sample",});
You can use files.list to list all of the files on drive.
FilesResource.ListRequest request = service.Files.List();
request.Q = "trashed=false";
title = 'hello'
FileList files = request.Execute();
loop though the items returned find the file you want it is a file resource you can pass it to the following method to down load your file
/// <summary>
/// Download a file
/// Documentation: https://developers.google.com/drive/v2/reference/files/get
/// </summary>
/// <param name="_service">a Valid authenticated DriveService</param>
/// <param name="_fileResource">File resource of the file to download</param>
/// <param name="_saveTo">location of where to save the file including the file name to save it as.</param>
/// <returns></returns>
public static Boolean downloadFile(DriveService _service, File _fileResource, string _saveTo)
{
if (!String.IsNullOrEmpty(_fileResource.DownloadUrl))
{
try
{
var x = _service.HttpClient.GetByteArrayAsync(_fileResource.DownloadUrl );
byte[] arrBytes = x.Result;
System.IO.File.WriteAllBytes(_saveTo, arrBytes);
return true;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
return false;
}
}
else
{
// The file doesn't have any content stored on Drive.
return false;
}
}
code ripped from Google drive authentication C#

Related

HttpClient object does not works second time on Xamarin.iOS

I use HttpClient object for PostAsync. I need to add BackgroundSessionConfiguration for iOS while I am creating HttpClient object. So I changed my code like this:
var configuration = NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration ("my.app.identifier");
_client = new HttpClient (new NSUrlSessionHandler (configuration));
This works when I send first request with PostAsync. But when I send request second time, it doesn't work.
I did it for Login Operation like this: (It works first time but if I logout and login again, it doesn't work.)
public class LoginService
{
private HttpClient _client;
public LoginService()
{
if (_client == null)
{
_client = Helper.CreateHttpClientLogin(_client);
}
}
public async Task<LoginResponse<LoginDataResponse>> Login(LoginRequest request)
{
LoginResponse<LoginDataResponse> responseModel = new LoginResponse<LoginDataResponse>();
try
{
string json = JsonConvert.SerializeObject(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var jsonBody = await _client.PostAsync(App.ServiceURL.Login_Url, content);
string jsonstr = await jsonBody.Content.ReadAsStringAsync();
if (jsonstr == null || jsonstr == "")
{
responseModel.Success = false;
responseModel.Status = 0;
responseModel.Message = AppResources.UnknownHostException;
}
else
responseModel = (LoginResponse<LoginDataResponse>)JsonConvert.DeserializeObject(jsonstr, typeof(LoginResponse<LoginDataResponse>));
}
catch (Exception ex)
{
string text = ex.ToString();
responseModel.Status = 0;
AppResources.Culture = CrossMultilingual.Current.CurrentCultureInfo;
responseModel.Message = AppResources.UnknownHostException;
}
return responseModel;
}
}
public class Helper
{
public static HttpClient CreateHttpClientLogin(HttpClient _client)
{
if (Device.RuntimePlatform == Device.iOS)
{
var configuration = NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration("my.app.identifier");
_client = new HttpClient(new NSUrlSessionHandler(configuration));
}
else
{
//_client = new HttpClient(new System.Net.Http.HttpClientHandler());
HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;
_client = new HttpClient(handler);
}
return _client;
}
}
And I have this code on AppDelegate: (I don't know but maybe it causes the bug)
public static Action BackgroundSessionCompletionHandler;
public override void HandleEventsForBackgroundUrl(UIApplication application, string sessionIdentifier, Action completionHandler)
{
// We get a completion handler which we are supposed to call if our transfer is done.
BackgroundSessionCompletionHandler = completionHandler;
}
What must I do for this?
Edit:
I solved the problem I mentioned above by creating the Login Service object once the application was first opened. (After logout previously, I was rebuilding every time I login)
But now I have other error. When I run my app on "iPhone 7 plus - iOS 13.6" device I got this error:
System.Net.Http.HttpRequestException: unknown error ---> Foundation.NSErrorException: Error Domain=NSURLErrorDomain Code=-1 "unknown error" UserInfo={NSErrorFailingURLStringKey=https://mydomain/Api/Login, NSErrorFailingURLKey=https://mydomain/Api/Login, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"BackgroundDataTask <E69F3EAF-0AE9-4FAE-A01B-988167B7F6BC>.<3>"
), _NSURLErrorFailingURLSessionTaskErrorKey=BackgroundDataTask <E69F3EAF-0AE9-4FAE-A01B-988167B7F6BC>.<3>, NSLocalizedDescription=unknown error}
--- End of inner exception stack trace ---
at System.Net.Http.NSUrlSessionHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x001d4] in /Library/Frameworks/Xamarin.iOS.framework/Versions/13.20.2.2/src/Xamarin.iOS/Foundation/NSUrlSessionHandler.cs:527
at System.Net.Http.HttpClient.FinishSendAsyncBuffered (System.Threading.Tasks.Task`1[TResult] sendTask, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationTokenSource cts, System.Boolean disposeCts) [0x0017e] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/System.Net.Http/src/System/Net/Http/HttpClient.cs:506
at App.Services.LoginService.Login (FileOrbis.Models.RequestModels.LoginRequest request) [0x00084] in C:\Users\PcName\Desktop\App\App\Services\LoginService.cs:40
And simulator log file is:
Startup:
arguments: --device=06098E5B-1853-4A83-8434-8071D8973A14 --launchsim=//Users/deytek/Library/Caches/Xamarin/mtbs/builds/App.iOS/b2c75f2acbd4ff91c305dba10ca791b7/bin/iPhoneSimulator/Debug/App.iOS.app -argument=-monodevelop-port -argument=51890 -setenv=__XAMARIN_DEBUG_PORT__=51890 --sdkroot=/Applications/Xcode.app -h=192.168.1.7 -ssh=deytek --launched-by=devenv-16.0
version: 16.7.0.0 (54a29526ef6f853bdd37adbcc3791ce90ca82735)
Connecting to existing client
Exit:
Exit Code: 0
I encounter with this error when I use Background Session Configuration. If I use normal HttpClient object (without Background Session Configuration), it works
NOTE: I also tried iPhone 5s iOS 12.4.8 and iPad Pro (3rd Generation) iOS 13.6.1 It works these devices. But it doesn't work on iPhone 7 Plus 13.6

HttpClient.SendAsync exeption : The underlying connection was closed: The connection was closed unexpectedly

I've got an asp.net core 2.0 web app (Running using Kestrel) with following controller :
public IActionResult GetUpdateList(string apiCode, int softwareId, [FromBody] List<SoftwareFile> updateFiles)
{
try
{
var stream = SoftwareUpdateFilesHandler.GetUpdateZipFileStream(updateFiles, softwareId);
return File(stream.BaseStream, "application/octet-stream", "UpdateFile");
}
catch (System.Exception ex)
{
return NotFound(ex.ToString());
}
}
and this code on my client :
public async static Task<byte[]> GetUpdateAsync(string apiCode, int softwareId, List<SoftwareFile> updatefiles)
{
try
{
StringContent content = null;
if (updatefiles != null && updatefiles.Count > 0)
{
content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(updatefiles));
content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");
}
string address = $"{baseAddress}GetUpdate?softwareId={softwareId}";
HttpRequestMessage request = new HttpRequestMessage(new HttpMethod("POST"), address);
request.Content = content;
var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
var responseContent = await response.Content.ReadAsByteArrayAsync();
return responseContent;
}
catch(Exception ex)
{
return null;
}
}
But when code reaches to httpClient.SendAsync code hangs and after a few seconds client app crashes and I get this exception : The underlying connection was closed: The connection was closed unexpectedly
All of this works fine when I test my code in local but when I publish code and try to call GetUpdateList I get exception.
Odd thing about this is I can't handle exception in my catch block. Somehow catch block doesn't catch this exception and I can see exception in application crash.

Signup user to ASP.NET Identity from Xamarin

I have been stuck all day on a stupid problem with registering a user to my application.
Here is my code once the 'Register' button is clicked:
public ICommand RegisterCommand
{
get
{
return new Command(async() =>
{
var isSuccess = await _apiServices.RegisterAsync(Email, Password, ConfirmPassword);
if (isSuccess){
Message = "Registered Successfully";
}
else
{
Message = "Retry later";
}
});
}
}
Api services Register Async method:
public async Task<bool> RegisterAsync(string email, string password, string confirmPassword)
{
try
{
System.Diagnostics.Debug.WriteLine("Email: "+email);
var client = new HttpClient();
var model = new RegisterBindingModel
{
Email = email,
Password = password,
ConfirmPassword = confirmPassword
};
var json = JsonConvert.SerializeObject(model);
HttpContent content = new StringContent(json);
// content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await client.PostAsync("http://localhost:63724/api/Account/Register", content);
if (response.IsSuccessStatusCode)
{
return true;
}
return false;
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("Error: "+e);
throw;
}
}
}
The Error that I get is:
System.Net.Http.HttpRequestException: An error occurred while sending the request ---> System.Net.WebException: Error: ConnectFailure (Connection refused) ---> System.Net.Sockets.SocketException: Connection refused
at System.Net.Sockets.Socket.Connect (System.Net.EndPoint remoteEP) [0x000b6] in <6c708cf596db438ebfc6b7e012659eee>:0
at System.Net.WebConnection.Connect (System.Net.HttpWebRequest request) [0x0016d] in <6c708cf596db438ebfc6b7e012659eee>:0
--- End of inner exception stack trace ---
To me this is very frustrating as I can register a use using Postman with the exact same localhost address. I am following Houssem Dellai's Xamarin.Forms mvc web api tutorials which can be found here
I had an issue with httpclient during the development of my app. I believe there was an issue with the cross-platform implementation of the httpclient class. iOS didn't know how to handle it.
Instead I implemented a very simple httpclient library called flurl: http://tmenier.github.io/Flurl/
First, you will need to install flurl in all project directories (iOS, Android, and the PCL) then the implementation is very simple.
using Flurl;
using Flurl.Http;
public async Task<User> CreateUserAsync(RegisterUserModel userModel)
{
string url = "your/backend/here";
//resp is a user object received and automatically converted into a c# object through the use of .ReceiveJson<typeofobject>();
var resp = await (url).PostJsonAsync(userModel)
.ReceiveJson<User>();
if (resp.LoginSession != null)
{
//Raise my registered event to let other classes know to proceed
OnUserRegistered(resp);
}
return resp;
}
As you can see it makes httpclient implementation very simple. Hopefully this helps.

Corresponding web api function to accept file

I am trying to upload file using retrofit, send it to the server side and save that file in my uploads folder.
This is my retrofit API instance:
#Multipart
#POST("file/uploaddocument")
Call<ResponseBody> uploadFile(#Part MultipartBody.Part file );
UploadFile:
private void uploadFile(Uri fileUri) {
// create upload service client
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
MyApiEndpointInterface apiService =
retrofit.create(MyApiEndpointInterface.class);
// https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
// use the FileUtils to get the actual file by uri
File file = Utils.getFileForUri(fileUri);
// create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(
MediaType.parse(getContentResolver().getType(fileUri)),
file
);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body =
MultipartBody.Part.createFormData("file", file.getName(), requestFile);
// finally, execute the request
Call<ResponseBody> call = apiService.uploadFile(body);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call,
Response<ResponseBody> response) {
UploadProgressDialog.dismiss();
Log.v("Upload", "success");
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
UploadProgressDialog.dismiss();
Log.e("Upload error:", t.getMessage());
}
});
}
And I'm calling this method on button click as :
uploadFile(myfileuri);
This is my Web API call(Is this correct ? If not how to accept the image from client side ?)
<HttpPost>
<Route("api/File/UploadDocument", Name:="UploadDocument")>
Public Function Upload() As HttpResponseMessage
Try
Dim UploadedPath As String = HttpContext.Current.Server.MapPath("~/UploadedFiles")
Dim httpRequest = HttpContext.Current.Request
If httpRequest.Files.Count > 0 Then
For Each file As String In httpRequest.Files
Dim postedFile = httpRequest.Files(file)
postedFile.SaveAs(UploadedPath + "/")
Next
Else
End If
Dim message = Request.CreateResponse(HttpStatusCode.OK, "True")
Return message
Catch ex As Exception
Return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex)
End Try
End Function
This is how I done it...Posting here so that some one else might be found it useful
<HttpPost, Route("api/UploadFile")>
Public Function Post() As HttpResponseMessage
Try
Dim httpRequest = HttpContext.Current.Request
If httpRequest.Files.Count < 1 Then
Return Request.CreateResponse(HttpStatusCode.BadRequest)
End If
For Each file As String In httpRequest.Files
Dim postedFile = httpRequest.Files(file)
Dim filePath = HttpContext.Current.Server.MapPath("~/UploadedFiles/" + postedFile.FileName)
' NOTE: To store in memory use postedFile.InputStream
postedFile.SaveAs(filePath)
Next
Return Request.CreateResponse(HttpStatusCode.NoContent)
Catch ex As Exception
Return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex)
End Try
End Function

ASP.NET Core RC-1 file upload

I am currently uploading a file via the kendo fileuploader to an api controller using ASP.NET core RC-1. I am receiving a periodic error of "object reference not set to instance of object" when attempting to read the stream following opening the stream with IFormFile.OpenReadStream().
My controller is:
[HttpPost]
[Route("api/{domain}/[controller]")]
public async Task<IActionResult> Post([FromRoute]string domain, [FromForm]IFormFile file, [FromForm]WebDocument document)
{
if (ModelState.IsValid)
{
if (file.Length > 0)
{
var userName =
Request.HttpContext.User.Claims
.FirstOrDefault(c => c.Type == ClaimTypesEx.FullName)?
.Value;
var uploadedFileName =
ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
document.Domain = domain;
document.MimeType = file.ContentType;
document.SizeInBytes = file.Length;
document.ChangedBy = userName;
document.FileName = (string.IsNullOrEmpty(document.FileName)) ? uploadedFileName : document.FileName;
try
{
document = await CommandStack.For<WebDocument>()
.AddOrUpdateAsync(document, file.OpenReadStream()).ConfigureAwait(false);
}
catch (Exception e)
{
return new HttpStatusCodeResult(500);
}
return Ok(document);
}
}
return new BadRequestResult();
}
And the error is being thrown when I actually try to read the stream when it is going into blob storage:
public async Task<Uri> CreateOrUpdateBlobAsync(string containerName, string fileName, string mimeType,
Stream fileStream)
{
var container = Client.GetContainerReference(containerName);
var blob = container.GetBlockBlobReference(fileName);
//Error HERE
await blob.UploadFromStreamAsync(fileStream);
blob.Properties.ContentType = mimeType;
await blob.SetPropertiesAsync();
return blob.Uri;
}
What I am having trouble with is this is sporadic and there seems to be no defined pattern of which files are accepted and which ones generate the error. At first I thought it might be a size issue but that is not the case as I have several larger files uploaded successfully and then one small file will throw the error. Images seem to work fine and it is hit or miss on other file types with no rhyme or reason that I can figure out.

Resources