近期开发项目中用到的编码小技巧汇总说明(二)

以前有总结发表过《近期开发项目中用到的编码小技巧汇总说明》,虽没有涉及什么高大上的东西,但都是一些很实用的平时你们可能用到的知识,今天继续分享一些小技巧,欢迎你们了解,不足之处,能够直接评论留言谢谢!html

接上篇序号数组

6.解决当同一个类在不一样的项目中(命名空间不一样,但类的定义彻底相同的状况)使用BinaryFormatter进行序列化后再反序列化时出现找不到程序集的问题或反序列化的结果为nullide

原代码:(DataSetSurrogate分别在API项目中,客户端项目中都存在,类定义同样但因为不在同一个项目,即便命名空间改为同样仍然是会报错的)优化

        public static DataSet GZipBytesToDataSet(byte[] data)
        {
            byte[] buffer2 = data;
            BinaryFormatter ser = new BinaryFormatter();
            var ms = new MemoryStream(buffer2);
            var obj = ser.Deserialize(ms);
            DataSetSurrogate dss = obj as DataSetSurrogate;
            return dss.ConvertToDataSet();
        }

报错缘由是:序列化后的byte数组中包含了程序集的信息,故若是想要在另外一个程序集中成功的反序列化,则须要动态替换反序列化中的类型对应的程序集信息,改进后的代码:ui

先定义一个类型名称替换序列化绑定器:this

    public class TypeNameConvertBinder : SerializationBinder
    {
        public TypeNameConvertBinder():base()
        {

        }

        public TypeNameConvertBinder(string oldNameSapce, string newNameSapce):this()
        {
            this.OldNameSapce = oldNameSapce;
            this.NewNameSapce = newNameSapce;
        }

        public string OldNameSapce { get; set; }

        public string NewNameSapce { get; set; }

        public override Type BindToType(string assemblyName, string typeName)
        {
            typeName = typeName.Replace(OldNameSapce, NewNameSapce);
            assemblyName = assemblyName.Replace(OldNameSapce, NewNameSapce);
            return Type.GetType(string.Format("{0}, {1}", typeName, assemblyName));
        }
    }

而后序列化的时候直接给 BinaryFormatter设置Binder便可,代码以下:编码

        public static DataSet GZipBytesToDataSet(byte[] data)
        {
            byte[] buffer2 = data;
            BinaryFormatter ser = new BinaryFormatter();
            ser.Binder = new TypeNameConvertBinder() { OldNameSapce = "WMS.Common", NewNameSapce = "Zuowj" };
            var ms = new MemoryStream(buffer2);
            var obj = ser.Deserialize(ms);
            DataSetSurrogate dss = obj as DataSetSurrogate;
            return dss.ConvertToDataSet();
        }  

以上这样就解决了序列化时由于程序集不相同而致使的反序列化失败的问题。spa

7.控制台程序中实现输入密码遮罩功能,这个功能我是摘抄自网上的,还能够有优化空间日志

实现代码以下:orm

        static string ReadLineForPassword()
        {
            string input = null;
            while (true)
            {
                //存储用户输入的按键,而且在输入的位置不显示字符
                ConsoleKeyInfo ck = Console.ReadKey(true);

                //判断用户是否按下的Enter键
                if (ck.Key != ConsoleKey.Enter)
                {
                    if (ck.Key != ConsoleKey.Backspace)
                    {
                        //将用户输入的字符存入字符串中
                        input += ck.KeyChar.ToString();
                        //将用户输入的字符替换为*
                        Console.Write("*");
                    }
                    else
                    {
                        if (!string.IsNullOrEmpty(input)
                            && input.Length >= 1)
                        {
                            input = input.Remove(input.Length - 1, 1);
                        }
                        //删除错误的字符
                        Console.Write("\b \b");
                    }
                }
                else
                {
                    Console.WriteLine();
                    break;
                }
            }

            return input;
        }


//使用:
 string token = ReadLineForPassword();

 这样当用户在控制台上输入密码时则会以*号隐藏掉了。

8.直接使用String拼接XML的时候,有时可能由于字符串中包含了XML的保留字符,那么拼成后就会报错,故须要转义这些保留字,若是本身写可能考虑得不全,这时可使用:SecurityElement.Escape(String) 方法进行转义便可。

原来的代码:

            var st =new  System.Diagnostics.StackTrace();
            string msg = "<key>无效,使用'key'也无效 ";

            string xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><root><Msg>" + msg + "</Msg><StackTrace>" + st.ToString() + "</StackTrace></root>";
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xml);

            StringBuilder strBuilder=new StringBuilder();
            using (var xmlWriter = XmlWriter.Create(strBuilder))
            {
                xmlDoc.WriteTo(xmlWriter);
            }

            Console.WriteLine("new xml:" + strBuilder.ToString());
            

            Console.ReadKey();

 执行到xmlDoc.LoadXml(xml);报错,由于msg中包含了XML的保留字符,改进一下 msg = System.Security.SecurityElement.Escape("<key>无效,使用'key'也无效 ");而后再用一样的代码便可正常显示完整的XML,结果以下:

能够看到XML的保留字符都被转义了。

 9.关于WINDOWS服务安装或卸载批处理脚本bat在WIN10下执行报错问题解决办法(2019-5-28日 增长)

目前网上转载的安装与卸载的Windows服务的bat内容以下:(注意需放到服务程序exe相同的目录中)

// install.bat内容:

%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil.exe 服务程序exe
Net Start 服务名
sc config 服务名 start= auto

pause


// uninstall.bat内容:

net stop 服务名
%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil.exe /u 服务程序exe

pause

  在WIN 7或WIN SERVER中直接双击运行bat文件就可轻松完成服务的安装启动或服务中止卸载,但若是是在WIN10 下 直接双击运行bat文件则会报:

在“安装”阶段发生异常。
System.Security.SecurityException: 未找到源,但未能搜索某些或所有事件日志。 不可访问的日志: Security。

  经过这个错误信息咱们应该知道是权限不足致使的,故换成右键“以管理员身份运行”,结果仍然报以下错误:

在初始化安装时发生异常:
System.IO.FileNotFoundException: 未能加载文件或程序集“file:///C:\Windows\system32\服务名.exe”或它的某一个依 赖项。系统找不到指定的文件。。

    竟然报服务程序路径不存在,仔细一看,发现路径都不是当前的BAT路径,而变成了system32目录下了,这怎么回事呢?原来是以管理员身份运行惹的祸,会改变当前的执行目前环境为C:\Windows\system32,这样就致使了咱们脚本中写的服务程序.exe 这样的相对路径就会在执行时变成了是C:\Windows\system32\服务名.exe,这样确定是不行的,故解决方法有两种:

第一种:将上述脚本中的服务程序exe换成写死完整的exe路径,如:%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil.exe d:\test\testservice.exe

第二种:脚本中最开始行添加 动态切换cd到当前exe目录的命令(命令:cd /d %~dp0  ,含义:将扩充映射到一个驱动器和路径,简单点是切换到当前目录,命今详情可参见:http://www.javashuo.com/article/p-wtuczrof-dv.html),后续的脚本保持不变便可,完整代码以下:

//install.bat:

cd /d %~dp0
%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil.exe 服务程序exe路径
Net Start 服务名
sc config 服务名 start= auto

pause

//uninstall.bat:

cd /d %~dp0
net stop 服务名
%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil.exe /u 服务程序exe路径

pause

很显然第二种方法优于第一种,第一种须要写死服务程序EXE路径不便通用。

相关文章
相关标签/搜索