DotNetCoreCore跨平台打印深入

上一篇证实Linux能用DotNetCore打印,能正常驱动虚拟打印机打印PDF。这里就适配实际的打印到多平台支持上。打印动态库先改为DotNetCore版本,并且把UI交互部分抽取接口(称为Shell)。控制台、GTK、Asp.NetCore各自实现接口来做打印程序,这样把UI交互部分剥离成一个壳。所以叫Shell的意思。

执行入口

using System;

namespace LISConsoleClient
{
    class Program
    {
        /// <summary>
        /// 执行入口
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            OperPrintShell shell = new OperPrintShell();
            shell.ShowMsgInfo("欢迎使用iMedicalLIS控制台客户端");
            shell.ShowMsgInfo("准备初始化消息服务");
            //开启消息侦听
            MessageServer server = new MessageServer();
            string ret = server.InitServer();
            shell.ShowMsgInfo("初始化消息服务返回:"+ret);
            string input = "";
            while(input.ToLower()!="y")
            {
                shell.ShowMsgInfo("退出程序请输入:y");
                input = Console.ReadLine();
            }
        }
    }
}

消息服务

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LIS.BLL.MsgCore;
using Fleck;
using System.Timers;
using System.Net.NetworkInformation;
using System.Net;

namespace LISConsoleClient
{
    /// <summary>
    /// 消息服务类
    /// </summary>
    public class MessageServer
    {

        /// <summary>
        /// 消息历史队列
        /// </summary>
        public static Queue<HosDto> HosQueue = new Queue<HosDto>();

        /// <summary>
        /// 消息服务
        /// </summary>
        private static WebSocketServer server = null;

        /// <summary>
        /// 存所有套接字
        /// </summary>
        private static List<IWebSocketConnection> allSockets = new List<IWebSocketConnection>();

        /// <summary>
        /// 消息处理链对象
        /// </summary>
        MsgDealLink dealLinks = null;

        /// <summary>
        /// 消息端口
        /// </summary>
        public int port = 8082;

        /// <summary>
        /// 壳
        /// </summary>
        OperPrintShell shell = new OperPrintShell();

        /// <summary>
        /// 初始化消息服务
        /// </summary>
        /// <returns></returns>
        public string InitServer()
        {
            //取消息链对象
            dealLinks = new MsgDealLink();
            dealLinks.LinkList = new List<IMessageDeal>();
            MessagePrintDeal printDeal = new MessagePrintDeal();
            dealLinks.LinkList.Add(printDeal);
            //检查端口占用
            bool isUse = PortInUse(port);
            if (isUse == true)
            {
                port = 10210;
                isUse = PortInUse(port);
            }
            if (isUse == true)
            {
                port = 19910;
                isUse = PortInUse(port);
            }
            if (isUse == true)
            {
                port = 19902;
                isUse = PortInUse(port);
            }
            if (isUse == true)
            {
                shell.ShowMsgInfo("8082端口和10210,19910,19902端口都被占用!无法启动消息服务!", "");
                return "8082端口和10210,19910,19902端口都被占用!无法启动消息服务!";
            }
            try
            {
                server = new WebSocketServer("ws://127.0.0.1:" + port);
                server.Start(socket =>
                {
                    socket.OnOpen = () =>
                    {
                        shell.ShowMsgInfo(socket.ConnectionInfo.Id + socket.ConnectionInfo.Path, "S消息服务打开连接:");
                        allSockets.Add(socket);
                    };
                    socket.OnClose = () =>
                    {
                        shell.ShowMsgInfo(socket.ConnectionInfo.Id + socket.ConnectionInfo.Path, "S消息服务关闭连接:");
                        allSockets.Remove(socket);
                    };
                    socket.OnMessage = message =>
                    {
                        shell.ShowMsgInfo(socket.ConnectionInfo.Id + socket.ConnectionInfo.Path + "内容:" + message, "S消息服务收到消息:");
                        shell.ShowMsgInfo("S消息服务准备调用消息链...", "");
                        try
                        {
                            HosDto hosDto = new HosDto();
                            hosDto.Msg = message;
                            hosDto.Socket = socket;
                            HosQueue.Enqueue(hosDto);
                            if (HosQueue.Count > 30)
                            {
                                HosQueue.Dequeue();
                            }
                            if (dealLinks != null && dealLinks.LinkList != null && dealLinks.LinkList.Count > 0)
                            {
                                foreach (IMessageDeal deal in dealLinks.LinkList)
                                {
                                    shell.ShowMsgInfo("#S调用:" + deal.GetType().FullName + "...", "");
                                    bool ret = deal.DealMessage(socket, message);
                                    shell.ShowMsgInfo("#S调用:" + deal.GetType().FullName + "结束...", "");
                                    //返回false不传递消息了
                                    if (ret == false)
                                    {
                                        shell.ShowMsgInfo("#S消息链不继续传递消息...", "");
                                        break;
                                    }
                                }
                            }
                            shell.ShowMsgInfo("#S消息服务调用消息链结束...", "");
                        }
                        catch (Exception ex)
                        {
                            shell.ShowMsgInfo("消息服务调用消息链异常:" + ex.Message, "");
                        }

                    };
                });
            }
            catch (Exception ex)
            {
                shell.ShowMsgInfo("启动消息服务出错:" + ex.Message, "");
                return "#S启动消息服务出错:" + ex.Message + "调用堆栈:" + ex.StackTrace;
            }
            return "";
        }

