NCF 的Azure Cosmos DB 演示案例

2022-06-20 12:04:16

簡介

NCF想必看過我之前發的NCF的文章的同學們都已經很熟悉了

今天我們要來聊一聊的是NCF遇到Azure Cosmos DB後會碰撞出什麼樣的火花,讓我們一起往下看

我們先來說說什麼是Azure Cosmos DB

 

 Azure Cosmos DB 是一個完全託管的無伺服器 NoSQL 資料庫,適用於任何大小或規模的高效能應用程式。獲得保證的單位數毫秒效能和 99.999% 的可用性,由 SLA 提供支援自動和即時可伸縮性,適用於 NoSQL 資料庫(包括 MongoDB 和 Cassandra)的企業級安全性和開源 API。使用多區域寫入和資料複製,在全球任何位置享受快速寫入和讀取功能。使用適用於 Azure Cosmos DB 的 Azure Synapse Link,通過無 ETL (提取、轉換、載入)分析獲取實時資料的見解。

 

 主要優勢

保證任何規模的速度(獲得無與倫比的 SLA 支援的速度和吞吐量、快速的全域性存取和即時彈性)

簡化應用程式的開發(使用開源 API、多個 SDK、無架構資料和對運算元據的無 ETL 分析進行快速構建。)

關鍵任務就緒(保證每個應用程式的業務連續性、99.999% 的可用性和企業級安全性。)

完全託管和經濟高效(端到端資料庫管理,具有與應用程式和 TCO 需求相匹配的無伺服器和自動縮放功能)

步驟

  • 下載NCF原始碼
  • 開啟Visual Studio,切換分支到master
  • 修改資料庫設定
  • 執行NCF
  • 安裝Xncf模組生成器
  • 生成Azure Cosmos DB的Xncf模組
  • 安裝Azure Cosmos DB的Xncf模組
  • 在Azure Cosmos DB模組中引入ML.Blend
  • 建立管理Cosmos DB的介面
  • 編寫管理Cosmos DB的方法
  • 處理頁面上的資料展示方式
  • 對比Cosmos DB Emulator的資料
  • 自由發揮

實施

  • 下載NCF原始碼

下載地址:https://github.com/NeuCharFramework/NCF (歡迎大家Star)

分支:master

  • 開啟Visual Studio,切換分支到master

 

 

 

  • 修改資料庫設定

開啟資料庫組態檔

 

 修改Sql-Server節點的內容,如下所示

 

 修改這三個位置即可

  • 執行NCF

 

 

  • 安裝Xncf模組生成器

 

 點選黃色背景區域的後邊的按鈕安裝

 

 點選開啟模組生成器

  • 生成Azure Cosmos DB的Xncf模組

