服务器端的html或pdf打印c#

时间:2012-06-26 13:18:04

标签: c# wcf printing server-side ghostscript

我知道它在许多论坛和博客中都是一个众所周知的主题。我读了很多文章。其中许多都是安静的信息。但对我来说,它似乎需要新的方法来完成这项任务。

我正在寻找在服务器端打印html的解决方案。但在与许多选项合作后,我意识到我们

  1. 无法提供打印机名称或
  2. 打印html原始内容,如txt文件
  3. 后来才知道ghostscript(https://stackoverflow.com/a/2600189/1238159)可以用来在服务器端静默打印PDF。

    还尝试了水晶报告(但是如果它不支持很多标签,如何动态地将HTML内容传递给它),itextsharp,ssrs,pdfsharp等等,但它们都没有支持许多HTMl标签& W3C标准。所以我在某一时刻结束了生成PDF。只有wkhtmltopdf非常适合将html转换为pdf。它支持每个html标签,不同于我的经验。但印刷PDF对我来说是多年来的问题。

    但即使使用GhostScript,我现在也面临着一个问题(使用的是ver 9.05)。使用localhost,我可以完美地使用它。我可以在服务器端打印来自UI的打印机名称。但是IP地址或机器名称无效。我甚至实施了模仿。即使在调用GhostScript时进程被挂起了。

    现在我想要明白的是

    1. 是否可以在服务器端打印html或pdf(实际内容)?
    2. 任何开源工具都可以实现这一目标
    3. 打印机名称我想动态传递
    4. 任何线索或解决方法都可能有助于全球数小时的人们。 :)

      非常感谢提前。

      此致 Pavan N

      使用刘的建议后。能够在命令提示符下执行此操作(意味着cmd.exe在我的帐户下运行)。但我的应用程序将在网络服务下运行。 现在我遇到的问题只是一种ACCESS Denied

      呀。最后我能够开始这个过程。并且能够使用我的域凭据在任务管理器下查看我的gswin32c.exe进程。代码如下:

      public bool PrintVSPDF(string ghostScriptPath, int numberOfCopies, string printerName, string pdfFileName)
      {
          Logger.AddToLog("printerName", printerName);
          string impersonationUsername = "";
          string impersonationDomain = "";
          string impersonationPWD = "";
      
          if (ConfigurationManager.AppSettings["UName"] != null)
          {
              impersonationUsername = Encryption.Decrypt(ConfigurationManager.AppSettings["UName"].ToString(), Encryption.DEFAULT_KEY, Encryption.DEFAULT_SEED);
              impersonationDomain = impersonationUsername.Split('\\').Count() > 1 ? impersonationUsername.Split('\\')[0] : "";
              impersonationUsername = impersonationUsername.Split('\\').Count() > 1 ? impersonationUsername.Split('\\')[1] : impersonationUsername.Split('\\')[0];
          }
      
          if (ConfigurationManager.AppSettings["PD"] != null)
          {
              impersonationPWD = Encryption.Decrypt(ConfigurationManager.AppSettings["PD"].ToString(), Encryption.DEFAULT_KEY, Encryption.DEFAULT_SEED);
          }
      
          using (Impersonation imp = new Impersonation(impersonationUsername, impersonationDomain, impersonationPWD))
          {
              ProcessStartInfo startInfo = new ProcessStartInfo();
              startInfo.Arguments = "-dPrinted -dNoCancel -dNOPAUSE -dBATCH -dNumCopies=" + Convert.ToString(numberOfCopies) + "  -sDEVICE=mswinpr2 -sOutputFile=%printer%\"" + printerName + "\" \"" + pdfFileName + "\" ";
              startInfo.FileName = ghostScriptPath;
              startInfo.UseShellExecute = false;
              startInfo.CreateNoWindow = true;
              //startInfo.RedirectStandardInput = true;
              startInfo.RedirectStandardError = true;
              startInfo.RedirectStandardOutput = true;
              startInfo.WindowStyle = ProcessWindowStyle.Hidden;
              startInfo.UserName = impersonationUsername;
              startInfo.Domain = impersonationDomain;
              SecureString ss = new SecureString();
              for (int i = 0; i < impersonationPWD.Length; i++)
              {
                  ss.AppendChar(impersonationPWD[i]);
              }
              startInfo.Password = ss;
              Process process = null;
              try
              {
                  process = Process.Start(startInfo);
                  //Logger.AddToLog("Error VS", process.StandardError.ReadToEnd());
                  //Logger.AddToLog("Output VS", process.StandardOutput.ReadToEnd());
                  //Logger.AddToLog(process.StartInfo.Arguments.ToString(), "VS Print Arguments");
                  //Console.WriteLine(process.StandardError.ReadToEnd() + process.StandardOutput.ReadToEnd());
                  //Logger.AddToLog(process.StartInfo.FileName.ToString(), "VS Print file name");
                  process.WaitForExit(30000);
                  if (process.HasExited == false) 
                      process.Kill();
                  int exitcode = process.ExitCode;
                  process.Close();
                  return exitcode == 0;
              }
              catch (Exception ex)
              {
                  Logger.AddToLog(ex);
                  return false;
              }
          }
      }
      

      但是这个过程在localhost:5030中完美运行,即从我的visual studio运行时。但使用IP地址或机器名称。它只是挂起并抛出此错误

      adobe reader,foxit等也在发生同样的事情。

      ( Process must exit before requested information can be determined. :    at System.Diagnostics.Process.EnsureState(State state)
      at System.Diagnostics.Process.get_ExitCode() )
      

