[.NET] 一步步打造一個簡單的 MVC 電商網站 - BooksStore(四)

来源:http://www.cnblogs.com/liqingwen/archive/2017/04/04/6658975.html
-Advertisement-
Play Games

一步步打造一個簡單的 MVC 電商網站 - BooksStore(四) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore 《一步步打造一個簡單的 MVC 電商網站 - BooksStore(一)》(發佈時間:2017-03-3 ...


一步步打造一個簡單的 MVC 電商網站 - BooksStore(四)

  本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore

  《一步步打造一個簡單的 MVC 電商網站 - BooksStore(一)》(發佈時間:2017-03-30 )

      《一步步打造一個簡單的 MVC 電商網站 - BooksStore(二)》(發佈時間:2017-03-31)

  《一步步打造一個簡單的 MVC 電商網站 - BooksStore(三)》(發佈時間:2017-04-01)

  《一步步打造一個簡單的 MVC 電商網站 - BooksStore(四)》(發佈時間:2017-04-05)

簡介

  上一節我們完成了兩個主要功能:完成了整個購物車的流程,以及訂單處理(發郵件進行通知),今天我們來學習一下最基本的增刪改查,以及登錄認證過濾器,加入防 CSRF 攻擊,本系列已完結。

  該系列主要功能與知識點如下:

    分類、產品瀏覽、購物車、結算、CRUD(增刪改查) 管理、發郵件、分頁、模型綁定、認證過濾器和單元測試等。

     【備註】項目使用 VS2015 + C#6 進行開發,有問題請發表在留言區哦,還有,頁面長得比較醜,請見諒。

 

目錄

  • 基本的增刪改查 CRUD
  • 登錄授權認證過濾

 

基本的增刪改查 CRUD

  我們創建一個新的控制器進行增刪改查功能,AdminController,並添加一個顯示所有數據的方法:

    /// <summary>
    /// 後臺管理控制器
    /// </summary>
    public class AdminController : Controller
    {
        private readonly IBookRepository _bookRepository;

        public AdminController(IBookRepository bookRepository)
        {
            _bookRepository = bookRepository;
        }

        /// <summary>
        /// 首頁
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            return View(_bookRepository.Books);
        }
    }

 

  不在沿用之前的佈局頁了,創建一個新的佈局頁 _AdmindLayout.cshtml:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link href="~/Contents/admin/Site.css" rel="stylesheet" />
</head>
<body>
    <div>
        @RenderBody()
    </div>
</body>
</html>
.table {
    width: 100%;
    padding: 0;
    margin: 0;
}

    .table th {
        font: bold 12px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
        color: #4f6b72;
        border-right: 1px solid #C1DAD7;
        border-bottom: 1px solid #C1DAD7;
        border-top: 1px solid #C1DAD7;
        letter-spacing: 2px;
        text-transform: uppercase;
        text-align: left;
        padding: 6px 6px 6px 12px;
        background: #CAE8EA no-repeat;
    }

    .table td {
        border-right: 1px solid #C1DAD7;
        border-bottom: 1px solid #C1DAD7;
        background: #fff;
        font-size: 14px;
        padding: 6px 6px 6px 12px;
        color: #4f6b72;
    }

        .table td.alt {
            background: #F5FAFA;
            color: #797268;
        }

    .table th.spec, td.spec {
        border-left: 1px solid #C1DAD7;
    }
Site.css

 

  對應的 Index.cshtml:

@model IEnumerable<Wen.BooksStore.Domain.Entities.Book>

@{
    Layout = "~/Views/Shared/_AdminLayout.cshtml";
}

<p>
    @Html.ActionLink("新增", "Edit")
</p>
<table class="table">
    <tr>
        <th>
            名稱
        </th>
        <th>
            描述
        </th>
        <th>
            價格
        </th>
        <th>
            分類
        </th>
        <th></th>
    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Description)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Category)
            </td>
            <td>
                @Html.ActionLink("編輯", "Edit", new { id = item.Id })
                @using (Html.BeginForm("Delete", "Admin", FormMethod.Post, new { style = "display:inline;" }))
                {
                    @Html.Hidden("id", item.Id)
                    <input type="submit" value="刪除" />
                }
            </td>
        </tr>
    }

