GhostScript.NET GSPrint permissions on IIS 8 - asp.net

I've added a GhostScript.NET to my application, and have been able to successfully print PDFs using GSPrint on my local machine. Unfortunately, after deploying the updated application to the server as well as installing GSView (includes GSPrint), the function to print just hangs without any errors.
My first guess is that since I am writing to the filesystem in order for GSPrint to print the file, is that it has something to do with access security rights. I'm using IIS 8 on windows server 2012. If anyone has any experience with deploying GSPrint or on how to troubleshoot this issue, I'd appreciate it.
Here's the code:
public static void PrintingQueue(Queue<byte[]> printQueue, string printer, int copies)
{
Parallel.ForEach(printQueue, (currentFile) =>
{
PrintWithGSPrint(currentFile, printer, copies);
});
printQueue.Clear();
}
private static void PrintWithGSPrint(byte[] pdfFormBytes, string printer, int copies)
{
try
{
var fileName = Path.GetTempFileName();
using (var file = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite))
{
file.Write(pdfFormBytes, 0, pdfFormBytes.Length);
//this uses GSPrint, which console commands are different from vanilla ghostscript.
var gsArguments = $"-noquery -portrait -printer\"{printer}\" \"{fileName}\"";
var gsLocation = #"C:\Program Files\Ghostgum\gsview\gsprint.exe";
var gsProcessInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Hidden,
FileName = gsLocation,
Arguments = gsArguments
};
var gsProcess = Process.Start(gsProcessInfo);
gsProcess.WaitForExit();
file.Close();
}
File.Delete(fileName);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

Related

Switch from Visual Studio 2012 --> 2019 Broke async Task and FileResult

An ASP.NET MVC solution that was working fine in VS 2012 stopped working in 2019 and I cannot find what has changed to break it.
Originally I had the code in the first block - the async task would go to the file storage and retrieve the file, and then the file was sent to the browser using a FileResult that the controller called automatically. After a VERY painful change to VS 2019 and updating everything (.NET runtime, 3rd party libraries, etc.) I have the application working again except for this issue.
I tried creating a new FileStreamResult (which is in the 2nd block) but that does not get called either. When I click on a link that calls this:
<a href="/Cert/File?folder=&filename=#HttpUtility.UrlEncode(FilePath)" ...
It gives me a blank page instead of downloading the file as it used to.
public async Task FileAsync(string folder, string filename)
{
AsyncManager.OutstandingOperations.Increment();
var ReadObjectTask = _fileStorageProvider.ReadObjectDataAsync(folder, filename);
Stream ROResult = await ReadObjectTask;
AsyncManager.Parameters["stream"] = ROResult;
AsyncManager.Parameters["filename"] = filename;
AsyncManager.OutstandingOperations.Decrement();
}
public FileResult FileCompleted(Stream stream, string filename)
{
if (stream == null)
{
return File(Server.MapPath(Url.Content("~/Content/bad_file.png")), "image/png");
}
var file = new FileStreamResult(stream, MIMEAssistant.GetMIMEType(filename));
if (filename.Contains("/"))
{
filename = filename.Split('/').Last();
}
file.FileDownloadName = filename;
return file;
}
Here is the FileStreamResult I tried:
public System.Web.Mvc.FileStreamResult FileCompleted(Stream stream, string contentType, string filename)
{
if (stream == null)
{
string bFile = Server.MapPath(Url.Content("~/Content/bad_file.png"));
Stream blankfile = System.IO.File.OpenRead(bFile);
return File(blankfile, MIMEAssistant.GetMIMEType(bFile), System.IO.Path.GetFileName(bFile));
}
if (filename.Contains("/"))
{
filename = filename.Split('/').Last();
}
return File(stream, MIMEAssistant.GetMIMEType(filename), filename);
}
(The filename.Contains part is old code from a predecessor that I just need to replace with Path.GetFileName - sorry I did not clean it up before I posted.)
I decided to make the Async Task one of type and moved the
stream processing into that procedure to solve my problem. I do not know
why the Async Task that was working in 2012 stopped in 2019.
public async Task<FileResult> FileAsync(string folder, string filename)
{
AsyncManager.OutstandingOperations.Increment();
var ReadObjectTask = _fileStorageProvider.ReadObjectDataAsync(folder, filename);
Stream ROResult = await ReadObjectTask;
AsyncManager.Parameters["stream"] = ROResult;
AsyncManager.Parameters["filename"] = filename;
AsyncManager.OutstandingOperations.Decrement();
if (ROResult == null)
{
return File(Server.MapPath(Url.Content("~/Content/bad_file.png")), "image/png");
}
var file = new FileStreamResult(ROResult, MIMEAssistant.GetMIMEType(filename));
file.FileDownloadName = System.IO.Path.GetFileName(filename);
return file;
}

