<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          ASP.NET Core 實現(xiàn)一個簡單的靜態(tài)網(wǎng)站滾動更新

          共 6138字,需瀏覽 13分鐘

           ·

          2021-08-10 23:05

          ASP.NET Core 實現(xiàn)一個簡單的靜態(tài)網(wǎng)站滾動更新

          Intro

          最近我們老板想讓我實現(xiàn)一個靜態(tài)網(wǎng)站“滾動更新”的功能,其實就是希望網(wǎng)站部署的時候網(wǎng)站內(nèi)容完整的切換,不能網(wǎng)站部署的過程中一部分是新的內(nèi)容,另外一部分是老的內(nèi)容。

          這讓我想到了微軟的 Azure App Service,上家公司主要是用微軟的云服務(wù) Azure,站點是部署到 Azure App Service 上的,Azure App Service 有一個部署槽的概念,我們的應(yīng)用一個版本可以對應(yīng)一個部署槽,通過部署槽我們就基本可以無縫地從一個版本切換到另外一個版本。

          FileProvider

          ASP.NET Core 里靜態(tài)文件的托管是允許自定義一個 IFileProvider 的,默認(rèn)會使用物理路徑文件, ASP.NET Core 默認(rèn)使用 wwroot 目錄下作為默認(rèn)的靜態(tài)文件來源。

          對于靜態(tài)文件而言我們簡單地使用兩個目錄來模擬兩個部署槽,當(dāng)需要的時候通過修改配置來動態(tài)修改生效的部署槽,基于 IOptionMonitorPhysicalFileProvider 來實現(xiàn)一個簡單的 DynamicFileProvider,實現(xiàn)代碼如下:

          public class DynamicFileProviderOptions
          {
              public string CurrentSlot { getset; }
          }

          public class DynamicFileProvider : IFileProvider
          {
              private PhysicalFileProvider _physicalFileProvider;
              private const string DefaultSlotName = "Slot1";

              public DynamicFileProvider(IOptionsMonitor<DynamicFileProviderOptions> optionsMonitor, IWebHostEnvironment webHostEnvironment)
              {
                  var webRoot = webHostEnvironment.ContentRootPath;
                  _physicalFileProvider = new PhysicalFileProvider(Path.Combine(webRoot, optionsMonitor.CurrentValue.CurrentSlot ?? DefaultSlotName));
                  optionsMonitor.OnChange(options =>
                  {
                      var path = Path.Combine(webRoot, options.CurrentSlot);
                      _physicalFileProvider = new PhysicalFileProvider(path);
                  });
              }

              public IDirectoryContents GetDirectoryContents(string subpath)
              {
                  return _physicalFileProvider.GetDirectoryContents(subpath);
              }

              public IFileInfo GetFileInfo(string subpath)
              {
                  return _physicalFileProvider.GetFileInfo(subpath);
              }

              public IChangeToken Watch(string filter)
              {
                  return _physicalFileProvider.Watch(filter);
              }
          }

          看起來是不是簡單,其實就是在 PhysicalFileProvider 的基礎(chǔ)上封裝了一下,配置發(fā)生變化的時候構(gòu)建一個新的 PhysicalFileProvider

          Construct Host

          接著我們來看一下如何使用,使用代碼如下:

          var builder = Host.CreateDefaultBuilder(args);
          builder.ConfigureWebHostDefaults(webHostBuilder =>
          {
              webHostBuilder.ConfigureServices((context, services) =>
              {
                  services.Configure<DynamicFileProviderOptions>(context.Configuration);
                  services.AddSingleton<DynamicFileProvider>();
              });
              webHostBuilder.Configure(app =>
              {
                  var dynamicFileProvider = app.ApplicationServices.GetRequiredService<DynamicFileProvider>();
                  app.UseStaticFiles(new StaticFileOptions()
                  {
                      FileProvider = dynamicFileProvider,
                  });
              });
          });
          var host = builder.Build();
          host.Run();

          這里的示例只需要這些代碼我們的應(yīng)用就可以跑起來了,接著我們就來看一下使用效果吧

          Demo

          在項目根目錄運(yùn)行 dotnet run 啟動項目,然后訪問 http://localhost:5000/index.html

          然后我們再修改配置文件中的配置,把配置文件中 CurrentSlot 配置修改為 Slot2,然后再刷新頁面,如下圖所示:

          那么是不是可以不修改配置文件實現(xiàn)部署槽切換呢,也是可以的,我提供了一個做切換的一個簡單的 API

          app.Map(new PathString("/redeploy"), appBuilder => appBuilder.Run(context =>
          {
              if (context.RequestServices.GetRequiredService<IConfiguration>() is ConfigurationRoot configuration)
              {
                  var currentSlot = configuration["CurrentSlot"];
                  configuration["CurrentSlot"] = "Slot2" != currentSlot ? "Slot2" : "Slot1";
                  configuration.Reload();
                  return context.Response.WriteAsync("Success");
              }
              return Task.CompletedTask;
          }));

          這個 API 做的事情很簡單,在 Slot1 和 Slot2 之間進(jìn)行切換,如果原來是 Slot2 則切換成 Slot1 否則切換成 Slot2,修改配置之后調(diào)用一下 Reload 以觸發(fā)配置更新,刪除配置文件中的 CurrentSlot 配置,重新運(yùn)行示例,查看 http://localhost:5000/index.html,還是看到的 Slot1 中的內(nèi)容,然后我們調(diào)用一下 /redeploy 接口來動態(tài)切換一下配置,然后再次刷新頁面就會看到 Slot2 中的內(nèi)容,再調(diào)用一下 redeploy 之后刷新頁面就會變回 Slot1 中的內(nèi)容

          More

          這樣一個簡單的 DynamicFileProvider 的功能就完成了,我們就可以動態(tài)的切換靜態(tài)資源的不同版本了。

          如果實際使用的話可以考慮更新一下 redeploy 接口,把新的網(wǎng)站內(nèi)容通過上傳文件的形式上傳到網(wǎng)站下,上傳結(jié)束后觸發(fā)配置的更新,而且可以保留最近幾個版本的更新,這樣部署歷史也有了,也方便進(jìn)行回滾。

          可以思考一下,如果我們的站點是集群部署的,需要改造什么?

          對于集群部署的場景,可能會有兩個問題,一個是文件訪問的問題, 我們可以使用一個自定義的文件提供者來訪問文件服務(wù)器上的文件,如果使用容器部署的場景,那么我們使用同一個 Volume 就可以實現(xiàn)統(tǒng)一的文件訪問, 另一個問題是配置的管理和更新,對于集群部署的配置,通常我們需要使用配置中心來統(tǒng)一管理配置,這樣就和上面的配置一樣了,配置更新時也會觸發(fā)更新。

          References

          • https://docs.microsoft.com/en-us/aspnet/core/fundamentals/static-files
          • https://docs.microsoft.com/zh-cn/azure/app-service/deploy-best-practices
          • https://github.com/WeihanLi/SamplesInPractice/tree/master/DynamicStaticFileProvider







          回復(fù) 【關(guān)閉】學(xué)關(guān)
          回復(fù) 【實戰(zhàn)】獲取20套實戰(zhàn)源碼
          回復(fù) 【被刪】學(xué)
          回復(fù) 【訪客】學(xué)
          回復(fù) 【小程序】學(xué)獲取15套【入門+實戰(zhàn)+賺錢】小程序源碼
          回復(fù) 【python】學(xué)微獲取全套0基礎(chǔ)Python知識手冊
          回復(fù) 【2019】獲取2019 .NET 開發(fā)者峰會資料PPT
          回復(fù) 【加群】加入dotnet微信交流群
          瀏覽 41
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久99久视频 | 做受 视频毛片下载 | 欧洲三级片视频 | 中国农村乱婬片AA片 | 靠逼网站在线看 |