From 7f6552f22ffe72f89a8bf0c00c90fe539af66037 Mon Sep 17 00:00:00 2001 From: Halil ibrahim Kalkan Date: Tue, 18 Dec 2018 14:00:09 +0300 Subject: [PATCH] Resolved #486: AutoFac integration document. --- docs/en/Autofac-Integration.md | 85 ++++++++++++++++++- docs/en/Dependency-Injection.md | 44 ++++++---- .../Getting-Started-AspNetCore-Application.md | 18 ++-- .../en/Getting-Started-Console-Application.md | 71 ++++++++++++++-- .../AbpConsoleDemo/AbpConsoleDemo.csproj | 2 +- .../AbpConsoleDemo/AppModule.cs | 2 + .../AbpConsoleDemo/Program.cs | 9 +- 7 files changed, 193 insertions(+), 38 deletions(-) diff --git a/docs/en/Autofac-Integration.md b/docs/en/Autofac-Integration.md index 355313235fc..b3aced3e940 100644 --- a/docs/en/Autofac-Integration.md +++ b/docs/en/Autofac-Integration.md @@ -1,3 +1,84 @@ -## Autofac Integration +# Autofac Integration + +Autofac is one of the most used dependency injection frameworks for .Net. It provides some advanced features compared to .Net Core standard DI library, like dynamic proxying and property injection. + +## Install Autofac Integration + +> All startup templates and samples are Autofac integrated. So, most of the time you don't need to manually install this package. + +Install [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) nuget package to your project (for a multi-projects application, it's suggested to add to the executable/web project.) + +```` +Install-Package Volo.Abp.Autofac +```` + +Then add `AbpAutofacModule` dependency to your module: + +```csharp +using Volo.Abp.Modularity; +using Volo.Abp.Autofac; + +namespace MyCompany.MyProject +{ + [DependsOn(typeof(AbpAutofacModule))] + public class MyModule : AbpModule + { + //... + } +} +``` + +Finally, configure `AbpApplicationCreationOptions` to replace default dependency injection services by Autofac. It depends on the application type. + +### ASP.NET Core Application + +Call `UseAutofac()` in the **Startup.cs** file as shown below: + +````csharp +public class Startup +{ + public IServiceProvider ConfigureServices(IServiceCollection services) + { + services.AddApplication(options => + { + //Integrate Autofac! + options.UseAutofac(); + }); + + return services.BuildServiceProviderFromFactory(); + } + + public void Configure(IApplicationBuilder app) + { + app.InitializeApplication(); + } +} +```` + +### Console Application + +Call `UseAutofac()` method in the `AbpApplicationFactory.Create` options as shown below: + +````csharp +using System; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; + +namespace AbpConsoleDemo +{ + class Program + { + static void Main(string[] args) + { + using (var application = AbpApplicationFactory.Create(options => + { + options.UseAutofac(); //Autofac integration + })) + { + //... + } + } + } +} +```` -TODO \ No newline at end of file diff --git a/docs/en/Dependency-Injection.md b/docs/en/Dependency-Injection.md index a001d52ec9b..5186f29717f 100644 --- a/docs/en/Dependency-Injection.md +++ b/docs/en/Dependency-Injection.md @@ -1,8 +1,10 @@ -## Dependency Injection +# Dependency Injection ABP's Dependency Injection system is developed based on Microsoft's [dependency injection extension](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection) library (Microsoft.Extensions.DependencyInjection nuget package). So, it's documentation is valid in ABP too. -### Modularity +> While ABP has no core dependency to any 3rd-party DI provider, it's required to use a provider that supports dynamic proxying and some other advanced features to make some ABP features properly work. Startup templates come with Autofac installed. See [Autofac integration](Autofac-Integration.md) document for more information. + +## Modularity Since ABP is a modular framework, every module defines it's own services and registers via dependency injection in it's own seperate [module class](Module-Development-Basics.md). Example: @@ -16,7 +18,7 @@ public class BlogModule : AbpModule } ```` -### Conventional Registration +## Conventional Registration ABP introduces conventional service registration. You need not do anything to register a service by convention. It's automatically done. If you want to disable it, you can set `SkipAutoServiceRegistration` to `true` by overriding the `PreConfigureServices` method. @@ -49,7 +51,7 @@ public class BlogModule : AbpModule The section below explains the conventions and configurations. -#### Inherently Registered Types +### Inherently Registered Types Some specific types are registered to dependency injection by default. Examples: @@ -71,7 +73,7 @@ public class BlogPostAppService : ApplicationService ``BlogPostAppService`` is automatically registered with transient lifetime since it's derived from a known base class. -#### Dependency Interfaces +### Dependency Interfaces If you implement these interfaces, your class is registered to dependency injection automatically: @@ -89,7 +91,7 @@ public class TaxCalculator : ITransientDependency ``TaxCalculator`` is automatically registered with a transient lifetime since it implements ``ITransientDependency``. -#### Dependency Attribute +### Dependency Attribute Another way of configuring a service for dependency injection is to use ``DependencyAttribute``. It has the following properties: @@ -110,7 +112,7 @@ public class TaxCalculator ``Dependency`` attribute has a higher priority than other dependency interfaces if it defines the ``Lifetime`` property. -#### ExposeServices Attribute +### ExposeServices Attribute ``ExposeServicesAttribute`` is used to control which services are provided by the related class. Example: @@ -124,14 +126,14 @@ public class TaxCalculator: ICalculator, ITaxCalculator, ICanCalculate, ITransie ``TaxCalculator`` class only exposes ``ITaxCalculator`` interface. That means you can only inject ``ITaxCalculator``, but can not inject ``TaxCalculator`` or ``ICalculator`` in your application. -#### Exposed Services by Convention +### Exposed Services by Convention If you do not specify which services to expose, ABP expose services by convention. So taking the ``TaxCalculator`` defined above: * The class itself is exposed by default. That means you can inject it by ``TaxCalculator`` class. * Default interfaces are exposed by default. Default interfaces are determined by naming convention. In this example, ``ICalculator`` and ``ITaxCalculator`` are default interfaces of ``TaxCalculator``, but ``ICanCalculate`` is not. -#### Combining All Together +### Combining All Together Combining attributes and interfaces is possible as long as it's meaningful. @@ -144,7 +146,7 @@ public class TaxCalculator : ITaxCalculator, ITransientDependency } ```` -#### Manually Registering +### Manually Registering In some cases, you may need to register a service to the `IServiceCollection` manually, especially if you need to use custom factory methods or singleton instances. In that case, you can directly add services just as [Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection) describes. Example: @@ -157,16 +159,18 @@ public class BlogModule : AbpModule context.Services.AddSingleton(new TaxCalculator(taxRatio: 0.18)); //Register a factory method that resolves from IServiceProvider - context.Services.AddScoped(sp => sp.GetRequiredService()); + context.Services.AddScoped( + sp => sp.GetRequiredService() + ); } } ```` -### Injecting Dependencies +## Injecting Dependencies There are three common ways of using a service that has already been registered. -#### Contructor Injection +### Contructor Injection This is the most common way of injecting a service into a class. For example: @@ -191,7 +195,7 @@ public class TaxAppService : ApplicationService Constructor injection is preffered way of injecting dependencies to a class. In that way, the class can not be constructed unless all constructor-injected dependencies are provided. Thus, the class explicitly declares it's required services. -#### Property Injection +### Property Injection Property injection is not supported by Microsoft Dependency Injection library. However, ABP can integrate with 3rd-party DI providers ([Autofac](https://autofac.org/), for example) to make property injection possible. Example: @@ -222,7 +226,7 @@ One restriction of property injection is that you cannot use the dependency in y Property injection is also useful when you want to design a base class that has some common services injected by default. If you're going to use constructor injection, all derived classes should also inject depended services into their own constructors which makes development harder. However, be very careful using property injection for non-optional services as it makes it harder to clearly see the requirements of a class. -#### Resolve Service from IServiceProvider +### Resolve Service from IServiceProvider You may want to resolve a service directly from ``IServiceProvider``. In that case, you can inject IServiceProvider into your class and use ``GetService`` method as shown below: @@ -244,7 +248,7 @@ public class MyService : ITransientDependency } ```` -#### Releasing/Disposing Services +### Releasing/Disposing Services If you used a constructor or property injection, you don't need to be concerned about releasing the service's resources. However, if you have resolved a service from ``IServiceProvider``, you might, in some cases, need to take care about releasing the service resources. @@ -266,6 +270,12 @@ using (var scope = _serviceProvider.CreateScope()) Both services are released when the created scope is disposed (at the end of the using block). -### See Also +## 3rd-Party Providers + +While ABP has no core dependency to any 3rd-party DI provider, it's required to use a provider that supports dynamic proxying and some other advanced features to make some ABP features properly work. + +Startup templates come with Autofac installed. See [Autofac integration](Autofac-Integration.md) document for more information. + +## See Also * [ASP.NET Core Dependency Injection Best Practices, Tips & Tricks](https://medium.com/volosoft/asp-net-core-dependency-injection-best-practices-tips-tricks-c6e9c67f9d96) diff --git a/docs/en/Getting-Started-AspNetCore-Application.md b/docs/en/Getting-Started-AspNetCore-Application.md index f242f8cd46b..8c0d03b6bb4 100644 --- a/docs/en/Getting-Started-AspNetCore-Application.md +++ b/docs/en/Getting-Started-AspNetCore-Application.md @@ -1,8 +1,8 @@ -## Getting Started ABP With AspNet Core MVC Web Application +# Getting Started ABP With AspNet Core MVC Web Application This tutorial explains how to start ABP from scratch with minimal dependencies. You generally want to start with a **[startup template](https://abp.io/Templates)**. -### Create A New Project +## Create A New Project 1. Create a new empty AspNet Core Web Application from Visual Studio: @@ -14,7 +14,7 @@ This tutorial explains how to start ABP from scratch with minimal dependencies. You could select another template, but I want to show it from a clear project. -### Install Volo.Abp.AspNetCore.Mvc Package +## Install Volo.Abp.AspNetCore.Mvc Package Volo.Abp.AspNetCore.Mvc is AspNet Core MVC integration package for ABP. So, install it to your project: @@ -22,7 +22,7 @@ Volo.Abp.AspNetCore.Mvc is AspNet Core MVC integration package for ABP. So, inst Install-Package Volo.Abp.AspNetCore.Mvc ```` -### Create First ABP Module +## Create First ABP Module ABP is a modular framework and it requires a **startup (root) module** class derived from ``AbpModule``: @@ -62,7 +62,7 @@ ABP packages define module classes and a module can depend on another module. In Instead of Startup class, we are configuring ASP.NET Core pipeline in this module class. -### The Startup Class +## The Startup Class Next step is to modify Startup class to integrate to ABP module system: @@ -95,7 +95,7 @@ Changed ``ConfigureServices`` method to return ``IServiceProvider`` instead of ` ``app.InitializeApplication()`` call in ``Configure`` method initializes and starts the application. -### Hello World! +## Hello World! The application above does nothing. Let's create an MVC controller does something: @@ -120,13 +120,13 @@ If you run the application, you will see a "Hello World!" message on the page. Derived ``HomeController`` from ``AbpController`` instead of standard ``Controller`` class. This is not required, but ``AbpController`` class has useful base properties and methods to make your development easier. -### Using Autofac as the Dependency Injection Framework +## Using Autofac as the Dependency Injection Framework While AspNet Core's Dependency Injection (DI) system is fine for basic requirements, Autofac provides advanced features like Property Injection and Method Interception which are required by ABP to perform advanced application framework features. Replacing AspNet Core's DI system by Autofac and integrating to ABP is pretty easy. -1. Install Volo.Abp.Autofac package +1. Install [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) package ```` Install-Package Volo.Abp.Autofac @@ -152,6 +152,6 @@ services.AddApplication(options => }); ```` -### Source Code +## Source Code Get source code of the sample project created in this tutorial from [here](https://github.com/abpframework/abp/tree/master/samples/BasicAspNetCoreApplication). diff --git a/docs/en/Getting-Started-Console-Application.md b/docs/en/Getting-Started-Console-Application.md index 4200bb6ca7f..f6ba588ac74 100644 --- a/docs/en/Getting-Started-Console-Application.md +++ b/docs/en/Getting-Started-Console-Application.md @@ -1,14 +1,14 @@ -## Getting Started ABP With Console Application +# Getting Started ABP With Console Application This tutorial explains how to start ABP from scratch with minimal dependencies. You generally want to start with a **[startup template](https://abp.io/Templates)**. -### Create A New Project +## Create A New Project Create a new Regular .Net Core Console Application from Visual Studio: ![](images/create-new-net-core-console-application.png) -### Install Volo.Abp Package +## Install Volo.Abp Package Volo.Abp.Core is the core nuget package to create ABP based applications. So, install it to your project: @@ -16,7 +16,7 @@ Volo.Abp.Core is the core nuget package to create ABP based applications. So, in Install-Package Volo.Abp.Core ```` -### Create First ABP Module +## Create First ABP Module ABP is a modular framework and it requires a **startup (root) module** class derived from ``AbpModule``: @@ -35,7 +35,7 @@ namespace AbpConsoleDemo ``AppModule`` is a good name for the startup module for an application. -### Initialize The Application +## Initialize The Application The next step is to bootstrap the application using the startup module created above: @@ -64,7 +64,7 @@ namespace AbpConsoleDemo ``AbpApplicationFactory`` is used to create the application and load all modules taking ``AppModule`` as the startup module. ``Initialize()`` method starts the application. -### Hello World! +## Hello World! The application above does nothing. Let's create a service that does something: @@ -119,6 +119,63 @@ namespace AbpConsoleDemo While it's enough for this simple code example, it's always suggested to create scopes in case of directly resolving dependencies from ``IServiceProvider`` (see the [Dependency Injection documentation](Dependency-Injection.md)). -### Source Code +## Using Autofac as the Dependency Injection Framework + +While AspNet Core's Dependency Injection (DI) system is fine for basic requirements, Autofac provides advanced features like Property Injection and Method Interception which are required by ABP to perform advanced application framework features. + +Replacing AspNet Core's DI system by Autofac and integrating to ABP is pretty easy. + +1. Install [Volo.Abp.Autofac](https://www.nuget.org/packages/Volo.Abp.Autofac) package + +``` +Install-Package Volo.Abp.Autofac +``` + +1. Add ``AbpAutofacModule`` Dependency + +```c# +[DependsOn(typeof(AbpAutofacModule))] //Add dependency to ABP Autofac module +public class AppModule : AbpModule +{ + ... +} +``` + +1. Change ``Program.cs`` file as shown below: + +```c# +using System; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; + +namespace AbpConsoleDemo +{ + class Program + { + static void Main(string[] args) + { + using (var application = AbpApplicationFactory.Create(options => + { + options.UseAutofac(); //Autofac integration + })) + { + application.Initialize(); + + //Resolve a service and use it + var helloWorldService = + application.ServiceProvider.GetService(); + helloWorldService.SayHello(); + + Console.WriteLine("Press ENTER to stop application..."); + Console.ReadLine(); + } + } + } +} +``` + +Just called `options.UseAutofac()` method in the `AbpApplicationFactory.Create` options. + +## Source Code Get source code of the sample project created in this tutorial from [here](https://github.com/abpframework/abp/tree/master/samples/BasicConsoleApplication). diff --git a/samples/BasicConsoleApplication/AbpConsoleDemo/AbpConsoleDemo.csproj b/samples/BasicConsoleApplication/AbpConsoleDemo/AbpConsoleDemo.csproj index 04d15573929..a08c8bd0b9d 100644 --- a/samples/BasicConsoleApplication/AbpConsoleDemo/AbpConsoleDemo.csproj +++ b/samples/BasicConsoleApplication/AbpConsoleDemo/AbpConsoleDemo.csproj @@ -6,7 +6,7 @@ - + diff --git a/samples/BasicConsoleApplication/AbpConsoleDemo/AppModule.cs b/samples/BasicConsoleApplication/AbpConsoleDemo/AppModule.cs index 0449d84b996..07b4fa3ec35 100644 --- a/samples/BasicConsoleApplication/AbpConsoleDemo/AppModule.cs +++ b/samples/BasicConsoleApplication/AbpConsoleDemo/AppModule.cs @@ -1,8 +1,10 @@ using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Autofac; using Volo.Abp.Modularity; namespace AbpConsoleDemo { + [DependsOn(typeof(AbpAutofacModule))] public class AppModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) diff --git a/samples/BasicConsoleApplication/AbpConsoleDemo/Program.cs b/samples/BasicConsoleApplication/AbpConsoleDemo/Program.cs index 5f0dc68d368..651fda3c4fd 100644 --- a/samples/BasicConsoleApplication/AbpConsoleDemo/Program.cs +++ b/samples/BasicConsoleApplication/AbpConsoleDemo/Program.cs @@ -8,11 +8,16 @@ class Program { static void Main(string[] args) { - using (var application = AbpApplicationFactory.Create()) + using (var application = AbpApplicationFactory.Create(options => + { + options.UseAutofac(); //Autofac integration + })) { application.Initialize(); - var helloWorldService = application.ServiceProvider.GetService(); + //Resolve a service and use it + var helloWorldService = + application.ServiceProvider.GetService(); helloWorldService.SayHello(); Console.WriteLine("Press ENTER to stop application...");