</table>

 

 

 

   編輯,我把新增和編輯的位置放在一塊,使用 id 進行區分,如果 id = 0 就表示新增的信息。

  在 AdminCtroller 中添加關於編輯的方法

        /// <summary>
        /// 編輯
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult Edit(int id = 0)
        {
            if (id == 0)
            {
                return View(new Book());
            }

            var model = _bookRepository.Books.FirstOrDefault(x => x.Id == id);
            return View(model);
        }

        /// <summary>
        /// 編輯
        /// </summary>
        /// <param name="book"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult Edit(Book book)
        {
            if (!ModelState.IsValid)
            {
                return View(book);
            }

            _bookRepository.SaveBook(book);
            return RedirectToAction("Index");
        }

 

  更新存儲庫中的方法:

  IBookRepository.cs

    /// <summary>
    /// 書存儲庫介面
    /// </summary>
    public interface IBookRepository
    {
        /// <summary>
        /// 書模型集合
        /// </summary>
        IQueryable<Book> Books { get; }

        /// <summary>
        /// 保存書
        /// </summary>
        /// <param name="book"></param>
        /// <returns></returns>
        int SaveBook(Book book);

        /// <summary>
        /// 刪除書
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        Book DeleteBook(int id);
    }

 

  EfBookRepository.cs

    /// <summary>
    /// 書存儲庫
    /// </summary>
    public class EfBookRepository : IBookRepository
    {
        private readonly EfDbContext _context = new EfDbContext();

        /// <summary>
        /// 書模型集合
        /// </summary>
        public IQueryable<Book> Books => _context.Books;

        /// <summary>
        /// 保存書
        /// </summary>
        /// <param name="book"></param>
        /// <returns></returns>
        public int SaveBook(Book book)
        {
            if (book.Id == 0)
            {
                _context.Books.Add(book);
            }
            else
            {
                var model = _context.Books.Find(book.Id);

                if (model==null)
                {
                    return 0;
                }

                model.Category = book.Category;
                model.Description = book.Description;
                model.Name = book.Name;
                model.Price = book.Price;
            }

            return _context.SaveChanges();
        }

        /// <summary>
        /// 刪除書
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Book DeleteBook(int id)
        {
            var model = _context.Books.Find(id);

            if (model == null)
            {
                return null;
            }

            _context.Books.Remove(model);
            _context.SaveChanges();

            return model;
        }
    }

 

  需要對 Book 模型加上驗證用的特性:

    [Table("Book")]
    public class Book
    {
        /// <summary>
        /// 標識
        /// </summary>
        public int Id { get; set; }

        /// <summary>
        /// 名稱
        /// </summary>
        [Required(ErrorMessage = "名稱不能為空")]
        public string Name { get; set; }

        /// <summary>
        /// 描述
        /// </summary>
        [Required(ErrorMessage = "描述不能為空")]
        public string Description { get; set; }

        /// <summary>
        /// 價格
        /// </summary>
        [Required(ErrorMessage = "價格不能為空")]
        [Range(0.01, double.MaxValue, ErrorMessage = "請填寫合適的價格")]
        public decimal Price { get; set; }

        /// <summary>
        /// 分類
        /// </summary>
        [Required(ErrorMessage = "分類不能為空")]
        public string Category { get; set; }
    }

 

  _AdminLayout.cshtml 需要引入驗證用的 js(客戶端驗證):

    <script src="~/Scripts/jquery-1.10.2.js"></script>
    <script src="~/Scripts/jquery.validate.js"></script>
    <script src="~/Scripts/jquery.validate.unobtrusive.js"></script>

 

  Edit.cshtml

@model Wen.BooksStore.Domain.Entities.Book

@{
    Layout = "~/Views/Shared/_AdminLayout.cshtml";
}

