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