user3163213
user3163213

Reputation: 701

How to run process in background? c#

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

Answers (2)

shujaat siddiqui
shujaat siddiqui

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

Ghasem
Ghasem

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

Related Questions