简体   繁体   English

如何通过IIS中托管的应用程序打印到网络打印机

[英]How to print to network printer through application hosted in IIS

I have scenario of printing pdf (generated from stream) to network printer through application hosted in IIS. 我有通过IIS中托管的应用程序将pdf(从流生成)打印到网络打印机的方案。 I tried with PrintDocument.Print() and problem I'm facing is: 1. Document is getting queued to the print job queue with size 0 bytes. 我尝试了PrintDocument.Print(),遇到的问题是:1.文档正在排队到大小为0字节的打印作业队列中。 2. Document is getting queued to the print job queue with owner name as machine_name. 2.文档正在以所有者名称为machine_name进入打印作业队列。 Here is the code which i tried using PdfiumViewer (to generate PrintDocument from bytearray) and System.Drawing.Printing.PrintDocument: 这是我尝试使用PdfiumViewer(从字节数组生成PrintDocument)和System.Drawing.Printing.PrintDocument的代码:

 public void SendPdfToPrinter(byte[] byteArray, string fileName, string printerNetworkPath)
    {
        using (Stream fileStream = new MemoryStream(byteArray)) //byte array for the file content
        {

            var printerSettings = new System.Drawing.Printing.PrinterSettings
            {
                PrinterName = printerNetworkPath, //this is the printer full name. i.e. \\10.10.0.12\ABC-XEROX-01
                PrintFileName = fileName, //file name. i.e. abc.pdf
                PrintRange = System.Drawing.Printing.PrintRange.AllPages,
            };
            printerSettings.DefaultPageSettings.Margins = new System.Drawing.Printing.Margins(0, 0, 0, 0);

            // Now print the PDF document
            using (PdfiumViewer.PdfDocument document = PdfiumViewer.PdfDocument.Load(fileStream))
            {
                using (System.Drawing.Printing.PrintDocument printDocument = document.CreatePrintDocument())
                {
                    printDocument.DocumentName = fileName;
                    printDocument.PrinterSettings = printerSettings;
                    printDocument.PrintController = new System.Drawing.Printing.StandardPrintController();
                    printDocument.Print();
                }
            }

For both the problems, answer is impersonating the user to do the printing. 对于这两个问题,答案都是冒充用户进行打印。

In my case app pool is running under LocalSystem account which is obviously is not a domain user and printer is exposed to the domain user only. 在我的情况下,应用程序池在LocalSystem帐户下运行,该帐户显然不是域用户,并且打印机仅向域用户公开。

Note: Application pool is 64bit, if you use 32bit you will face another set of challenges which is well described here: https://blogs.msdn.microsoft.com/winsdk/2015/05/19/printing-successfully-using-impersonation-from-a-32-bit-application-on-a-64-bit-system/ 注意:应用程序池是64位的,如果使用32位,则将面临另一组挑战,在此处对此进行了详细说明: https : //blogs.msdn.microsoft.com/winsdk/2015/05/19/printing-successfully-using-模拟-从-A-32位应用程序上-A-64位的系统/

Below is code which required to do the impersonation for domain user: 以下是对域用户进行模拟所需的代码:

 [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class Impersonation : IDisposable
{
    private readonly SafeTokenHandle _handle;
    private readonly WindowsImpersonationContext _context;
    bool disposed = false;

    const int LOGON32_PROVIDER_DEFAULT = 0;
    const int LOGON32_LOGON_INTERACTIVE = 2;

    public Impersonation(ImpersonateUserDetails user) : this(user.Domain, user.UserName, user.Password)
    { }
    public Impersonation(string domain, string username, string password)
    {
        var ok = LogonUser(username, domain, password,
                       LOGON32_LOGON_INTERACTIVE, 0, out this._handle);
        if (!ok)
        {
            var errorCode = Marshal.GetLastWin32Error();
            throw new ApplicationException(string.Format("Could not impersonate the elevated user.  LogonUser returned error code {0}.", errorCode));
        }

        this._context = WindowsIdentity.Impersonate(this._handle.DangerousGetHandle());
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            this._context.Dispose();
            this._handle.Dispose();
        }           
        disposed = true;
    }

    ~Impersonation()
    {
        Dispose(false);
    }


    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);

    sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        private SafeTokenHandle()
            : base(true) { }

        [DllImport("kernel32.dll")]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [SuppressUnmanagedCodeSecurity]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr handle);

        protected override bool ReleaseHandle()
        {
            return CloseHandle(handle);
        }
    }
}

public class ImpersonateUserDetails
{
    public string UserName { get; set; }

    public string Password { get; set; }

    public string Domain { get; set; }
}

另一个可能且容易的解决方案是将您的应用程序池标识配置为具有访问/权限以在网络打印机中进行打印的自定义/域用户。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM