健保卡讀取程式 (console app sample) 第二版


Posted by kennyshu on 2024-09-30

承之前的第一版,這版改成用監聽的方式、事件(event)發生才做事

public class CardReader : BackgroundService
{
    public CardReader()
    {
        using (var readerCtx = PCSC.ContextFactory.Instance.Establish(PCSC.SCardScope.System))
        {
            var monitor = MonitorFactory.Instance.Create(PCSC.SCardScope.System);
            monitor.CardInserted += Monitor_CardInserted;
            monitor.CardRemoved += Monitor_CardRemoved;
            monitor.Start(readerCtx.GetReaders().FirstOrDefault());
        }
    }

    private async void Monitor_CardRemoved(object sender, CardStatusEventArgs e)
    {
        // 卡片移除event
    }

    private async void Monitor_CardInserted(object sender, CardStatusEventArgs e)
    {
        try
        {
            using (var readerCtx = PCSC.ContextFactory.Instance.Establish(PCSC.SCardScope.User))
            using (var reader = new PCSC.Iso7816.IsoReader(
               context: readerCtx,
               readerName: readerCtx.GetReaders().FirstOrDefault(),
               mode: PCSC.SCardShareMode.Shared,
               protocol: PCSC.SCardProtocol.Any))
            {
                var apduInit = new PCSC.Iso7816.CommandApdu(PCSC.Iso7816.IsoCase.Case4Short, reader.ActiveProtocol)
                {
                    CLA = 0x00,
                    INS = 0xA4,
                    P1 = 0x04,
                    P2 = 0x00,
                    Data = new byte[]
                        { 0xD1, 0x58, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11 }
                };

                var apduInitResponse = reader.Transmit(apduInit);
                if (!(apduInitResponse.SW1.Equals(144) && apduInitResponse.SW2.Equals(0)))
                {
                    Console.WriteLine("晶片卡非健保卡");
                    return;
                }

                var apduProfile = new PCSC.Iso7816.CommandApdu(PCSC.Iso7816.IsoCase.Case4Short, reader.ActiveProtocol)
                {
                    CLA = 0x00,
                    INS = 0xCA,
                    P1 = 0x11,
                    P2 = 0x00,
                    Data = new byte[] { 0x00, 0x00 }
                };
                var apduProfileResponse = reader.Transmit(apduProfile);
                if (apduProfileResponse.HasData)
                {
                    //位元組資料
                    byte[] aryData = apduProfileResponse.GetData();
                    //文字編碼解碼器
                    var oUTF8 = Encoding.UTF8;
                    var oBIG5 = Encoding.GetEncoding("big5");

                    var patientName = oBIG5.GetString(aryData.Skip(12).Take(20).ToArray()).Trim().TrimEnd('\0');
                    var patientId = oUTF8.GetString(aryData.Skip(32).Take(10).ToArray()).Trim();
                    var patientBirth = oUTF8.GetString(aryData.Skip(42).Take(7).ToArray()).Trim();
                    var patientGender = oUTF8.GetString(aryData.Skip(49).Take(1).ToArray()).Trim();

                    Console.WriteLine($"讀取健保卡:[{patientName}]");
                    return;
                }
            }
        }
        catch (PCSC.Exceptions.RemovedCardException)
        {
            return;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.InnerException?.Message ?? ex.Message);
            return;
        }
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            // 循環偵測/讀取讀卡機
            await CheckCardReaderAsync();
            // ...
        }
    }

    private async Task CheckCardReaderAsync()
    {
        using (var readerCtx = PCSC.ContextFactory.Instance.Establish(PCSC.SCardScope.User))
        {
            // 找到讀卡機
            if (readerCtx.GetReaders().Any())
            {
                var readerName = readerCtx.GetReaders().FirstOrDefault();
                Console.WriteLine($"找到讀卡機:[{readerName}]");
            }
            else
            {
                Console.WriteLine("找不到讀卡機");
            }
        }
    }
}

Reference:


#C# #健保卡







Related Posts

React 只會更新畫面中有變化的部分

React 只會更新畫面中有變化的部分

Pinia練習-製作購物車

Pinia練習-製作購物車

【Day07】透過Github將個人網頁上架至Netlify靜態網站服務

【Day07】透過Github將個人網頁上架至Netlify靜態網站服務


Comments