C#製作ActiveX控制項中調用海康SDK的問題

来源:http://www.cnblogs.com/zzuwangzhen/archive/2017/09/05/7479858.html
-Advertisement-
Play Games

這個事情就是一個坑,耽誤了兩周時間,之前並沒有做過ActiveX這玩意,現在客戶需求如此,只能說是在網上看著教程做了。 事情是這樣的,有一臺海康威視的攝像頭,客戶需要一個ActiveX控制項嵌入到網頁中,通過點擊按鈕開始錄製和結束錄製來進行視頻的錄製和保存,關於海康攝像頭的二次開發在此就不多說了,可以 ...


  這個事情就是一個坑,耽誤了兩周時間,之前並沒有做過ActiveX這玩意,現在客戶需求如此,只能說是在網上看著教程做了。

  事情是這樣的,有一臺海康威視的攝像頭,客戶需要一個ActiveX控制項嵌入到網頁中,通過點擊按鈕開始錄製和結束錄製來進行視頻的錄製和保存,關於海康攝像頭的二次開發在此就不多說了,可以參考SDK中的說明。

  直接上流程:

  1.開發環境:

    VS2010,這個打包方便,之前用VS2013打包的,總是調用不了,不知道原因是什麼;SDK是32位的,用64位的在Winform中可以正常使用,在網頁中使用控制項時會報錯。

  2.新建項目:

    新建一個類庫項目,如下:

 

    右鍵點擊項目,添加“用戶控制項”,如下:

    界面拖控制項,如下:

    控制項代碼如下,其中Guid是“工具”->“創建GUID”自動生成的,#region->#endregion摺疊部分是實現的IObjectSafety介面

using System;

namespace VideoHelper
{
    [System.Security.SecuritySafeCritical]
    public class Videos
    {
        private bool m_initSDK = false;
        /// <summary>
        /// 正在錄製
        /// </summary>
        private bool m_Record = false;
        private uint LastErr = 0;
        private Int32 m_RealHandle = -1;
        private Int32 m_lUserID = -1;
        public IntPtr handle { get; set; }
        public bool Initialize(string ip = "192.168.1.64", int port = 8000, string username = "admin", string password = "8910jqk#")
        {
            try
            {
                m_initSDK = CHCNetSDK.NET_DVR_Init();
                if (m_initSDK)
                {
                    CHCNetSDK.NET_DVR_SetLogToFile(3, "C:\\SdkLog\\", true);
                    //設備參數結構體
                    CHCNetSDK.NET_DVR_DEVICEINFO_V30 DeviceInfo = new CHCNetSDK.NET_DVR_DEVICEINFO_V30();
                    //註冊設備
                    m_lUserID = CHCNetSDK.NET_DVR_Login_V30(ip, port, username, password, ref DeviceInfo);
                    return m_lUserID >= 0;
                }
                return false;
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show("Initialize:" + ex.Message);
                return false;
            }
        }

