2019年5月29日 星期三

Visual Studio 版本號介紹與說明

Visual Studio 一般常見的版本號樣式

























是以 1.2.3.4 的樣式呈現

對應在英文上

為 Major(1).Minor(2).Build(3).Revision(4)



現在針對每個欄位的意義

做一個簡單的說明



Major

通常是大更新,使的程式無法向下相容,這個版號會遞增



Minor

也是大更新,但是程式可以向下相容,這個版號會遞增



Build

通常是一些小更新,例如:修正 Bug,這個版號會遞增

PS.這個欄位也有人用更新日期代表



Revision

通常是內部版本,或修正安全性漏洞,這個版號會遞增







Visual Studio 2017 發佈後,執行批次檔(配合 pscp、plink 一鍵更新遠端 Ubuntu 伺服器檔案)

首先先要設定完發佈設定檔 FolderProfile.pubxml

再來修改檔案內容


  <Target Name="ExecuteBatAfterPublish" AfterTargets="AfterPublish">
    <Exec Command="C:\Batch\WinToUbuntu.bat" WorkingDirectory="$(publishUrl)" />
  </Target>






















PS.記得 *.bat 檔案檔案屬性要選「永遠複製」不然執行階段會出現找不到批次檔的訊息















還有 *.bat 檔案在專案編譯後在根目錄下 Exec Command=WinToUbuntu.bat 可以不需要 *.bat 路徑。

批次檔內可以利用上次提到的 pscp 將檔案複製到遠端的 Ubuntu 伺服器內
就能做到一鍵發佈並更新遠端 Ubuntu 檔案
例如:
pscp -i "C:/ppk/ubuntu.ppk" -pw password *.* user@1.2.3.4:/home

plink 可以執行遠端的 Ubuntu 指令
例如:
plink -ssh -i ubuntu.ppk user@1.2.3.4 -pw password cd /home; ls;

PS.
1.寫完 *.bat 檔案,記得實際操作 pscp 與 plink 指令測試一次,這樣 Register 會記錄過授權記錄, *.bat 才能正常執行。

2.Windows 10 安裝 PuTTY 後,pscp 與 plink 的路徑會被引用,所以不需要複製 pscp 與 plink 的執行檔。























利用 pscp、plink 將 Windows 10 的檔案複製到 Ubuntu 指定目錄中

安裝 PuTTY 會有 pscp 、plink 執行檔,pscp  可以用來複製檔案到遠端的 Ubuntu 上

plink 可以執行遠端 Ubuntu 的命令

pscp  指令如下:
pscp -i "C:/ppk/ubuntu.ppk" -pw password *.* user@1.2.3.4:/home

上列指令目的:
複製 "C:/linux-x64/*.*" 的檔案到遠端 IP : 1.2.3.4 的 Ubuntu 目錄 /home 下

說明:
-i 讀取 ppk 路徑(EC2 預設都需要 ppk)
-pw Ubuntu 密碼
user@ 是指帳戶名稱加上@

plink 指令如下:
plink -ssh -i ubuntu.ppk user@1.2.3.4 -pw password cd /home; ls;

上列指令目的:
登入遠端 IP:1.2.3.4 的 Ubuntu 執行 cd /home 與 ls

說明:
-i 讀取 ppk 路徑(EC2 預設都需要 ppk)
-pw Ubuntu 密碼
user@ 是指帳戶名稱加上@

2019年5月28日 星期二

ASP.NET Core WebAPI 中的分析工具 MiniProfiler

NuGet 安裝 MiniProfiler.AspNetCore.Mvc


在 Startup.cs 上新增程式碼


public void ConfigureServices(IServiceCollection services)
{
 services.AddMvc();


 #region Register the MiniProfiler services

 services.AddMiniProfiler(options => options.RouteBasePath = "/profiler");

 #endregion Register the MiniProfiler services
 
 ....
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
 app.UseResponseCompression();

 if (env.IsDevelopment())
 {
  app.UseDeveloperExceptionPage();
 }


 #region Register the MiniProfiler

 app.UseMiniProfiler();

 #endregion Register the MiniProfiler

}


