[C#][.NETCore] 壓縮檔案 & 解壓縮檔案

在 .NET Framework 的時候有好用的 DotNetZip 可以快速壓縮&解壓縮檔案
但在寫 .NET Core 的時候發現這個套件不能使用,那只好默默地自己寫了

這邊就用 System.IO.Compression 提供的 ZipArchive 來簡單寫個壓縮 & 解壓縮範例

壓縮檔案:

string rootPath = AppDomain.CurrentDomain.BaseDirectory;
string saveFileName = Path.Combine(rootPath, "test.zip");
string zipFileName = Path.Combine(rootPath, "123.txt");

using (var fs = new FileStream(saveFileName, FileMode.OpenOrCreate))
{
    using (ZipArchive zipArchive = new ZipArchive(fs, ZipArchiveMode.Create))
    {
        string fileName = Path.GetFileName(zipFileName);

        var zipArchiveEntry = zipArchive.CreateEntry(fileName);
        using (var zipStream = zipArchiveEntry.Open())
        {
            byte[] bytes = File.ReadAllBytes(zipFileName);
            zipStream.Write(bytes, 0, bytes.Length);
        }
    }
}

 

解壓縮檔案:

string rootPath = AppDomain.CurrentDomain.BaseDirectory;
string zipFileName = Path.Combine(rootPath, "test.zip");
string saveFolder = rootPath;

using (var fs = new FileStream(zipFileName, FileMode.Open))
{
    using (ZipArchive zipArchive = new ZipArchive(fs, ZipArchiveMode.Read))
    {
        foreach (ZipArchiveEntry zipArchiveEntry in zipArchive.Entries)
        {
            string temp = Path.Combine(saveFolder, zipArchiveEntry.FullName);
            zipArchiveEntry.ExtractToFile(temp);
        }
    }
}

 

解壓縮的時候最好可以將 zipArchiveEntry.FullName 再做一層處理,避免產生資安問題 (詳情)

       

[Docker][Linux] SQL Server 安裝筆記

環境:Window 7

  1. 安裝 Docker Toolbox
  2. 新增 Volume
docker volume create vol-mssql

 

  1. 建立容器
docker run \
--restart=always \
--name mssql \
--mount "source=vol-mssql,target=/var/opt/mssql" \
-e "ACCEPT_EULA=Y" \
-e "SA_PASSWORD=1OCHWiY9O#RF" \
-e "MSSQL_PID=Express" \
-e "MSSQL_COLLATION=Chinese_Taiwan_Stroke_CI_AS" \
-p 1433:1433 \
-d microsoft/mssql-server-linux:latest

 

  1. 更新時區
docker exec -ti mssql bash
apt-get update
apt-get install tzdata -y
dpkg-reconfigure tzdata

 

參考資料:

  1. Linux Docker 運行 MSSQL
  2. 快速入門: 使用 Docker 執行 SQL Server 2017 容器映像
  3. 在Linux上使用环境变量配置SQL Server设置
       

[Docker][NetCore] Win7 可以在 Docker 下 Debug ASP.NET Core 嗎?

今天心血來潮想試試看可不可以把 ASP.NET Core 部屬在 Docker 裡面 Debug,但我的測試機是 Win7 無法安裝新版 Docker for Windows 於是乎抱著僥倖下載 Docker Toolbox 來試試看
兩者最大差異在於 Docker Toolbox 是運行在 Oracle VM VirtualBox,而 Docker for Windows 則是可以在微軟的虛擬化技術 Hyper-V 底下運行

肉身測試開始

如果想要讓現有專案支援 Docker 的話只要對 專案右鍵 -> 加入 -> Docker Support 強大的 Visual Studio 2017 就會搞定基礎設定

這邊的話要選擇 Linux 上面的 Windows 是給 Docker for Windows 選的
接著 Visual Studio 就會幫你下載與設定一些基本環境

接著直接按 F5 執行偵錯模式
噹噹… 他竟然說我沒有安裝 dotnet sdk

-------------------------------------------------------------------
You may only use the Microsoft .NET Core Debugger (vsdbg) with
Visual Studio Code, Visual Studio or Visual Studio for Mac software
to help you develop and test your applications.
-------------------------------------------------------------------
Did you mean to run dotnet SDK commands? Please install dotnet SDK from:
http://go.microsoft.com/fwlink/?LinkID=798306&clcid=0x409
The target process exited without raising a CoreCLR started event. Ensure that the target process is configured to use .NET Core. This may be expected if the target process did not run on .NET Core.
The program '[24] dotnet' has exited with code 145 (0x91).
'' 程式以返回碼 145 (0x91) 結束。

 

 

翻了很久才翻到一篇文章 Docker debugging for ASP.NET Core application is not working 國外也有個勇者想在 Win7 利用 Docker 來 Debug ASP.NET Core

最後被加上了 Closed - Won't Fix 的 Tag 看來這個問題應該是不會修正了

結論

想要在 Docker 上玩 ASP.NET Core 還是乖乖用 Win10 吧
哪天有空了來試試看在 Win10 安裝 Docker 玩玩看
不知道會不會又有其他地雷引爆

       

[C#][DI] 相互依賴造成循環注入死結

問題緣由

最近在寫 .NET Core 的時候遇到了一個問題

A circular dependency was detected for the service of type 'WebApplication1.Service.A1Service'

 

A1Service

public class A1Service
{
    private readonly string guid = null;
    private readonly A2Service _a2Service = null;

    public A1Service(A2Service a2Service)
    {
        _a2Service = a2Service;

        if (guid == null)
        {
            guid = Guid.NewGuid().ToString();
        }
    }

    public void Run()
    {
        Console.WriteLine("A1Service: " + guid);
    }

    public void RunOther()
    {
        _a2Service.Run();
    }
}

 

這是網路教學文章上常見的從建構子中依賴注入 A2Service 的程式
接著我們再來看看另外一支程式

A2Service

public class A2Service
{
    private readonly string guid = null;
    private readonly A1Service _a1Service = null;

    public A2Service(A1Service a1Service)
    {
        _a1Service = a1Service;

        if (guid == null)
        {
            guid = Guid.NewGuid().ToString();
        }
    }

    public void Run()
    {
        Console.WriteLine("A2Service: " + guid);
    }

    public void RunOther()
    {
        _a1Service.Run();
    }
}

 

 

這裡就發生了一個循環依賴的問題 A1Service 在建構子中注入了 A2Service,而 A2Service 也在建構子中注入了 A1Service,造成兩個物件互相依賴造成 Exception

解決方法

改成不直接在建構子中注入 Service ,改注入 IServiceProvider,再利用 GetService 這個方法來取得物件,這樣就可以順利解決這個問題囉。

A3Service

public class A3Service
{
    private readonly string guid = null;
    private readonly IServiceProvider _serviceProvider = null;

    public A3Service(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;

        if (guid == null)
        {
            guid = Guid.NewGuid().ToString();
        }
    }

    public void Run()
    {
        Console.WriteLine("A3Service: " + guid);
    }

    public void RunOther()
    {
        _serviceProvider.GetService<A4Service>().Run();
    }
}

 

A4Service

public class A4Service
{
    private readonly string guid = null;
    private readonly IServiceProvider _serviceProvider = null;

    public A4Service(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;

        if (guid == null)
        {
            guid = Guid.NewGuid().ToString();
        }
    }

    public void Run()
    {
        Console.WriteLine("A4Service: " + guid);
    }

    public void RunOther()
    {
        _serviceProvider.GetService<A3Service>().Run();
    }
}

 

       

[iOS] 越獄後 Whoscall 老是更新失敗無法使用?

不知道有沒有人跟我一樣手賤去點更新 Whoscall,來電辨識功能就掛掉了,無法開啟識別也無法更新資料庫,嘗試過無數次重新安裝與重開機都出現下圖狀況

今天剛好看到瘋先生 免電腦!直接用App Store替iOS App 將版/降回舊版教學 這篇文章,就趕快在我的手機上降級 App 版本看看還有沒有救,最後結果當然是…復活拉 ~

實測裝置

  • Device:Apple iPhone 7
  • Version:iOS 10.1.1

教學步驟

  1. 從 Cydia 安裝 App Admin (教學)
  2. 在 AppStore 找到 Whoscall 長按開啟 並點選 Downgrade

  3. 選擇 2.2.16 (最後一版可以成功啟用的版本)

  4. 大功告成 !!

不知道 Whoscall 是為了防堵越獄還是程式本身的 Bug,有回報粉絲團許久都沒有修正這個問題,在程式修復以前目前只好用降版的方式了。

       

[Windows] 更新 Visual Studio 2017 後偵錯模式會自己停止?

最近更新了 Visual Studio 2017 到最新版本,發現在debug的時候 IIS Express 總是被停止運行,再找 bug 的時候發生這件事情實在是很惱人的一件事情,拜了 google 大神後發現微軟竟然在更新的時候偷偷把這個設定啟用,這實在是太坑了 !!

解決方法:將下面兩張圖的勾勾都取消就可以恢復正常囉。

       

[C#][LeetCode] 28. Implement strStr()

從傳入參數 haystack 中找出參數 needle 中的索引位置,非常基礎的一題

我的答案

public class Solution {
    public int StrStr(string haystack, string needle) {
        if(needle == null || needle == string.Empty){
            return 0;
        } else if(haystack == null){
            return -1;
        }
        
        return haystack.IndexOf(needle);
    }
}

 

       

[C#][LeetCode] 2. Add Two Numbers

輸入兩個 ListNode 物件並將兩個相同層數的數值加總,其值若超過 10 需進位到下個節點,這題我覺得迴圈解法比遞迴更讓人腦袋卡住,可能是我功力不夠吧。

我的遞迴解答:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode AddTwoNumbers(ListNode l1, ListNode l2) {
        return Add(l1, l2, 0);
    }
    
    public ListNode Add(ListNode l1, ListNode l2, int addNum = 0)
    {
        if(l1 == null && l2 == null)
        {
            return null;                 
        }
        
        l1 = l1 ?? new ListNode(0);
        l2 = l2 ?? new ListNode(0);
        
        int i = (l1.val + l2.val) + addNum;
        ListNode totalNode = new ListNode(i % 10);
        if(l1.next != null || l2.next != null)
        {
            totalNode.next = Add(l1.next, l2.next, (i / 10));
        }
        
        if(i >= 10 && totalNode.next == null)
        {
            totalNode.next = new ListNode(1);
        }
             
        return totalNode;
    }
}

 

 

我的迴圈作法:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     public int val;
 *     public ListNode next;
 *     public ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public ListNode AddTwoNumbers(ListNode l1, ListNode l2) {
        
        int sumValue = 0;
        int carryValue = 0;
        
        ListNode ansNode = new ListNode(-1);
        
        // 將 ansNode 的記憶體位置指向給 node
        ListNode node = ansNode;
        
        while(l1 != null || l2 != null)
        {
            sumValue = carryValue;
            
            if(l1 != null)
            {
                sumValue += l1.val;
                l1 = l1.next;
            }
            
            if(l2 != null)
            {
                sumValue += l2.val;
                l2 = l2.next;
            }
            
            carryValue = (sumValue / 10);
            if(carryValue > 0)
            {
                sumValue = (sumValue % 10);
                
                // 若大於 10 且 l1 與 l2 都沒有下個節點,那就自己創造一個
                if(l1 == null && l2 == null)
                {
                    l1 = new ListNode(0);
                }
            }
                        
            if(ansNode.val == -1)
            {
                ansNode.val = sumValue;
            }
            else
            {                
                node.next = new ListNode(sumValue);
                
                // 將當前物件 node.next 的記憶體位置指向到 node,這樣就可以達到一層一層改變 ansNode.next 值的效果
                node = node.next;
            }
        }
        
        return ansNode;
    }

    
}

 

 

       

[C#][LeetCode] 804. Unique Morse Code Words

這題要將英文轉換成摩斯密碼,並計算出重複字串的數量,我用 Linq 輕鬆解決。

public class Solution {
    
    public int UniqueMorseRepresentations(string[] words) {
        
        string[] morseCode = new string[] {".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."};
        
        List<char> listAToZ = Enumerable.Range('a', 26)
                                        .Select(x => (char)x)
                                        .ToList();
        
        var morseCodeAns = words.Select(x => 
        {
            var temp = x.Select(y => morseCode[listAToZ.IndexOf(y)]);            
            return string.Join(string.Empty, temp);
        });
        
        return morseCodeAns.Distinct().Count();
    }
}

 

       

[C#][LeetCode] 8. String to Integer (atoi)

外部輸入一個字串,若開頭為數字的話或 +- 符號的話則轉換為 int 的型態,且若超過 int 的最大或最小值則取極限值為準。

我的第一版答案如下:

public class Solution {
    public int MyAtoi(string str) {
        var arrNum = "0123456789".ToList();
        var arrSymbol = "-".ToList();

        if (string.IsNullOrWhiteSpace(str))
        {
            return 0;
        }
        else
        {
            str = str.Trim();
        }

        bool isFirstAddSymbol = (str[0] == '+');

        if (isFirstAddSymbol)
        {
            str = str.Substring(1);
        }

        if (string.IsNullOrWhiteSpace(str))
        {
            return 0;
        }

        bool isFirstNum = (arrNum.IndexOf(str[0]) != -1);
        bool isFirstSymbol = (arrSymbol.IndexOf(str[0]) != -1);

        if ((isFirstAddSymbol && isFirstSymbol) ||
            (!isFirstNum && !isFirstSymbol) ||
            (isFirstSymbol && str.All(x => arrNum.IndexOf(x) == -1)) ||
            (isFirstSymbol && str.Length > 1 && (arrNum.IndexOf(str[1]) == -1)))
        {
            return 0;
        }

        string numString = string.Empty;
        str = isFirstSymbol ? str.Substring(1) : str;

        for (int i = 0; i < str.Length; i++)
        {

            bool isNum = (arrNum.IndexOf(str[i]) != -1);

            if (!isNum)
            {
                break;
            }

            if (numString == "0")
            {
                numString = str[i].ToString();
            }
            else
            {
                numString += str[i].ToString();
            }

        }

        int maxValueLength = int.MaxValue.ToString().Length;
        long ans = int.MaxValue;

        bool isMoreMax = (numString.Length > maxValueLength) || (long.Parse(numString) > int.MaxValue);

        if (!isMoreMax)
        {
            ans = long.Parse(numString);
        }

        if (isFirstSymbol && isMoreMax)
        {
            ans += 1;
        }

        return Convert.ToInt32(isFirstSymbol ? -ans : ans);
    }
}

 

 

參考最佳解答後的優化版:

public class Solution {
    public int MyAtoi(string str) {
        str = (str ?? string.Empty).Trim();
        
        if (string.IsNullOrWhiteSpace(str))
        {
            return 0;
        }
        
        bool isMinusSign = (str[0] == '-');
        if (isMinusSign || (str[0] == '+'))
        {
            
            if ((str.Length == 1) ||
                ((str.Length > 1) && (str[1] < '0' || str[1] > '9')))
            {
                return 0;
            }
            
            str = str.Substring(1);
        }
        
        string numString = string.Empty;
        foreach (var item in str)
        {
            bool isNum = (item >= '0' && item <= '9');
            
            if (!isNum) {
                break;
            }
            
            if (numString == "0")
            {
                numString = item.ToString();
            }
            else
            {
                numString += item.ToString();
            }
        }
        
        if (numString == string.Empty)
        {
            return 0;
        }

        int maxValueLength = int.MaxValue.ToString().Length;
        long ans = int.MaxValue;

        bool isMoreMax = (numString.Length > maxValueLength) || (long.Parse(numString) > int.MaxValue);

        if (!isMoreMax)
        {
            ans = long.Parse(numString);
        }

        if (isMinusSign && isMoreMax)
        {
            ans += 1;
        }

        return Convert.ToInt32(isMinusSign ? -ans : ans);
    }
}