ShowProgramCode

2022年1月20日 星期四

ASP.NET CORE3.1 使用EF Core處理資料庫問題

建立書本的範例,書本使用的是Asp.Net Core 2.2版本,但考量實際專案改使用Asp.Net Core 3.1版本,然後自然會開始遇到一連串狀況了。目前的進度只到使用EF Core自動建立資料庫與資料表,後續的新增、修改、刪除、查詢功能都還沒開始處理,先記錄目前為止的問題。

  • EF Core需要安裝:
第一個狀況就是EF Core安裝,在書中並沒有說明這一段,猜測可能Asp.Net Core 2.2包含EF Core不須安裝此套件,總之第一個遇上的問題就是該安裝EF Core哪一個版本?
之後在同事的建議下,安裝了5.04版,這邊特別說明6.01需要.NET Core 6以上版本才能安裝,我目前的版本裝不了。

EF Core安裝截圖






安裝之後我開始依照範例處理DTO、資料庫連線設定等等,然後問題出現了,在Startup.cs的ConfigureServices中加入SQL服務時Error了,原因是找不到我使用的函式,如下圖:

設定使用EF Core做資料庫連線錯誤










  • EF Core相關套件需要安裝:
後來在同事的幫忙下,了解這是因為我少裝了一個套件,EF Core.SqlServer,如下圖:

安裝EF Core的SqlServer相關套件





安裝版本基本是跟EF Core的版本,安裝完剛剛在Startup.cs的錯誤就沒問題了。
接著我按照書上的說明,準備使用Code First方式,通過Migration建立資料庫與資料表。
首先要先找到使用指令的地方,工具/NuGet事件管理員/套件管理器主控台,順道一提因為書籍是簡體版,兩邊翻譯的不同,這個位置讓我找了很久。

使用命令列位置
















接著下達命令來建置Migration參考檔案,命令如下:

Add-Migration InitalCreation
然後當然又錯誤了(實際的錯誤訊息忘了,這是我將參考拿掉產生的)。

命令錯誤資訊







查了一陣子,發現又少裝一個套件,EF Core Tools。

安裝EF Core的Tools相關套件





緊接著,執行Add Migration沒有問題成功了,得到一個Migrations的資料夾,裡面設定了資料庫與資料表的建置方式。

於是依照範例繼續準備寫入資料庫中,命令如下:

Update-Database

然後又錯誤了,原來的錯誤訊息好像是和Initial Catalog相關,因為已經無法重現原來的問題,講一下印象中大意是說不可使用Initial Catalog字元,或者使用Initial Catalog有問題之類的。

這個錯誤大概是我找最久的,我當時不再公司只能自己尋找問題,偏偏對這個不熟悉找到的資訊也大多有問題,沒有人幫忙的情況下,最終才發現錯誤訊息的問題跟我考慮和尋找的方向有落差。

原因是我資料庫連線設定錯誤,把設定值放上來。

"DefaultConnection": "Data Source=localhost\\資料庫連線;Initial Catalog=資料庫名稱;Integrated Security=SSPI"

這是我從各式各樣的網頁找的答案拼湊出來的,這個設定值並不是給我目前的狀況使用,但範例原先的設定讓我新增成功卻找不到新增的資料庫,總之結論我把正確的設定值貼上。

"DefaultConnection": "server=localhost\\資料庫連線;database=資料庫名稱;Integrated Security=SSPI"

到此為止終於新增成功,且在資料庫連線工具中找到新增的資料庫了,可喜可賀。

繼續補充之後Migration自動建立假資料的動作

在連線設定繼承DbContext的物件中複寫OnModelCreating函式

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<AuthorDBDto>().HasData(List<AuthorDBDto>authors);
            modelBuilder.Entity<BookDBDto>().HasData(List<AuthorDBDto>books);
}

工具/NuGet事件管理員/套件管理器主控台

在此輸入指令 Add-Migration SeedData,在Migration資料夾中會多出SeedData的檔案,內容是List中想要新增的資料。然後在輸入指令Update-Database,將資料新增到資料庫中。如下圖:








要注意的是Add-Migration SeedData之後即便把SeedData檔案刪除,仍然已經將資料寫入某個地方,重新填寫資料時,剛剛已經寫入的資料不會寫入新的SeedData檔案。

