2018年8月19日 星期日

在 ASP.NET Core 專案內使用 Autofac 相依性注入 DI 容器

在 ASP.NET Core 專案內使用 Autofac 相依性注入 DI 容器

若使要在 ASP.NET Core 專案開發環境,將會使用 ASP.NET Core 內建的相依性注入容器功能用來在類別與其相依性之間達成控制權反轉 (IoC),不過,若您想要使用 Autofac DI Container 相依性注入容器來進行取代 ,也就是我們想要在開發 ASP.NET Core 專案的時候,能夠使用 Autofac 相依性注入容器來進行開發設計,首先,您需要安裝這個 Autofac.Extensions.DependencyInjection 套件( 因為,這個套件已經整合了 ASP.NET Core 的 Microsoft.Extensions.DependencyInjection 功能 ) 到您的 ASP.NET Core 專案內。
ASP.NET Core Autofac Nuget Package Install
ASP.NET Core Autofac Nuget Package Preview
接下來,我們需要打開 [Program.cs] 檔案節點,在 WebHost 之後,加入這個方法呼叫 .ConfigureServices(services => services.AddAutofac()),如底下程式碼所示;不過,您還需要加入 [Autofac.Extensions.DependencyInjection] 這個命名空間,以便可以使用 [AddAutofac] 這個方法。
C Sharp / C#
public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureServices(services => services.AddAutofac())
            .UseStartup<Startup>();
}
現在,我們需要打開 [Startup.cs] 這個檔案,在這個 Startup 類別內,加入底下這段方法宣告。在這個方法裡面,我們將會需要進行抽象介面與具體實作類別的對應定義;在這裡,我們需要加入 Autofac 命名空間的參考。在 ConfigureContainer 這個方法內,我們看到了他會使用 ContainerBuilder.RegisterModel 這個方法,所以,我們將會需要自己建立的繼承 Autofac.Module 類別的衍生類別 AutofacModule 類別出來。
C Sharp / C#
public void ConfigureContainer(ContainerBuilder builder)
{
    builder.RegisterModule(new AutofacModule());
}
在這裡,我們需要建立一個 AutofacModule 類別,用來定義抽象型別與具體實作類別的對應關係。不過,由於這個不過,由於這個類別需要繼承 Autofac.Module 這個類別,因此,我們需要在底下的程式碼中,加入 Autofac 的命名參考空間。在這裡,我們將會宣告了,當要註冊 IMessage 這個抽象介面的時候,Autofac DI Container 將會幫我們產生一個 ConsoleMessage 類別的物件。
C Sharp / C#
public class AutofacModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<ConsoleMessage>().As<IMessage>();
    }
}
為了要方便我們進行測試在 ASP.NET Core 專案內,可以使用 Autofac 相依性注入容器之功能,我們建立了底下測試用的抽象介面與兩個有實作這個介面的類別。
C Sharp / C#
public interface IMessage
{
    void Send(string message);
}

public class ConsoleMessage : IMessage
{
    public void Send(string message)
    {
        Console.WriteLine($"ConsoleMessage :{message}");
    }
}
public class FileMessage : IMessage
{
    public void Send(string message)
    {
        Console.WriteLine($"FileMessage :{message}");
    }
}
我們要來在 Controller 內,建立這個控制器的建構函式,所以,請打開 [HomeController.cs] 這個節點檔案,在這裡,我們宣告一個 IMessage 介面型別的欄位 _Message,並且建立該控制器的建構函式,我們將在該建構式內,加入 IMessage 型別參數,確認 ASP.NET Core 專案,可以透過 Autofac DI Container,提供 HomeController 控制器的建構式注入能力,所以,我們將會在該建構式內,將 DI Container 注入進來的 IMessage 參數,設定給該控制器類別的欄位 _Message。
現在,我們可以在 HomeController 類別內來使用 IMessage 的各項功能了,所以,我們在 Index 動作方法內,執行了 _Message.Send("Vulcan Lee") 這個敘述,接下來,我們執行這個專案,看看是否有任何內容輸出到命令字元視窗內。
當我們執行該 ASP.NET Core 專案後,我們在命令提示字元視窗中 (下圖) ,看到了 ConsoleMessage 類別的輸出內容。
Autofac DI Container Constructor Injection
C Sharp / C#
public class HomeController : Controller
{
    IMessage _Message;
    public HomeController(IMessage message)
    {
        _Message = message;
    }
    public IActionResult Index()
    {
        _Message.Send("Vulcan Lee");
        return View();
    }