        /// <summary>
        /// 历史实体
        /// </summary>
        public class HosDto
        {
            /// <summary>
            /// 消息
            /// </summary>
            public string Msg
            {
                get;
                set;
            }

            /// <summary>
            /// 套接字
            /// </summary>
            public IWebSocketConnection Socket
            {
                get;
                set;
            }
        }

        /// <summary>
        /// 判断端口是否被占用
        /// </summary>
        /// <param name="port">端口</param>
        /// <returns></returns>
        public bool PortInUse(int port)
        {
            bool inUse = false;

            IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
            IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners();

            foreach (IPEndPoint endPoint in ipEndPoints)
            {
                if (endPoint.Port == port)
                {
                    inUse = true;
                    break;
                }
            }
            return inUse;
        }
    }
}

打印处理类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Net;
using System.Xml;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

namespace LISConsoleClient
{
    /// <summary>
    /// 打印消息处理实现
    /// </summary>
    public class MessagePrintDeal:IMessageDeal
    {
        /// <summary>
        /// 处理消息
        /// </summary>
        /// <param name="socket">套接字,可以获得id,发送消息给socket</param>
        /// <param name="message">约定#分割的第一位描述消息类型,收到的消息内容</param>
        /// <returns>是否继续往后传递消息,true是,false否</returns>
        public bool DealMessage(Fleck.IWebSocketConnection socket, string message)
        {
            /// <summary>
            /// 壳
            /// </summary>
            OperPrintShell shell = new OperPrintShell();

            //传入壳
            DHCLabtrakReportPrint.ReportAccess.Shell = shell;

            shell.ShowMsgInfo("识别以print#开头的消息", "");
            //识别打印消息
            if (message.Split('#')[0] == "print")
            {
                shell.ShowMsgInfo("确定为打印消息,准备处理", "");
                int index = message.IndexOf('#');
                string msg = message.Substring(index+1);
                //包含版本参数分隔符
                string TRANVetionInfo = "";
                if(msg.Contains("$TRAKVTSP$"))
                {
                    msg = msg.Replace("$TRAKVTSP$", ""+(char)0);
                    string [] mvArr = msg.Split((char)0);
                    TRANVetionInfo = mvArr[1];
                    msg = mvArr[0];
                    string LoacalVetion = "0";
                    if(TRANVetionInfo!="")
                    {
                        if(System.IO.File.Exists(@"C:\TRAK\TRAKVetionInfo.json"))
                        {
                            string VetionInfoStr = ReadTxt(@"C:\TRAK\TRAKVetionInfo.json");
                            VetionInfoStr = VetionInfoStr.Replace("\r\n", "" + (char)0);
                            string[] VArr = VetionInfoStr.Split((char)0);
                            LoacalVetion = VArr[0];
                        }
                        string[] TRANVetionInfoArr = TRANVetionInfo.Split('^');
                        int LoacalVetionInt = Convert.ToInt32(LoacalVetion);
                        int ServerVetionInt= Convert.ToInt32(TRANVetionInfoArr[0]);
                    }
                }
                string [] arrMsg=msg.Split('@');
                //报告打印消息直接处理,不驱动exe,提高速度
                if (arrMsg.Length > 5 && (!arrMsg[4].Contains("PDF#")) && (arrMsg[0] == "iMedicalLIS://0" || arrMsg[0] == "iMedicalLIS://1") && (arrMsg[4] != "ReportView"))
                {
                    string cmdLine = msg.Substring(14);
                    string[] tmpStrings = cmdLine.Split((char)64);
                    string printFlag = tmpStrings[0];
                    string connectString = tmpStrings[1].Replace("&", "&amp;");
                    string rowids = tmpStrings[2];
                    string userCode = tmpStrings[3];
                    //PrintOut:打印  PrintPreview打印预览
                    string printType = tmpStrings[4];
                    //参数
                    string paramList = tmpStrings[5];    ///模块名称(LIS工作站,DOC医生,SELF自助,OTH其它)

                    string clsName = "";
                    string funName = "";
                    if (tmpStrings.Length >= 8)
                    {
                        clsName = tmpStrings[6];
                        funName = tmpStrings[7];
                    }

                    //没传报告主键退出
                    if (rowids == "" && printType != "ReportView")
                    {
                        shell.ShowMsgInfo("未传入报告主键", "");
                        return true;
                    };
                    string ip = "";
                    string hostName = Dns.GetHostName();  //本机名
                    System.Net.IPAddress[] addressList = Dns.GetHostEntry(Dns.GetHostName()).AddressList;
                    for (int i = 0; i < addressList.Length; i++)
                    {
                        if (addressList[i].AddressFamily.Equals(System.Net.Sockets.AddressFamily.InterNetwork))
                        {
                            ip = addressList[i].ToString();
                        }
                    }

                    string mac = "";
                    paramList = paramList + "^HN" + hostName + "^IP" + ip + "^MAC" + mac;
                    //printFlag  0:打印所有报告 1:循环打印每一份报告
                    if (printFlag.Substring(0, 1) == "0")
                    {
                        DHCLabtrakReportPrint.ReportAccess reportPrint = new DHCLabtrakReportPrint.ReportAccess(rowids, userCode, paramList, connectString, printType, clsName, funName);
                    }
                    else
                    {
                        string[] tmpRowids = rowids.Split((char)94);
                        for (int i = 0; i < tmpRowids.Length; i++)
                        {
                            rowids = tmpRowids[i];
                            if (rowids != "")
                            {
                                DHCLabtrakReportPrint.ReportAccess reportPrint = new DHCLabtrakReportPrint.ReportAccess(rowids, userCode, paramList, connectString, printType, clsName, funName);
                            }
                        }
                    }
                }
                else
                {
                    if (System.IO.File.Exists(@"C:\TRAK\ResultPrint.exe"))
                    {
                        shell.ShowMsgInfo("调用打印程序", "");
                        System.Diagnostics.Process.Start(@"C:\TRAK\ResultPrint.exe", msg.Replace("\"", "\\\"").Replace("+", "%2B"));
                    }
                    else
                    {
                        shell.ShowMsgInfo(@"C:\TRAK\ResultPrint.exe", "");
                    }
                }
                if (System.IO.File.Exists(@"C:\TRAK\ResultPrint.exe"))
                {
                    shell.ShowMsgInfo("调用打印程序", "");
                    System.Diagnostics.Process.Start(@"C:\TRAK\ResultPrint.exe", msg.Replace("\"", "\\\"").Replace("+", "%2B"));
                }
                else
                {
                    shell.ShowMsgInfo(@"C:\TRAK\ResultPrint.exe", "");
                }
                shell.ShowMsgInfo("处理完成,截断消息链", "");
                return false;
            }
            shell.ShowMsgInfo("不是打印消息,传递消息链", "");
            return true;
        }


        
        /// <summary>
        /// 删除指定目录指定后缀名的文件
        /// </summary>
        /// <param name="path"></param>
        /// <param name="extend"></param>
        private void DeleteFile(string path, string extend)
        {
            if (Directory.Exists(path))
            {
                DirectoryInfo di = new DirectoryInfo(path);
                FileInfo[] files = di.GetFiles();
                if (files != null && files.Length > 0)
                {
                    foreach (var v in files)
                    {
                        try
                        {
                            if (v.Extension == extend)
                            {
                                System.IO.File.Delete(v.FullName);
                            }
                        }
                        catch
                        {
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 读取文件数据
        /// </summary>
        /// <param name="path">文件全路径</param>
        /// <returns></returns>
        private string ReadTxt(string path)
        {
            FileStream fs = null;
            try
            {

                fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                StreamReader sr = new StreamReader(fs, GetFileEncodeType(fs));
                string str = sr.ReadToEnd();
                return str;
            }
            finally
            {
                fs.Close();
            }
        }

        /// <summary>
        /// 获得编码格式
        /// </summary>
        /// <param name="fs"></param>
        /// <returns></returns>
        private Encoding GetFileEncodeType(FileStream fs)
        {
            byte[] Unicode = new byte[] { 0xFF, 0xFE, 0x41 };
            byte[] UnicodeBIG = new byte[] { 0xFE, 0xFF, 0x00 };
            byte[] UTF8 = new byte[] { 0xEF, 0xBB, 0xBF }; //带BOM 
            Encoding reVal = Encoding.Default;
            BinaryReader r = new BinaryReader(fs, System.Text.Encoding.Default);
            int i;
            int.TryParse(fs.Length.ToString(), out i);
            byte[] ss = r.ReadBytes(i);
            if (IsUTF8Bytes(ss) || (ss[0] == 0xEF && ss[1] == 0xBB && ss[2] == 0xBF))
            {
                reVal = Encoding.UTF8;
            }
            else if (ss[0] == 0xFE && ss[1] == 0xFF && ss[2] == 0x00)
            {
                reVal = Encoding.BigEndianUnicode;
            }
            else if (ss[0] == 0xFF && ss[1] == 0xFE && ss[2] == 0x41)
            {
                reVal = Encoding.Unicode;
            }
            fs.Position = 0;
            return reVal;
        }

        /// <summary>   
        /// 判断是否是不带 BOM 的 UTF8 格式   
        /// </summary>   
        /// <param name="data"></param>   
        /// <returns></returns>   
        private static bool IsUTF8Bytes(byte[] data)
        {
            int charByteCounter = 1;  //计算当前正分析的字符应还有的字节数   
            byte curByte; //当前分析的字节.   
            for (int i = 0; i < data.Length; i++)
            {
                curByte = data[i];
                if (charByteCounter == 1)
                {
                    if (curByte >= 0x80)
                    {
                        //判断当前   
                        while (((curByte <<= 1) & 0x80) != 0)
                        {
                            charByteCounter++;
                        }
                        //标记位首位若为非0 则至少以2个1开始 如:110XXXXX...........1111110X    
                        if (charByteCounter == 1 || charByteCounter > 6)
                        {
                            return false;
                        }
                    }
                }
                else
                {
                    //若是UTF-8 此时第一位必须为1   
                    if ((curByte & 0xC0) != 0x80)
                    {
                        return false;
                    }
                    charByteCounter--;
                }
            }
            if (charByteCounter > 1)
            {
                throw new Exception("非预期的byte格式!");
            }
            return true;
        }
    }
}

消息处理链

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LISConsoleClient
{
    ///<summary  NoteObject="Class">
    /// [功能描述:消息处理链] <para/>
    /// [创建者:zlz] <para/>
    /// [创建时间:2017年03月28日] <para/>
    ///<说明>
    ///  [说明:路径工具类,提供路径操作]<para/>
    ///</说明>
    ///<修改记录>
    ///    [修改时间:本次修改时间]<para/>
    ///    [修改内容:本次修改内容]<para/>
    ///</修改记录>
    ///<修改记录>
    ///    [修改时间:本次修改时间]<para/>
    ///    [修改内容:本次修改内容]<para/>
    ///</修改记录>
    ///</summary>
    public class MsgDealLink
    {
        /// <summary>
        /// 处理连接集合
        /// </summary>
        public List<IMessageDeal> LinkList
        {
            get;
            set;
        }
    }
}

初版操作外壳,不同交互体系各自实现接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LISConsoleClient
{
    /// <summary>
    /// 操作打印的壳
    /// </summary>
    public class OperPrintShell : DHCLabtrakReportPrint.IOperPrintShell
    {
        /// <summary>
        /// 保存文件对话框
        /// </summary>
        /// <param name="Filter"></param>
        /// <returns></returns>
        public string SaveFileDialog(string Filter)
        {
            Console.WriteLine("请输入要保存的路径:");
            string path = Console.ReadLine();
            return path;
        }

        /// <summary>
        /// 显示App信息
        /// </summary>
        /// <param name="info"></param>
        /// <param name="coderInfo"></param>
        public void ShowAppInfo(string info, string coderInfo)
        {
            string head = DateTime.Now.ToString("hh:mm:ss") + "#";
            //head = head.PadRight(30);
            Console.WriteLine(head + info);
            Console.WriteLine(head + coderInfo);
        }

        /// <summary>
        /// 显示消息
        /// </summary>
        /// <param name="info"></param>
        /// <param name="title"></param>
        public void ShowMsgInfo(string info, string title = "")
        {
            string head = DateTime.Now.ToString("hh:mm:ss") + "#" + title;
            //head = head.PadRight(30);
            Console.WriteLine(head + info);
        }
    }
}

控制台运行
在这里插入图片描述

浏览器驱动打印
在这里插入图片描述

打印报告
在这里插入图片描述

引入壳的概念后剥离了交互部分,也使其他UI对接变的容易,如果微软不支持Linux的桌面就可以做个GTK界面来当Linux客户端界面。或者直接用控制台支持打印。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: FastReport.NET Web打印是一款基于FastReport.NET报表引擎的网页打印解决方案。它提供了一个简单而强大的工具,允许开发人员直接在Web应用程序中生成和打印报表。 FastReport.NET Web打印有以下几个主要特点: 1. 强大的报表设计工具:FastReport.NET提供了一个直观、易于使用的报表设计器,开发人员可以通过拖放方式添加数据和控件,自定义报表样式和布局,轻松设计出符合需求的报表。 2. 多种数据源支持:FastReport.NET Web打印支持多种数据源,包括数据库、XML文件、JSON数据等,可以方便地从不同来源获取数据进行报表生成。 3. 支持多种输出格式:FastReport.NET Web打印支持多种输出格式,包括PDF、Excel、Word、图片等,用户可以将报表输出为多种常见的文件格式,方便保存和分享。 4. 可定制的报表模板:开发人员可以根据需求创建自定义的报表模板,包括添加公司Logo、设置页眉页脚、调整字体颜色、样式等,实现报表的个性化定制。 5. 跨平台支持:FastReport.NET Web打印可以在各种操作系统和浏览器上运行,包括Windows、Linux、Mac等,兼容主流的浏览器,如Chrome、Firefox、IE等。 6. 安全性保障:FastReport.NET Web打印提供了安全的报表导出和打印功能,可以通过权限控制、加密处理等手段来保障报表数据的安全性。 总之,FastReport.NET Web打印是一种高效、灵活、易用的网页打印解决方案,可以帮助开发人员快速生成和打印各种类型的报表,提升工作效率,满足不同用户需求。 ### 回答2: FastReport.Net是一款优秀的报表生成工具,它不仅可以在桌面应用程序中生成报表,还可以在web应用程序中进行报表打印。 FastReport.Net Web打印功能允许我们在web浏览器中直接打印报表,而无需将报表导出为PDF或其他格式再进行打印。这样可以大大简化打印流程,节省时间和工作量。 要使用FastReport.Net进行Web打印,我们需要在web应用程序中引入FastReport.Net的相关库文件,并创建报表模板。报表模板的设计可以通过FastReport.Net提供的可视化设计器完成,也可以通过代码进行动态生成。 在Web应用程序中,我们可以通过浏览器中的打印按钮或者自定义的打印按钮来触发打印操作。当用户点击打印按钮时,FastReport.Net会将报表模板加载,并根据数据源中的数据生成报表内容。 FastReport.Net提供了丰富的打印选项,包括打印份数、纸张类型、页眉页脚、页码等。我们可以根据需要自定义这些选项,以满足打印要求。 同时,FastReport.Net还支持导出报表为PDF、Excel、Word等格式,以满足不同的使用需求。导出的报表可以方便地保存、打印或分享给其他人。 总之,FastReport.Net的Web打印功能使得在web应用程序中生成和打印报表变得简单高效。它的强大功能和简便操作为我们提供了一个便捷而强大的报表打印解决方案。 ### 回答3: FastReport.Net是一个用于创建报表的.NET框架。它具有强大的报表设计工具和丰富的功能,可以帮助开发人员快速而轻松地创建各种报表。 FastReport.Net支持Web打印的功能,可以将报表轻松地集成到Web应用程序中。用户只需要通过Web浏览器访问应用程序,就可以查看和打印报表。这为用户提供了方便和灵活的报表访问方式。 使用FastReport.Net进行Web打印非常简单。开发人员只需设计好报表并将其与Web应用程序集成,然后将报表保存为指定的格式,如PDF或HTML。当用户在Web应用程序中请求打印报表时,应用程序会动态地生成报表文件,并将其提供给用户进行打印。 通过FastReport.Net的Web打印功能,用户可以方便地打印报表,无需额外安装任何软件或工具。报表可以在任何设备上打印,包括计算机、平板电脑和手机等。 此外,FastReport.Net还提供了自定义打印设置和打印预览功能,用户可以根据自己的需求设置打印样式,并在打印之前预览报表的内容。这为用户提供了更加个性化和精确的报表打印体验。 总而言之,FastReport.Net的Web打印功能为用户提供了方便、灵活和个性化的报表打印方式。无论是开发者还是最终用户,都能够从中受益并轻松地实现报表的访问和打印

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小乌鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值