        public bool Start(IntPtr handle, string filename)
        {
            try
            {
                CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
                lpPreviewInfo.lChannel = 1;
                lpPreviewInfo.dwLinkMode = 0;
                lpPreviewInfo.dwStreamType = 0;
                lpPreviewInfo.bBlocked = true;
                lpPreviewInfo.dwDisplayBufNum = 15;
                lpPreviewInfo.hPlayWnd = handle;
                IntPtr pUser = IntPtr.Zero;//new IntPtr();         
                //獲取實時視頻流
                m_RealHandle = CHCNetSDK.NET_DVR_RealPlay_V40(m_lUserID, ref lpPreviewInfo, null, pUser);
                if (m_Record == false)
                {
                    CHCNetSDK.NET_DVR_MakeKeyFrame(m_lUserID, 1);
                    if (!CHCNetSDK.NET_DVR_SaveRealData(m_RealHandle, filename))
                    {
                        LastErr = CHCNetSDK.NET_DVR_GetLastError();
                        return false;
                    }
                    else
                    {
                        m_Record = true;
                        return true;
                    }
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                return false;
            }
        }

        public bool End()
        {
            if (m_Record)
            {
                if (!CHCNetSDK.NET_DVR_StopSaveRealData(m_RealHandle))
                {
                    LastErr = CHCNetSDK.NET_DVR_GetLastError();
                    return false;
                }
                m_Record = false;
                m_RealHandle = -1;
                return true;
            }
            else
            {
                return false;
            }
        }

        public void Dispose()
        {
            try
            {
                if (m_lUserID >= 0)
                {
                    CHCNetSDK.NET_DVR_Logout_V30(m_lUserID);
                    m_lUserID = -1;
                }

                if (m_RealHandle >= 0)
                {
                    CHCNetSDK.NET_DVR_StopRealPlay(m_RealHandle);
                    m_RealHandle = -1;
                }

                CHCNetSDK.NET_DVR_Cleanup();
            }
            catch
            { }
        }
    }
}
錄製視頻操作類
using System;
using System.Runtime.InteropServices;

namespace VideoHelper
{
    [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IObjectSafety
    {
        [PreserveSig]
        int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);

        [PreserveSig()]
        int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
    }
}
介面代碼
using System;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
namespace VideoHelper
{
    [System.Security.SecuritySafeCritical]
    [Guid("79629620-3C0C-4D47-B93B-2D36AEF8EF31")]
    public partial class VideoControl : UserControl,IObjectSafety
    {
        public VideoControl()
        {
            InitializeComponent();
        }
        string videopath = Environment.CurrentDirectory;
        Videos video;
        IntPtr handle;
        private void btnLogin_Click(object sender, EventArgs e)
        {
            if (btnLogin.Text == "登錄")
            {
                try
                {
                    if (string.IsNullOrWhiteSpace(this.txtIP.Text))
                    {
                        MessageBox.Show("IP地址不能為空!");
                        return;
                    }
                    if (string.IsNullOrWhiteSpace(this.txtUserID.Text))
                    {
                        MessageBox.Show("用戶名不能為空!");
                        return;
                    }
                    if (string.IsNullOrWhiteSpace(this.txtPwd.Text))
                    {
                        MessageBox.Show("密碼不能為空!");
                        return;
                    }
                    video = new Videos();
                    if (video.Initialize(this.txtIP.Text, Convert.ToInt32(this.numericUpDown1.Value), this.txtUserID.Text, this.txtPwd.Text))
                    {
                        this.btnLogin.Text = "註銷";
                        MessageBox.Show("登錄成功!");
                        this.btnStart.Enabled = true;
                        this.btnSave.Enabled = true;
                    }
                    else
                    {
                        MessageBox.Show("登錄失敗!");
                    }
                }
                catch (Exception ee)
                {
                    MessageBox.Show("登錄異常:" + ee.Message);
                }
            }
            else if (btnLogin.Text == "註銷")
            {
                try
                {
                    video.Dispose();
                    this.btnLogin.Text = "登錄";
                    this.btnStart.Enabled = false;
                    this.btnSave.Enabled = false;
                }
                catch (Exception ee)
                {
                    MessageBox.Show("註銷異常:" + ee.Message);
                }
            }
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            try
            {
                string filename = txtFile.Text.Trim();
                if (filename.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0 || string.IsNullOrWhiteSpace(filename))
                {
                    MessageBox.Show("文件名含有非法字元或空格,請重新輸入");
                    txtFile.Focus();
                    return;
                }
                video.Start(handle, filename + comboBox1.SelectedItem.ToString());
                this.btnStart.Enabled = false;
                this.btnSave.Enabled = true;
            }
            catch (Exception ee)
            {
                MessageBox.Show("異常:" + ee.Message);
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            try
            {
                if (video.End())
                {
                    MessageBox.Show("視頻已保存!");
                    this.btnStart.Enabled = true;
                    this.btnSave.Enabled = false;
                }
                else
                {
                    MessageBox.Show("保存失敗!");
                    this.btnStart.Enabled = true;
                    this.btnSave.Enabled = true;
                }
            }
            catch (Exception ee)
            { MessageBox.Show("異常:" + ee.Message); }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                System.Diagnostics.Process.Start(videopath);

            }
            catch
            { }
        }

        private void VideoControl_Load(object sender, EventArgs e)
        {
            this.comboBox1.SelectedItem = ".mp4";
            this.handle = pictureBox1.Handle;
            this.btnStart.Enabled = false;
            this.btnSave.Enabled = false;
        }

        #region IObjectSafety 成員
        private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
        private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
        private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
        private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
        private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";

        private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
        private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
        private const int S_OK = 0;
        private const int E_FAIL = unchecked((int)0x80004005);
        private const int E_NOINTERFACE = unchecked((int)0x80004002);

        private bool _fSafeForScripting = true;
        private bool _fSafeForInitializing = true;

        public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
        {
            int Rslt = E_FAIL;

            string strGUID = riid.ToString("B");
            pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
            switch (strGUID)
            {
                case _IID_IDispatch:
                case _IID_IDispatchEx:
                    Rslt = S_OK;
                    pdwEnabledOptions = 0;
                    if (_fSafeForScripting == true)
                        pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
                    break;
                case _IID_IPersistStorage:
                case _IID_IPersistStream:
                case _IID_IPersistPropertyBag:
                    Rslt = S_OK;
                    pdwEnabledOptions = 0;
                    if (_fSafeForInitializing == true)
                        pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
                    break;
                default:
                    Rslt = E_NOINTERFACE;
                    break;
            }

            return Rslt;
        }

