--- tags : .NET --- <style> .red{ background-color:#fff1f0; border-color:#ffa39e; color:#cf1322; padding:4px; font-size:1.75rem; } .blue{ background-color:#e6f7ff; border-color:#91d5ff; color:#096dd9; padding:4px; width:150px; text-align:center; } .green{ background-color:#f6ffed; border-color:#b7eb8f; color:#389e0d; padding:4px; width:150px; text-align:center; } .yellow{ background-color:#fffbe6; border-color:#ffe58f; color:#d48806; padding:4px; width:150px; text-align:center; } .orange{ background-color:#fffbe6; border-color:#ffd591; color:#d46b08; padding:4px; width:150px; text-align:center; } </style> # 10. 專案部屬 ## 10-1 角色權限設定 在專案部屬之前,要先確認角色權限看到的頁面是否正常,以避免一般使用者更動系統的設定。 接下來要將店家操作的功能,讓一般使用者無法看到該頁面。 1. 開啟AspDotNetDemo/Admin/Controllers/CategoryController.cs,新增部分程式碼 ```C#= using AspDotNetDemo.DataAccess; using AspDotNetDemo.DataAccess.Repository.IRepository; using AspDotNetDemo.Models; using AspDotNetDemo.Utility; //本次新增部分 using Microsoft.AspNetCore.Authorization; //本次新增部分 using Microsoft.AspNetCore.Mvc; namespace AspDotNetDemo.Areas.Admin.Controllers { [Area("Admin")] [Authorize(Roles = SD.Role_Admin)] //本次新增部分 public class CategoryController : Controller { . .[省略] . } } ``` ```Authorize```跟```SD```會出現錯誤提示,將滑鼠移至紅底線部分,出現燈泡後點選 `using AspDotNetDemo.Utility; using Microsoft.AspNetCore.Authorization;` 這兩個套件即可解決。 接著對CompanyController.cs跟ProductController.cs,做同樣的操作,同樣加上```[Authorize(Roles = SD.Role_Admin)]```並引入套件即可。 * 在訂單管理的部分,因為我們有針對角色權限去控制不同功能,因此在這邊不需要針對訂單 Controllor 去做角色控制。 現在要將下拉式選單調整為只有店家管理者可以看到。 2. 開啟AspDotNetDemo/Views/Shared/_Layout.cshtml,找到程式碼下拉式選單的部分,並修改程式碼 ```html= @if (User.IsInRole(SD.Role_Admin)) { <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">內容管理</a> <div class="dropdown-menu"> <a class="dropdown-item" asp-area="Admin" asp-controller="Category" asp-action="Index">類別</a> <a class="dropdown-item" asp-area="Admin" asp-controller="Product" asp-action="Index">產品</a> <div class="dropdown-divider"></div> <a class="dropdown-item" asp-area="Admin" asp-controller="Company" asp-action="Index">公司</a> </div> </li> } ``` 這邊如果要記得在最上方加上`@using AspDotNetDemo.Utility` 才不會有底線錯誤,也可以使用點擊燈泡的方式引入。 完成之後就會發現如果登入的帳號權限不為 Admin 的話,下拉式選單就不會出現。 ## 10-2 Session Session 是 ASP.NET 的核心方案,用於在用戶瀏覽網站時儲存用戶資料。Session 狀態使用一個由應用程式維護的儲存,再來自客戶端得請求中維持資料。Session 可以幫我們把資料存在Server記憶體,方便我們下次請求使用。比較重要的網站資訊應該儲存在用戶的數據庫中,並且只會在Session中,作為一種性能優化。 開啟AspDotNetDemo/Program.cs,新增部分程式碼 ```C#= . .[省略] . builder.Services.ConfigureApplicationCookie(options => { options.LoginPath = $"/Identity/Account/Login"; options.LogoutPath = $"/Identity/Account/Logout"; options.AccessDeniedPath = $"/Identity/Account/AccessDenied"; }); // 本次新增部分 builder.Services.AddDistributedMemoryCache(); builder.Services.AddSession(option => { option.IdleTimeout = TimeSpan.FromSeconds(100); option.Cookie.HttpOnly = true; option.Cookie.IsEssential = true; }); . .[省略] . app.UseAuthorization(); // 本次新增部分 app.UseSession(); . .[省略] . ``` 開啟AspDotNetDemo.Utility/SD.cs,新增下方程式碼 ```C#= public const string SessionCart = "SessionShoppingCart"; ``` 開啟AspDotNetDemo/Areas/Customer/Controllers/HomeController.cs,修改程式碼 ```C#= [HttpPost] [ValidateAntiForgeryToken] [Authorize] public IActionResult Details(ShoppingCart shoppingCart) { . . .[省略] if (cartFromDb == null) { // 本次修改部分 _unitOfWork.ShoppingCart.Add(shoppingCart); _unitOfWork.Save(); HttpContext.Session.SetInt32(SD.SessionCart, _unitOfWork.ShoppingCart.GetAll(u => u.ApplicationUserId == claim.Value).ToList().Count()); } else { // 本次修改部分 _unitOfWork.ShoppingCart.UpdateIceAndSweetness(shoppingCart); _unitOfWork.Save(); _unitOfWork.ShoppingCart.IncrementCount(cartFromDb, shoppingCart.Count); } return RedirectToAction(nameof(Index)); } ``` 開啟AspDotNetDemo/Views/Shared/_Layout.cshtml,修改購物車Icon的部分 ```html= // 本次新增部分 @using Microsoft.AspNetCore.Http @using AspDotNetDemo.Utility @inject IHttpContextAccessor HttpContextAccessor . .[省略] . <li class="nav-item"> <a class="nav-link" asp-area="Admin" asp-controller="Order" asp-action="Index"> 訂單管理 </a> </li> <!-- 本次修改部分--> @if (HttpContextAccessor.HttpContext.Session.GetInt32(SD.SessionCart) != null) { <li class="nav-item"> <a class="nav-link" asp-area="Customer" asp-controller="Cart" asp-action="Index"> <span class="d-flex align-items-center"><i class="bi bi-cart"></i><p class="mb-0 ms-1">購物車 &nbsp; (@HttpContextAccessor.HttpContext.Session.GetInt32(SD.SessionCart))</p></span> </a> </li> } else { <li class="nav-item"> <a class="nav-link" asp-area="Customer" asp-controller="Cart" asp-action="Index"> <span class="d-flex align-items-center"><i class="bi bi-cart"></i><p class="mb-0 ms-1">購物車 &nbsp; (0)</p></span> <!--0307修改--> </a> </li> } . .[省略] . ``` 開啟AspDotNetDemo/Areas/Customer/Controllers/CartController.cs,修改程式碼 ```C#= . .[省略] . [HttpPost] [ActionName("Summary")] [ValidateAntiForgeryToken] public IActionResult SummaryPOST() { . .[省略] . // 本次新增部分 HttpContext.Session.Clear(); _unitOfWork.ShoppingCart.RemoveRange(ShoppingCartVM.ListCart); _unitOfWork.Save(); return RedirectToAction("Index", "Home"); } . .[省略] . public IActionResult Minus(int cartId) { var cart = _unitOfWork.ShoppingCart.GetFirstOrDefault(u => u.Id == cartId); if (cart.Count <= 1) { _unitOfWork.ShoppingCart.Remove(cart); //本次新增部分 var count = _unitOfWork.ShoppingCart.GetAll(u => u.ApplicationUserId == cart.ApplicationUserId).ToList().Count - 1; HttpContext.Session.SetInt32(SD.SessionCart, count); } else { _unitOfWork.ShoppingCart.DecrementCount(cart, 1); } _unitOfWork.Save(); return RedirectToAction(nameof(Index)); } public IActionResult Remove(int cartId) { var cart = _unitOfWork.ShoppingCart.GetFirstOrDefault(u => u.Id == cartId); _unitOfWork.ShoppingCart.Remove(cart); _unitOfWork.Save(); //本次新增部分 var count = _unitOfWork.ShoppingCart.GetAll(u => u.ApplicationUserId == cart.ApplicationUserId).ToList().Count; HttpContext.Session.SetInt32(SD.SessionCart, count); return RedirectToAction(nameof(Index)); } ``` 完成之後就可以看到新增產品進購物車時,會出現有幾項身品在購物車內囉。 ## 10-3 Component 但會發現使用者在剛登入時,即便購物車內有東西,但還是會顯示0。 對AspDotNetDemo點擊滑鼠右鍵 -> 加入 -> 新增資料夾,命名為ViewComponents 對剛建立好的ViewComponents資料夾點擊滑鼠右鍵 -> 加入 -> 類別,命名為ShoppingCartViewComponent後建立 ![](https://i.imgur.com/5QqZXgz.png) 將剛建立好的ShoppingCartViewComponent.cs修改為下方程式碼。 ```C#= using AspDotNetDemo.DataAccess.Repository.IRepository; using AspDotNetDemo.Utility; using Microsoft.AspNetCore.Mvc; using System.Security.Claims; namespace AspDotNetDemo.ViewComponents { public class ShoppingCartViewComponent : ViewComponent { private readonly IUnitOfWork _unitOfWork; public ShoppingCartViewComponent(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; } public async Task<IViewComponentResult> InvokeAsync() { var claimsIdentity = (ClaimsIdentity)User.Identity; var claim = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier); if (claim != null) { if (HttpContext.Session.GetInt32(SD.SessionCart) != null) { return View(HttpContext.Session.GetInt32(SD.SessionCart)); } else { HttpContext.Session.SetInt32(SD.SessionCart, _unitOfWork.ShoppingCart.GetAll(u => u.ApplicationUserId == claim.Value).ToList().Count); return View(HttpContext.Session.GetInt32(SD.SessionCart)); } } else { HttpContext.Session.Clear(); return View(0); } } } } ``` AspDotNetDemo/Views/Shared點擊滑鼠右鍵 -> 加入 -> 新增資料夾,命名為Components 對剛建立好的Components資料夾點擊滑鼠右鍵 -> 加入 -> 新增資料夾,命名為ShoppingCart 對剛建立好的ShoppingCart資料夾點擊滑鼠右鍵 -> 加入 -> 檢視 -> 選擇Razor 檢視 - 空白 -> 加入,命名為Default.cshtml後點選新增 ![](https://i.imgur.com/d0FQTZD.png) 將剛建立好的Default.cshtml,修改為下方程式碼。 ```html= @model int <span class="d-flex align-items-center"><i class="bi bi-cart"></i><p class="mb-0 ms-1">購物車 &nbsp; (@Model)</p></span> ``` 接著開啟AspDotNetDemo/Views/Shared/_Layout.cshtml,修改購物車部分的程式碼,將原先的 if-else 判斷式改為用 Component 顯示數量。 ```html= . .[省略] . <li class="nav-item"> <a class="nav-link" asp-area="Admin" asp-controller="Order" asp-action="Index"> 訂單管理 </a> </li> <!-- 本次修改部分--> <li class="nav-item"> <a class="nav-link" asp-area="Customer" asp-controller="Cart" asp-action="Index"> @await Component.InvokeAsync("ShoppingCart") </a> </li> ``` 完成後就會發現使用者在剛登入時也可以顯示購物車內的產品數量了。 ## 10-4 修改註冊功能 到了這階段,使用者在註冊時還是可以選擇公司、管理員、顧客等角色,如果有人選擇了管理員角色,那對我們的網站並不是一件好事。因此,接下來我們要修改我們的註冊程式碼。 開啟AspDotNetDemo/Areas/Identity/Pages/Account/Register.cshtml,修改程式碼。 ```html= @page @using AspDotNetDemo.Utility @model RegisterModel @{ ViewData["Title"] = "Register"; } <!-- 本次修改部分--> @if (User.IsInRole(SD.Role_Admin)) { <h1 class="pt-4">註冊管理者帳號</h1> } else { <h1 class="pt-4">@ViewData["Title"]</h1> } <div class="row pt-4"> <div class="col-md-7 row"> <form id="registerForm" class="row" asp-route-returnUrl="@Model.ReturnUrl" method="post"> . .[省略] . <!-- 本次修改部分--> @if (User.IsInRole(SD.Role_Admin)) { <div class="form-floating py-2 col-6"> <select asp-for="Input.Role" asp-items="@Model.Input.RoleList" class="form-select"> <option disabled selected>-Select Role-</option> </select> </div> <div class="form-floating py-2 col-6"> <select asp-for="Input.CompanyId" style="display:none;" asp-items="@Model.Input.CompanyList" class="form-select"> <option disabled selected>-Select Company-</option> </select> </div> } <button id="registerSubmit" type="submit" class="w-100 btn btn-primary">Register</button> </form> </div> <!-- 本次修改部分--> @if (!User.IsInRole(SD.Role_Admin)) { <div class="col-md-5"> <section> . .[省略] . </section> </div> } </div> ``` 在下拉式選單新增選項,讓管理者可以新增其他使用者 開啟AspDotNetDemo/Views/Shared/_Layout.cshtml,修改部分程式碼 ```html= @if (User.IsInRole(SD.Role_Admin)) { <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">內容管理</a> <div class="dropdown-menu"> <a class="dropdown-item" asp-area="Admin" asp-controller="Category" asp-action="Index">類別</a> <a class="dropdown-item" asp-area="Admin" asp-controller="Product" asp-action="Index">產品</a> <div class="dropdown-divider"></div> <a class="dropdown-item" asp-area="Admin" asp-controller="Company" asp-action="Index">公司</a> <!-- 本次修改部分--> <div class="dropdown-divider"></div> <a class="dropdown-item" asp-area="Identity" asp-page="/Account/Register">建立使用者</a> </div> </li> } ``` 開啟AspDotNetDemo/Areas/Identity/Pages/Account/Register.cshtmlRegister.cshtml.cs,修改部分程式碼 使用 Ctrl + F 尋找 ```_userManager.Options.SignIn.RequireConfirmedAccount``` ```C#= if (_userManager.Options.SignIn.RequireConfirmedAccount) { return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl }); } else { // 本次新增部分 if (User.IsInRole(SD.Role_Admin)) { TempData["Success"] = "建立新使用者成功!"; } else { await _signInManager.SignInAsync(user, isPersistent: false); } return LocalRedirect(returnUrl); } ``` 這邊的目的為讓管理者在新增其他使用者後,不會以該使用者帳號登入及跳轉頁面。 ## 10-5 資料庫初始化 DBInitializer interface 在發佈網站時,資料庫裡面不會存在任何角色,所以也就不會有管理員的角色出現。在這個章節中,我們有三件事情要完成。首先,如果未使用 migration,我們將使用migration。其次,如果沒有創建角色,我們將創建角色。最後,如果沒有創建角色,那麼我們也將創建管理員用戶。 1. 打開AspDotNetDemo/Areas/Identity/Pages/Account/Register.cshtml/Register.cshtml.cs,接著找到 OnGetAsync 的 Function,並註解下方程式碼。 ```C#= public async Task OnGetAsync(string returnUrl = null) { //if (!_roleManager.RoleExistsAsync(SD.Role_Admin).GetAwaiter().GetResult()) //{ // _roleManager.CreateAsync(new IdentityRole(SD.Role_Admin)).GetAwaiter().GetResult(); // _roleManager.CreateAsync(new IdentityRole(SD.Role_Employee)).GetAwaiter().GetResult(); // _roleManager.CreateAsync(new IdentityRole(SD.Role_User_Cust)).GetAwaiter().GetResult(); // _roleManager.CreateAsync(new IdentityRole(SD.Role_User_Comp)).GetAwaiter().GetResult(); //} . .[省略] . } ``` 2. 實作介面。對AspDotNetDemo.DataAccess 點擊滑鼠右鍵 -> 加入 -> 新增資料夾,命名為DbInitializer。 3. 接著對 DbInitializer 點擊滑鼠右鍵 -> 加入 -> 類別 -> 介面,命名為IDbInitializer.cs,並修改為以下程式碼。 ```C#= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AspDotNetDemo.DataAccess.DbInitializer { public interface IDbInitializer { void Initialize(); } } ``` 4. 接著對 DbInitializer 點擊滑鼠右鍵 -> 加入 -> 新增項目 -> 類別,命名為DbInitializer.cs。 ```C#= using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AspDotNetDemo.DataAccess.DbInitializer { public class DbInitializer : IDbInitializer { public void Initialize() { // migrations if they are not applied // create roles if they are not created // if roles are not created,then we well create admin user as well } } } ``` * 可以直接對 IDbInitializer 點擊燈泡 -> 實作介面 5. 接下來我們想要管理角色和創建用戶。因此,我們將通過依賴注入的方式將一些內置的輔助模型做使用。我們想要 UserManager 和 RoleManager 以及 ApplicationDbContext 來跟資料庫做連線,修改 DbInitializer.cs 程式碼。 ```C#= using AspDotNetDemo.Models; using AspDotNetDemo.Utility; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AspDotNetDemo.DataAccess.DbInitializer { public class DbInitializer : IDbInitializer { private readonly UserManager<IdentityUser> _userManager; private readonly RoleManager<IdentityRole> _roleManager; private readonly ApplicationDbContext _db; public DbInitializer( UserManager<IdentityUser> userManager, RoleManager<IdentityRole> roleManager, ApplicationDbContext db) { _roleManager = roleManager; _userManager = userManager; _db = db; } public void Initialize() { // migrations if they are not applied try { if(_db.Database.GetPendingMigrations().Count()>0) { _db.Database.Migrate(); } }catch (Exception ex) { } // create roles if they are not created if (!_roleManager.RoleExistsAsync(SD.Role_Admin).GetAwaiter().GetResult()) { _roleManager.CreateAsync(new IdentityRole(SD.Role_Admin)).GetAwaiter().GetResult(); _roleManager.CreateAsync(new IdentityRole(SD.Role_Employee)).GetAwaiter().GetResult(); _roleManager.CreateAsync(new IdentityRole(SD.Role_User_Cust)).GetAwaiter().GetResult(); _roleManager.CreateAsync(new IdentityRole(SD.Role_User_Comp)).GetAwaiter().GetResult(); // if roles are not created,then we well create admin user as well _userManager.CreateAsync(new ApplicationUser { UserName = "admin@gmail.com", Email = "admin@gmail.com", Name = "Administrator", PhoneNumber = "0911111111", StreetAddress = "test address 123", State = "IL", PostalCode = "408", City = "Taichung", }, ".Admin123").GetAwaiter().GetResult(); ApplicationUser user = _db.ApplicationUsers.FirstOrDefault(u => u.Email == "admin@gmail.com"); _userManager.AddToRoleAsync(user, SD.Role_Admin).GetAwaiter().GetResult(); } return; } } } ``` 6. 在 Program.cs 中,引入 seedDatabase。打開 Program.cs,新增以下程式碼 ```C#= . .[省略] . builder.Services.AddScoped<IUnitOfWork, UnitOfWork>(); builder.Services.AddScoped<IDbInitializer, DbInitializer>(); //本次新增程式碼 . .[省略] . app.UseRouting(); SeedDatabase(); //本次新增程式碼 . .[省略] . app.Run(); //本次新增程式碼 void SeedDatabase() { using (var scope = app.Services.CreateScope()) { var dbInitializer = scope.ServiceProvider.GetRequiredService<DbInitializer>(); dbInitializer.Initialize(); } } ``` 做完上述操作後,在部屬網站時,就會先幫我們檢查我們的資料庫,是否有還沒有被Migrations 的資料,之後也會幫我們建立起我們的管理員用戶,因此,我們就完成我們在部屬之前的準備了。 7. 修改資料庫名稱。打開 appsettings.json,並修改資料庫的名稱 ```C#= { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "ConnectionStrings": { "DefaultConnection": "Server=DESKTOP-DOBPPDJ\\SQLEXPRESS;Database=Demo1;Trusted_Connection=True;", "ApplicationDbContextConnection": "Server=(localdb)\\mssqllocaldb;Database=AspDotNetDemo;Trusted_Connection=True;MultipleActiveResultSets=true" } } ``` * 這邊的 Demo1 在word的時候要幫我用紅框框起來。 接著我們啟動我們的專案,即使我們沒有使用`update-database`這個指令,但是可以發現到我們的資料庫新增了我們修改的 Demo1,我們在建立專案需要用到的資料表跟 admin 帳戶也一併幫我們產生了。 ![](https://i.imgur.com/wqsKPU3.png) ## 10-6 建立 Azure SQL Server 最後的任務是部署我們的網站。為了完成這個目標,我們必須先在Azure創建一個帳戶。 接著進入https://portal.azure.com/#home網站後登入我們的帳號,如果是第一次註冊會有200美元的免費額度。 ![](https://i.imgur.com/fWTNbcZ.png) 1. 首先我們要做的就是建立我們的 SQL Server 以及 Database。 在搜尋資源中,輸入 SQL 資料庫 -> 並按下建立。 ![](https://i.imgur.com/unmeLY1.png) 創建新的資源群組 ![](https://i.imgur.com/HoaFgik.png) 建立新的 server ![](https://i.imgur.com/62B1qah.png) ![](https://i.imgur.com/hYf1NS5.png) 上方完成後會變這樣 ![](https://i.imgur.com/leN3CVh.png) 接下來點選設定資料庫,要選擇容量及額度,這邊選擇基本就好。 ![](https://i.imgur.com/MTTb2uo.png) 接著就可以按下 檢閱+建立 的按鈕 -> 建立,等待部屬完成就建立好了。 ![](https://i.imgur.com/jg9yzaJ.png) 2. 再來點擊前往資源 -> 設定伺服器防火牆 ![](https://i.imgur.com/7iQw4R3.png) 3. 在公用選取中,點擊選取的網路 -> 防火牆規則底下 -> 點擊新增您的用戶端,之後就可以點擊儲存。 ![](https://i.imgur.com/tW8kpAC.png) 4. 接著回到資源中,找到連接字串 ![](https://i.imgur.com/4TJZ0m2.png) ![](https://i.imgur.com/1GxcIHv.png) ![](https://i.imgur.com/shyteK6.png) ## 10-7 部屬網站到 Azure 服務 1. 回到 Visual Studio 中,對 AspDotNetDemo 點擊右鍵 -> 發佈 -> Azure -> 下一步 -> App Service (Windows) -> 下一步 ![](https://i.imgur.com/bSEQbOS.png) 登入我們的 Azure 帳戶,加入我們的資源群組。 ![](https://i.imgur.com/TQGowOG.png) 對主控方案點選新增,選擇免費的大小,因為我們不想立即付費訂閱,接著點選建立。 ![](https://i.imgur.com/73ZrRLV.png) ![](https://i.imgur.com/az8GFUi.png) 完成後就可以點選完成按鈕了。 ![](https://i.imgur.com/C16nj52.png) 之後點選網站那個連結,可以看到服務正在啟動跟運行。 ![](https://i.imgur.com/MFFxSjd.png) 接著我們對部屬模式點選編輯,將部屬模式改為獨立式,打開資料庫的按鈕貼上我們在Azure 的連線字串。 ![](https://i.imgur.com/hYoYhGB.png) 修改完成後就可以點選儲存了。 2. 修該連線字串 打開 appsettings.json 檔案,複製我們Azure的連線字串,並貼在DefaultConnection中,記得將密碼修改為我們的密碼。 ```C#= { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "ConnectionStrings": { //"DefaultConnection": "Server=DESKTOP-DOBPPDJ\\SQLEXPRESS;Database=Demo1;Trusted_Connection=True;", "DefaultConnection": "Server=tcp:aspdotnetdemoserver.database.windows.net,1433;Initial Catalog=AspDotNetDemo_db;Persist Security Info=False;User ID=aspdotnetdemo;Password=admin123*;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;", "ApplicationDbContextConnection": "Server=(localdb)\\mssqllocaldb;Database=AspDotNetDemo;Trusted_Connection=True;MultipleActiveResultSets=true" } } ``` 再來點選上方的發佈按鈕。 ![](https://i.imgur.com/bRbhcuZ.png) 3. 接著回到我們的 azure 首頁,點選應用程式服務。 ![](https://i.imgur.com/8XcM1bx.png) 選擇我們的服務 ![](https://i.imgur.com/Qn45Fkg.png) 找到屬性,複製輸出IP位置。 ![](https://i.imgur.com/w8DYZ4U.png) 可以先貼在記事本上。 ![](https://i.imgur.com/ledtcNY.png) 4. 新增 ip 到Azure SQL Server 我們可以觀察到 20.119.109 出現很多次,因此,我們將這組IP加進我們的防火牆規則裡面,如下圖所示。 ![](https://i.imgur.com/hIH3ZAD.png) 確保已經在這邊保存了所有的IP。 ![](https://i.imgur.com/z8XxD3Z.png) 接著點選上方的發佈按鈕。 ![](https://i.imgur.com/bRbhcuZ.png) 可以看到我們的網站已經順利發佈到Azure的網站上了。 ![](https://i.imgur.com/643gnT0.png)