    public IActionResult About()
    {
        ViewData["Message"] = "Your application description page.";

        return View();
    }

    public IActionResult Contact()
    {
        ViewData["Message"] = "Your contact page.";

        return View();
    }

    public IActionResult Privacy()
    {
        return View();
    }

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()
    {
        return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
    }
}
我們要來在 Controller 內,建立這個控制器的建構函式,所以,請打開 [HomeController.cs] 這個節點檔案,在這裡,我們宣告一個 IMessage 介面型別的欄位 _Message,並且建立該控制器的建構函式,我們將在該建構式內,加入 IMessage 型別參數,確認 ASP.NET Core 專案,可以透過 Autofac DI Container,提供 HomeController 控制器的建構式注入能力,所以,我們將會在該建構式內,將 DI Container 注入進來的 IMessage 參數,設定給該控制器類別的欄位 _Message。
現在,我們可以在 HomeController 類別內來使用 IMessage 的各項功能了,所以,我們在 Index 動作方法內,執行了 _Message.Send("Vulcan Lee") 這個敘述,接下來,我們執行這個專案,看看是否有任何內容輸出到命令字元視窗內。
當我們執行該 ASP.NET Core 專案後,我們在命令提示字元視窗中 (下圖) ,看到了 ConsoleMessage 類別的輸出內容。
Autofac DI Container Constructor Injection

關於 Xamarin 在台灣的學習技術資源

Xamarin 實驗室 粉絲團
歡迎加入 Xamarin 實驗室 粉絲團,在這裡,將會經常性的貼出各種關於 Xamarin / Visual Studio / .NET 的相關消息、文章、技術開發等文件,讓您可以隨時掌握第一手的 Xamarin 方面消息。
Xamarin.Forms @ Taiwan
歡迎加入 Xamarin.Forms @ Taiwan,這是台灣的 Xamarin User Group,若您有任何關於 Xamarin / Visual Studio / .NET 上的問題,都可以在這裡來與各方高手來進行討論、交流。
Xamarin 實驗室 部落格
Xamarin 實驗室 部落格 是作者本身的部落格,這個部落格將會專注於 Xamarin 之跨平台 (Android / iOS / UWP) 方面的各類開技術探討、研究與分享的文章,最重要的是,它是全繁體中文。
Xamarin.Forms 系列課程
Xamarin.Forms 系列課程 想要快速進入到 Xamarin.Forms 的開發領域,學會各種 Xamarin.Forms 跨平台開發技術,例如:MVVM、Prism、Data Binding、各種 頁面 Page / 版面配置 Layout / 控制項 Control 的用法等等,千萬不要錯過這些 Xamarin.Forms 課程



在 ASP.NET Core 專案內使用 Unity 相依性注入 DI 容器

在 ASP.NET Core 專案內使用 Unity 相依性注入 DI 容器

