4

我知道它是许多论坛和博客中的一个已知主题。我读了很多文章。他们中的许多人都安静地提供信息。但对我来说,似乎需要新的方法来完成这项任务。

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

  1. 不能给出打印机名称或
  2. 它打印 html 原始内容,如 txt 文件

后来知道ghostscript(https://stackoverflow.com/a/2600189/1238159)可以用来在服务器端静默打印PDF。

还尝试使用水晶报告(但如何动态地将 HTML 内容传递给它,即使它不支持许多标签)、itextsharp、ssrs、pdfsharp 等,但它们都不支持许多 HTMl 标签和 W3C 标准。所以我在某一时刻结束了生成PDF。只有 wkhtmltopdf 非常适合将 html 转换为 pdf。根据我的经验,它支持每个 html 标签,这与其他任何标签都不一样。但是打印 PDf 对我来说是多年以来的问题。

但是现在即使使用 GhostScript(我使用的是 9.05 版)也面临一个问题。使用 localhost 我可以完美地使用它。我可以在服务器端以静默方式打印来自 UI 的任何打印机名称。但使用 IP 地址或机器名称无法正常工作。我什至实施了模拟。即使进程在调用 GhostScript 时挂起。

现在我想弄清楚的是

  1. 是否可以在服务器端打印 html 或 pdf(实际内容)?
  2. 任何开源工具都可以实现这一目标
  3. 我想动态传递的打印机名称

任何线索或解决方法都可能帮助全球数小时的人。:)

提前谢谢了。

问候, 帕万 N

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

是的。最后我能够开始这个过程。并且能够使用我的域凭据在任务管理器下查看我的 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 中运行良好,即在我的视觉工作室运行时。但带有 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() )
4

2 回答 2

3

我一直在做一个正在做这个的项目。这是一次非常令人沮丧的经历。我发现最可靠的方法是将我的报告导出为 PDF,然后通过 Diagnostics.Process 使用 Foxit Reader(由于安全问题而不是 Adob​​e 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>
于 2012-06-26T13:50:32.840 回答
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 文件用于传真。数据量大时性能也不错。

问候, 帕万 N

于 2013-02-07T05:44:05.960 回答