<h2>編輯</h2>

<div>
    @Html.ValidationSummary()

    <div>
        @using (Html.BeginForm())
        {
            @Html.HiddenFor(x => x.Id)
            <table>
                <tr>
                    <td>名稱</td>
                    <td>@Html.TextBoxFor(x => x.Name)</td>
                </tr>
                <tr>
                    <td>價格</td>
                    <td>@Html.TextBoxFor(x => x.Price)</td>
                </tr>
                <tr>
                    <td>分類</td>
                    <td>@Html.TextBoxFor(x => x.Category)</td>
                </tr>
                <tr>
                    <td>描述</td>
                    <td>@Html.TextAreaFor(x => x.Description)</td>
                </tr>
            </table>
            <input type="submit" value="提交" />
        }
    </div>
</div>

圖:錯誤提示

 

  刪除

        /// <summary>
        /// 刪除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult Delete(int id)
        {
            _bookRepository.DeleteBook(id);
            return RedirectToAction("Index");
        }

 

  加入提示,我們在新增、編輯和刪除時應該加入必要的提示信息,使用 TempData。

 

  /Admin/Index.cshtml 下的也要添加:

 

  執行效果:

 

  【備註】TempData 臨時數據保存了一條信息,是一個“鍵/值”字典,類似會話 Session 和 ViewBag,它和 Session 的差別是,在 HTTP 請求結束後會被刪除。因為這裡使用了 RedirectToAction ,一條重定向指令,會告訴瀏覽器重定向請求到一個新地址,這時就不能使用 ViewBag,ViewBag 用於在控制器與視圖之間傳遞數據,但它保持數據的時間不能比當前的 HTTP 請求長,重定向意味著用戶是跨請求的,ViewBag 不能用於跨請求時傳遞數據。

 

登錄授權認證過濾

  上面是一個 Admin 的後臺管理操作,不是每一個用戶都能夠進入管理的,所以現在加入登錄授權認證功能,只有成功後,才能進入管理界面。

  先在配置文件 WebConfig.cs 中加入

<authentication mode="Forms">
      <forms loginUrl="~/Account/Login" timeout="2880">
        <credentials passwordFormat="Clear">
          <user name="admin" password="123"/>
        </credentials>
      </forms>
</authentication>
<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=301880
  -->
<configuration>
  <connectionStrings>
    <add name="EfDbContext" connectionString="server=.;database=TestDb;uid=sa;pwd=123" providerName="System.Data.SqlClient"/>
  </connectionStrings>

  <appSettings>
    <add key="webpages:Version" value="3.0.0.0"/>
    <add key="webpages:Enabled" value="false"/>
    <add key="ClientValidationEnabled" value="true"/>
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
    <add key="SendEmailName" value="[email protected]"/>
  </appSettings>
  <system.web>
    <authentication mode="Forms">
      <forms loginUrl="~/Account/Login" timeout="2880">
        <credentials passwordFormat="Clear">
          <user name="admin" password="123"/>
        </credentials>
      </forms>
    </authentication>
    <compilation debug="true" targetFramework="4.6.1"/>
    <httpRuntime targetFramework="4.6.1"/>
    <httpModules>
      <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web"/>
    </httpModules>
  </system.web>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs"
        type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701"/>
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
        type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"/>
    </compilers>
  </system.codedom>
  <system.webServer>

    <validation validateIntegratedModeConfiguration="false"/>
    <modules>
      <remove name="ApplicationInsightsWebTracking"/>
      <add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web"
        preCondition="managedHandler"/>
    </modules>
  </system.webServer>
