只有累積,沒有奇蹟

顯示具有 Kestrel 標籤的文章。 顯示所有文章
顯示具有 Kestrel 標籤的文章。 顯示所有文章

2023年9月18日 星期一

[NETCore] ASP.NET Core 啟動失敗 - 嘗試存取通訊端被拒絕,因為存取權限不足

問題 
接獲同事詢問專案無法正常啟用,專案是使用 ASP.NET Core 2.2 開發並搭配 Kestrel 使用,在過去開發時都正常運作但今天忽然就遭遇啟動異常的狀況,在啟用時會跳出錯誤訊息為 'Unable to bind to http://localhost:5000 on the IPv4 loopback interface: '嘗試存取通訊端被拒絕,因為存取權限不足。''  ,這篇文章就針對此問題的解決方式做分享若是有不清楚或是錯誤的地方歡迎討論予糾正

異常現場
異常發生時畫面如下
Log 中紀錄的詳細錯誤訊息如下
info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0]
      User profile is available. Using 'C:\Users\user\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.
warn: Microsoft.AspNetCore.Server.Kestrel[0]
      Unable to bind to http://localhost:5000 on the IPv4 loopback interface: '嘗試存取通訊端被拒絕,因為存取權限不足。'.
warn: Microsoft.AspNetCore.Server.Kestrel[0]
      Unable to bind to http://localhost:5000 on the IPv6 loopback interface: '嘗試存取通訊端被拒絕,因為存取權限不足。'.
crit: Microsoft.AspNetCore.Server.Kestrel[0]
      Unable to start Kestrel.
System.IO.IOException: Failed to bind to address http://localhost:5000. ---> System.AggregateException: One or more errors occurred. (嘗試存取通訊端被拒絕,因為存取權限不足。) (嘗試存取通訊端被拒絕,因為存取權限不足。) ---> System.Net.Sockets.SocketException: 嘗試存取通訊端被拒絕,因為存取權限不足。
   at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
   at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Bind(EndPoint localEP)
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransport.BindAsync()
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer.<>c__DisplayClass21_0`1.<<StartAsync>g__OnBind|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.LocalhostListenOptions.BindAsync(AddressBindContext context)
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Server.Kestrel.Core.LocalhostListenOptions.BindAsync(AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.AddressesStrategy.BindAsync(AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindAsync(IServerAddressesFeature addresses, KestrelServerOptions serverOptions, ILogger logger, Func`2 createBinding)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken)

C:\Program Files\dotnet\dotnet.exe (process 31468) exited with code -1.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops.
Press any key to close this window . . . 
根據錯誤訊息提供的線索,異常原因可能是因為 Kestrel 在啟動時失敗造成 (Startup failure),Kestrel 預設是使用 5000 port,懷疑該已被占用造成啟用時使用該 port 號卻無法正常執行,才跳出 嘗試存取通訊端被拒絕,因為存取權限不足 錯誤訊息,首先先來釐清推測是否正確,查詢 port 使用狀況可以透過以下兩種方式

命令提示字元
開啟 Windows Terminal 使用命令提示字元,輸入  netstat -nat | findstr 5000  指令查看 port 使用狀況 
PS C:\> netstat -nat | findstr 5000 
查詢後可以看到目前系統中 5000 port 已被占用

TCPView
TCPView 是一個非常實用的小工具,可以顯示目前系統中 TCP 與 UDP 連接的狀態,不用在命令提示字元下指令就可以看到需要的資訊,之前用過此工具幫忙在 Production 解決不少問題,如果之前未使用過強烈建議可以下載使用看看,在微軟官方就有提供下載連結 : 傳送門,解完壓縮之後直接執行 TCPView.exe 執行檔,可以看到 5000 Port 已被其他應用程式所占用

解決方案
透過上述步驟可以看到,主要原因是因為 Kestrel 所要用的 Port 已被其他應用程式所佔用,占用的應用程式 ProcessID 是 4,可以透過以下幾種方式解決

設定 IIS
在過去的經驗中告訴我們 system ProcessID 為 4 時候 87% 是 IIS,推測可能是因為在 IIS 中某一個 Application 中有設定使用到該機器的 5000 Port,可以開啟 IIS 檢查在建立 Application 所設定到的 Port 號,有與 5000 衝突的部分替換為新的 Port 號即可,果然在同事的電腦中發現測是的應用程式已將指定 Port 占用,調整後 ASP.NET Core 專案即可正常運行。

