一般的な Web アプリケーション アーキテクチャCommon web application architectures

"優れたアーキテクチャが高価であると思うならば、不完全なアーキテクチャを試してみてください。""If you think good architecture is expensive, try bad architecture."
- Brian Foote および Joseph Yoder- Brian Foote and Joseph Yoder

従来の .NET アプリケーションのほとんどは、実行可能ファイルに対応する単一のユニットとして、または 1 つの IIS appdomain 内で実行される単一の Web アプリケーションとして展開されます。Most traditional .NET applications are deployed as single units corresponding to an executable or a single web application running within a single IIS appdomain. これは最も簡単な展開モデルであり、多くの内部的アプリケーションおよび小さなパブリック アプリケーションに適切に対応します。This is the simplest deployment model and serves many internal and smaller public applications very well. ただし、このように単位ユニットとして展開されても、重要なビジネス アプリケーションの大部分は複数のレイヤーへの論理的な分離から恩恵を受けます。However, even given this single unit of deployment, most non-trivial business applications benefit from some logical separation into several layers.

モノリシック アプリケーションとは?What is a monolithic application?

モノリシック アプリケーションは、そのビヘイビアーの観点から見ると、完全な自己独立型のアプリケーションです。A monolithic application is one that is entirely self-contained, in terms of its behavior. このアプリケーションは、操作の実行中に他のサービスまたはデータ ストアとやり取りすることがありますが、アプリケーションのビヘイビアーの中核を成す部分は独自のプロセス内で実行され、通常はアプリケーション全体が単一ユニットとして展開されます。It may interact with other services or data stores in the course of performing its operations, but the core of its behavior runs within its own process and the entire application is typically deployed as a single unit. このようなアプリケーションを水平方向にスケーリングする必要がある場合、通常は、アプリケーション全体を複数のサーバーまたは仮想マシンに複製します。If such an application needs to scale horizontally, typically the entire application is duplicated across multiple servers or virtual machines.

オールインワン アプリケーションAll-in-one applications

アプリケーション アーキテクチャ用の最小限のプロジェクト数は 1 となります。The smallest possible number of projects for an application architecture is one. このアーキテクチャでは、アプリケーションのロジック全体が単一のプロジェクトに含められ、単一のアセンブリにコンパイルされ、単一ユニットとして展開されます。In this architecture, the entire logic of the application is contained in a single project, compiled to a single assembly, and deployed as a single unit.

新しい ASP.NET Core プロジェクトは、Visual Studio またはコマンド ラインのいずれで作成されたかに関係なく、簡単な "オールインワン" モノシリックとして開始されます。A new ASP.NET Core project, whether created in Visual Studio or from the command line, starts out as a simple "all-in-one" monolith. これには、プレゼンテーション、ビジネス、データ アクセス ロジックなど、アプリケーションのあらゆるビヘイビアーが含まれています。It contains all of the behavior of the application, including presentation, business, and data access logic. 図 5-1 に、単一プロジェクト アプリのファイル構造を示します。Figure 5-1 shows the file structure of a single-project app.

図 5-1Figure 5-1. 単一プロジェクトの ASP.NET Core アプリ。A single project ASP.NET Core app.

単一プロジェクトのシナリオでは、フォルダーを使用して懸念事項の分離が実現されます。In a single project scenario, separation of concerns is achieved through the use of folders. 既定のテンプレートには、Models、Views、および Controllers の MVC パターン責任用の分離フォルダーに加えて、Data および Services 用の追加のフォルダーが含まれています。The default template includes separate folders for MVC pattern responsibilities of Models, Views, and Controllers, as well as additional folders for Data and Services. この配置では、プレゼンテーションの詳細は可能な限り Views フォルダーに限定する必要があり、データ アクセス実装の詳細は Data フォルダー内に保持されるクラスに限定する必要があります。In this arrangement, presentation details should be limited as much as possible to the Views folder, and data access implementation details should be limited to classes kept in the Data folder. ビジネス ロジックは、Models フォルダーにあるサービスとモデル内に配置する必要があります。Business logic should reside in services and classes within the Models folder.

単一プロジェクトのモノリシック ソリューションは簡単なのですが、いくつかの欠点があります。Although simple, the single-project monolithic solution has some disadvantages. プロジェクトの規模と複雑さが増大するに従い、ファイルとフォルダーの数も増加し続けます。As the project's size and complexity grows, the number of files and folders will continue to grow as well. アルファベット順にグループ化されていない複数のフォルダーには、ユーザー インターフェイス (UI) の懸念事項 (モデル、ビュー、コントローラー) が存在します。User interface (UI) concerns (models, views, controllers) reside in multiple folders, which aren't grouped together alphabetically. この問題は、Filters や ModelBinders などの UI レベル構造が独自のフォルダーに追加される場合にのみ深刻になります。This issue only gets worse when additional UI-level constructs, such as Filters or ModelBinders, are added in their own folders. ビジネス ロジックは Models フォルダーと Services フォルダーに分散され、どのフォルダーのどのクラスが他のどれに依存すべきかは明示されません。Business logic is scattered between the Models and Services folders, and there's no clear indication of which classes in which folders should depend on which others. プロジェクト レベルでのこの編成不足は、スパゲティ コードの原因となることがよくあります。This lack of organization at the project level frequently leads to spaghetti code.

これらの問題に対処するために、アプリケーションは多くの場合、マルチ プロジェクト ソリューションに展開されます。ここで、各プロジェクトは、アプリケーションの特定の_レイヤー_ に配置されているとみなされます。To address these issues, applications often evolve into multi-project solutions, where each project is considered to reside in a particular layer of the application.

レイヤーとは?What are layers?