        public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
        {
            int Rslt = E_FAIL;
            string strGUID = riid.ToString("B");
            switch (strGUID)
            {
                case _IID_IDispatch:
                case _IID_IDispatchEx:
                    if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true))
                        Rslt = S_OK;
                    break;
                case _IID_IPersistStorage:
                case _IID_IPersistStream:
                case _IID_IPersistPropertyBag:
                    if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true))
                        Rslt = S_OK;
                    break;
                default:
                    Rslt = E_NOINTERFACE;
                    break;
            }

            return Rslt;
        }

        #endregion
    }
}
控制項代碼
namespace VideoHelper
{
    partial class VideoControl
    {
        /// <summary> 
        /// 必需的設計器變數。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// 清理所有正在使用的資源。
        /// </summary>
        /// <param name="disposing">如果應釋放托管資源,為 true;否則為 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region 組件設計器生成的代碼

        /// <summary> 
        /// 設計器支持所需的方法 - 不要
        /// 使用代碼編輯器修改此方法的內容。
        /// </summary>
        private void InitializeComponent()
        {
            this.button1 = new System.Windows.Forms.Button();
            this.comboBox1 = new System.Windows.Forms.ComboBox();
            this.label4 = new System.Windows.Forms.Label();
            this.txtFile = new System.Windows.Forms.TextBox();
            this.btnSave = new System.Windows.Forms.Button();
            this.btnStart = new System.Windows.Forms.Button();
            this.btnLogin = new System.Windows.Forms.Button();
            this.label3 = new System.Windows.Forms.Label();
            this.txtPwd = new System.Windows.Forms.TextBox();
            this.label2 = new System.Windows.Forms.Label();
            this.txtUserID = new System.Windows.Forms.TextBox();
            this.label1 = new System.Windows.Forms.Label();
            this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
            this.IP = new System.Windows.Forms.Label();
            this.txtIP = new System.Windows.Forms.TextBox();
            this.pictureBox1 = new System.Windows.Forms.PictureBox();
            ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
            this.SuspendLayout();
            // 
            // button1
            // 
            this.button1.Cursor = System.Windows.Forms.Cursors.Hand;
            this.button1.Font = new System.Drawing.Font("微軟雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.button1.Location = new System.Drawing.Point(377, 360);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(138, 22);
            this.button1.TabIndex = 58;
            this.button1.Text = "打開視頻存放位置";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // comboBox1
            // 
            this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
            this.comboBox1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.comboBox1.Font = new System.Drawing.Font("微軟雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.comboBox1.FormattingEnabled = true;
            this.comboBox1.Items.AddRange(new object[] {
            ".mp4",
            ".avi",
            ".wmv",
            ".3gp",
            ".flv"});
            this.comboBox1.Location = new System.Drawing.Point(303, 361);
            this.comboBox1.Name = "comboBox1";
            this.comboBox1.Size = new System.Drawing.Size(55, 25);
            this.comboBox1.TabIndex = 57;
            // 
            // label4
            // 
            this.label4.AutoSize = true;
            this.label4.Font = new System.Drawing.Font("微軟雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.label4.Location = new System.Drawing.Point(14, 360);
            this.label4.Name = "label4";
            this.label4.Size = new System.Drawing.Size(116, 17);
            this.label4.TabIndex = 56;
            this.label4.Text = "請輸入視頻文件名:";
            // 
            // txtFile
            // 
            this.txtFile.Location = new System.Drawing.Point(136, 360);
            this.txtFile.Name = "txtFile";
            this.txtFile.Size = new System.Drawing.Size(161, 21);
            this.txtFile.TabIndex = 55;
            // 
            // btnSave
            // 
            this.btnSave.Cursor = System.Windows.Forms.Cursors.Hand;
            this.btnSave.Font = new System.Drawing.Font("微軟雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.btnSave.Location = new System.Drawing.Point(490, 298);
            this.btnSave.Name = "btnSave";
            this.btnSave.Size = new System.Drawing.Size(57, 45);
            this.btnSave.TabIndex = 54;
            this.btnSave.Text = "保存";
            this.btnSave.UseVisualStyleBackColor = true;
            this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
            // 
            // btnStart
            // 
            this.btnStart.Cursor = System.Windows.Forms.Cursors.Hand;
            this.btnStart.Font = new System.Drawing.Font("微軟雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.btnStart.Location = new System.Drawing.Point(421, 298);
            this.btnStart.Name = "btnStart";
            this.btnStart.Size = new System.Drawing.Size(57, 45);
            this.btnStart.TabIndex = 53;
            this.btnStart.Text = "錄製";
            this.btnStart.UseVisualStyleBackColor = true;
            this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
            // 
            // btnLogin
            // 
            this.btnLogin.Cursor = System.Windows.Forms.Cursors.Hand;
            this.btnLogin.Font = new System.Drawing.Font("微軟雅黑", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.btnLogin.Location = new System.Drawing.Point(352, 298);
            this.btnLogin.Name = "btnLogin";
            this.btnLogin.Size = new System.Drawing.Size(57, 45);
            this.btnLogin.TabIndex = 52;
            this.btnLogin.Text = "登錄";
            this.btnLogin.UseVisualStyleBackColor = true;
            this.btnLogin.Click += new System.EventHandler(this.btnLogin_Click);
            // 
            // label3
            // 
            this.label3.AutoSize = true;
            this.label3.Font = new System.Drawing.Font("微軟雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.label3.Location = new System.Drawing.Point(172, 325);
            this.label3.Name = "label3";
            this.label3.Size = new System.Drawing.Size(44, 17);
            this.label3.TabIndex = 51;
            this.label3.Text = "密碼:";
            // 
            // txtPwd
            // 
            this.txtPwd.Location = new System.Drawing.Point(221, 322);
            this.txtPwd.Name = "txtPwd";
            this.txtPwd.PasswordChar = '*';
            this.txtPwd.Size = new System.Drawing.Size(115, 21);
            this.txtPwd.TabIndex = 50;
            this.txtPwd.Text = "8910jqk#";
            this.txtPwd.UseSystemPasswordChar = true;
            // 
            // label2
            // 
            this.label2.AutoSize = true;
            this.label2.Font = new System.Drawing.Font("微軟雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.label2.Location = new System.Drawing.Point(8, 322);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(44, 17);
            this.label2.TabIndex = 49;
            this.label2.Text = "用戶名";
            // 
            // txtUserID
            // 
            this.txtUserID.Location = new System.Drawing.Point(66, 322);
            this.txtUserID.Name = "txtUserID";
            this.txtUserID.Size = new System.Drawing.Size(100, 21);
            this.txtUserID.TabIndex = 48;
            this.txtUserID.Text = "admin";
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Font = new System.Drawing.Font("微軟雅黑"<

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 添加引用 創建表 創建列 創建行 賦值和取值 篩選行 刪除行 複製表 表排序 ...
  • 前段時間,用CefSharp.WinForms寫了一個可以播放flash以及一些展示頁面的小程式,涉及到跨域訪問之類的問題。CefSharp.WinForms版本49.0.1。 剛開始挺順利,做到播放flash的時候各種黑屏,無法播放。先是回退32那個版本 用NPAPI解決的但是貌似32那個版本在客 ...
  • 在《asp.net core認證與授權》中講解了固定和自定義角色授權系統許可權,其實我們還可以通過其他方式來授權,比如可以通過角色組,用戶名,生日等,但這些主要取決於ClaimTypes,其實我們也可以自定義鍵值來授權,這些統一叫策略授權,其中更強大的是,我們可以自定義授權Handler來達到靈活授權... ...
  • 在asp.net core中,微軟提供了基於認證(Authentication)和授權(Authorization)的方式,來實現許可權管理的,本篇博文,介紹基於固定角色的許可權管理和自定義角色許可權管理,本文內容,更適合傳統行業的BS應用,而非互聯網應用。 ...
  • 1 public bool IsRegistered() 2 { 3 string clsid = ConfigurationManager.AppSettings["clsid"]; 4 //參數檢查 5 Debug.Assert(!String.IsNullOrEmpty(clsid), "cl ...
  • 代碼中包含了檢測本地安裝盤符代碼 1 一,定義下載委托事件(用於實現前臺進度條更新和下載完成後事件的回調): 2 private delegate void Action(); 3 private string diverUrl = ConfigurationManager.AppSettings[ ...
  • 如果想體驗Linux環境下開發和運行.NET Core應用,我們有多種選擇。一種就是在一臺物理機上安裝原生的Linux,我們可以根據自身的喜好選擇某種Linux Distribution,目前來說像RHEL、Ubuntu、Debian、Fedora、CentOS和SUSE這些主流的Distribut... ...
  • 資料庫管理:access是資料庫其中之一。 語文:重點應用文 ,第一部字典通聞解字,第一部詩集詩經,第一部詞典爾雅,爾:接近,雅:普通話。蟲:有生命的生物,䖵:有翅膀的蟲,蟲:有毒的蟲 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...