設定 Kestrel 
另外一種方式是調整 Kestrel 的指定 Port,在 ASP.NET Core 預設是使用 5000 port,如果電腦中應用程式的 5000 Port 是無法調整的,及可以透過設定的方式將預設的 Port 改用其他指定 port 避免衝突的狀況發生,如果是使用 ASP.NET Core Web template 建立專案,其中  CreateDefaultBuilder  方法會呼叫 serverOptions.Configure(context.Configuration.GetSection("Kestrel")) 載入設定,因此我們可以到 appsettings.json 調整,以下列設定為例是將 Kestrel port 指定為 5050
{
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://localhost:5050"
      }
    }
  }, 
  ....other settings
} 
以上兩種方式都可以解決當 Kestrel 預設 Port 被占用,造成應用程式啟動失敗的問題,各位看官可以依據情境選擇適合是自己的解決方案,若是有更好的方法也歡迎提出來一起討論,Thanks & Happy Coding :)

參考
ASP.NET Core 中的 Kestrel 網頁伺服器實作

2019年3月18日 星期一

[.NETCore] 'IWebHostBuilder' does not contain a definition for 'ConfigureKestrel' and no accessible extension method 'ConfigureKestrel'

問題
Kestrel web server 是一個輕量級的 Web Server 服務,同事求救在實作 How to use Kestrel in ASP.NET Core apps 其中的 Kestrel option 的 ConfigureKestrel 設定時發生錯誤,顯示不支援 ConfigureKestrel 方法簽章,以下就針對解決此問題的方式說簡單說明,若有問題歡迎提出一起討論或是給予指導。

解決方案
錯誤訊息文字為 : 'IWebHostBuilder' does not contain a definition for 'ConfigureKestrel' and no accessible extension method 'ConfigureKestrel' accepting a first argument of type 'IWebHostBuilder' could be found (are you missing a using directive or an assembly reference?)"  
在確認 從 ASP.NET Core 2.1 至 2.2 移轉 線上文件提到, 2.2 版開始 Kestrel Web Server 設定有所調整,原因是為了避免衝突 IIS 同處理序主控模型,忽然間恍然大悟發現是版本更新造成,下列先列出兩個不同版本所用的 API 簽章差異

ASP.NET Core 2.1
在 .NET Core 2.1 中要設定 Kestrel Web Server 設定的話要用  UseKestrel  方法,使用方式如下
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .UseKestrel(options =>
        {
            options.Limits.MaxConcurrentConnections = 100;
        });

ASP.NET Core 2.2
在 .NET Core 2.2 中要設定 Kestrel option 則需要使用  ConfigureKestrel  方法,使用方式如下
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureKestrel((context, options) =>
        {
            // Set properties and call methods on options
        });

確認 ASP.NET Core 版本
兩個版本使用方式不同,因此第一步是確認目前同事Visual Studio 使用的 target Framwork 版本為何,可以再專案按右鍵,點選屬性,得知目前使用版本為 2.1 且沒有並未安裝新版 

下載 .NET Core 2.2
安裝傳送門 : 請點我 
點選下載 .NET Core SDK & Runtime,接著進行安裝其安裝檔,無止盡點擊進行下一步

設定 Target Framework
下載完畢 ASP.NET Core 2.2 SDK & Runtime 之後,來確認在  Microsoft.AspNetCore.Hosting  namespace 底下是否有 ConfigureKestrel 方法
/// <summary>
/// Configures Kestrel options but does not register an IServer. See <see cref="M:Microsoft.AspNetCore.Hosting.WebHostBuilderKestrelExtensions.UseKestrel(Microsoft.AspNetCore.Hosting.IWebHostBuilder)" />.
/// </summary>
/// <param name="hostBuilder">
/// The Microsoft.AspNetCore.Hosting.IWebHostBuilder to configure.
/// </param>
/// <param name="configureOptions">A callback to configure Kestrel options.</param>
/// <returns>The Microsoft.AspNetCore.Hosting.IWebHostBuilder.</returns>
public static IWebHostBuilder ConfigureKestrel(this IWebHostBuilder hostBuilder, Action<WebHostBuilderContext, KestrelServerOptions> configureOptions)
{
  if (configureOptions == null)
    throw new ArgumentNullException(nameof (configureOptions));
  return hostBuilder.ConfigureServices((Action<WebHostBuilderContext, IServiceCollection>) ((context, services) => services.Configure<KestrelServerOptions>((Action<KestrelServerOptions>) (options => configureOptions(context, options)))));
}
確定有其方法,重新至專案調整 target Framework 為 2.2 版,在重新建置專案後即可正常 Build 成功,成功解決,打完收工 ! 

後記
在 ASP.NET Core 推行速度相當快,在練習以及查詢網路資料時得先確定方法是否是舊的 API 與應用,才可以避免下次踩到相同地雷,MSDN 官網文章也有提到各版本移轉時的說明,詳細可以參考看 從 ASP.NET Core 2.1 至 2.2 移轉,或許下次從 2.2 升級到 3.0 或更新版本問題時可以先看一下版本升級說明也可以找到答案 :)

參考
從 ASP.NET Core 2.1 至 2.2 移轉

Copyright © m@rcus 學習筆記 | Powered by Blogger

Design by Anders Noren | Blogger Theme by NewBloggerThemes.com