2012-06-26 1 views
3

Я знаю его известную тему на многих форумах и блогах. Я прочитал много статей. И многие из них тихо информативны. Но для меня, похоже, он требует нового подхода для достижения этой задачи.html или pdf-печать на стороне сервера C#

Ищет решение для печати html на стороне сервера. Но после работы с большим количеством вариантов я понял, что мы

  1. не могу дать имя принтера или
  2. его печать HTML содержание сырого, как текстовый файл

Позже стало известно о Ghostscript (https://stackoverflow.com/a/2600189/1238159) может быть используется для печати PDF на стороне сервера.

попытался также с кристаллом отчета (но как передать содержание HTML для него динамически Eventhough оно не поддерживает много тегов), itextsharp, SSRS, PDFsharp и т.д. и т.п., но ни один из них не поддерживает многие из HTML-теги & стандартам W3C. Итак, я закончил с одной точкой генерировать PDF. Только wkhtmltopdf идеально подходит для преобразования html в pdf. он поддерживает все теги html, в отличие от других, по моему опыту. но печать PDf - вопрос для меня с многих лет.

Но теперь я столкнулся с проблемой даже с GhostScript (использую ver 9.05). С localhost я могу использовать его отлично. Я могу печатать на стороне сервера, что бы ни было имя принтера, выходящее из пользовательского интерфейса. но с IP-адресом или именем компьютера его не работает. Я даже реализовал олицетворение. Несмотря на то, что процесс вызывает зависание при вызове GhostScript.

Теперь то, что я хочу, чтобы получить ясно

  1. Можно ли напечатать HTML или PDF (фактическое содержание) на стороне сервера?
  2. Любые открытые инструменты источника есть для достижения этого имени
  3. принтера Я хотел бы передать динамически

Любой ключ или обходной путь может помочь много часов людей по всему земному шару. :)

Большое спасибо заранее.

Привет, Паван N

После использования предложения по Lau. я могу сделать это в командной строке (значит, 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; 
     } 
    } 
} 

Но процесс прекрасно работает в локальном хосте:. 5030 то есть, во время работы с моей визуальной студии. но с IP-адресом или именем машины. он просто зависает и выдает эту ошибку

То же самое происходит и в Adobe Acrobat Reader, Foxit, и т.д. и т.п.

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

Я смущен тем, что вы имеете в виду под «печатной стороне сервера». Где принтер подключен? Вы говорите об инициировании печати на локальном принтере пользователя с удаленного веб-сервера? – Joe

+0

«сторона сервера печати» означает, что я пытаюсь напечатать строку HTML, сгенерированную XML + XSL на стороне сервера, то есть IIS. И да принтер подключен к серверу IIS. его приложение для интрасети. –

ответ

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

+1

отлично подходит для меня, даже загружает изображения из ссылок https и включает в себя ... размер документа соответствует ширине страницы (там, где не было других инструментов, таких как CutePDF printer) – TCC

3

Я работаю над проектом, который делает именно это.Это был очень неприятный опыт. Самый надежный метод, который я нашел, - экспортировать мои отчеты в PDF, а затем использовать Foxit Reader (НЕ Adobe Reader из-за проблем с безопасностью) через Diagnostics.Process для печати документа.

Имя принтера может быть предоставлено в командной строке Foxit Reader.

Окружающая среда, с которой я работаю, - это ASP.net 3.5 на IIS 7 на Windows Server 2008 R2 x64. Я также использую 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> 
+0

кажется полезным для меня. Я отправлю его и найду код C#. Спасибо лау. –

+0

Dusty Lau, похоже, мы не можем отправить количество копий для печати. для этого мне нужно навязать бизнес-правило :). Может быть полезно использование петли. Но это буквально влияет на производительность с буферизацией и количеством процессов. Ссылки, которые я упоминал, это [Это (http://stackoverflow.com/q/4868982/1238159)] и [Это (http://stackoverflow.com/q/7383349/1238159)] –

+1

Мне нужно то же самое. Я разрешаю отчету обрабатывать количество страниц, отправляя ему количество копий для генерации. –