在 xxxxController 新增測試碼



[HttpGet]
public IEnumerable Get()
{
 string url1 = string.Empty;
 string url2 = string.Empty;
 using (MiniProfiler.Current.Step("Get方法"))
 {
  using (MiniProfiler.Current.Step("準備數據"))
  {
   using (MiniProfiler.Current.CustomTiming("SQL", "SELECT * FROM Config"))
   {
    // 模擬一個SQL查詢
    Thread.Sleep(500);

    url1 = "https://www.baidu.com";
    url2 = "https://www.sina.com.cn/";
   }
  }


  using (MiniProfiler.Current.Step("使用從數據庫中查詢的數據,進行Http請求"))
  {
   using (MiniProfiler.Current.CustomTiming("HTTP", "GET " + url1))
   {
    var client = new WebClient();
    var reply = client.DownloadString(url1);
   }

   using (MiniProfiler.Current.CustomTiming("HTTP", "GET " + url2))
   {
    var client = new WebClient();
    var reply = client.DownloadString(url2);
   }
  }
 }
 return new string[] { "value1", "value2" };
}


在瀏覽器上輸入 http://localhost:port/api/xxxx 可呼叫此程式







執行完畢

在 http://localhost:port/profiler/results 可以看到 MiniProfiler












2019年5月25日 星期六

ASP.NET Core 安裝 NSwag 自動產生 API 說明文件檔案

目的:自動抓取註解產生下面的 API 說明文件網頁


























上次講到 Swashbuckle 在 Ubuntu 環境,
專案執行發生異常,
於是就換了 NSwag,
目前執行下來沒什麼問題,
這邊記錄一下安裝的過程與要注意的事項。


安裝 NuGet 套件:
NSwag.AspNetCore                                  NSwag 主要套件
NSwag.SwaggerGeneration.AspNetCore 自動從 cs 抓註解到我們指定的 xml 檔案























新增「隱藏警告:1591」

PS.特別要注意 xml 檔案名稱要跟專案一樣,才能自動抓取到註解內容


先引用 NSwag.AspNetCore


using NSwag.AspNetCore;


設定一下 Startup.cs 的 ConfigureServices


public void ConfigureServices(IServiceCollection services)
{
 services.AddMvc();


 #region Register the Swagger services

 // Register the Swagger services
 services.AddSwaggerDocument();

 #endregion Register the Swagger services
}


與設定一下 Startup.cs 的 Configure


public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{


       #region Register the Swagger generator and the Swagger UI middlewares

       // Register the Swagger generator and the Swagger UI middlewares
 
        app.UseSwagger();
        app.UseSwaggerUi3();

        #endregion Register the Swagger generator and the Swagger UI middlewares


        app.UseMvc(routes =>
        {
             routes.MapRoute(name: "default", template: "{controller}/{action}/{id?}");
        });
}


記得註解 <summary> 要寫,每次編譯後 XML 的內容都會更新唷!


/// <summary>
/// 簡單的 Controller 範例
/// </summary>


程式開啟後,輸入網址 http://localhost:port/swagger
就能開啟 Swagger UI 網頁















2019年5月23日 星期四

c# async 和 await 簡易說明

函式前面增加 async 就會成為異步函式(執行過程中不會等待函式執行完畢才往下跑)



/// <summary>
/// 異步函式
/// </summary>
static async void AsyncFun()
{
 // 裡面要有 await 關鍵字

 // await 後面要接回傳 Task 的函式
 // 因為回傳 Task 簡稱他為異步任務

 List<formatter> f_ = new List<formatter>{
  new Formatter("「異步任務」", Color.Red)};

 Print("執行 {0} 『開始』", Color.Yellow, f_.ToArray());
 bool ret_ = await DelayFun();
 Print("執行 {0} 『結束』", Color.Yellow, f_.ToArray());
}


