Hanging TuesPechkin after initial conversion - c#

I am attempting to create a Web API that can convert a styled HTML file into a PDF.
I am using TuesPechkin and have installed my application into IIS (as a 32-bit app: I have modified the application pool to run in 32bit mode).
IIS 8.5 is running on Windows Server 2012 R2.
PDFConversion class in C#:
using System.Drawing.Printing;
using System.IO;
using TuesPechkin;
namespace PDFApi
{
public class PDFcreator
{
public void convert(string path, string uri)
{
IConverter converter = new StandardConverter(
new RemotingToolset<PdfToolset>(
new Win64EmbeddedDeployment(
new TempFolderDelpoyment())));
var document = new HtmlToPdfDocument
{
GlobalSettings =
{
ProduceOutline = true,
DocumentTitle = "Converted Form",
PaperSize = PaperKind.A4,
Margins =
{
All = 1.375,
Unit = Unit.Centimeters
}
},
Objects =
{
new ObjectSettings { RawData = File.ReadAllBytes(uri) }
}
};
byte[] pdfBuf = converter.Convert(document);
FileStream fs = new FileStream(path, FileMode.Create);
fs.Write(pdfBuf, 0, pdfBuf.Length);
fs.Close();
}
}
}
The Controller is as follows:
[Route("converthtml")]
[HttpPost]
[MIMEContentFilter]
public async Task<HttpResponseMessage> ConvertHtml()
{
string temppath = System.IO.Path.GetTempPath();
var streamProvider = new MultipartFormDataStreamProvider(temppath);
await Request.Content.ReadAsMultipartAsync(streamProvider);
string filepath = streamProvider.FileData.Select(entry => entry.LocalFileName.Replace(temppath + "\\", "")).First<string>();
string pdfpath = System.IO.Path.GetTempFileName();
pdfpath = pdfpath.Substring(0, pdfpath.LastIndexOf('.')) + ".pdf";
new PDFcreator().convert(pdfpath, filepath);
var stream = new FileStream(pdfpath, FileMode.Open);
var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return result;
}
Here's where it gets a little odd: Experimenting in Fiddler, sending a file once will return the PDF immediately. However, all subsequent POSTs will leave Fiddler hanging.
Examining Task Manager shows the CPU and Memory for this task to jump up to 13.5% and ~96MB respectively.
The Temp folder (where the files are stored), on a successful run, will have three files in it: the original uploaded file (stored with a GUID-like name), the file generated via wkHtmlToPdf (in the form "wktemp-"), and the generated pdf (as tempXXXX.pdf).
In the case of it hanging, only the first file can be found, indicating that the problem is somewhere in wkHtmlToPdf itself.
However, the real kicker is when the process is manually killed in Task Manager, the API completes successfully, returns the pdf, fully created!
If IIS is reset, the process returns to the original state; a new attempt will work without issue.
Obviously, resetting IIS after every call is hardly viable, nor is manually killing the process each time...
Is this a bug / are there any solutions to this issue?

EDIT: Very important - this answer had a lot of votes, but is not complete. Check the marked solution
var tempFolderDeployment = new TempFolderDeployment();
var win32EmbeddedDeployment = new Win32EmbeddedDeployment(tempFolderDeployment);
var remotingToolset = new RemotingToolset<PdfToolset>(win32EmbeddedDeployment);
var converter =
new ThreadSafeConverter(remotingToolset);
byte[] pdfBuf = converter.Convert(document);
remotingToolset.Unload();
Unload remotingToolset will prevent hanging
RemotingToolset.Unload();

Very important-
#toshkata-tonev answer helped me, but when a lot of sessions used this function our server crushed because over CPU!
The point is that the process should be shared by all sessions as static shared function.
So this was the solution for me:
Implementation:
Create a static class in your application:
public static class TuesPechkinInitializerService {
private static string staticDeploymentPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wkhtmltopdf");
public static void CreateWkhtmltopdfPath()
{
if (Directory.Exists(staticDeploymentPath) == false)
{
Directory.CreateDirectory(staticDeploymentPath);
}
}
public static IConverter converter =
new ThreadSafeConverter(
new RemotingToolset<PdfToolset>(
new Win64EmbeddedDeployment(
new StaticDeployment(staticDeploymentPath)
)
)
);
}
In GLOBAL.asax, I initialize that class on project start:
TuesPechkinInitializerService.CreateWkhtmltopdfPath();
And to use it:
HtmlToPdfDocument pdfDocument = new HtmlToPdfDocument
{
GlobalSettings = new GlobalSettings(),
Objects =
{
new ObjectSettings
{
ProduceLocalLinks = true,
ProduceForms = true,
HtmlText = htmlContent
}
}
};
byte[] pdfDocumentData = TuesPechkinInitializerService.converter.Convert(pdfDocument);
Thanks to:
https://github.com/tuespetre/TuesPechkin/issues/152