若使要在 ASP.NET Core 專案開發環境,將會使用 ASP.NET Core 內建的相依性注入容器功能用來在類別與其相依性之間達成控制權反轉 (IoC),不過,若您想要使用 Unity DI Container 相依性注入容器來進行取代 ,也就是我們想要在開發 ASP.NET Core 專案的時候,能夠使用 Unity 相依性注入容器來進行開發設計,首先,您需要安裝這個 Unity.Microsoft.DependencyInjection 套件( 因為,這個套件已經整合了 ASP.NET Core 的 Microsoft.Extensions.DependencyInjection 功能 ) 到您的 ASP.NET Core 專案內。
ASP.NET Core Unity Nuget Package Install
ASP.NET Core Unity Nuget Package Preview
接下來,我們需要打開 [Program.cs] 檔案節點,在 WebHost 之後,加入這個方法呼叫 .UseUnityServiceProvider(),如底下程式碼所示;不過,您還需要加入 [Unity.Microsoft.Depende] 這個命名空間,以便可以使用 [UseUnityServiceProvider] 這個方法。
C Sharp / C#
public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseUnityServiceProvider()
            .UseStartup<Startup>();
}
現在,我們需要打開 [Startup.cs] 這個檔案,在這個 Startup 類別內,加入底下這段方法宣告。在這個方法裡面,我們將會需要進行抽象介面與具體實作類別的對應定義;在這裡,我們需要加入 Unity 命名空間的參考。
C Sharp / C#
public void ConfigureContainer(IUnityContainer container)
{
    // Could be used to register more types
    container.RegisterType<IMessage, ConsoleMessage>();
}
為了要方便我們進行測試在 ASP.NET Core 專案內,可以使用 Unity 相依性注入容器之功能,我們建立了底下測試用的抽象介面與兩個有實作這個介面的類別。
C Sharp / C#
public interface IMessage
{
    void Send(string message);
}

public class ConsoleMessage : IMessage
{
    public void Send(string message)
    {
        Console.WriteLine($"ConsoleMessage :{message}");
    }
}
public class FileMessage : IMessage
{
    public void Send(string message)
    {
        Console.WriteLine($"FileMessage :{message}");
    }
}
我們要來在 Controller 內,建立這個控制器的建構函式,所以,請打開 [HomeController.cs] 這個節點檔案,在這裡,我們宣告一個 IMessage 介面型別的欄位 _Message,並且建立該控制器的建構函式,我們將在該建構式內,加入 IMessage 型別參數,確認 ASP.NET Core 專案,可以透過 Unity DI Container,提供 HomeController 控制器的建構式注入能力,所以,我們將會在該建構式內,將 DI Container 注入進來的 IMessage 參數,設定給該控制器類別的欄位 _Message。
現在,我們可以在 HomeController 類別內來使用 IMessage 的各項功能了,所以,我們在 Index 動作方法內,執行了 _Message.Send("Vulcan Lee") 這個敘述,接下來,我們執行這個專案,看看是否有任何內容輸出到命令字元視窗內。
當我們執行該 ASP.NET Core 專案後,我們在命令提示字元視窗中 (下圖) ,看到了 ConsoleMessage 類別的輸出內容。
Unity DI Container Constructor Injection
C Sharp / C#
public class HomeController : Controller
{
    IMessage _Message;
    public HomeController(IMessage message)
    {
        _Message = message;
    }
    public IActionResult Index()
    {
        _Message.Send("Vulcan Lee");
        return View();
    }

    public IActionResult About()
    {
        ViewData["Message"] = "Your application description page.";

        return View();
    }

    public IActionResult Contact()
    {
        ViewData["Message"] = "Your contact page.";

        return View();
    }

    public IActionResult Privacy()
    {
        return View();
    }