接著測試自動刪除檔案,先輸入指令Add-Migration RemoveSeededData,在Migration資料夾中會多出RemoveSeededData的檔案,內容是剛剛新增的資料。然後在輸入指令Update-Database,將資料從資料庫中刪除。如下圖:








到此EF Core的測試完畢,真是太好了。

2022年1月6日 星期四

ASP.NET C# Fotify Cross-Site Scripting: Poor Validation(XSS)問題解決

 這次客戶使用Fortify進行掃描,多數的問題都已經解決,或者將公用函式做成.dll檔後,也都通過掃描標準。唯獨標題的問題,從開始到前日一直沒有解決,今天終於處理完畢,所以特別記錄下來。

依照我之前查詢的諸多參考網頁,多數說明解決這個問題的方法就是使用HtmlEncode()處理input,不讓程式執行含有HTML標籤的內容,也避免資料庫存入。

因此我將被掃描出來的地方,只要有被呼叫到的部分,不管input、output全部都使用HtmlEncode()處理,然而這沒有用,Fortify依舊堅持把這段程式掃出來了。

目前解決方法:
input:依舊使用HttpUtility.HtmlEncode()處理。
output:
HtmlSanitizer sanitizer = new HtmlSanitizer();
output = sanitizer.Sanitize(HttpUtility.HtmlDecode(data));

程式碼無法放上來,只能這樣說明,希望下次要是再遇到這樣的問題能夠提供參考。

後續發生一個意想不到的問題,這個第三方套件和Framework4.6.2的版本居然有參考檔會衝突。

原因是客戶不希望保留Nuget參考,希望所有第三方套件全部轉成.dll來參考,加上客戶的Framework版本是4.5升上來的,所以本機執行一直沒有發現錯誤,等到程式發佈到IIS上後居然無法執行。今天找了一整天終於知道有兩個套件參考的dll與4.6.2衝突了,需要改寫web.config設定。

將web.config修改部分放上來,真是始料未及的問題。

  <runtime>

          <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

<dependentAssembly>

<assemblyIdentity name="AngleSharp.Css" publicKeyToken="XXXXX" culture="neutral"/>

<bindingRedirect oldVersion="0.0.0.0-0.16.3.0" newVersion="0.16.3.0"/>

</dependentAssembly>

                  <dependentAssembly>

                          <assemblyIdentity name="AngleSharp" publicKeyToken="XXXXX" culture="neutral"/>

                          <bindingRedirect oldVersion="0.0.0.0-0.16.1.0" newVersion="0.16.1.0"/>

                  </dependentAssembly>

          </assemblyBinding>

  </runtime>


2021年12月3日 星期五

MS SQL工具改變資料表欄位自動增值失敗問題

今天我發現資料庫沒有建立主Key,且主Key欄位非自動增值造成我新增資料失敗後,便來調整資料庫的欄位設定。 

使用的工具是Microsoft SQL Server Management Studio。

不過當我把主Key調整好,設定自動增值如下圖:

將設定存檔時卻發生錯誤無法調整,如下圖:


最終在同事的幫忙下發現,這個錯誤訊息必須調整『工具』選項中的『設計師』中,把『防止儲存需要資料表重建的變更』這項設定取消。如下圖:













這樣就可以調整資料表的主Key欄位並讓它自動增加數值了。



2021年11月25日 星期四

改變.NET Framework版本

 如何不透過UI直接從檔案更改Framework版本?

原先我都是利用Visual Studio的介面更改Framework的版本,不過這次的專案不知為何改變版本後,Web Reference就發生錯誤,甚至無法編譯。

本來應該設法好好找出Web Reference就發生錯誤的原因,不過由於時程問題,我想到如果不透過介面直接從檔案更改Framework版本,是否可以避免因為重新讀取專案檔,系統檔改寫後編譯錯誤的問題。

終於,那麼更改Framework應該從哪個系統檔處理呢?

基本上就是.csproj檔案。

在這個檔案內容可以找到Framework目前的版本,直接修改版本號碼就可以改變Framework版本。

改變.sln專案檔版本

如何將.sln專案檔提升至2017版本

最近遇到客戶提出了這個要求,順便參考官方文件的說法,整理一下如何提升專案檔版本?