It seems you are using WkHtmlToPdf 64 bits and you've installed the 32 bits one.
You should change :
IConverter converter = new StandardConverter(
new RemotingToolset<PdfToolset>(
new Win64EmbeddedDeployment(
new TempFolderDelpoyment())));
to
IConverter converter = new StandardConverter(
new RemotingToolset<PdfToolset>(
new Win32EmbeddedDeployment(
new TempFolderDelpoyment())));

Related

Calling WEB API to download excel file

below is C# WEB API Code to generate Excel :
public class FileExportController : ApiController
{
[HttpGet]
public HttpResponseMessage Get()
{
var callerContext = CallerContext.DefaultCallerContext;
ReportingInput userInput = new ReportingInput();
userInput.ClientOneCode = "AVON";
string handle = Guid.NewGuid().ToString();
var #event = new GetJobReprotDataBlEvent(callerContext, userInput);
WebApiApplication.ApplicationInitializerObj.EventBus.Publish(#event);
XLWorkbook wb = new FileExportEngine().ExportExcel(#event.ReportData); //this is returning XLWorkbook
string fileName = "JobReport_" + DateTime.Now.ToString("yyyy -MM-dd HH':'mm':'ss") + ".xlsx";
using (MemoryStream memoryStream = new MemoryStream())
{
wb.SaveAs(memoryStream);
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(memoryStream.ToArray())
};
result.Content.Headers.ContentDisposition =
new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = fileName
};
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
return result;
}
}
When I call this API from browser, I am able to generate excel file.
http://localhost/ETLScheduler/api/FileExport -- this is working when hit direct in browser
Now I want to use consume this API in angular 5 application.I have a button.On click button I call the component method downloadFile() to download the file.
Below is the code :
downloadReport() {
this._service.downloadJobReport('AVON');
}
where downloadJobReport() is in my service file as below :
downloadJobReport(clientCode: string) {
return this._http.get(APIs.downloadJobReport);
}
When I am running the application and click on Download button, I am getting nothing, I mean file is not downloading. Can anyone have idea,how should I update my angular code to consume the API.
Thanks in advance.
As you mentioned above in comments you are using below angular code to download file:
downloadFile(data: Blob) {
const contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
const blob = new Blob([data], { type: contentType });
const url = window.URL.createObjectURL(blob);
window.open(url);
}
As I also have tried this code, it is working in chrome browser but not working in IE and edge.
You may update your method somthing like below:
var downloadFile=function (file_name, content) {
var csvData = new Blob([content], { type: 'text/csv' });
if (window.navigator && window.navigator.msSaveOrOpenBlob) { // for IE
window.navigator.msSaveOrOpenBlob(csvData, file_name);
} else { // for Non-IE (chrome, firefox etc.)
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
var csvUrl = URL.createObjectURL(csvData);
a.href = csvUrl;
a.download = file_name;
a.click();
URL.revokeObjectURL(a.href)
a.remove();
}
};
you can refer below link for more information:
Open links made by createObjectURL in IE11
Problem is, that Angular expects JSON as a result. You need to configure your GET request so, that it expects something different.
public downloadJobReport(clientCode: string)): Observable<Blob> {
return this._http.get(APIs.downloadJobReport, { responseType: 'blob' });
}
Just a tiny question, you pass an argument clientCode to the downloadJobReport, but never use it. Maybe wise to leave that out?

Display a local PDF file with CefSharp

