Reputation: 701
I am using wkhtmltopdf
for reporting purpose in my application. However it works great as expected.
Problem- In below method for I am converting strings source to pdf and writing bytes.
Note- I am starting process before reading all bytes and trying to run a process. The main problem is background ability of running this process. I don't get this process to run in background.
Currently what happens is until pdf is not generated the whole application goes in halt mode.This is something to do with background process is not working.
How do I modify this process so it works in background without halting my application?
I have read about task factory and multiple threads but I didn't get the clue.
Method for pdf conversion-
public byte[] ConverToPdf(string source, string commandLocation)
{
string HtmlToPdfExePath = Server.MapPath("~/wkhtmltopdf.exe");
Process p;
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = Path.Combine(commandLocation, HtmlToPdfExePath);
psi.WorkingDirectory = Path.GetDirectoryName(psi.FileName);
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
string args = "-q -n ";
args += "--enable-javascript ";
args += "--enable-plugins ";
args += "--disable-smart-shrinking ";
args += "--margin-bottom 20 ";
args += "--margin-left 20 ";
args += "--margin-right 20 ";
args += "--margin-top 20 ";
args += "--orientation Landscape ";
args += "--outline-depth 0 ";
args += "--page-size A4 ";
args += "--encoding utf-8";
args += " - -";
psi.Arguments = args;
p = Process.Start(psi);
try
{
using (StreamWriter stdin = new StreamWriter(p.StandardInput.BaseStream, Encoding.UTF8))
{
stdin.AutoFlush = true;
stdin.Write(source);
}
byte[] buffer = new byte[32768];
byte[] file;
using (var ms = new MemoryStream())
{
while (true)
{
int read = p.StandardOutput.BaseStream.Read(buffer, 0, buffer.Length);
if (read <= 0)
break;
ms.Write(buffer, 0, read);
}
file = ms.ToArray();
}
p.StandardOutput.Close();
p.WaitForExit(60000);
int returnCode = p.ExitCode;
p.Close();
if (returnCode == 0)
return file;
else
return file;
}
catch (Exception ex)
{
ModelState.AddModelError("Could not create PDF", ex);
}
finally
{
p.Close();
p.Dispose();
}
return null;
}
Update- I was actually trying to find a way of background worker to do its job and return bytes from above method.
My main purpose of calling this method with background worker is Communicating back to from where it was called with results.
public ActionResult DuesPDF()
{
var relativePath = "~/Views/Shared/_TestView.cshtml";
string content;
var view = ViewEngines.Engines.FindView(ControllerContext, relativePath, null);
using (var writer = new StringWriter())
{
TempData["req"] = "DuesAndOverDuesChart";
var context = new ViewContext(ControllerContext, view.View, ViewData, TempData, writer);
view.View.Render(context, writer);
writer.Flush();
content = writer.ToString();
byte[] pdfBuf = ConverToPdf(content, Server.MapPath("~/PDF/"));
if (pdfBuf == null)
return null;
return File(pdfBuf, "application/pdf");
}
}
Here is in this method I am calling pdf method- ConverToPdf(content, Server.MapPath("~/PDF/"))
Note-
I am asking for communication from ConverToPdf
method above with background worker.
Upvotes: 0
Views: 2184
Reputation: 1587
Use Thread Class it will run your method in background thread other than the main thread. More over you are returning null in your method so its better to make the return type void and do not return null.
Thread threadObj = new Thread(new ThreadStart(()=>ConverToPdf("a","b")));
threadObj.Start();
Update : I am assuming you are using windows form. As per your updates you can easily see that your main method need the response to execute further. now for this i would suggest you to show some progress bar in background thread so that i would not halt the application. and when the converttoPDF
method finishes it process stop the progress bar. in this case your application would not stuck and you will get the response as you need.
Upvotes: 2
Reputation: 15613
private void Button1_Click(object sender, EventArgs e)
{
bgworker.RunWorkerAsync();
}
private void bgworker_DoWork(object sender, DoWorkEventArgs e)
{
ConverToPdf(source, commandLocation);
}
Upvotes: 0