2 个答案:

答案 0 :(得分:3)

我一直致力于一个正在做这件事的项目。这是一次非常令人沮丧的经历。我找到的最可靠的方法是将我的报告导出为PDF,然后通过Diagnostics.Process使用福昕阅读器(因安全问题而不是Adobe Reader)来打印文档。

可以将打印机名称提供给Foxit Reader命令行参数。

我正在使用的环境是Windows Server 2008 R2 x64上的IIS 7上的ASP.net 3.5。 我也在使用Sql Server Reporting Services。

也许这段代码会帮助你:

    public FileContentResult GetPOReport(DataTable reportData, int poNumber, string copies, out string fileName, out string downloadPath)
    {
        fileName = "PO_" + poNumber.ToString().Trim() + "_" + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".pdf";
        downloadPath = "/Generated/" + fileName;

        var outputFiles = new Dictionary<string, string>
                              {
                                  {"", Server.MapPath("~" + downloadPath)}
                              };

        if (!string.IsNullOrWhiteSpace(copies))
        {
            var copyList = copies.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var temp in copyList)
                outputFiles.Add(temp, Server.MapPath("~" + "/Generated/" + temp.Trim() + ".pdf"));
        }

        FileContentResult returnFile = null;

        foreach (var outputFile in outputFiles)
        {
            var file = WriteReportToDisk(reportData, outputFile.Value, outputFile.Key);

            if (file == null)
                continue;

            if (string.IsNullOrWhiteSpace(outputFile.Key))
                returnFile = file;
            else
                PrintReport(outputFile.Value);
        }

        return returnFile;
    }

    public void PrintReport(string filePath)
    {
        try
        {
            if (!ConfigurationManager.AppSettings.AllKeys.Contains("AdobeReaderPath") ||
                !ConfigurationManager.AppSettings.AllKeys.Contains("AdobePrintParameters") ||
                !ConfigurationManager.AppSettings.AllKeys.Contains("PrinterName"))
                return;

            var adobeReaderPath = ConfigurationManager.AppSettings["AdobeReaderPath"].Trim();
            var adobePrintParameters = ConfigurationManager.AppSettings["AdobePrintParameters"].Trim();
            var printerName = ConfigurationManager.AppSettings["PrinterName"].Trim();
            var printProcessDomain = ConfigurationManager.AppSettings["PrintProcessDomain"].Trim();
            var printProcessUserName = ConfigurationManager.AppSettings["PrintProcessUserName"].Trim();
            var printProcessPassword = ConfigurationManager.AppSettings["PrintProcessPassword"].Trim();

            var userPrinter = Entities.UserPrinters.FirstOrDefault(p => p.UserName == User.Identity.Name);

            if (userPrinter != null)
                printerName = userPrinter.PrinterName.Trim();

            using (var process = new Process
            {
                StartInfo =
                    new ProcessStartInfo(
                    adobeReaderPath,
                    string.Format(adobePrintParameters, filePath, printerName)
                    )
            })
            {
                if (!string.IsNullOrWhiteSpace(printProcessUserName))
                {
                    if (!string.IsNullOrWhiteSpace(printProcessDomain))
                        process.StartInfo.Domain = printProcessDomain;

                    process.StartInfo.UserName = printProcessUserName;

                    var securePassword = new SecureString();

                    foreach (var passwordCharacter in printProcessPassword)
                        securePassword.AppendChar(passwordCharacter);

                    process.StartInfo.Password = securePassword;

                    process.StartInfo.UseShellExecute = false;
                    process.StartInfo.CreateNoWindow = true;

                    process.StartInfo.LoadUserProfile = true;
                }

                process.Start();

                process.WaitForExit(30000);
            }
        }
        catch (Exception exception)
        {
            EventLog.WriteEntry("PO Suggestion Viewer", string.Format("PO Suggestion Viewer Error:\n{0}", exception.Message));
            throw;
        }
    }

    public FileContentResult WriteReportToDisk(DataTable reportData, string filePath, string copy)
    {
        var webReport = new WebReport()
        {
            ExportFileName = "PO Report",
            ReportPath = Server.MapPath("~/Reports/PurchaseOrderReport.rdlc")
        };

        if (!string.IsNullOrWhiteSpace(copy))
            webReport.ReportParameters.Add(new ReportParameter("Copy", copy));

        if ((User != null) && (User.Identity != null) && (User.Identity.Name != null))
            webReport.ReportParameters.Add(new ReportParameter("User", User.Identity.Name));

        webReport.ReportDataSources.Add(new ReportDataSource("ReportData", reportData));

        var report = webReport.GetReport();

        Response.AddHeader("content-disposition", string.Format("attachment; filename={0}.{1}", webReport.ExportFileName, webReport.FileNameExtension));
        Response.ContentType = "application/pdf";

        var file = File(report, webReport.MimeType, "POReport");

        System.IO.File.WriteAllBytes(filePath, file.FileContents);

        return file;
    }