I'm trying to display a local pdf file using a custom LocalSchemeHandler which reads a memory stream from the file.
The file exists and the memory stream is being read properly. But there is nothing being displayed in the browser window. Displaying the same file via file scheme works.
ResourceHandler:
public class LocalSchemeHandler : ResourceHandler
{
public override bool ProcessRequestAsync(IRequest request, ICallback callback)
{
var uri = new Uri(request.Url);
var file = uri.AbsolutePath;
Task.Run(() =>
{
using (callback)
{
if (!File.Exists(file))
{
callback.Cancel();
return;
}
byte[] bytes = File.ReadAllBytes(file);
var stream = new MemoryStream(bytes);
if (stream == null)
{
callback.Cancel();
}
else
{
stream.Position = 0;
ResponseLength = stream.Length;
var fileExtension = Path.GetExtension(file);
MimeType = GetMimeType(fileExtension);
StatusCode = (int)HttpStatusCode.OK;
Stream = stream;
callback.Continue();
}
}
});
return true;
}
}
ISchemeHandlerFactory:
public class CustomProtocolSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "local";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
return new LocalSchemeHandler();
}
}
Settings:
var settings = new CefSettings();
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = CustomProtocolSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new CustomProtocolSchemeHandlerFactory()
});
// Increase the log severity so CEF outputs detailed information, useful for debugging
settings.LogSeverity = LogSeverity.Default;
Cef.Initialize(settings);
EDIT
Trying to display the PDF file via ResourceHandler.FromFilePath also doesn't work (nothing is displayed).
public class CustomProtocolSchemeHandlerFactory : ISchemeHandlerFactory
{
public const string SchemeName = "local";
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
var uri = new Uri(request.Url);
var file = uri.AbsolutePath;
var fileExtension = Path.GetExtension(file);
var mimeType = ResourceHandler.GetMimeType(fileExtension);
return ResourceHandler.FromFilePath(file, mimeType);
}
}
EDIT2
After setting LogSeverity to Default the log says: [0524/150955.108:INFO:CONSOLE(20)] "Refused to load plugin data from 'local://c/Users/abidh/Desktop/pdf.pdf' because it violates the following Content Security Policy directive: "object-src * blob: externalfile: file: filesystem: data:".
Didn't find a solution using google. Thanks to amaitland, using the IsCSPBypassing property solved the problem:
var settings = new CefSettings();
settings.RegisterScheme(new CefCustomScheme
{
SchemeName = CustomProtocolSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new CustomProtocolSchemeHandlerFactory(),
IsCSPBypassing = true
});
settings.LogSeverity = LogSeverity.Error;
Cef.Initialize(settings);
Set the PDF file path to ChromiumWebBrowser.Address as format like file:///C:/Users/xxx/yyy.pdf, the CEFSharp will render PDF just like Chrome browser.

Starting a specific Firefox Profile with Selenium 3