    [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
    public IActionResult Error()
    {
        return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
    }
}

關於 Xamarin 在台灣的學習技術資源

Xamarin 實驗室 粉絲團
歡迎加入 Xamarin 實驗室 粉絲團,在這裡,將會經常性的貼出各種關於 Xamarin / Visual Studio / .NET 的相關消息、文章、技術開發等文件,讓您可以隨時掌握第一手的 Xamarin 方面消息。
Xamarin.Forms @ Taiwan
歡迎加入 Xamarin.Forms @ Taiwan,這是台灣的 Xamarin User Group,若您有任何關於 Xamarin / Visual Studio / .NET 上的問題,都可以在這裡來與各方高手來進行討論、交流。
Xamarin 實驗室 部落格
Xamarin 實驗室 部落格 是作者本身的部落格,這個部落格將會專注於 Xamarin 之跨平台 (Android / iOS / UWP) 方面的各類開技術探討、研究與分享的文章,最重要的是,它是全繁體中文。
Xamarin.Forms 系列課程
Xamarin.Forms 系列課程 想要快速進入到 Xamarin.Forms 的開發領域,學會各種 Xamarin.Forms 跨平台開發技術,例如:MVVM、Prism、Data Binding、各種 頁面 Page / 版面配置 Layout / 控制項 Control 的用法等等,千萬不要錯過這些 Xamarin.Forms 課程

2018年8月11日 星期六

在 async void 方法內,無法捕捉到例外異常 Exception 的情況與解決方法

在 async void 方法內,無法捕捉到例外異常 Exception 的情況與解決方法

在這篇文章,我們將會透過 ILSpy 來進行 .NET 組件反組譯碼,來查看當我們使用了 async void 這樣的非同步方式設計,並且產生了一個例外異常,在我們呼叫這個非同步方法的時候,是無法捕捉到例外異常 Exception 的範例程式碼。
為了要能夠查看我們寫的範例專案的反組譯 IL 碼,我們可以安裝 ICSharpCode.Decompiler 這個 NuGet 套件,這樣,我們就可以在 Visual Studio 2017 內,直接查看到建置完成後的組件 IL 碼。所以,請在您建立的專案中,在 NuGet 安裝視窗中,輸入 ICSharpCode.Decompiler 關鍵字,找出這個套件,我們在這裡將會安裝 搶鮮版 的 4.0.0.4285-beta1 這個版本套件。
Install ICSharpCode.Decompiler NuGet Package
現在,我們完成我們的測試程式碼,我們在主程式將會同步呼叫 AsyncVoidException_Capture() 方法,在這個方法內,我們會呼叫 ThrowExcpetionAsync() 方法,不過,這個方法我們將會使用 async void 來宣告他是個非同步方法。接著,我們使用 try...catch 將會捕捉這個函數 ThrowExcpetionAsync() 會發生的任何例外異常。當您完成這個範例程式碼之後,請在 throw 這個敘述上設定一個中斷點,我們來看看 AsyncVoidException_Capture() 這個方法,是否可以捕捉到 ThrowExcpetionAsync() 方法內所產生的例外異常。
C Sharp / C#
class Program
{
    static void Main(string[] args)
    {
        AsyncVoidException_Capture();
    }

    private static void AsyncVoidException_Capture()
    {
        try
        {
            ThrowExcpetionAsync();
        }
        catch (Exception)
        {
            // 這裡無法捕捉到例外異常
            throw;
        }
    }