參考網站:https://docs.microsoft.com/zh-tw/visualstudio/extensibility/internals/solution-dot-sln-file?view=vs-2017


先不考慮專案內容是否會有衝突的問題,單純紀錄該如何修改.sln版本。

依照官網文件的說法,基本上相當簡單,只要修改檔案的表頭即可。

下列附上每個不同VS版本的.sln表頭。

  • VS2022

Microsoft Visual Studio Solution File, Format Version 12.00

# Visual Studio Version 16

VisualStudioVersion = 16.0.28701.123

MinimumVisualStudioVersion = 10.0.40219.1


  • VS2019

Microsoft Visual Studio Solution File, Format Version 12.00

# Visual Studio Version 16

VisualStudioVersion = 16.0.28701.123

MinimumVisualStudioVersion = 10.0.40219.1


  • VS2017

Microsoft Visual Studio Solution File, Format Version 12.00

# Visual Studio 15

VisualStudioVersion = 15.0.26730.15

MinimumVisualStudioVersion = 10.0.40219.1


  • VS2013

Microsoft Visual Studio Solution File, Format Version 12.00

# Visual Studio 2013

VisualStudioVersion = 12.0.40629.0

MinimumVisualStudioVersion = 10.0.40219.1

VS2022與VS2019的設定表頭設定基本是相同的,關於這個我暫時沒有找到更詳細的說法,因為我最近修改的版本為VS2013 => VS2017,經過修正之後,客戶那邊確認可以使用。

將官網針對表頭的說明複製上來,若有侵權疑慮請先告知,謝謝!


Microsoft Visual Studio Solution File, Format Version 12.00
定義檔案格式版本的標準標頭。

# Visual Studio 15
Visual Studio 的主要版本, (最近) 儲存此方案檔。 這項資訊會控制解決方案圖示中的版本號碼。

VisualStudioVersion = 15.0.26730.15
Visual Studio 的完整版本, (最近) 儲存的方案檔。 如果解決方案檔是由具有相同主要版本的較新版本 Visual Studio 所儲存,則不會更新此值,以便減少解決方案檔中的流失情形。

MinimumVisualStudioVersion = 10.0.40219.1
可以開啟此方案檔之 Visual Studio 的最小 () 版本。

也就是說,基本上只要置換中間兩行就能將.sln版本更換。

# Visual Studio 15

VisualStudioVersion = 15.0.26730.15

查詢此問題時,還有看到可以將專案拷貝各種不同版本的.sln檔案,方便使用不同的VS版本開啟的說法。

通常專案檔版本還是需要配合客戶需求,所以更改版本是有機會發生的問題,特別記錄下來。


2021年9月7日 星期二

C# ASP.NET web.config的RSA加密

 通常我們會在web.config中放入很多設定值,其中不乏帳密之類的機密資料。按理說,這支檔案是無法被截取的,不過為了安全起見,倘若可以做更多加密處理,也能更加放心。

這次客戶提供的web.config就有加密處理,並且因為沒有RSA Key的原因,整個程式無法順利編譯。因此我將這個RSA加密web.config的方式記錄下來。

使用RAS Key加密,必須用到Visual Studio的一個執行檔(aspnet_regiis.exe),所以必須將cmd用管理者權限執行後,將路徑移動到那個執行檔的資料夾。

C:\Windows\Microsoft.NET\Framework\v4.0.30319,這是我使用的資料夾。

在HelloWorld中加上讀取appSettings的內容,確認加密前後程式可以正常編譯。



















[WebMethod]

public string HelloWorld()

{

    string temp = ConfigurationManager.AppSettings["test"];

    return temp;

}


一、以本機的RSA Key加解密:

這個方法比較簡單,不過一旦將檔案移到別的主機上,就會發生最前面所述,整個程式無法編譯的問題,所以自己玩一下可以,並不是那麼實用。

加密:

1.在命令列執行aspnet_regiis.exe -pef appSettings "專案的web.config所在資料夾"

以本機RAS Key加密





2.確認web.config加密後內容

web.config加密後內容
















3.編譯執行程式,看看是否可以順利讀到appSettings內容

解密:

1.在命令列執行aspnet_regiis.exe -pdf appSettings "專案的web.config所在資料夾"

以本機RAS Key解密






2.確認web.config是否解密還原最初的內容

二、以固定的RSA Key加解密