I am trying to upgrade from Selenium 2 to Selenium 3 but the old handling, which was pretty easy and fast doesn't work anymore (and the documentation is nonexisting as it seems)
This is the program at the moment and what I want is to open a Firefox driver with the profile: SELENIUM
Sadly it doesn't work and always shuts down with the Error:
An unhandled exception of type 'System.InvalidOperationException' > occurred in WebDriver.dll
Additional information: corrupt deflate stream
This is my program at the moment:
public Program()
{
FirefoxOptions _options = new FirefoxOptions();
FirefoxProfileManager _profileIni = new FirefoxProfileManager();
FirefoxDriverService _service = FirefoxDriverService.CreateDefaultService(#"C:\Programme\IMaT\Output\Release\Bin");
_service.FirefoxBinaryPath = #"C:\Program Files (x86)\Mozilla Firefox\firefox.exe";
try
{
if ((_options.Profile = _profileIni.GetProfile("SELENIUM")) == null)
{
Console.WriteLine("SELENIUM PROFILE NOT FOUND");
_profile.SetPreference("network.proxy.type", 0); // disable proxy
_profile = new FirefoxProfile();
}
}
catch
{
throw new Exception("Firefox needs a Profile with \"SELENIUM\"");
}
IWebDriver driver = new FirefoxDriver(_service,_options,new System.TimeSpan(0,0,30));
driver.Navigate().GoToUrl("ld-hybrid.fronius.com");
Console.Write("rtest");
}
static void Main(string[] args)
{
new Program();
}
Without Loading the Profile it works with just new FirefoxDriver(_service) but the profile is mandatory.
In Selenium 2 I handled it with this code:
FirefoxProfileManager _profileIni = new FirefoxProfileManager();
// use custom temporary profile
try {
if ((_profile = _profileIni.GetProfile("SELENIUM")) == null)
{
Console.WriteLine("SELENIUM PROFILE NOT FOUND");
_profile.SetPreference("network.proxy.type", 0); // disable proxy
_profile = new FirefoxProfile();
}
}
catch
{
throw new Exception("Firefox needs a Profile with \"SELENIUM\"");
}
_profile.SetPreference("intl.accept_languages", _languageConfig);
_driver = new FirefoxDriver(_profile);
Fast and simple, but as the Driver doesn't support a Constructor with service and profile I don't really know how to get this to work, any help would be appreciated
This exception is due to a bug in the .Net library. The code generating the Zip of the profile is failing to provide a proper Zip.
One way to overcome this issue would be to overload FirefoxOptions and use the archiver from .Net framework (System.IO.Compression.ZipArchive) instead of the faulty ZipStorer:
var options = new FirefoxOptionsEx();
options.Profile = #"C:\Users\...\AppData\Roaming\Mozilla\Firefox\Profiles\ez3krw80.Selenium";
options.SetPreference("network.proxy.type", 0);
var service = FirefoxDriverService.CreateDefaultService(#"C:\downloads", "geckodriver.exe");
var driver = new FirefoxDriver(service, options, TimeSpan.FromMinutes(1));
class FirefoxOptionsEx : FirefoxOptions {
public new string Profile { get; set; }
public override ICapabilities ToCapabilities() {
var capabilities = (DesiredCapabilities)base.ToCapabilities();
var options = (IDictionary)capabilities.GetCapability("moz:firefoxOptions");
var mstream = new MemoryStream();
using (var archive = new ZipArchive(mstream, ZipArchiveMode.Create, true)) {
foreach (string file in Directory.EnumerateFiles(Profile, "*", SearchOption.AllDirectories)) {
string name = file.Substring(Profile.Length + 1).Replace('\\', '/');
if (name != "parent.lock") {
using (Stream src = File.OpenRead(file), dest = archive.CreateEntry(name).Open())
src.CopyTo(dest);
}
}
}
options["profile"] = Convert.ToBase64String(mstream.GetBuffer(), 0, (int)mstream.Length);
return capabilities;
}
}
And to get the directory for a profile by name:
var manager = new FirefoxProfileManager();
var profiles = (Dictionary<string, string>)manager.GetType()
.GetField("profiles", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(manager);
string directory;
if (profiles.TryGetValue("Selenium", out directory))
options.Profile = directory;

Uploading objects to google cloud storage buckets in c#

Can someone please provide an example of how to use Google.Apis.Storage.v1 for uploading files to google cloud storage in c#?
I found that this basic operation is not as straight forward as you might expect. Google's documentation about it's Storage API is lacking in information about using it in C# (or any other .NET language). Searching for 'how to upload file to google cloud storage in c#' didn't exactly help me, so here is my working solution with some comments:
Preparation:
You need to create OAuth2 account in your Google Developers Console - go to Project/APIs & auth/Credentials.
Copy Client ID & Client Secret to your code. You will also need your Project name.
Code (it assumes that you've added Google.Apis.Storage.v1 via NuGet):
First, you need to authorize your requests:
var clientSecrets = new ClientSecrets();
clientSecrets.ClientId = clientId;
clientSecrets.ClientSecret = clientSecret;
//there are different scopes, which you can find here https://cloud.google.com/storage/docs/authentication
var scopes = new[] {#"https://www.googleapis.com/auth/devstorage.full_control"};
var cts = new CancellationTokenSource();
var userCredential = await GoogleWebAuthorizationBroker.AuthorizeAsync(clientSecrets,scopes, "yourGoogle#email", cts.Token);
Sometimes you might also want to refresh authorization token via:
await userCredential.RefreshTokenAsync(cts.Token);
You also need to create Storage Service:
var service = new Google.Apis.Storage.v1.StorageService();
Now you can make requests to Google Storage API.
Let's start with creating a new bucket:
var newBucket = new Google.Apis.Storage.v1.Data.Bucket()
{
Name = "your-bucket-name-1"
};
var newBucketQuery = service.Buckets.Insert(newBucket, projectName);
newBucketQuery.OauthToken = userCredential.Result.Token.AccessToken;
//you probably want to wrap this into try..catch block
newBucketQuery.Execute();
And it's done. Now, you can send a request to get list of all of your buckets:
var bucketsQuery = service.Buckets.List(projectName);
bucketsQuery.OauthToken = userCredential.Result.Token.AccessToken;
var buckets = bucketsQuery.Execute();
Last part is uploading new file:
//enter bucket name to which you want to upload file
var bucketToUpload = buckets.Items.FirstOrDefault().Name;
var newObject = new Object()
{
Bucket = bucketToUpload,
Name = "some-file-"+new Random().Next(1,666)
};
FileStream fileStream = null;
try
{
var dir = Directory.GetCurrentDirectory();
var path = Path.Combine(dir, "test.png");
fileStream = new FileStream(path, FileMode.Open);
var uploadRequest = new Google.Apis.Storage.v1.ObjectsResource.InsertMediaUpload(service, newObject,
bucketToUpload,fileStream,"image/png");
uploadRequest.OauthToken = userCredential.Result.Token.AccessToken;
await uploadRequest.UploadAsync();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (fileStream != null)
{
fileStream.Dispose();
}
}
And bam! New file will be visible in you Google Developers Console inside of selected bucket.
You can use Google Cloud APIs without SDK in the following ways:
Required api-key.json file
Install package Google.Apis.Auth.OAuth2 in order to authorize the
HTTP web request
You can set the default configuration for your application in this
way
I did the same using .NET core web API and details are given below:
Url details:
"GoogleCloudStorageBaseUrl": "https://www.googleapis.com/upload/storage/v1/b/",
"GoogleSpeechBaseUrl": "https://speech.googleapis.com/v1/operations/",
"GoogleLongRunningRecognizeBaseUrl": "https://speech.googleapis.com/v1/speech:longrunningrecognize",
"GoogleCloudScope": "https://www.googleapis.com/auth/cloud-platform",
public void GetConfiguration()
{
// Set global configuration
bucketName = _configuration.GetValue<string>("BucketName");
googleCloudStorageBaseUrl = _configuration.GetValue<string>("GoogleCloudStorageBaseUrl");
googleSpeechBaseUrl = _configuration.GetValue<string>("GoogleSpeechBaseUrl");
googleLongRunningRecognizeBaseUrl = _configuration.GetValue<string>("GoogleLongRunningRecognizeBaseUrl");
// Set google cloud credentials
string googleApplicationCredentialsPath = _configuration.GetValue<string>("GoogleCloudCredentialPath");
using (Stream stream = new FileStream(googleApplicationCredentialsPath, FileMode.Open, FileAccess.Read))
googleCredential = GoogleCredential.FromStream(stream).CreateScoped(_configuration.GetValue<string>("GoogleCloudScope"));
}
Get Oauth token:
public string GetOAuthToken()
{
return googleCredential.UnderlyingCredential.GetAccessTokenForRequestAsync("https://accounts.google.com/o/oauth2/v2/auth", CancellationToken.None).Result;
}
To upload file to cloud bucket:
public async Task<string> UploadMediaToCloud(string filePath, string objectName = null)
{
string bearerToken = GetOAuthToken();
byte[] fileBytes = File.ReadAllBytes(filePath);
objectName = objectName ?? Path.GetFileName(filePath);
var baseUrl = new Uri(string.Format(googleCloudStorageBaseUrl + "" + bucketName + "/o?uploadType=media&name=" + objectName + ""));
using (WebClient client = new WebClient())
{
client.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + bearerToken);
client.Headers.Add(HttpRequestHeader.ContentType, "application/octet-stream");
byte[] response = await Task.Run(() => client.UploadData(baseUrl, "POST", fileBytes));
string responseInString = Encoding.UTF8.GetString(response);
return responseInString;
}
}
In order to perform any action to the cloud API, just need to make a HttpClient get/post request as per the requirement.
Thanks
This is for Google.Cloud.Storage.V1 (not Google.Apis.Storage.v1), but appears to be a bit simpler to perform an upload now. I started with the Client libraries "Getting Started" instructions to create a service account and bucket, then experimented to find out how to upload an image.
The process I followed was:
Sign up for Google Cloud free trial
Create a new project in Google Cloud (remember the project name\ID for later)
Create a Project Owner service account - this will result in a json file being downloaded that contains the service account credentials. Remember where you put that file.
The getting started docs get you to add the path to the JSON credentials file into an environment variable called GOOGLE_APPLICATION_CREDENTIALS - I couldn't get this to work through the provided instructions. Turns out it is not required, as you can just read the JSON file into a string and pass it to the client constructor.
I created an empty WPF project as a starting point, and a single ViewModel to house the application logic.
Install the Google.Cloud.Storage.V1 nuget package and it should pull in all the dependencies it needs.
Onto the code.
MainWindow.xaml
<StackPanel>
<Button
Margin="50"
Height="50"
Content="BEGIN UPLOAD"
Click="OnButtonClick" />
<ContentControl
Content="{Binding Path=ProgressBar}" />
</StackPanel>
MainWindow.xaml.cs
public partial class MainWindow
{
readonly ViewModel _viewModel;
public MainWindow()
{
_viewModel = new ViewModel(Dispatcher);
DataContext = _viewModel;
InitializeComponent();
}
void OnButtonClick(object sender, RoutedEventArgs args)
{
_viewModel.UploadAsync().ConfigureAwait(false);
}
}
ViewModel.cs
public class ViewModel
{
readonly Dispatcher _dispatcher;
public ViewModel(Dispatcher dispatcher)
{
_dispatcher = dispatcher;
ProgressBar = new ProgressBar {Height=30};
}
public async Task UploadAsync()
{
// Google Cloud Platform project ID.
const string projectId = "project-id-goes-here";
// The name for the new bucket.
const string bucketName = projectId + "-test-bucket";
// Path to the file to upload
const string filePath = #"C:\path\to\image.jpg";
var newObject = new Google.Apis.Storage.v1.Data.Object
{
Bucket = bucketName,
Name = System.IO.Path.GetFileNameWithoutExtension(filePath),
ContentType = "image/jpeg"
};
// read the JSON credential file saved when you created the service account
var credential = Google.Apis.Auth.OAuth2.GoogleCredential.FromJson(System.IO.File.ReadAllText(
#"c:\path\to\service-account-credentials.json"));
// Instantiates a client.
using (var storageClient = Google.Cloud.Storage.V1.StorageClient.Create(credential))
{
try
{
// Creates the new bucket. Only required the first time.
// You can also create buckets through the GCP cloud console web interface
storageClient.CreateBucket(projectId, bucketName);
System.Windows.MessageBox.Show($"Bucket {bucketName} created.");
// Open the image file filestream
using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open))
{
ProgressBar.Maximum = fileStream.Length;
// set minimum chunksize just to see progress updating
var uploadObjectOptions = new Google.Cloud.Storage.V1.UploadObjectOptions
{
ChunkSize = Google.Cloud.Storage.V1.UploadObjectOptions.MinimumChunkSize
};
// Hook up the progress callback
var progressReporter = new Progress<Google.Apis.Upload.IUploadProgress>(OnUploadProgress);
await storageClient.UploadObjectAsync(
newObject,
fileStream,
uploadObjectOptions,
progress: progressReporter)
.ConfigureAwait(false);
}
}
catch (Google.GoogleApiException e)
when (e.Error.Code == 409)
{
// When creating the bucket - The bucket already exists. That's fine.
System.Windows.MessageBox.Show(e.Error.Message);
}
catch (Exception e)
{
// other exception
System.Windows.MessageBox.Show(e.Message);
}
}
}
// Called when progress updates
void OnUploadProgress(Google.Apis.Upload.IUploadProgress progress)
{
switch (progress.Status)
{
case Google.Apis.Upload.UploadStatus.Starting:
ProgressBar.Minimum = 0;
ProgressBar.Value = 0;
break;
case Google.Apis.Upload.UploadStatus.Completed:
ProgressBar.Value = ProgressBar.Maximum;
System.Windows.MessageBox.Show("Upload completed");
break;
case Google.Apis.Upload.UploadStatus.Uploading:
UpdateProgressBar(progress.BytesSent);
break;
case Google.Apis.Upload.UploadStatus.Failed:
System.Windows.MessageBox.Show("Upload failed"
+ Environment.NewLine
+ progress.Exception);
break;
}
}
void UpdateProgressBar(long value)
{
_dispatcher.Invoke(() => { ProgressBar.Value = value; });
}
// probably better to expose progress value directly and bind to
// a ProgressBar in the XAML
public ProgressBar ProgressBar { get; }
}
Use of Google.Apis.Storage.v1 for uploading files using SDK to google cloud storage in c#:
Required api-key.json file
Install the package Google.Cloud.Storage.V1; and Google.Apis.Auth.OAuth2;
The code is given below to upload the file to the cloud
private string UploadFile(string localPath, string objectName = null)
{
string projectId = ((Google.Apis.Auth.OAuth2.ServiceAccountCredential)googleCredential.UnderlyingCredential).ProjectId;
try
{
// Creates the new bucket.
var objResult = storageClient.CreateBucket(projectId, bucketName);
if (!string.IsNullOrEmpty(objResult.Id))
{
// Upload file to google cloud server
using (var f = File.OpenRead(localPath))
{
objectName = objectName ?? Path.GetFileName(localPath);
var objFileUploadStatus1 = storageClient.UploadObject(bucketName, objectName, null, f);
}
}
}
catch (Google.GoogleApiException ex)
{
// Error code =409, means bucket already created/exist then upload file in the bucket
if (ex.Error.Code == 409)
{
// Upload file to google cloud server
using (var f = File.OpenRead(localPath))
{
objectName = objectName ?? Path.GetFileName(localPath);
var objFileUploadStatus2 = storageClient.UploadObject(bucketName, objectName, null, f);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
return objectName;
}
To set the credentials
private bool SetStorageCredentials()
{
bool status = true;
try
{
if (File.Exists(credential_path))
{
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", credential_path);
using (Stream objStream = new FileStream(Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS"), FileMode.Open, FileAccess.Read))
googleCredential = GoogleCredential.FromStream(objStream);
// Instantiates a client.
storageClient = StorageClient.Create();
channel = new Grpc.Core.Channel(SpeechClient.DefaultEndpoint.Host, googleCredential.ToChannelCredentials());
}
else
{
DialogResult result = MessageBox.Show("File " + Path.GetFileName(credential_path) + " does not exist. Please provide the correct path.");
if (result == System.Windows.Forms.DialogResult.OK)
{
status = false;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
status = false;
}
return status;
}
I used SDK in one of my window application. You can use the same code according to your needs/requirements.
You'll be happy to know it still works in 2016...
I was googling all over using fancy key words like "google gcp C# upload image", until I just plain asked the question: "How do I upload an image to google bucket using C#"... and here I am. I removed the .Result in the user credential, and this was the final edit that worked for me.
// ******
static string bucketForImage = ConfigurationManager.AppSettings["testStorageName"];
static string projectName = ConfigurationManager.AppSettings["GCPProjectName"];
string gcpPath = Path.Combine(Server.MapPath("~/Images/Gallery/"), uniqueGcpName + ext);
var clientSecrets = new ClientSecrets();
clientSecrets.ClientId = ConfigurationManager.AppSettings["GCPClientID"];
clientSecrets.ClientSecret = ConfigurationManager.AppSettings["GCPClientSc"];
var scopes = new[] { #"https://www.googleapis.com/auth/devstorage.full_control" };
var cts = new CancellationTokenSource();
var userCredential = await GoogleWebAuthorizationBroker.AuthorizeAsync(clientSecrets, scopes, ConfigurationManager.AppSettings["GCPAccountEmail"], cts.Token);
var service = new Google.Apis.Storage.v1.StorageService();
var bucketToUpload = bucketForImage;
var newObject = new Google.Apis.Storage.v1.Data.Object()
{
Bucket = bucketToUpload,
Name = bkFileName
};
FileStream fileStream = null;
try
{
fileStream = new FileStream(gcpPath, FileMode.Open);
var uploadRequest = new Google.Apis.Storage.v1.ObjectsResource.InsertMediaUpload(service, newObject,
bucketToUpload, fileStream, "image/"+ ext);
uploadRequest.OauthToken = userCredential.Token.AccessToken;
await uploadRequest.UploadAsync();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (fileStream != null)
{
fileStream.Dispose();
}
}
// ******
Here is the link to their official C# example of ".NET Bookshelf App" using Google Cloud storage.
https://cloud.google.com/dotnet/docs/getting-started/using-cloud-storage
Source on github:
https://github.com/GoogleCloudPlatform/getting-started-dotnet/blob/master/aspnet/3-binary-data/Services/ImageUploader.cs
https://github.com/GoogleCloudPlatform/getting-started-dotnet/tree/master/aspnet/3-binary-data
Nuget
https://www.nuget.org/packages/Google.Cloud.Storage.V1/
Here are 2 examples that helped me to upload files to a bucket in Google Cloud Storage with Google.Cloud.Storage.V1 (not Google.Apis.Storage.v1):
Upload files to Google cloud storage using c#
Uploading .csv Files to Google Cloud Storage using C# .Net
I got both working on a C# Console Application just for testing purposes.
#February 2021
string _projectId = "YOUR-PROJECT-ID-GCP"; //ProjectID also present in the json file
GoogleCredential _credential = GoogleCredential.FromFile("credential-cloud-file-123418c9e06c.json");
/// <summary>
/// UploadFile to GCS Bucket
/// </summary>
/// <param name="bucketName"></param>
/// <param name="localPath">my-local-path/my-file-name</param>
/// <param name="objectName">my-file-name</param>
public void UploadFile(string bucketName, string localPath, string objectName)
{
var storage = StorageClient.Create(_credential);
using var fileStream = File.OpenRead(localPath);
storage.UploadObject(bucketName, objectName, null, fileStream);
Console.WriteLine($"Uploaded {objectName}.");
}
You get the credentials JSON file from the google cloud portal where you create a bucket under your project..
Simple, with auth:
private void SaveFileToGoogleStorage(string path, string? fileName, string ext)
{
var filePath = Path.Combine(path, fileName + ext);
var gcCredentialsPath = Path.Combine(Environment.CurrentDirectory, "gc_sa_key.json");
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", gcCredentialsPath);
var gcsStorage = StorageClient.Create();
using var f = File.OpenRead(filePath);
var objectName = Path.GetFileName(filePath);
gcsStorage.UploadObject(_bucketName, objectName, null, f);
Console.WriteLine($"Uploaded {objectName}.");
}

Simplest way to Upload a document to sharepoint using web services

I want to upload to a Selected Document (from my system.I am having it's path with me).
To a destination path on Sharepoint ( may be list or folder ).
I am accessing sharepoint remotely using web services (C#).
I read various solutions like by using CopyIntoItems method.
But not getting proper example for it ( unable to pass parameters properly.tried example given on msdn)
Can anyone help me out to get simple and understandable solution.
Example:
Source_FileUrl = "c:/SampleFile.txt";
Desination_Url = "http://MyServer/Site/List/Folder";
Just want to upload "SampleFile.txt" on Destination_Url.
try this one
try
{
//Copy WebService Settings
string webUrl = "http://sharepointportal.ABC.com/";
WSCopy.Copy copyService = new WSCopy.Copy();
copyService.Url = webUrl + "/_vti_bin/copy.asmx";
copyService.Credentials = new NetworkCredential("username", "****", "Domain");
//Declare and initiates the Copy WebService members for uploading
string sourceUrl = "C:\\Work\\Ticket.Doc";
//Change file name if not exist then create new one
string[] destinationUrl = { "http://sharepointportal.ABC.com/personal/username/Document Upload/Testing Document/newUpload.Doc" };
WSCopy.CopyResult cResult1 = new WSCopy.CopyResult();
WSCopy.CopyResult cResult2 = new WSCopy.CopyResult();
WSCopy.CopyResult[] cResultArray = { cResult1, cResult2 };
WSCopy.FieldInformation fFiledInfo = new WSCopy.FieldInformation();
fFiledInfo.DisplayName = "Description";
fFiledInfo.Type = WSCopy.FieldType.Text;
fFiledInfo.Value = "Ticket";
WSCopy.FieldInformation[] fFiledInfoArray = { fFiledInfo };
FileStream strm = new FileStream(sourceUrl, FileMode.Open, FileAccess.Read);
byte[] fileContents = new Byte[strm.Length];
byte[] r = new Byte[strm.Length];
int ia = strm.Read(fileContents, 0, Convert.ToInt32(strm.Length));
strm.Close();
//Copy the document from Local to SharePoint
uint copyresult = copyService.CopyIntoItems(sourceUrl, destinationUrl, fFiledInfoArray, fileContents, out cResultArray);
MessageBox.Show("Suceess");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}

Categories