異步函式內需要有await 關鍵字
await 後面要接回傳 Task 的函式
因為回傳 Task 簡稱他為異步任務



/// <summary>
/// 異步任務
/// </summary>
/// <returns>true</returns>
static Task<bool> DelayFun()
{
 return Task.Run(() =>
 {
  List<Formatter> f_ = new List<Formatter>{
   new Formatter("等待五秒", Color.YellowGreen)};

  Print("{0} 開始", Color.Red, f_.ToArray());
  Thread.Sleep(5000);
  Print("{0} 結束", Color.Red, f_.ToArray());
  return true;
 });
}



異步函式呼叫與一般函式一樣
只差在執行中不等待函式執行完


static void Main(string[] args)
{
 ....
 // 異步函式
 List<Formatter> f0_ = new List<Formatter>{
  new Formatter("「異步函式」", Color.Red)};
 Print("執行 {0} 開始", Color.Green, f0_.ToArray());
 AsyncFun();
 Print("執行 {0} 結束", Color.Green, f0_.ToArray());
 ....
}



最後可以看到「異步任務」
在程式執行完畢後
才把任務跑完











利用 .NET Standard 函式庫 的 C# 取得 Git 版本號



這邊遇到找不到 Git 的環境變數
所以在 @"Git\cmd" 做了一些修改
這邊得看看你 Git 的執行檔在那個目錄內
再做調整與修改



public class CommitID
{
 private static string EnvironmentVariable
 {
  get
  {
   string sPath = Environment.GetEnvironmentVariable("Path");
   var result = sPath.Split(';');
   for (int i = 0; i < result.Length; i++)
   {
    if (result[i].Contains(@"Git\cmd"))
    {
     sPath = result[i];
    }

   }
   return sPath;
  }
 }

 public static void GetCommitID()
 {
  string gitPath = System.IO.Path.Combine(EnvironmentVariable, "git.exe");
  Console.WriteLine($"環境路徑:{gitPath}");
  Process p = new Process();
  p.StartInfo.FileName = gitPath;
  p.StartInfo.Arguments = "rev-parse HEAD";
  p.StartInfo.CreateNoWindow = true;
  p.StartInfo.UseShellExecute = false;
  p.StartInfo.RedirectStandardOutput = true;
  p.OutputDataReceived += OnOutputDataReceived;
  p.Start();
  p.BeginOutputReadLine();
  p.WaitForExit();
 }

 private static void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
 {
  if (e != null && !string.IsNullOrEmpty(e.Data))
  {
   ID = e.Data;

   Console.WriteLine(e.Data);
  }
 }

 public static string ID { get; set; } = "";
}


使用方法:
先呼叫 GetCommitID()
之後 ID 就會有 Git 的版本號
他會取得目前執行目錄上的 Git 版本號


























Visual Studio 2017利用 T4 自動產生版本號(寫入 Git 版本號)


「工具」 「擴充功能與更新」

安裝「T4Executer 」後 T4 的關鍵字都會有對應的顏色標示

























安裝 「Devart T4 Editor」可以設定編譯前先執行 T4 範本

























設定編譯前執行 T4 (圖為執行狀態)














設定畫面
























新建文字檔 附檔名為 *.tt
就會出現「轉換所有 T4 範本」
點擊就會執行 T4 範本




















首先註解 AssemblyInfo.cs 裡面的
[assembly: AssemblyFileVersion("0.0.0.0")]
與
[assembly: AssemblyTitle("ConsoleApp")]
下面的 SharedInfo.tt 檔案(T4 範例)
會自動產生一個 SharedInfo.cs
並自動填入
[assembly: AssemblyFileVersion("0.0.0.0")]
與
[assembly: AssemblyTitle("ConsoleApp")]
的內容