アプリケーションの複雑さが増すにつれて、その複雑さを管理することが必要です。その方法の 1 つが、アプリケーションをその責任や懸念事項に従って分割するというものです。As applications grow in complexity, one way to manage that complexity is to break up the application according to its responsibilities or concerns. この方法は懸念事項の分離の原則に従って実施されます。また、この方法を使用すれば、特定の機能が実装されている場所を開発者が容易に見つけられるように、増大するコードベースを常に整理された状態に維持することができます。This follows the separation of concerns principle, and can help keep a growing codebase organized so that developers can easily find where certain functionality is implemented. ただし、レイヤー化されたアーキテクチャには、単なるコード編成に勝る利点が複数あります。Layered architecture offers a number of advantages beyond just code organization, though.

コードをレイヤーに編成することにより、よく使われる下位機能をアプリケーション全体で再利用できるようになります。By organizing code into layers, common low-level functionality can be reused throughout the application. この再利用を行うと、コードをほとんど記述する必要がなくなり、DRY (don't repeat yourself) 原則に従って単一の実装でアプリケーションを標準化できるようになるので、便利です。This reuse is beneficial because it means less code needs to be written and because it can allow the application to standardize on a single implementation, following the don't repeat yourself (DRY) principle.

レイヤー化されたアーキテクチャの場合、アプリケーションではレイヤー間のやり取りに対して制限を加えることができます。With a layered architecture, applications can enforce restrictions on which layers can communicate with other layers. この制限を利用することで、カプセル化を容易に実現できます。This helps to achieve encapsulation. レイヤーを変更または置換した場合、そのレイヤーと連携しているその他のレイヤーのみが影響を受けます。When a layer is changed or replaced, only those layers that work with it should be impacted. レイヤー同士の依存関係を制限することにより、1 つの変更がアプリケーション全体に影響しないように変更の及ぼす影響を軽減することができます。By limiting which layers depend on which other layers, the impact of changes can be mitigated so that a single change doesn't impact the entire application.

レイヤー (およびカプセル化) により、アプリケーション内で機能を容易に置換できるようになります。Layers (and encapsulation) make it much easier to replace functionality within the application. たとえば、アプリケーションで最初は永続化のために独自の SQL Server データベースが使用されている場合でも、後でクラウド ベースの永続化の方法または Web API の背後での永続化の方法を使用するように選択することが可能です。For example, an application might initially use its own SQL Server database for persistence, but later could choose to use a cloud-based persistence strategy, or one behind a web API. 論理層内でアプリケーションによって永続化の実装が適切にカプセル化されている場合、その SQL Server に固有のレイヤーを、同じパブリック インターフェイスを実装する新しいレイヤーに置き換えることが可能です。If the application has properly encapsulated its persistence implementation within a logical layer, that SQL Server specific layer could be replaced by a new one implementing the same public interface.

将来的な要件の変更に合わせて実装を交換できることに加えて、アプリケーション レイヤーではテスト目的で実装を容易に交換することもできます。In addition to the potential of swapping out implementations in response to future changes in requirements, application layers can also make it easier to swap out implementations for testing purposes. アプリケーションの実際のデータ レイヤーまたは UI レイヤーに対して動作するテストを記述しなくても、これらのレイヤーをテスト時に、要求に対して既知の応答を提供するフェイク実装に置き換えることができます。Instead of having to write tests that operate against the real data layer or UI layer of the application, these layers can be replaced at test time with fake implementations that provide known responses to requests. この方法は、アプリケーションの実際のインフラストラクチャに対してテストを実行する場合と比較して、一般的にテストの記述が簡単であり、テストをより迅速に実行することができます。This typically makes tests much easier to write and much faster to run when compared to running tests again the application's real infrastructure.

論理的なレイヤー化は、エンタープライズ ソフトウェア アプリケーションでのコード編成を改善するための一般的な手法です。コードをレイヤーに編成する方法には複数あります。Logical layering is a common technique for improving the organization of code in enterprise software applications, and there are several ways in which code can be organized into layers.

注意

"レイヤー" とは、アプリケーション内での論理的な分離を表します。Layers represent logical separation within the application. アプリケーション ロジックを個々のサーバーまたはプロセスに物理的に分散するイベントでは、このような個々の物理的展開ターゲットを "階層" と呼んでいます。In the event that application logic is physically distributed to separate servers or processes, these separate physical deployment targets are referred to as tiers. N レイヤー アプリケーションを単一の階層に展開することは可能であり、これは非常に一般的な方法です。It's possible, and quite common, to have an N-Layer application that is deployed to a single tier.

従来の "N レイヤー" アーキテクチャ アプリケーションTraditional "N-Layer" architecture applications

図 5-2 に、レイヤーへのアプリケーション ロジックの最も一般的な編成を示します。The most common organization of application logic into layers is shown in Figure 5-2.

図 5-2Figure 5-2. 代表的なアプリケーション レイヤー。Typical application layers.

これらのレイヤーは多くの場合、UI、BLL (ビジネス ロジック層)、DAL (データ アクセス層) と略称で表現されます。These layers are frequently abbreviated as UI, BLL (Business Logic Layer), and DAL (Data Access Layer). このアーキテクチャを使用する場合、ユーザーは UI レイヤーを介して要求を行います。UI レイヤーは BLL とのみやり取りします。Using this architecture, users make requests through the UI layer, which interacts only with the BLL. 次に BLL は、データ アクセス要求のために DAL を呼び出すことができます。The BLL, in turn, can call the DAL for data access requests. UI レイヤーは DAL に要求を直接出すことも、他の手段によって永続化と直接やり取りすることもありません。The UI layer shouldn't make any requests to the DAL directly, nor should it interact with persistence directly through other means. 同様に、BLL は DAL を経由して永続化とやり取りするだけです。Likewise, the BLL should only interact with persistence by going through the DAL. この方法では、各レイヤーには独自の既知の責任があります。In this way, each layer has its own well-known responsibility.

この従来のレイヤー化アプローチの欠点の 1 つは、コンパイル時の依存関係が上位から下位に向かって適用されるということです。One disadvantage of this traditional layering approach is that compile-time dependencies run from the top to the bottom. つまり、UI レイヤーは BLL に依存し、BLL は DAL に依存するということです。That is, the UI layer depends on the BLL, which depends on the DAL. このことは、アプリケーション内で、通常、最も重要なロジックを保持する BLL が、データ アクセスの実装の詳細 (およびしばしばデータベースの存在) に依存することを意味します。This means that the BLL, which usually holds the most important logic in the application, is dependent on data access implementation details (and often on the existence of a database). このようなアーキテクチャでビジネス ロジックをテストするのは困難なことが多く、テスト データベースが必要となります。Testing business logic in such an architecture is often difficult, requiring a test database. 次のセクションで示すように、依存関係逆転の原則 (Dependency Inversion principle) を使用すれば、この問題に対処できます。The dependency inversion principle can be used to address this issue, as you'll see in the next section.

図 5-3 に、責任 (またはレイヤー) ごとに 3 つのプロジェクトにアプリケーションを分割するソリューションの例を示します。Figure 5-3 shows an example solution, breaking the application into three projects by responsibility (or layer).

図 5-3Figure 5-3. 3 つのプロジェクトによる単純なモノリシック アプリケーション。A simple monolithic application with three projects.

このアプリケーションでは編成上の目的で複数のプロジェクトを使用していますが、アプリケーションは引き続き単一ユニットとして展開され、そのクライアントは単一の Web アプリとしてこのアプリケーションとやり取りします。Although this application uses several projects for organizational purposes, it's still deployed as a single unit and its clients will interact with it as a single web app. これにより、展開プロセスが非常に簡単になります。This allows for very simple deployment process. 図 5-4 に、そのようなアプリを Azure を使用してホストする場合の方法を示します。Figure 5-4 shows how such an app might be hosted using Azure.

図 5-4Figure 5-4. Azure Web アプリの単純な展開Simple deployment of Azure Web App

アプリケーション ニーズの拡大に合わせて、より複雑で堅牢な展開ソリューションが必要な場合があります。As application needs grow, more complex and robust deployment solutions may be required. 図 5-5 に、追加の機能をサポートするより複雑な展開計画の例を示します。Figure 5-5 shows an example of a more complex deployment plan that supports additional capabilities.

図 5-5Figure 5-5. Azure App Service への Web アプリの公開Deploying a web app to an Azure App Service

内部的には、このプロジェクトを責任に基づいて複数のプロジェクトに編成することにより、アプリケーションの保守容易性が向上します。Internally, this project's organization into multiple projects based on responsibility improves the maintainability of the application.

このユニットをスケール アップまたはスケール アウトすることで、クラウド ベースのオンデマンドのスケーラビリティを活用することができます。This unit can be scaled up or out to take advantage of cloud-based on-demand scalability. スケール アップとは、アプリをホストしているサーバーに CPU、メモリ、ディスク領域などのリソースを追加することを意味します。Scaling up means adding additional CPU, memory, disk space, or other resources to the server(s) hosting your app. スケール アウトとは、そのようなサーバーが物理サーバーか仮想マシンかに関係なく、サーバーのインスタンスを追加することを意味します。Scaling out means adding additional instances of such servers, whether these are physical servers or virtual machines. アプリが複数のインスタンスでホストされている場合は、ロード バランサーを使用して個々のアプリ インスタンスに要求が割り当てられます。When your app is hosted across multiple instances, a load balancer is used to assign requests to individual app instances.

Azure 内で Web アプリケーションをスケーリングする最も簡単な方法は、アプリケーションの App Service プランでスケーリングを手動で構成するというものです。The simplest approach to scaling a web application in Azure is to configure scaling manually in the application's App Service Plan. 図 5-6 に、アプリを提供しているインスタンスの数を構成する適切な Azure ダッシュボード画面を示します。Figure 5-6 shows the appropriate Azure dashboard screen to configure how many instances are serving an app.

図 5-6Figure 5-6. App での App Service プランによるスケーリング。App Service Plan scaling in Azure.

クリーン アーキテクチャClean architecture

依存関係逆転の原則ならびにドメイン駆動設計 (DDD) の原則に従うアプリケーションは、同様のアーキテクチャに到達する傾向があります。Applications that follow the Dependency Inversion Principle as well as the Domain-Driven Design (DDD) principles tend to arrive at a similar architecture. このアーキテクチャには長年にわたってさまざまな名称が付けられてきました。This architecture has gone by many names over the years. 最初の名前の 1 つがヘキサゴナル アーキテクチャ (Hexagonal Architecture) でした。その後に使用された名前がポート アンド アダプター (Ports-and-Adapters) でした。One of the first names was Hexagonal Architecture, followed by Ports-and-Adapters. 最近では、このアーキテクチャはオニオン アーキテクチャまたはクリーン アーキテクチャとして引用されています。More recently, it's been cited as the Onion Architecture or Clean Architecture. 後者のクリーン アーキテクチャは、この電子書籍でアーキテクチャの名前として使用されています。The latter name, Clean Architecture, is used as the name for this architecture in this e-book.

注意

クリーン アーキテクチャという用語は、DDD 原則を使用して構築されたアプリケーションにも、DDD 原則を使用して構築されていないアプリケーションにも適用できます。The term Clean Architecture can be applied to applications that are built using DDD Principles as well as to those that are not built using DDD. 前者の場合、この組み合わせを "クリーン DDD アーキテクチャ" と呼ぶことがあります。In the case of the former, this combination may be referred to as "Clean DDD Architecture".

クリーン アーキテクチャでは、ビジネス ロジックとアプリケーション モデルをアプリケーションの中心に配置します。Clean architecture puts the business logic and application model at the center of the application. ビジネス ロジックはデータ アクセスまたはその他のインフラストラクチャの懸念事項に依存するのでなく、この依存関係は逆転されます。つまり、インフラストラクチャおよび実装の詳細はアプリケーション コアに依存します。Instead of having business logic depend on data access or other infrastructure concerns, this dependency is inverted: infrastructure and implementation details depend on the Application Core. これを達成するには、アプリケーション コア内で抽象化またはインターフェイスを定義し、それらをインフラストラクチャ レイヤーで定義された型によって実装します。This is achieved by defining abstractions, or interfaces, in the Application Core, which are then implemented by types defined in the Infrastructure layer. このアーキテクチャを視覚化するための一般的な方法としては、オニオンに似た一連の同心円を使用します。A common way of visualizing this architecture is to use a series of concentric circles, similar to an onion. 図 5-7 に、このスタイルのアーキテクチャを表現した例を示します。Figure 5-7 shows an example of this style of architectural representation.

図 5-7Figure 5-7. クリーン アーキテクチャ。オニオン ビューClean Architecture; onion view

この図では、依存関係が最も内側の円に向かっています。In this diagram, dependencies flow toward the innermost circle. アプリケーション コアという名前は、この図の中心に位置するところから取ったものです。The Application Core takes its name from its position at the core of this diagram. この図から、アプリケーション コアが他のアプリケーション レイヤーに依存していないことがわかります。And you can see on the diagram that the Application Core has no dependencies on other application layers. アプリケーションのエンティティとインターフェイスは真中にあります。The application's entities and interfaces are at the very center. そのすぐ外側 (まだアプリケーション コア内) は、ドメイン サービスです。ここでは通常、内側の円で定義されたインターフェイスを実装します。Just outside, but still in the Application Core, are domain services, which typically implement interfaces defined in the inner circle. アプリケーション コアの外側には、UI レイヤーとインフラストラクチャ レイヤーがあり、これらの両方がアプリケーション コアに依存しますが、相互に依存関係があるとは限りません。Outside of the Application Core, both the UI and the Infrastructure layers depend on the Application Core, but not on one another (necessarily).

図 5-8 に、UI とその他のレイヤーの間の依存関係をより正確に反映させた、従来の水平方向レイヤー図を示します。Figure 5-8 shows a more traditional horizontal layer diagram that better reflects the dependency between the UI and other layers.

図 5-8Figure 5-8. クリーン アーキテクチャ。水平方向のレイヤー ビューClean Architecture; horizontal layer view

破線の矢印はコンパイル時の依存関係を表し、実線の矢印は実行時専用の依存関係を表します。Note that the solid arrows represent compile-time dependencies, while the dashed arrow represents a runtime-only dependency. クリーン アーキテクチャを使用する場合、UI レイヤーではコンパイル時にアプリケーション コアで定義されたインターフェイスを操作します。インフラストラクチャ レイヤーで定義された実装型を把握しなくてもよいのが理想的です。With the clean architecture, the UI layer works with interfaces defined in the Application Core at compile time, and ideally shouldn't know about the implementation types defined in the Infrastructure layer. ただし、実行時にこれらの実装型は、アプリを実行するために必須となるので、存在する必要があり、また依存関係挿入を介してアプリケーション コアのインターフェイスに接続される必要があります。At run time, however, these implementation types are required for the app to execute, so they need to be present and wired up to the Application Core interfaces via dependency injection.

図 5-9 に、これらの推奨事項に従って ASP.NET Core アプリケーションのアーキテクチャを構築した場合の詳細なビューを示します。Figure 5-9 shows a more detailed view of an ASP.NET Core application's architecture when built following these recommendations.

ASPNET コア アーキテクチャ

図 5-9Figure 5-9. クリーン アーキテクチャに基づく ASP.NET Core アーキテクチャの図。ASP.NET Core architecture diagram following Clean Architecture.

アプリケーション コアはインフラストラクチャに依存していないので、このレイヤーを対象にした自動化された単体テストを記述するのは非常に簡単です。Because the Application Core doesn't depend on Infrastructure, it's very easy to write automated unit tests for this layer. 図 5-10 と図 5-11 に、このアーキテクチャにテストがどのように適合するのかを示します。Figures 5-10 and 5-11 show how tests fit into this architecture.

UnitTestCore

図 5-10Figure 5-10. 分離環境でのアプリケーション コアの単体テスト。Unit testing Application Core in isolation.

IntegrationTests

図 5-11Figure 5-11. 外部依存関係を持つインフラストラクチャ実装の統合テスト。Integration testing Infrastructure implementations with external dependencies.

UI レイヤーはインフラストラクチャ プロジェクトで定義された型に対して直接的な依存関係を持たないことから、テストの促進、またはアプリケーション要件の変更への対応を目的として実装を交換することも容易にできます。Since the UI layer doesn't have any direct dependency on types defined in the Infrastructure project, it's likewise very easy to swap out implementations, either to facilitate testing or in response to changing application requirements. ASP.NET Core には依存関係挿入の使用とサポートが組み込まれているので、このアーキテクチャは重要なモノリシック アプリケーションを構築する方法として最適です。ASP.NET Core's built-in use of and support for dependency injection makes this architecture the most appropriate way to structure non-trivial monolithic applications.

モノリシック アプリケーションの場合、アプリケーション コア、インフラストラクチャ、UI の各プロジェクトはいずれも単一のアプリケーションとして実行されます。For monolithic applications the Application Core, Infrastructure, and UI projects are all run as a single application. ランタイム アプリケーションのアーキテクチャは、図 5-12 のようなものになります。The runtime application architecture might look something like Figure 5-12.

ASP.NET Core アーキテクチャ 2

図 5-12Figure 5-12. ASP.NET Core アプリのランタイム アーキテクチャの例。A sample ASP.NET Core app's runtime architecture.

クリーン アーキテクチャ内でのコードの整理Organizing code in Clean Architecture

クリーン アーキテクチャでは、各プロジェクトが明確な責任を担っています。In a Clean Architecture solution, each project has clear responsibilities. そのため、各プロジェクトにはそれぞれ特定の型が属しており、該当するプロジェクトではこれらの型に対応するフォルダーを頻繁に確認できます。As such, certain types belong in each project and you'll frequently find folders corresponding to these types in the appropriate project.

アプリケーション コアでは、エンティティ、サービス、およびインターフェイスが含まれるビジネス モデルを保持します。The Application Core holds the business model, which includes entities, services, and interfaces. これらのインターフェイスには、データ アクセス、ファイル システム アクセス、ネットワーク呼び出しなどのインフラストラクチャを使用して実行される操作のための抽象化が含まれます。このレイヤーで定義されたサービスまたはインターフェイスは場合によって、UI またはインフラストラクチャに対して依存関係を持たない非エンティティ型を操作する必要があります。These interfaces include abstractions for operations that will be performed using Infrastructure, such as data access, file system access, network calls, etc. Sometimes services or interfaces defined at this layer will need to work with non-entity types that have no dependencies on UI or Infrastructure. これらは単純なデータ転送オブジェクト (DTO) として定義することができます。These can be defined as simple Data Transfer Objects (DTOs).

アプリケーション コアの種類Application Core types

  • エンティティ (永続化されたビジネス モデル クラス)Entities (business model classes that are persisted)
  • インターフェイスInterfaces
  • ServicesServices
  • DTODTOs

インフラストラクチャ プロジェクトには、通常、データ アクセス実装が含まれます。The Infrastructure project typically includes data access implementations. 代表的な ASP.NET Core Web アプリケーションの場合、これらの実装には Entity Framework (EF) DbContext、定義済みの任意の EF Core Migration オブジェクト、およびデータ アクセス実装クラスが含まれます。In a typical ASP.NET Core web application, these implementations include the Entity Framework (EF) DbContext, any EF Core Migration objects that have been defined, and data access implementation classes. データ アクセス実装コードを抽象化するには、リポジトリ デザイン パターンを使用するのが最も一般的な方法です。The most common way to abstract data access implementation code is through the use of the Repository design pattern.

データ アクセス実装に加えて、インフラストラクチャ プロジェクトにはインフラストラクチャの懸念事項とやり取りする必要があるサービスの実装を含める必要があります。In addition to data access implementations, the Infrastructure project should contain implementations of services that must interact with infrastructure concerns. これらのサービスではアプリケーション コアで定義されているインターフェイスを実装する必要があります。そのため、インフラストラクチャにはアプリケーション コア プロジェクトへの参照を含める必要があります。These services should implement interfaces defined in the Application Core, and so Infrastructure should have a reference to the Application Core project.

インフラストラクチャの種類Infrastructure types

  • EF Core 型 (DbContextMigration)EF Core types (DbContext, Migration)
  • データ アクセス実装型 (リポジトリ)Data access implementation types (Repositories)
  • インフラストラクチャに固有のサービス (FileLoggerSmtpNotifier など)Infrastructure-specific services (for example, FileLogger or SmtpNotifier)

ASP.NET Core MVC アプリケーション内のユーザー インターフェイス レイヤーは、アプリケーションのエントリ ポイントです。The user interface layer in an ASP.NET Core MVC application is the entry point for the application. このプロジェクトはアプリケーション コア プロジェクトを参照する必要があり、その型はアプリケーション コアで定義されているインターフェイスを介してインフラストラクチャと厳密にやり取りする必要があります。This project should reference the Application Core project, and its types should interact with infrastructure strictly through interfaces defined in Application Core. UI レイヤーでは、インフラストラクチャ レイヤー型の直接的なインスタンス化や静的呼び出しを許可すべきではありません。No direct instantiation of or static calls to the Infrastructure layer types should be allowed in the UI layer.

UI レイヤーの種類UI layer types

  • ControllersControllers
  • フィルターFilters
  • ViewsViews
  • ViewModelsViewModels
  • スタートアップStartup

スタートアップ クラスはアプリケーションの構成と、インターフェイスへの実装型の接続とを担当します。これにより、依存関係挿入は実行時に適切に機能します。The Startup class is responsible for configuring the application, and for wiring up implementation types to interfaces, allowing dependency injection to work properly at run time.

注意

UI プロジェクトの Startup.cs ファイル内の ConfigureServices で依存関係挿入を接続するために、プロジェクトはインフラストラクチャ プロジェクトを参照することが必要な場合があります。In order to wire up dependency injection in ConfigureServices in the Startup.cs file of the UI project, the project may need to reference the Infrastructure project. この依存関係を排除するには、カスタム DI コンテナーを使用するのが最も簡単な方法です。This dependency can be eliminated, most easily by using a custom DI container. このサンプルの目的を考慮すると、UI プロジェクトでインフラストラクチャ プロジェクトを参照できるようにするのが最も簡単な方法です。For the purposes of this sample, the simplest approach is to allow the UI project to reference the Infrastructure project.

モノリシック アプリケーションとコンテナーMonolithic applications and containers

モノリシックに展開された単一の Web アプリケーションまたはサービスを構築し、それをコンテナーとして展開することができます。You can build a single and monolithic-deployment based Web Application or Service and deploy it as a container. アプリケーション内では、それはモノリシックとはならずにいくつかのライブラリ、コンポーネント、またはレイヤーに編成される場合があります。Within the application, it might not be monolithic but organized into several libraries, components, or layers. 外部的には、単一のプロセス、単一の Web アプリケーション、または単一のサービスのような単一のコンテナーです。Externally, it's a single container like a single process, single web application, or single service.

このモデルを管理するには、アプリケーションを表す単一のコンテナーを展開します。To manage this model, you deploy a single container to represent the application. ロード バランサーを前面に配置してコピーを追加するだけで、スケーリングできます。To scale, just add additional copies with a load balancer in front. 単一のコンテナーまたは VM で単一の展開を管理することで、このように簡単になります。The simplicity comes from managing a single deployment in a single container or VM.

図 5-13 に示すように、複数のコンポーネント/ライブラリ、または内部レイヤーを各コンテナーに含めることができます。You can include multiple components/libraries or internal layers within each container, as illustrated in Figure 5-13. しかし、"コンテナーは 1 つのことを実行し、それを 1 つのプロセスで実行する" というコンテナーの原則に従えば、このモノリシック パターンは矛盾する可能性があります。But, following the container principle of "a container does one thing, and does it in one process", the monolithic pattern might be a conflict.

このアプローチの欠点は、アプリケーションが大きくなり、スケーリングする必要が出てきた場合に顕著になります。The downside of this approach comes if/when the application grows, requiring it to scale. アプリケーション全体がスケーリングすれば、実際には問題ではありません。If the entire application scales, it's not really a problem. ただし、ほとんどの場合、スケーリングする必要があるネックはアプリケーションの一部であり、他のコンポーネントはそれほど使用されません。However, in most cases, a few parts of the application are the choke points requiring scaling, while other components are used less.

一般的な E コマースを例にとると、スケーリングする必要が生じるのは多くの場合、製品情報のコンポーネントです。Using the typical eCommerce example, what you likely need to scale is the product information component. 製品を購入するユーザーよりも多くのユーザーが製品を参照します。Many more customers browse products than purchase them. より多くの顧客が、支払いパイプラインではなくバスケットを使用します。More customers use their basket than use the payment pipeline. コメントを追加したり、購入履歴を表示したりする顧客はそれほどいません。Fewer customers add comments or view their purchase history. また、単一のリージョンで、コンテンツとマーケティング キャンペーンを管理する必要がある従業員数は多分、ほんの一握りです。And you likely only have a handful of employees, in a single region, that need to manage the content and marketing campaigns. モノリシック デザインのスケーリングにより、コード全体は複数回展開されます。By scaling the monolithic design, all the code is deployed multiple times.

"すべてをスケーリングする" 問題に加えて、単一のコンポーネントを変更するには、アプリケーション全体を完全に再テストし、すべてのインスタンスを完全に再展開する必要があります。In addition to the "scale everything" problem, changes to a single component require complete retesting of the entire application, and a complete redeployment of all the instances.

モノリシック アプローチは一般的であり、多くの組織が、このアーキテクチャ アプローチによって開発を行っています。The monolithic approach is common, and many organizations are developing with this architectural approach. 多くの組織が十分に良好な結果を収めている一方で、限界に達している組織もあります。Many are having good enough results, while others are hitting limits. 多くの組織は、このモデルでアプリケーションを設計していました。これは、ツールとインフラストラクチャのせいでサービス指向アーキテクチャ (SOA) の構築が非常に困難だったためと、アプリケーションが大きくなるまで SOA の必要性がわからなかったためです。Many designed their applications in this model, because the tools and infrastructure were too difficult to build service-oriented architectures (SOA), and they didn't see the need until the app grew. モノリシック アプローチの限界に達しているとわかった場合は、コンテナーとマイクロサービスを有効活用できるようにアプリを分割することを次の論理的な手順とすることができます。If you find you're hitting the limits of the monolithic approach, breaking up the app to enable it to better leverage containers and microservices may be the next logical step.

Microsoft Azure のモノリシック アプリケーションは、各インスタンスに専用の VM を使用して展開できます。Deploying monolithic applications in Microsoft Azure can be achieved using dedicated VMs for each instance. Azure Virtual Machine Scale Sets を使用すると、VM のスケーリングを簡単に行うことができます。Using Azure Virtual Machine Scale Sets, you can easily scale the VMs. Azure App Service では、VM の管理を必要とせずに、モノリシック アプリケーションを実行し、インスタンスを簡単にスケーリングすることができます。Azure App Services can run monolithic applications and easily scale instances without having to manage the VMs. Azure App Services では、Docker コンテナーの単一インスタンスも実行できるため、展開が簡単になります。Azure App Services can run single instances of Docker containers as well, simplifying the deployment. Docker を使用すれば、1 つの VM を Docker ホストとして展開し、複数のインスタンスを実行できます。Using Docker, you can deploy a single VM as a Docker host, and run multiple instances. 図 5-14 に示すように、Azure バランサーを使用してスケーリングを管理できます。Using the Azure balancer, as shown in the Figure 5-14, you can manage scaling.

さまざまなホストへの展開は、従来の展開手法で管理できます。The deployment to the various hosts can be managed with traditional deployment techniques. Docker ホストは、docker run などのコマンドを使用して手動で管理するか、継続的デリバリー (CD) パイプラインなどのオートメーションによって管理できます。The Docker hosts can be managed with commands like docker run performed manually, or through automation such as Continuous Delivery (CD) pipelines.

コンテナーとして展開するモノリシック アプリケーションMonolithic application deployed as a container

コンテナーを使用してモノリシック アプリケーションの展開を管理することには利点があります。There are benefits of using containers to manage monolithic application deployments. コンテナーのインスタンスをスケーリングする処理は、追加の VM を展開するよりもはるかに高速で簡単です。Scaling the instances of containers is far faster and easier than deploying additional VMs. 仮想マシン スケール セットを使用して VM をスケーリングする場合も、インスタンス化には時間がかかります。Even when using virtual machine scale sets to scale VMs, they take time to instance. アプリのインスタンスとして展開する場合、アプリの構成は VM の一部として管理されます。When deployed as app instances, the configuration of the app is managed as part of the VM.

更新プログラムを Docker イメージとして展開する方がはるかに高速で、ネットワークの効率が高くなります。Deploying updates as Docker images is far faster and network efficient. 通常、Docker イメージは秒単位で起動するので、ロールアウトが高速になります。Docker Images typically start in seconds, speeding rollouts. Docker インスタンスの破棄は、docker stop コマンドの発行と同じくらい簡単で、通常は 1 秒未満で完了します。Tearing down a Docker instance is as easy as issuing a docker stop command, typically completing in less than a second.

コンテナーは本質的に設計上、変更不可であるため、VM の破損について心配する必要はありません。一方、更新スクリプトではディスク上に残された特定の構成またはファイルが考慮されない場合があります。As containers are inherently immutable by design, you never need to worry about corrupted VMs, whereas update scripts might forget to account for some specific configuration or file left on disk.

Docker コンテナーは、単純な Web アプリケーションのモノリシックな展開に使用できます。これにより継続的な統合と継続的な展開のパイプラインが向上し、展開から実稼働を成功に導くのために役立ちます。"自分のコンピューターでは動作するのに実稼働環境では動作しないのはなぜ" と悩むことがなくなります。You can use Docker containers for monolithic deployment of simpler web applications. This improves continuous integration and continuous deployment pipelines and helps achieve deployment-to-production success. No more “It works in my machine, why does it not work in production?”

マイクロサービスベースのアーキテクチャには、多くの利点がありますが、それらの利点のために複雑さが増加します。A microservices-based architecture has many benefits, but those benefits come at a cost of increased complexity. 場合によっては、コストが利点を上回り、1 つのコンテナーまたは少数のコンテナーで実行されているモノリシック展開アプリケーションの方が有効なことがあります。In some cases, the costs outweigh the benefits, a monolithic deployment application running in a single container or in just a few containers is a better option.

モノリシック アプリケーションを適切に区切られたマイクロサービスに簡単に分解できない場合があります。A monolithic application might not be easily decomposable into well-separated microservices. マイクロサービスは相互に独立して起動することで、より回復力のあるアプリケーションを提供します。Microservices should work independently of each other to provide a more resilient application. アプリケーションの独立した機能のスライスを提供できない場合、分割しても複雑さが増すだけです。If you can't deliver independent feature slices of the application, separating it only adds complexity.

場合によっては、アプリケーションを機能に依存せずに拡張できる必要がありますAn application might not yet need to scale features independently. 多くのアプリケーションでは、単一のインスタンスの範囲を超えてスケーリングする必要がある場合、そのインスタンス全体を複製する比較的シンプルなプロセスで行うことができます。Many applications, when they need to scale beyond a single instance, can do so through the relatively simple process of cloning that entire instance. アプリケーションを個別のサービスに分割する追加の作業では、アプリケーションのすべてのインスタンスをスケーリングするのがシンプルかつコスト効率に優れている場合、最小限のメリットしか得られません。The additional work to separate the application into discrete services provides minimal benefit when scaling full instances of the application is simple and cost-effective.

アプリケーション開発の早い段階では、自然の機能的な境界を明確に把握できないことがあります。Early in the development of an application, you might not have a clear idea where the natural functional boundaries are. 最小の実行可能な製品を開発したときには、自然な境界がまだ明らかにならないことがあります。As you develop a minimum viable product, the natural separation might not yet have emerged. これらの条件の一部は、一時的な可能性があります。Some of these conditions might be temporary. 最初にモノリシック アプリケーションを作成し、後で一部の個別の機能を開発して、マイクロサービスとして展開する場合があります。You might start by creating a monolithic application, and later separate some features to be developed and deployed as microservices. その他の条件はアプリケーションの問題の領域に不可欠な場合があります。つまり、アプリケーションを複数マイクロサービスに分割しない場合があります。Other conditions might be essential to the application’s problem space, meaning that the application might never be broken into multiple microservices.

多くの個別のプロセスにアプリケーションを分割すると、オーバーヘッドも発生します。Separating an application into many discrete processes also introduces overhead. 別のプロセスに機能を分離することで、複雑さが増します。There's more complexity in separating features into different processes. 通信プロトコルはより複雑になります。The communication protocols become more complex. メソッドの呼び出しではなく、サービス間の非同期通信を使用する必要があります。Instead of method calls, you must use asynchronous communications between services. マイクロサービス アーキテクチャに移動するきには、eShopOnContainers アプリケーションのマイクロサービス バージョンに実装される多くの構築ブロックを追加する必要があります。つまり、イベント バスの処理、メッセージの回復性と再試行、最終的な整合性などです。As you move to a microservices architecture, you need to add many of the building blocks implemented in the microservices version of the eShopOnContainers application: event bus handling, message resiliency and retries, eventual consistency, and more.

よりシンプルな eShopOnWeb 参照アプリケーションでは、単一コンテナーのモノリシック コンテナーの使用がサポートされます。The much simpler eShopOnWeb reference application supports single-container monolithic container usage. アプリケーションには、2 つの Web アプリケーションが含まれています。1 つのアプリケーションでは従来の MVC、もう 1 つでは Razor Pages を使用します。The application includes two web applications: one using traditional MVC and another using Razor Pages. docker-compose build および docker-compose up コマンドを使用して、ソリューション ルートからこれらの両方を起動することができます。Both can be launched from the solution root using the docker-compose build and docker-compose up commands. このコマンドでは、各 Web プロジェクトのルートで検出された Dockerfile を使用して、Web インスタンスごとに個別のコンテナーを構成し、各コンテナーを別のポートで実行します。This command configures separate containers for each web instance, using the Dockerfile found in each web project's root, and runs each container on a separate port. GitHub からこのアプリケーションのソースをダウンロードして、ローカルで実行できます。You can download the source for this application from GitHub and run it locally. このモノリシック アプリケーションは、コンテナー環境で展開すると有益です。Even this monolithic application benefits from being deployed in a container environment.

1 つは、コンテナー化した展開は、アプリケーションのすべてのインスタンスが同じ環境で実行されることを意味します。For one, the containerized deployment means that every instance of the application runs in the same environment. これには、初期のテストと開発を行う開発者環境が含まれます。This includes the developer environment where early testing and development take place. 開発チームは、実稼働環境に一致するコンテナー化した環境でアプリケーションを実行できます。The development team can run the application in a containerized environment that matches the production environment.

さらに、コンテナー化アプリケーションは低コストでスケールアウトされます。In addition, containerized applications scale out at lower cost. コンテナー環境を使用することで、従来の VM 環境よりも多くのリソースを共有できます。Using a container environment enables greater resource sharing than traditional VM environments.

最後に、アプリケーションのコンテナー化は、強制的にビジネス ロジックと記憶域サーバーの間を分離します。Finally, containerizing the application forces a separation between the business logic and the storage server. アプリケーションのスケール アウト時には、複数のコンテナーはすべて単一の物理記憶域メディアに移動します。As the application scales out, the multiple containers will all rely on a single physical storage medium. 通常、この記憶域メディアが SQL Server データベースを実行している高可用性サーバーになります。This storage medium would typically be a high-availability server running a SQL Server database.

Docker のサポートDocker support

eShopOnWeb プロジェクトは、.NET Core で実行されます。The eShopOnWeb project runs on .NET Core. そのため、Windows ベースまたは Linux ベースのコンテナーで実行できます。Therefore, it can run in either Linux-based or Windows-based containers. Docker の展開の場合、SQL Server に同じホストの種類を使用する必要があります。Note that for Docker deployment, you want to use the same host type for SQL Server. Linux ベースのコンテナーは、小さなフット プリントが可能なので優先されます。Linux-based containers allow a smaller footprint and are preferred.

Visual Studio 2017 を使用すれば、Docker サポートを既存のアプリケーションに追加することができます。その場合、ソリューション エクスプローラーでプロジェクトを右クリックし、[追加] > [Docker サポート] の順に選択します。You can use Visual Studio 2017 to add Docker support to an existing application by right-clicking on a project in Solution Explorer and choosing Add > Docker Support. これで、必要なファイルが追加され、そのファイルを使用するようにプロジェクトが変更されます。This adds the files required and modifies the project to use them. 現在の eShopOnWeb サンプルには既にこれらのファイルが用意されています。The current eShopOnWeb sample already has these files in place.

ソリューション レベルの docker-compose.yml ファイルには、どのようなイメージをビルドしてどのようなコンテナーを起動するかに関する情報が含まれています。The solution-level docker-compose.yml file contains information about what images to build and what containers to launch. このファイルでは、docker-compose コマンドを使用して、両方のバージョンの Web アプリケーションを同時に起動することができます。The file allows you to use the docker-compose command to launch both versions of the web application at the same time. 別のデータベース コンテナーなど、依存関係を構成する場合にも使用できます。You can also use it to configure dependencies, such as a separate database container.

version: '3'

services:
  eshopwebrazor:
    image: eshopwebrazor
    build:
      context: .
      dockerfile: src/WebRazorPages/Dockerfile
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
    ports:
      - "5107:5107"

  eshopwebmvc:
    image: eshopwebmvc
    build:
      context: .
      dockerfile: src/Web/Dockerfile
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
    ports:
      - "5106:5106"

networks:
  default:
    external:
      name: nat

docker-compose.yml ファイルでは、Web および WebRazorPages プロジェクトの Dockerfile を参照します。The docker-compose.yml file references the Dockerfile in the Web and WebRazorPages projects. Dockerfile は、使用される基本コンテナーと、その基本コンテナーでのアプリケーションの構成方法を指定する場合に使います。The Dockerfile is used to specify which base container will be used and how the application will be configured on it. WebRazorPagesDockerfile は次のとおりです。The WebRazorPages' Dockerfile:

FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80

FROM microsoft/aspnetcore-build:2.1.300-preview1 AS build
RUN npm install -g bower@1.8.4
WORKDIR /src
COPY . .
WORKDIR /src/src/WebRazorPages
RUN dotnet restore -nowarn:msb3202,nu1503
RUN dotnet build --no-restore -c Release -o /app

FROM build AS publish
RUN dotnet publish --no-restore -c Release -o /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "Microsoft.eShopWeb.RazorPages.dll"]