選擇生成XNCF,輸入對應的引數,即可生成模組,這裡以Azure Cosmos DB模組為例

  • 安裝Azure Cosmos DB的Xncf模組

 

 進入主頁的頁面如上圖所示。

  • 在Azure Cosmos DB模組中引入nuget包ML.Blend

 

 

 需要載入0.2.26的版本,裡面對Azure Cosmos DB的Core Api進行了優化,方便大家快速的完成應用

  • 建立管理Cosmos DB的介面

 

 

 建立一個管理的介面

 

 

 在Register.Area中增加一個選單的選項來進入CosmosDB的管理介面

  • 編寫管理Cosmos DB的方法
    • 建立頁面上的UI介面樣式
      @page
      @model ML.Xncf.CosmosDB.Areas.Admin.Pages.CosmosDB.ManageModel
      @{
          ViewData["Title"] = "Azure Cosmos DB Manage";
          Layout = "_Layout_Vue";
      }
      @*參考網址:https://element.eleme.cn/#/zh-CN/component/table*@
      @section HeaderContent{
      <style>
          .mb-10 {
              margin-bottom: 10px;
          }
      </style>
      }
      
      @section breadcrumbs {
      <el-breadcrumb-item>擴充套件模組</el-breadcrumb-item>
      <el-breadcrumb-item>Azure Cosmos DB</el-breadcrumb-item>
      <el-breadcrumb-item>管理</el-breadcrumb-item>
      }
      
      <div>
          <el-container class="mb-10">
              <el-row>
                  <el-button @@click="addItem()" type="primary">新增</el-button>
                  <el-button @@click="toggleSelection([cosmosData[0], cosmosData[1]])">選中前2行</el-button>
                  <el-button @@click="toggleSelection()">取消選擇</el-button>
              </el-row>
          </el-container>
          <el-container>
              <el-table tooltip-effect="dark"
                        ref="multipleTable"
                        :data="cosmosData.filter(data => !search ||
                  data.lastName.toLowerCase().includes(search.toLowerCase()))"
                        style="width: 100%"
                        @@selection-change="handleSelectionChange">
                  <el-table-column type="selection"
                                   show-overflow-tooltip="true"
                                   width="55">
                  </el-table-column>
                  <el-table-column label="Id"
                                   prop="id">
                  </el-table-column>
                  <el-table-column label="Key"
                                   prop="partitionKey">
                  </el-table-column>
                  <el-table-column label="LastName"
                                   prop="lastName">
                  </el-table-column>
                  <el-table-column align="right">
                      <template slot="header" slot-scope="scope">
                          <el-input v-model="search"
                                    size="mini"
                                    placeholder="輸入關鍵字搜尋" />
                      </template>
                      <template slot-scope="scope">
                          <el-button size="mini"
                                     @@click="handleEdit(scope.$index, scope.row)">Edit</el-button>
                          <el-button size="mini"
                                     type="danger"
                                     @@click="handleDelete(scope.$index, scope.row)">Delete</el-button>
                      </template>
                  </el-table-column>
              </el-table>
          </el-container>
      </div>

      以上程式碼內容完全可以參考Element UI中的元件部分,找到自己想使用的,直接使用就好了

    • 建立介面上的對應資料及按鈕需要呼叫的事件和方法
      @section scripts{
      <script>
          var app = new Vue({
              el: "#app",
              data() {
                  return {
                      moduleData: null,
                      uid: '',
                      search: '',
                      tableData: [],
                      cosmosData:[],
                      multipleSelection: []
                  }
              },
              computed: {
                  backgroundColor() {
                      let rgba = `rgba(${this.moduleData.colorDto.red},${this.moduleData.colorDto.green},${this.moduleData.colorDto.blue},1)`
                      return rgba;
                  }
              },
              mounted() {
                  this.getList();
              },
              methods: {
                  async getList(){
                      const res = await service.get('/Admin/CosmosDB/Manage?handler=List');
                      this.cosmosData = res.data.data;
                  },
                  async addItem(){
                      const res = await service.get('/Admin/CosmosDB/Manage?handler=Add');
                      this.getList();
                  },
                  async handleEdit(index, row) {
                    console.log(index, row);
                    const res = await service.get('/Admin/CosmosDB/Manage?handler=Edit&id=' + row.id + '&key=' + row.partitionKey);
                    this.getList();
                  },
                  async handleDelete(index, row) {
                    console.log(index, row);
                    const res = await service.get('/Admin/CosmosDB/Manage?handler=Delete&id=' + row.id + '&key=' + row.partitionKey);
                    this.getList();
                 },
                 toggleSelection(rows) {
              if (rows) {
                rows.forEach(row => {
                  this.$refs.multipleTable.toggleRowSelection(row);
                });
              } else {
                this.$refs.multipleTable.clearSelection();
              }
            },
            handleSelectionChange(val) {
              this.multipleSelection = val;
            }
              }
          });
      </script>
      }

      這是上一步中UI介面上對應的按鈕,Table元件需要呼叫的資料請求及按鈕觸發的方法

    • 建立CosmosDBService來處理增刪改查的業務

       

       在Domain/Services下建立業務類CosmosDBService

      public class CosmosDBService
          {
              private string strEndpointUrl = "https://localhost:8081";
              private string strPrimaryKey = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
              private string strApplicationName = "CosmosDBDotnetQuickstart";
              private string DatabaseName = "db01";
              private string ContainerName = "c01";
      
              public CosmosDBService()
              {
              }
      
              public async Task<List<Family>> GetList()
              {
                  CoreApi coreApi = new CoreApi(strEndpointUrl, strPrimaryKey, strApplicationName);
                  await coreApi.CreateDatabaseIfNotExistsAsync("TODOList01");
                  await coreApi.CreateContainerAsync(ContainerName);
                  await coreApi.ScaleContainerAsync();
                  await coreApi.AddItemsToContainerAsync();
                  var sqlQueryText = "SELECT * FROM c WHERE 1=1 ";
                  var result = await coreApi.QueryItemsAsync<Family>(sqlQueryText);
                  return result;
              }
      
              public async Task AddItem()
              {
                  CoreApi coreApi = new CoreApi(strEndpointUrl, strPrimaryKey, strApplicationName);
                  await coreApi.CreateDatabaseIfNotExistsAsync("TODOList01");
                  await coreApi.CreateContainerAsync(ContainerName);
                  await coreApi.ScaleContainerAsync();
                  string strName = "MartyZane";
                  Family andersenFamily = new Family
                  {
                      Id = $"{strName}{DateTime.Now.ToString("yyyyMMddHHmmssfff")}",
                      PartitionKey = $"{strName}{DateTime.Now.ToString("yyyyMMddHHmmssfff")}",
                      LastName = $"{strName}{DateTime.Now.ToString("yyyyMMddHHmmssfff")}",
                      Parents = new Parent[]
                      {
                          new Parent { FirstName = "Thomas" },
                          new Parent { FirstName = "Mary Kay" }
                      },
                      Children = new Child[]
                      {
                          new Child
                          {
                              FirstName = "Henriette Thaulow",
                              Gender = "female",
                              Grade = 5,
                              Pets = new Pet[]
                              {
                                  new Pet { GivenName = "Fluffy" }
                              }
                          }
                      },
                      Address = new Address { State = "WA", County = "King", City = "Seattle" },
                      IsRegistered = false
                  };
                  await coreApi.AddItemsToContainerAsync<Family>(andersenFamily, andersenFamily.Id, andersenFamily.PartitionKey);
              }
      
              public async Task UpdateItem(string id, string key)
              {
                  CoreApi coreApi = new CoreApi(strEndpointUrl, strPrimaryKey, strApplicationName);
                  await coreApi.CreateDatabaseIfNotExistsAsync("TODOList01");
                  await coreApi.CreateContainerAsync(ContainerName);
                  await coreApi.ScaleContainerAsync();
                  await coreApi.ReplaceFamilyItemAsync(id,key);
              }
      
              public async Task DeleteItem(string id,string key)
              {
                  CoreApi coreApi = new CoreApi(strEndpointUrl, strPrimaryKey, strApplicationName);
                  await coreApi.CreateDatabaseIfNotExistsAsync("TODOList01");
                  await coreApi.CreateContainerAsync(ContainerName);
                  await coreApi.ScaleContainerAsync();
                  await coreApi.DeleteFamilyItemAsync(id,key);
              }
          }

      以上原始碼,是所有的Service中的業務方法

    • 在頁面的呼叫方法中

       

       在此檔案中加入替換下面的原始碼

      public class ManageModel : Senparc.Ncf.AreaBase.Admin.AdminXncfModulePageModelBase
          {
              private readonly IServiceProvider serviceProvider;
      
              public ManageModel(IServiceProvider serviceProvider, Lazy<XncfModuleService> xncfModuleService) : base(xncfModuleService)
              {
                  this.serviceProvider = serviceProvider;
              }
      
              public async Task<IActionResult> OnGetListAsync()
              {
                  CosmosDBService cosmosDBService = new CosmosDBService();
                  var result = await cosmosDBService.GetList();
                  return Ok(result);
              }
      
              public async Task<IActionResult> OnGetAddAsync()
              {
                  CosmosDBService cosmosDBService = new CosmosDBService();
                  cosmosDBService.AddItem();
                  return Ok("200");
              }
      
              public async Task<IActionResult> OnGetEditAsync(string id, string key)
              {
                  CosmosDBService cosmosDBService = new CosmosDBService();
                  cosmosDBService.UpdateItem(id,key);
                  return Ok("200");
              }
      
              public async Task<IActionResult> OnGetDeleteAsync(string id,string key)
              {
                  CosmosDBService cosmosDBService = new CosmosDBService();
                  cosmosDBService.DeleteItem(id,key);
                  return Ok("200");
              }
          }

      以上內容就是我們今天要聊的範例的所有原始碼

  • 處理頁面上的資料展示方式

 

 

 經過上面的操作後,呈現出來的樣子如圖所示,列表的展示,查詢,新增,修改,刪除功能就全部擁有了。

那麼這些資料有沒有工具可以視覺化的檢視呢?

答案:是肯定的,就是我們馬上要聊的Azure Cosmos DB Emulator

 

 

 

  • 對比Cosmos DB Emulator的資料
    • 下載Cosmos DB Emulator的工具
      下載地址:https://aka.ms/cosmosdb-emulator
    • 執行Cosmos DB Emulator

       

       圖中展示的是Azure Cosmos DB的首頁

    • 操作管理的模組

       

       這個是資料的資源管理器,可以點選檢視的資料的內容

    • 對比資料
      當我們在NCF操作了增刪改資料的操作之後,那麼可以直接到Emulator中去對應資料檢視是否正確

       

       

      還可以根據自己的查詢條件來快速查詢資料

       

       查詢的語句沿用了SQL Server的一些語法,大家可以去嘗試一下

    • 檢視請求效能
      最後我們來看看使用Azure Cosmos DB的效能如何

       

       平均的請求效率在幾十毫秒,所以這個Azure Cosmos DB可以作為我們另外的一個管理資料的選擇之一

  • 自由發揮

到此一個NCF整合Azure Cosmos DB的Demo範例就完整展示了,希望能夠幫助到您。

後期精彩內容(敬請關注)