</configuration>
WebConfig.cs

  

  在這裡使用的授權認證模式為表單認證,為了簡化與資料庫的交互操作,採取的是硬編碼的形式。如果尚未得到認證,會跳轉到 Account/Login 的地址讓管理員先進行登錄,timeout 表示登錄(即認證)成功的保持時長為 2880 分鐘(即 48 小時),而 name 表示的就是用戶名, password 表示的就是登錄密碼。  

 

  這裡採用的是授權認證過濾器,我們需要對要認證後才能進入的控制器添加一個特性[Authorize],即對 AdminController 添加該特性。

 

 

  新建表單認證提供器,一個介面和一個實現:

  IAuthProvider.cs:

    public interface IAuthProvider
    {
        /// <summary>
        /// 認證
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        bool Auth(string userName, string password);
    }

 

  FormsAuthProvider.cs:

    /// <summary>
    /// 表單認證提供者
    /// </summary>
    public class FormsAuthProvider:IAuthProvider
    {
        /// <summary>
        /// 認證
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public bool Auth(string userName, string password)
        {
            var result = FormsAuthentication.Authenticate(userName, password);

            if (result)
            {
                //設置認證 Cookie
                FormsAuthentication.SetAuthCookie(userName, false);
            }

            return result;
        }
    }

  

  AddBindings() 方法中註冊:

        /// <summary>
        /// 添加綁定
        /// </summary>
        private void AddBindings()
        {
            _kernel.Bind<IBookRepository>().To<EfBookRepository>();
            _kernel.Bind<IOrderProcessor>().To<EmailOrderProcessor>();
            _kernel.Bind<IAuthProvider>().To<FormsAuthProvider>();
        }

 

    /// <summary>
    /// 登錄視圖模型
    /// </summary>
    public class LoginViewModel
    {
        [Required(ErrorMessage = "用戶名不能為空")]
        public string UserName { get; set; }

        [Required(ErrorMessage = "密碼不能為空")]
        [DataType(DataType.Password)]
        public string Password { get; set; }
    }

 

  新建 AccountController

 

    public class AccountController : Controller
    {
        private readonly IAuthProvider _authProvider;

        public AccountController(IAuthProvider authProvider)
        {
            _authProvider = authProvider;
        }

        /// <summary>
        /// 登錄
        /// </summary>
        /// <returns></returns>
        public ActionResult Login()
        {
            return View();
        }

        /// <summary>
        /// 登錄
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Login(LoginViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return View(new LoginViewModel());
            }

            var result = _authProvider.Auth(model.UserName, model.Password);
            if (result) return RedirectToAction("Index", "Admin");

            ModelState.AddModelError("", "賬號或用戶名有誤");
            return View(new LoginViewModel());
        }
    }

 

  Login.cshtml 登錄頁面:

