近期開發項目中用到的編碼小技巧彙總說明(二)

以前有總結髮表過《近期開發項目中用到的編碼小技巧彙總說明》,雖沒有涉及什麼高大上的東西,但都是一些很實用的平時你們可能用到的知識,今天繼續分享一些小技巧,歡迎你們瞭解,不足之處,能夠直接評論留言謝謝!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路徑不便通用。

相關文章
相關標籤/搜索