Xamarin forms how to Get existing local database

How do you Get an existing database from a device or emulator ?
device not rooted
I'm using Microsoft.WindowsAzure.MobileServices
public bool InitialiseDb()
{
try
{
Store = new MobileServiceSQLiteStore(offlineDbPath);
Store.DefineTable<Products>();
_client.SyncContext.InitializeAsync(Store);
this.productTable = _client.GetSyncTable<Products>();
return true;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
return false;
}
}
You can copy the existing database into a folder you can access
Create path to database :
string filepath = "data/data/[package-name]/files/[name-of-db]";
You can get your package name from your android project options
then use the following code to extract it:
string filepath = "data/data/com.foo.foo/files/localstorage.db";
var bytes = System.IO.File.ReadAllBytes(filepath);
var fileCopyName = string.Format("/sdcard/Database_{0:dd-MM-yyyy_HH-mm-ss-tt}.db", System.DateTime.Now);
System.IO.File.WriteAllBytes(fileCopyName, bytes);

Generating PDFs using Phantom JS on .NET applications

I have been looking into phantomJS and looks like it could be a great tool to use generating PDFs. I wonder if anyone have successfully used it for their .NET applications.
My specific question is: how would you use modules like rasterize.js on the server, receive requests and send back generated pdfs as a response.
My general question is: is there any best practice for using phantomJS with .NET Applications. What would be the best way to achieve it?
I am fairly new in .NET World and I would appreciate the more detailed answers. Thanks everyone. :)
I don't know about best practices, but, I'm using phantomJS with no problems with the following code.
public ActionResult DownloadStatement(int id)
{
string serverPath = HttpContext.Server.MapPath("~/Phantomjs/");
string filename = DateTime.Now.ToString("ddMMyyyy_hhmmss") + ".pdf";
new Thread(new ParameterizedThreadStart(x =>
{
ExecuteCommand("cd " + serverPath + #" & phantomjs rasterize.js http://localhost:8080/filetopdf/" + id.ToString() + " " + filename + #" ""A4""");
})).Start();
var filePath = Path.Combine(HttpContext.Server.MapPath("~/Phantomjs/"), filename);
var stream = new MemoryStream();
byte[] bytes = DoWhile(filePath);
return File(bytes, "application/pdf", filename);
}
private void ExecuteCommand(string Command)
{
try
{
ProcessStartInfo ProcessInfo;
Process Process;
ProcessInfo = new ProcessStartInfo("cmd.exe", "/K " + Command);
ProcessInfo.CreateNoWindow = true;
ProcessInfo.UseShellExecute = false;
Process = Process.Start(ProcessInfo);
}
catch { }
}
public ViewResult FileToPDF(int id)
{
var viewModel = file.Get(id);
return View(viewModel);
}
private byte[] DoWhile(string filePath)
{
byte[] bytes = new byte[0];
bool fail = true;
while (fail)
{
try
{
using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
bytes = new byte[file.Length];
file.Read(bytes, 0, (int)file.Length);
}
fail = false;
}
catch
{
Thread.Sleep(1000);
}
}
System.IO.File.Delete(filePath);
return bytes;
}
Here is the action flow:
The user clicks on a link to DownloadStatement Action. Inside there, a new Thread is created to call the ExecuteCommand method.
The ExecuteCommand method is responsible to call phantomJS. The string passed as an argument do the following.
Go to the location where the phantomJS app is and, after that, call rasterize.js with an URL, the filename to be created and a print format. (More about rasterize here).
In my case, what I really want to print is the content delivered by the action filetoupload. It's a simple action that returns a simple view. PhantomJS will call the URL passed as parameter and do all the magic.
While phantomJS is still creating the file, (I guess) I can not return the request made by the client. And that is why I used the DoWhile method. It will hold the request until the file is created by phantomJS and loaded by the app to the request.
If you're open to using NReco.PhantomJS, which provides a .NET wrapper for PhantomJS, you can do this very succinctly.
public async Task<ActionResult> DownloadPdf() {
var phantomJS = new PhantomJS();
try {
var temp = Path.Combine(Path.GetTempPath(),
Path.ChangeExtension(Path.GetRandomFileName(), "pdf")); //must end in .pdf
try {
await phantomJS.RunAsync(HttpContext.Server.MapPath("~/Scripts/rasterize.js"),
new[] { "https://www.google.com", temp });
return File(System.IO.File.ReadAllBytes(temp), "application/pdf");
}
finally {
System.IO.File.Delete(temp);
}
}
finally {
phantomJS.Abort();
}
}
Here's some very basic code to generate a PDF using Phantom.JS but you can find more information here: https://buttercms.com/blog/generating-pdfs-with-node
var webPage = require('webpage');
var page = webPage.create();
page.viewportSize = { width: 1920, height: 1080 };
page.open("http://www.google.com", function start(status) {
page.render('google_home.pdf, {format: 'pdf', quality: '100'});
phantom.exit();
});

Directory levels Quotas on remote shared folder

I have 2 servers in AD (2008R2)
On one of them I have shared folder (c:\Shared\dirForUserAAA ==> \DC1\dir1)
On other one I have c# program that must manage folder quota on \DC1\dir1
Is it possible and how it can be done?
I try to use this piece of code, but it works only on local paths :(
public static void SetQuotaToFolder(string UNCPathForQuota, int quotaLimitBytes)
{
if (!Directory.Exists(UNCPathForQuota))
{
Directory.CreateDirectory(UNCPathForQuota);
}
// Create our interface
IFsrmQuotaManager FSRMQuotaManager = new FsrmQuotaManagerClass();
IFsrmQuota Quota = null;
try
{
// First we need to see if there is already a quota on the directory.
Quota = FSRMQuotaManager.GetQuota(UNCPathForQuota);
// If there is quota then we just set it to our new size
Quota.QuotaLimit = quotaLimitBytes;
}
catch (COMException e)
{
unchecked
{
if (e.ErrorCode == (int)0x80045301)
{
// There is no quota on this directory so we need to create it.
Quota = FSRMQuotaManager.CreateQuota(UNCPathForQuota);
// And then set our desired quota
Quota.QuotaLimit = quotaLimitBytes;
}
else
{
// some other COM exception occured so we return the error
Console.WriteLine(e);
return;
}
}
}
catch (Exception e)
{
// Generic error handling would go here
Console.WriteLine(e);
return;
}
// and finally we commit our changes.
Quota.Commit();
}
}
Old Question, but if someone needs a hint:
Open a RemotePowershell on the server where your folders are saved. Then use the Cmdlets from here
Some code snippets:
Open Runspace:
public static Runspace CreateAndOpen(string domain, string username, string password, string computername)
{
string userName = username + "#" + domain;
var securePassword = password.ToSecureString();
PSCredential credential = new PSCredential(username, securePassword);
var connectionInfo = new WSManConnectionInfo(false, computername, 5985, "/wsman", shellUri, credential);
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Default;
connectionInfo.OpenTimeout = 2 * 60 * 1000; // 2 minutes
Runspace powershellRunspace = RunspaceFactory.CreateRunspace(connectionInfo);
powershellRunspace.Open();
return powershellRunspace;
}
Set a quota on a path
public void SetQuotaTemplateOnPath(Runspace runspace, string path, string template)
{
using (var pipe = runspace.CreatePipeline())
{
var newFsrmQuotaCommand = new Command("New-FsrmQuota");
newFsrmQuotaCommand.Parameters.Add("Path", path);
newFsrmQuotaCommand.Parameters.Add("Template", template);
newFsrmQuotaCommand.Parameters.Add("Confirm", false);
pipe.Commands.Add(newFsrmQuotaCommand);
var results = pipe.Invoke();
if (pipe.Error.Count > 0)
{
//Handle error
}
}
}

How to convert array of byte to original file (to provide download of file)

I m using Opendialogbox to read the file. Then stored the file in byte[] array.
file --> byte []
byte[] --> stored on SQL AZure in varbinary(max) field.
Here is my code:
OpenFileDialog ofd = new OpenFileDialog();
if ((bool)ofd.ShowDialog())
{
FileStream fileStream = ofd.File.OpenRead());
byte[] buffer = new byte[fileStream.Length];
int read = 0;
using (BinaryReader binaryReader = new BinaryReader(fileStream))
{
do
{
read = binaryReader.Read(buffer, 0, Convert.ToInt32(fileStream.Length));
// Stored the File in byte[] Array buffer
} while (read > 0);
}
}
Now I want to convert this byte array to the original file (like .doc,.txt,jpeg). i know the extension in which file is to be convert.
SQL AZure ---> byte[] // done
byte[] ---> to original file. // Problem
Please give solution to download the file.
One way - not necessarily the best - is as follows:
using (MemoryStream ms = new MemoryStream(theBytes))
{
using (FileStream fs = new FileStream(string.Format("C:\\tempfile.{0}", theExtension)))
{
ms.WriteTo(fs);
}
}
namespace FileSaveDialogDemo
{
public partial class MainPage : UserControl
{
#region Fields
SaveFileDialog dialog= new SaveFileDialog();
#endregion
#region Constructors
public MainPage()
{
InitializeComponent();
this.dialog = new SaveFileDialog();
try
{
this.dialog.DefaultExt = ".txt";
this.dialog.Filter = "Text Files|*.txt|Log Files|*.log|All Files|*.*";
this.dialog.FilterIndex = 2;
}
catch ( Exception ex )
{
this.tblError.Text = "Error configuring SaveFileDialog: " + ex.Message;
}
}
#endregion
private void btnSaveFile_Click( object sender, RoutedEventArgs e )
{
bool? dialogResult = this.dialog.ShowDialog();
if ( dialogResult == true )
{
try
{
byte[] fileBytes; // your varbinary file from database
using (Stream fs = (Stream)dialog.OpenFile())
{
fs.Write(fileBytes, 0, fileBytes.Length);
fs.Close();
lblMsg.Content = "File successfully saved!";
}
}
catch ( Exception ex )
{
this.tblError.Text = "Error calling service: " + ex.Message;
}
}
} // End of Function
}// End of MainPage class
}
It seems the issue you have has probably nothing to do with saving a binary file; it is more likely a basic security issue. Try saving to a path on which you have programmatic write access. For example, try saving to your My Documents directory instead of C:. Try using the Environment.SpecialFolder enumeration like this, and append the file name + extension.
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
You have a number of other ways to work around this issue, including starting Visual Studio in Elevated Mode (run as Administrator), and/or allow "Everyone" write access to your C:\ drive. But I wouldn't recommend these techniques necessarily; consider saving to a folder where the security settings are lower than c:\, such as My Documents.

Resources