@model Wen.BooksStore.WebUI.Models.LoginViewModel
@{
    Layout = null;
}

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登錄</title>
    @*<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">*@
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
    @*<link href="~/Contents/Login/css/htmleaf-demo.css" rel="stylesheet" />*@
    <style type="text/css">
        @@import url(https://fonts.googleapis.com/css?family=Roboto:300);

        .login-page {
            margin: auto;
            padding: 8% 0 0;
            width: 360px;
        }

        .form {
            background: #FFFFFF;
            box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24);
            margin: 0 auto 100px;
            max-width: 360px;
            padding: 45px;
            position: relative;
            text-align: center;
            z-index: 1;
        }

        .form input {
            background: #f2f2f2;
            border: 0;
            box-sizing: border-box;
            font-family: "Roboto", sans-serif;
            font-size: 14px;
            margin: 0 0 15px;
            outline: 0;
            padding: 15px;
            width: 100%;
        }

        .form button {
            -webkit-transition: all 0.3 ease;
            background: #4CAF50;
            border: 0;
            color: #FFFFFF;
            cursor: pointer;
            font-family: "Microsoft YaHei", "Roboto", sans-serif;
            font-size: 14px;
            outline: 0;
            padding: 15px;
            text-transform: uppercase;
            transition: all 0.3 ease;
            width: 100%;
        }

        .form button:hover, .form button:active, .form button:focus { background: #43A047; }

        .form .message {
            color: #b3b3b3;
            font-size: 12px;
            margin: 15px 0 0;
        }

        .form .message a {
            color: #4CAF50;
            text-decoration: none;
        }

        .form .register-form { display: none; }

        .container {
            margin: 0 auto;
            max-width: 300px;
            position: relative;
            z-index: 1;
        }

        .container:before, .container:after {
            clear: both;
            content: "";
            display: block;
        }

        .container .info {
            margin: 50px auto;
            text-align: center;
        }

        .container .info h1 {
            color: #1a1a1a;
            font-size: 36px;
            font-weight: 300;
            margin: 0 0 15px;
            padding: 0;
        }

        .container .info span {
            color: #4d4d4d;
            font-size: 12px;
        }

        .container .info span a {
            color: #000000;
            text-decoration: none;
        }

        .container .info span .fa { color: #EF3B3A; }

        body {
            -moz-osx-font-smoothing: grayscale;
            -webkit-font-smoothing: antialiased;
            background: #76b852; /* fallback for old browsers */
            background: -webkit-linear-gradient(right, #76b852, #8DC26F);
            background: -moz-linear-gradient(right, #76b852, #8DC26F);
            background: -o-linear-gradient(right, #76b852, #8DC26F);
            background: linear-gradient(to left, #76b852, #8DC26F);
            font-family: "Roboto", sans-serif;
        }
    </style>
    <!--[if IE]>
        <script src="http://cdn.bootcss.com/html5shiv/3.7.3/html5shiv.min.js"></script>
    <![endif]-->
    <script src="~/Scripts/jquery-1.10.2.js
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • http://www.pwnable.kr/ 逆向題目,upx脫殼: 找到flag: ...
  • CSRF(Cross-site request forgery)跨站請求偽造,也被稱為“One Click Attack”或者Session Riding,通常縮寫為CSRF或者XSRF,是一種對網站的惡意利用 一般被攻擊步驟: 1.登錄受信任網站A,併在本地生成Cookie。 2.在不登出A的情況 ...
  • 使用C#調用mingw的so文件,拿視頻數據回wpf的界面進行顯示,註冊了回調函數。C++在調用回調函數時遇到了委托被回收的問題,提示:“類型的已垃圾回收委托進行了回調。這可能會導致應用程式崩潰、損壞和數據丟失。向非托管代碼傳遞委托時,托管應用程式必須讓這些委托保持活動狀態,直到確信不會再次調用它們 ...
  • 本文主要介紹如何使用LightningChart擴展拖放功能為所有圖表組件創建圖表,如:系列,標題,軸線等等。支持用滑鼠放置自定義對象到另一個圖表中,如:可以添加或修改JSON/CSV或其他格式的數據。 開發人員也可以使用ChartManager工具來協調多個LightningChart控制項。 支持 ...
  • 1.服務端開發(包含寄宿) 1.1 WCF服務創建方式 創建一個WCF服務,總是會創建一個服務介面和一個服務介面實現。通常根據服務宿主的不同,有兩種創建方式。 (1)創建WCF應用程式 通過創建WCF服務應用程式,可生成一個帶.svc尾碼名的文件。該文件與webform中的aspx文件類似,有後置代 ...
  • 本文通過一個完整的實例,講解如何通過訪問中國天氣網提供的API介面,實現天氣預報功能。 實現天氣預報功能的相關知識點: 天氣預報介面【提供風向,風速等功能】:http://www.weather.com.cn/data/sk/101120201.html 天氣預報介面【提供天氣基礎功能】:http: ...
  • 我這裡集成好了一個自帶IK的版本,下載即用, https://github.com/xlb378917466/elasticsearch5.2.include_IK 添加了IK插件意味著你可以使用ik_smart(最粗粒度的拆分)和ik_max_word(最細粒度的拆分)兩種analyzer。 你也 ...
  • Epplus操作Excel基礎詳解 1.什麼是Epplus Epplus是一個使用Open Office XML文件格式,能讀寫Excel2007/2010文件的開源組件,在導出Excel的時候不需要電腦上安裝office。 其中,Open Office XML文檔格式包括我們常見的xlsx、doc ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...