1.確認使用本機或是取得其他RSA Key加密

    1.1使用本機的RSA Key加解密

    這應該是最常見的狀態,使用本機的RSA Key加密後,提供這把Key給其他使用者。

aspnet_regiis.exe關於說明建立RSA Key說明


參考上述的說明內容,在命令列執行aspnet_regiis.exe -pc "金鑰名稱" -exp,如下圖。

在命令列執行建立RSA金鑰







之後修改專案的web.config內容,加入一段設定指定金鑰加密的部分。

<configProtectedData>

    <providers>

      <add name="RuitingtechProvider" type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration, Version=4.0.0.0,  Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" keyContainerName="金鑰名稱" useMachineContainer="true"/>

    </providers>

  </configProtectedData>

web.config設定特定RSA金鑰加密





在命令列輸入加密命令,aspnet_regiis.exe -pef 加密區段 "web.config資料夾路徑" -prov "RuitingtechProvider"

在命令列輸入使用特定RSA金鑰對web.config特定區域加密




web.config加密後內容


















   
    1.2使用其他裝置密鑰加密
    這邊就不特別實作,大致應該是把金鑰檔匯入本機中,其他的動作應該是差不多的。

確認加密後程式可以正常編譯、執行。

2.確認使用本機或取得其他RSA Key解密
    2.1使用本機特定金鑰解密
    在命令列輸入解密命令,aspnet_regiis.exe -pdf 解密區域 "web.config所在資料夾路徑"
在命令列輸入解密命令









    web.config恢復未加密內容。

    2.2使用其他裝置密鑰解密
    這邊不特別實作,先將金鑰匯入本機中,其他動作應該是差不多的。
將其他裝置金鑰的xml匯入命令參考







3.將RSA Key匯出xml檔案給其他裝置使用
aspnet_regiis.exe -px “金鑰名稱” 金鑰xml路徑 -pri
在命令列輸入匯出xml檔案命令








尋找一下這個位置是否產生了xml的金鑰檔案。



最後補充一下刪除金鑰容器的說明。
 aspnet_regiis -pz "金鑰名稱"




參考網頁:
https://dotblogs.com.tw/wasichris/2016/01/01/235040
https://www.itread01.com/content/1549832402.html
以及C# Asp.Net官方文件


2021年9月1日 星期三

C# ASP.NET的DEBUG模式下執行特定程式

 今天把程式放上IIS後,居然出現在本機測試沒有出現的Error。去查了LOG,回到程式碼查看後,發現程式跑了一段我在本機處理時不曾跑過的函式,函式中需要驗證的機器因為沒有設定,所以才出現了Error。

但是為什麼在本機測試時,一直沒有出現這樣的錯誤呢?

程式中出現了下面的內容,於是我上網去查了C#的說明。

#if(!DEBUG)

.......

#endif

直接先說結論,這段程式的意思大致是,程式在非Debug模式下執行,會進入裡面的內容。而我在本機一直是用Debug模式在執行程式,所以才沒有發現這個問題。

這其實是個好用的設定,偶爾我們需要在Debug的模式下特別紀錄某些LOG或者特別執行某些程式來做測試,利用這個的功能就可以不調整程式的前提下,將一般模式與Debug模式分開處理。

要如何設定這個功能呢?

首先,在web.config中確認<compilation debug="true"/>這個設定是正確的。

接著關於如何判斷是否在Debug模式下,則有兩種做法。

1.如上方所述,利用#if(DEBUG)判斷:

將所有要在DEBUG模式下執行的程式,放在#if(DEBUG)與#endif之間即可,比較直觀,但是之後修改不易,可能讓程式中佈滿相關的if。一旦要修改也很難找到正確的修改位置。

2.利用 ConditionalAttribute 屬性來判斷:

這部分我目前尚未實測過,不過相較之下看起來比較容易將相關的程式放在一起,之後維護起來也比較方便。

在DEBUG模式下要處理的函式加上[Conditional("DEBUG")]即可,參考如下。

[Conditional("DEBUG")]
Public void DebugLog()
{
......
}

日後有需要我應該會採用第二種做法,有時間也可能做個測試程式。

參考網頁如下:
https://dotblogs.com.tw/joysdw12/2014/03/14/asp-net-debug-release-if-else-conditional