我的web.config包含:

<appSettings>
    <add key="webpages:Version" value="1.0.0.0" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
    <add key="AdobeReaderPath" value="C:\Program Files (x86)\Foxit Software\Foxit Reader\Foxit Re-ader.exe" />
    <add key="AdobePrintParameters" value="-t &quot;{0}&quot; &quot;{1}&quot;" />
    <add key="PrinterName" value="HP_Office" />
    <add key="PrintProcessDomain" value="DOMAIN_NAME" />
    <add key="PrintProcessUserName" value="DOMAIN_USER" />
    <add key="PrintProcessPassword" value="DOMAIN_PASSWORD" />
</appSettings>

答案 1 :(得分:1)

对于迟到的帖子感到抱歉。我教过我已经回答了这个问题。 我找到了将html转换为pdf的工作。 我正在使用WKHTMLTOPDF API将html转换为pdf。与许多商业产品相比,它看起来很棒。能够获得彩色/灰度,边距,索引。还有更多。

这是我跟随的链接 http://code.google.com/p/wkhtmltopdf/

ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + @"\bin\wkhtmltopdf.exe";
pdfFile = localReportPath + "\\Reports\\Savedfiles\\" + filename + ".pdf";
//Ref: http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf-0.9.9-doc.html
startInfo.Arguments = " --minimum-font-size 16 --margin-left 10mm --margin-right 10mm --zoom 3 " + htmlFile + " " + pdfFile;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process p = Process.Start(startInfo);
p.WaitForExit();
p.Dispose();
p.Close();

和我发送的ghostscript相同,以获得一个漂亮的TIFF文件进行传真。大数据也表现良好。

此致 Pavan N