Docker に関する問題のトラブルシューティングTroubleshooting Docker problems

コンテナー化アプリケーションを実行すると、それを停止するまで実行し続けます。Once you run the containerized application, it continues to run until you stop it. docker ps コマンドで実行されているコンテナーを表示することができます。You can view which containers are running with the docker ps command. docker stop コマンドを使用して、コンテナー ID を指定すれば、実行中のコンテナーを停止することができます。You can stop a running container by using the docker stop command and specifying the container ID.

実行中の Docker コンテナーは、開発環境では別の目的で使用を試みる可能性のあるポートにバインドされる場合があることに注意してください。Note that running Docker containers may be bound to ports you might otherwise try to use in your development environment. 実行中の Docker コンテナーと同じポートを使用して、アプリケーションの実行やデバッグを試みると、サーバーがそのポートにバインドできないことを示すエラーが表示されます。If you try to run or debug an application using the same port as a running Docker container, you'll get an error stating that the server can't bind to that port. 繰り返しになりますが、コンテナーを停止すると、問題は解決します。Once again, stopping the container should resolve the issue.

Visual Studio を使用して、ご利用のアプリケーションに Docker サポートを追加する場合は、その際に Docker が実行されていることを確認してください。If you want to add Docker support to your application using Visual Studio, make sure Docker is running when you do so. ウィザードを起動するときに、Docker が実行されていない場合、ウィザードは正しく実行されません。The wizard won't run correctly if Docker isn't running when you start the wizard. さらに、ウィザードでは、正しい Docker のサポートを追加するためにコンテナーの現在の選択について説明します。In addition, the wizard examines your current container choice to add the correct Docker support. Windows コンテナーのサポートを追加する場合は、Windows コンテナーが構成された状態で Docker が実行されているときに、ウィザードを実行する必要があります。If you want to add support for Windows Containers, you need to run the wizard while you have Docker running with Windows Containers configured. Linux コンテナーのサポートを追加する場合は、Linux コンテナーが構成された状態で Docker が実行されているときに、ウィザードを実行する必要があります。If you want to add support for Linux containers, run the wizard while you have Docker running with Linux containers configured.

参照 – 一般的な Web アーキテクチャReferences – Common web architectures