<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ import namespace="System.IO" #>
<#@ assembly name="$(SolutionDir)\CommitID\bin\Debug\netstandard2.0\MyLibrary.Git.dll" #>
<#@ import namespace="MyLibrary.Git" #>
<#@ assembly name="C:\Program Files\dotnet\sdk\2.1.700-preview-009597\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\netstandard.dll" #>
<#@ output extension=".cs" #>
<#
     int major = 0; 
     int minor = 0; 
     int build = 0; 
     int revision = 0; 
  
     try
     {
         using(var f = File.OpenText(Host.ResolvePath("SharedInfo.cs")))
         {
             // 取值做 +1 使用
             //string maj = f.ReadLine().Replace("//","");
             //string min = f.ReadLine().Replace("//","");
             //string b   = f.ReadLine().Replace("//","");
             //string r   = f.ReadLine().Replace("//","");
  
             // 轉成日期
             string maj = DateTime.Now.Year.ToString();
             string min = DateTime.Now.Month.ToString();
             string b   = DateTime.Now.Day.ToString();
             string r   = DateTime.Now.Minute.ToString() + "0" + DateTime.Now.Second.ToString();

             major    = int.Parse(maj); 
             minor    = int.Parse(min); 
             build    = int.Parse(b); 
             revision = int.Parse(r) + 1; 
         }
     }
     catch
     {
         major    = 1; 
         minor    = 0; 
         build    = 0; 
         revision = 255; 
     }

    // 呼叫自己個函式庫
 CommitID.GetCommitID();
 string gitver = CommitID.ID;
 #>
 //<#= major #>
 //<#= minor #>
 //<#= build #>
 //<#= revision #>

 //<#= gitver #>

 // 
 // This code was generated by a tool. Any changes made manually will be lost
 // the next time this code is regenerated.
 // 
  
 using System.Reflection;
  
 [assembly: AssemblyFileVersion("<#= major #>.<#= minor #>.<#= build #>.<#= revision #>")]
 [assembly: AssemblyTitle("<#= gitver #>")]



MyLibrary.Git 是我寫的 .NET Standard Library
透過


<#@ assembly name="$(SolutionDir)\CommitID\bin\Debug\netstandard2.0\MyLibrary.Git.dll" #>
<#@ import namespace="MyLibrary.Git" #>


使用 .NET Standard Library 還要加入 .NET Standard 的 dll


<#@ assembly name="C:\Program Files\dotnet\sdk\2.1.700-preview-009597\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\netstandard.dll" #>


不然編譯會有錯誤訊息:
錯誤 正在編譯轉換: 類型 'Object' 定義在未參考的組件中。您必須加入組件 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' 的參考。

請依據自己的 dotnet 版本選擇目錄,例如:我的是 net461














2019年5月22日 星期三

Visual Studio 2017 / 2019 自動產生版本號 Automatic Version 2

在「擴充功能與更新」安裝 Automatic Version 2




























「工具」欄位會多一個 「Automatic Version Setting」

























設定一下版本號的規則
記得先指定 「Custom System Version」
左邊如果選的是「User's Global Default」
皆下來每個專案都會自動產生版本號
一般都會指定專案(左邊最下面的那個)
做自動生產專案設定
































接下來編譯就會自動更新版本號了


































Visual Studio Code 的 cs 檔案中文亂碼解決方法

點擊右下編碼






選擇『以編碼重新開啟』














選擇『Traditional Chinese (Big5) cp950』
這時文件內的中文就會正常顯顯示了






























因為 Visual Studio Code 開啟檔案預設是 UTF-8
所以要避免每次都要設定『Traditional Chinese (Big5) cp950』
選擇『以編碼儲存』











選擇 UTF-8 下次打開檔案就能正常顯示中文了





Visual Studio Code 調整顯示字體大小

在「設定」中輸入

editor.fontsize
如下圖框內調整字體大小
















PS、目前不支援Ctrl + mouse scroll up/down 調整字體大小
Ctrl + 放大字體
Ctrl - 縮小字體












Visual Studio 2017/2019 推薦的擴充功能與更新

參考文章: 覺得 Google 的 Blogger 不太順手?透過 HTML 的 iframe 移花接木 HackMD