Bootstrap

C# IIS 调用文件打印时 Verbs为空 无法使用Print等verb命令

最近有个需求,要在网站中,自动调用打印机打印文件,踩了个坑,忙了整整两天才给解决掉
我写的代码如下:

public static bool PrintFile(string file)
        {
            try
            {
                PrintDocument print = new PrintDocument();
                string sDefault = print.PrinterSettings.PrinterName;//默认打印机名
                string filePath = ( file);
                string printer = sDefault;
                ProcessStartInfo info = new ProcessStartInfo(filePath);
                info.WorkingDirectory = PathDirectory.GetWorkRunDir();
                info.UseShellExecute = true;
                info.CreateNoWindow = true;
                info.WindowStyle = ProcessWindowStyle.Hidden;
                string verb = "";
                string verbStr = info.Verbs != null ? JsonHelp.SerializeObjectTimeFormat(info.Verbs) : "";
                Logger.Info($"{filePath},支持的命令为:{verbStr}");
                List<string> handles = info.Verbs.ToList().Select(i => i.ToLower()).ToList();
                if (info.Verbs.Contains("print"))
                {
                    verb = "print";
                }
                else if (info.Verbs.Contains("printto"))
                {
                    verb = "printto";
                }
                
                if (string.IsNullOrEmpty(verb))
                {
                    Logger.Info("没有有效的命令参数!");
                    return false;
                }
                info.Verb = verb;
               
                info.Arguments = "\"" + printer + "\"";
                Process p = new Process();
                p.StartInfo = info;
                p.Start();
                if (p.WaitForExit(30000))
                {
                    Logger.Info("调用打印30s后打印成功完成");
                    return true;
                }
                else
                {
                    p.Kill();
                    Logger.Info("调用打印30s后未打印完成,强制结束结束打印进程!");
                }
            }
            catch (Exception ex)
            {
                Logger.Info("打印文件异常:" + JsonHelp.SerializeObjectTimeFormat(ex));
            }
            return false;
        }

在本地测试的时候运行没有一切问题(本地启动web或启动exe使用该方法),可以读到excel支持的命令
并且打印成功。
但是一旦将程序放在IIS上,或者放在windows服务中调用时,坑来了,verbs 读不到相关的命令了
正常和失败的运行的日志如下:
在这里插入图片描述
经过不懈的网上查找,终于找到了原因

主要原因为,我们平常手动运行程序,或者使用vs调试程序,打开程序 的用户都是当前用户,这类型的用户为 交互式用户交互式用户是可以使用verb这类命令的。
而在IIS、windows服务中 启动的话,使用的用户是默认内置用户,非交互式用户,他们无法访问本地的部分资源

我也不清楚,这种非交互式用户到底影响多少,但是可以确定,文件的打印肯定是受影响了

https://www.cnblogs.com/XWCloud/p/6759697.htmlhttps://www.cnblogs.com/XWCloud/p/6759697.html
这篇文章的博主,采用了 组件服务配置来解决这个问题,但是这个配置太复杂,我没有采用,但是可以从中看到 非交互式的用户 也影响了 office的其他功能

最终我采取了外挂一个小程序,来解决问题:
解决步骤如下:
1.先做一个独立的exe程序,没有界面,同时监听本地的某个端口,对外发布api接口

		[HttpGet]
        [HttpPost]
        public Message TestFile(PITag tag)
        {
            Message msg = new Message()
            {
                Title = Message.Error,
                Content = "打印文件异常!"
            };
            PrintDocument print = new PrintDocument();
            string sDefault = print.PrinterSettings.PrinterName;//默认打印机名
            string filePath = (tag.Code);
            string printer = sDefault;
            ProcessStartInfo info = new ProcessStartInfo(filePath);
            info.UseShellExecute = true;
            info.CreateNoWindow = true;
            info.WindowStyle = ProcessWindowStyle.Hidden;
            string verbStr = info.Verbs != null ? JsonSerializer.SerializeObject(info.Verbs) : "";
            Logger.Info($"{filePath},支持的命令为:{verbStr}");
            string verb = "";
            List<string> handles = info.Verbs.ToList().Select(i => i.ToLower()).ToList();
            if (info.Verbs.Contains("print"))
            {
                verb = "print";
            }
            else if (info.Verbs.Contains("print"))
            {
                verb = "printto";
            }

            if (string.IsNullOrEmpty(verb))
            {
                Logger.Info("没有有效的命令参数!");
                msg.Content = "没有有效的命令参数!";
                return msg;
            }
            info.Verb = verb;

            info.Arguments = "\"" + printer + "\"";
            Process p = new Process();
            p.StartInfo = info;
            p.Start();
            if (p.WaitForExit(30000))
            {
                Logger.Info("调用打印30s后打印成功完成");
                msg.Content = "调用打印30s后打印成功完成";
            }
            else
            {
                p.Kill();
                Logger.Info("调用打印30s后未打印完成,强制结束结束打印进程!");
                msg.Content = "调用打印30s后未打印完成,强制结束结束打印进程!";
            }
            msg.Content = verbStr;
            return msg;
        }

可以参考我的文章:
.net framework4.5.2+HttpSelfHostConfiguration 使用异常过滤器来做api接口的思想(精简使用即可,没必要使用异常过滤器等)
https://blog.csdn.net/weixin_43627719/article/details/134536771?spm=1001.2014.3001.5501
2.创建任务计划程序,开机即启动 外挂的exe程序
可参考我的文章:开机自启动bat脚本(100%启动,使用任务计划程序)
https://blog.csdn.net/weixin_43627719/article/details/135754905?spm=1001.2014.3001.5501
3.在IIS上的程序调用该API接口,即可正常打印:

		[HttpGet]
 		public string PrintFile(string filePath)
        {
            var dic = JsonHelp.SerializeObjectTimeFormat(new Dictionary<string, string>()
            {
                ["Code"] = file
            });
            string result = Httprequest(dic, "http://localhost:8603/api/tppas/v1/OPC/TestFile");
            Logger.Info("调用打印api结束,任务结果是:" + result);
            return false;
        }
		/// <summary>
        /// 快速post请求 发送json字符串
        /// </summary>
        /// <param name="info"></param>
        /// <param name="IpAddress"></param>
        /// <returns></returns>
        public static string Httprequest(string info, string IpAddress)
        {
            string result = string.Empty;
            try
            {
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(IpAddress); // ip地址
                req.Method = "post"; // 请求方式
                req.ContentType = "application/json;charset=UTF-8";
                byte[] data = Encoding.UTF8.GetBytes(
                      info
                      ); //请求数据转字节
                req.Timeout = 10000;//10秒查询时间
                req.ContentLength = data.Length;
                using (Stream reqStream = req.GetRequestStream()) //获取
                {
                    reqStream.Write(data, 0, data.Length);//向当前流中写入字节
                    reqStream.Close(); //关闭当前流
                }
                HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); //响应结果
                Stream stream = resp.GetResponseStream();
                //获取响应内容
                using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                {
                    result = reader.ReadToEnd();
                }
                Logger.Info("请求结果是:" + result);
                return result;
            }
            catch (Exception ex)
            {
                Logger.Error("请求数据异常:" + JsonHelp.SerializeObjectTimeFormat(ex));
            }
            return result;

        }
;