    private static async void ThrowExcpetionAsync()
    {
        throw new Exception("Async Void Exception");
    }
}
底下是我們實際執行結果,您會看到,在第 19 行,我們是無法捕捉到這個方法所產生的例外異常,因為,我們所設定的中斷點的敘述並沒有執行到,例外異常直接停在 async void ThrowExcpetionAsync() 方法內。
async void 方法內產生例外異常 Exception
請停止程式執行,使用滑鼠右擊專案節點,選擇 [Open output in ILSpy] 選項。
在 Visual Studio 內,使用 ILSpy 檢查 IL 碼
此時,ILSpy 程式將會啟動執行起來,請先確認左上方紅色方框處,是否勾選 [C#] 選項,並且在左方點選 [Program] 節點,現在,我們就會看到在這個建置完成後的組件內,會有許多編譯器幫我們自動產生的程式碼,也就是右下方紅色方框標示處,從這裡,我們就可以知道為什麼當 async void ThrowExcpetionAsync() 方法發生了例外異常,而 AsyncVoidException_Capture() 方法卻無法捕捉到這個例外異常。
Async Void Method
讓我們在 ILSpy 中,點選左上方下拉選單,切換成為 IL with C# 選項,接著,點選左方清單的 ThrowExcpetionAsync 項目,我們就會看到這個方法的 IL 碼和 C# 程式碼。我們看到左方清單項目中,d__2 類別出現,這個類別將會是由編譯器自動產生的一個類別,這個類別就是一個有限狀態機,他會把這個 ThrowExcpetionAsync 方法內的敘述,使用有限狀態機包裝起來,讓我們可以順利進行非同步的程式碼呼叫。
ILSpy IL with C#
請展開左方類別 d__2 節點,將會看到 MoveNext():void 這個節點,請點選這個節點,您將會看到這個方法 ThrowExcpetionAsync 內的 相關敘述,右方視窗紅色方框標示處,就是這個方法的 throw new Exception("Async Void Exception"); 之 IL 碼。
ILSpy IL with C#
現在,我們將原先的 private static async void ThrowExcpetionAsync() 函式簽章,修改成為同步方法的 private static void ThrowExcpetionAsync() 函式簽章,也就是我們將 async 這個關鍵字移除了。現在,我們可以重新建置這個專案
C Sharp / C#
class Program
{
    static void Main(string[] args)
    {
        AsyncVoidException_Capture();
    }

    private static void AsyncVoidException_Capture()
    {
        try
        {
            ThrowExcpetionAsync();
        }
        catch (Exception)
        {
            // 這裡無法捕捉到例外異常
            throw;
        }
    }

    private static void ThrowExcpetionAsync()
    {
        throw new Exception("Async Void Exception");
    }
}
好的,讓我們來執行這個同步方法,現在,我們可以看到,在 AsyncVoidException_Capture() 內,確實可以捕捉到 ThrowExcpetionAsync() 所產生的例外異常了。請接著停止執行該專案。
Async Void Method
讓我們回到 ILSpy ,點選功能表 [File] > [Reload] 選項,並且左上方下拉選單,請選擇 [C#] 選項,最後,點選右方的 [Program] 節點,現在,我們可以看到在組件中所產生這樣的同步方法,並沒有被編譯器做額外的內容。
Async Void Method
讓我們在 ILSpy 左上方的下拉選單,切換選擇 [IL with C#],我們可以查看 ThrowExcpetionAsync() 的 IL 碼,也是沒有任何編譯器自動產生的類別與有限狀態機的設定程式碼,這裡將會是很單純的只有丟出一個例外異常而已。
Async Void Method

關於 Xamarin 在台灣的學習技術資源

Xamarin 實驗室 粉絲團
歡迎加入 Xamarin 實驗室 粉絲團,在這裡,將會經常性的貼出各種關於 Xamarin / Visual Studio / .NET 的相關消息、文章、技術開發等文件,讓您可以隨時掌握第一手的 Xamarin 方面消息。
Xamarin.Forms @ Taiwan
歡迎加入 Xamarin.Forms @ Taiwan,這是台灣的 Xamarin User Group,若您有任何關於 Xamarin / Visual Studio / .NET 上的問題,都可以在這裡來與各方高手來進行討論、交流。
Xamarin 實驗室 部落格
Xamarin 實驗室 部落格 是作者本身的部落格,這個部落格將會專注於 Xamarin 之跨平台 (Android / iOS / UWP) 方面的各類開技術探討、研究與分享的文章,最重要的是,它是全繁體中文。
Xamarin.Forms 系列課程
Xamarin.Forms 系列課程 想要快速進入到 Xamarin.Forms 的開發領域,學會各種 Xamarin.Forms 跨平台開發技術,例如:MVVM、Prism、Data Binding、各種 頁面 Page / 版面配置 Layout / 控制項 Control 的用法等等,千萬不要錯過這些 Xamarin.Forms 課程