From 7e5612a280022ece8eff7993bbe589a772b0e3ff Mon Sep 17 00:00:00 2001 From: Matthew Welke Date: Mon, 19 Feb 2018 16:58:30 -0500 Subject: [PATCH 1/7] Finished PostgreSQL chapter. --- SUMMARY.md | 2 + chapters/alternative-databases/README.md | 2 + .../pgadmin_aspnetcore_tables_created.png | Bin 0 -> 13152 bytes chapters/alternative-databases/postgresql.md | 87 ++++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 chapters/alternative-databases/README.md create mode 100644 chapters/alternative-databases/pgadmin_aspnetcore_tables_created.png create mode 100644 chapters/alternative-databases/postgresql.md diff --git a/SUMMARY.md b/SUMMARY.md index 1ba33ff..9ed8098 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -32,4 +32,6 @@ * [Deploy the application](chapters/deploy-the-application/README.md) * [Deploy to Azure](chapters/deploy-the-application/deploy-to-azure.md) * [Deploy with Docker](chapters/deploy-the-application/deploy-with-docker.md) +* [Alternative databases](chapters/alternative-databases/README.md) + * [PostgreSQL](chapters/alternative-databases/postgresql.md) * [Conclusion](chapters/conclusion/README.md) diff --git a/chapters/alternative-databases/README.md b/chapters/alternative-databases/README.md new file mode 100644 index 0000000..8e2b9dd --- /dev/null +++ b/chapters/alternative-databases/README.md @@ -0,0 +1,2 @@ +# Alternative databases +Now that you've learned how to create and deploy a basic ASP.NET Core application using SQLite, you can explore other databases you can use. diff --git a/chapters/alternative-databases/pgadmin_aspnetcore_tables_created.png b/chapters/alternative-databases/pgadmin_aspnetcore_tables_created.png new file mode 100644 index 0000000000000000000000000000000000000000..5e85ad3e4256546b6d69b2bd6931a54fba778c7c GIT binary patch literal 13152 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 + + + + + + +``` + +### Modify configuration + +In the project's `Startup.cs` file, modify the `ConfigureServices` method to replace the following code that enabled the SQLite provider: + +```csharp +services.AddDbContext(options => + options.UseSqlite(Configuration.GetConnectionString("DefaultConnection"))); +``` + +with the following code to instead enable the PostgreSQL provider: + +```csharp +services.AddEntityFrameworkNpgsql().AddDbContext(options => + options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"))); +``` + +The connection string `DefaultConnection` will also have to updated to reflect connecting to a PostgreSQL database instead of SQLite. Modify the `appsettings.json` file in the project root to change the following connection string: + +``` +"ConnectionStrings": { + "DefaultConnection": "DataSource=app.db" +} +``` + +to a new connection string for PostgreSQL: + +``` +"ConnectionStrings": { + "DefaultConnection": "Server=localhost;Port=5432;User Id=username;Password=secret;Database=todos;" +} +``` + +### Starting a PostgreSQL + +Setting up PostgreSQL on your development machine is outside of the scope of this book. You can install and start PostgreSQL any way you like, however, a convenient modern way of doing this is using Docker. With [Docker installed](https://docs.docker.com/install/) on your machine, you can create and run a container from the [`Postgres`](https://hub.docker.com/_/postgres/) image, using environment variables to set the username, password, and database used in the connection string set above. To do so, use the following command: + +``` +docker run -d -e POSTGRES_USER=username -e POSTGRES_PASSWORD=secret -e POSTGRES_DB=todos -p 5432:5432 --name postgres-todos postgres:latest +``` + +At this point, the container is running and is exposing port `5432` so that the running ASP.NET Core application and tools like pgAdmin can connect to it at `localhost`. + +### Updating the database + +At this point, we can update the database with the same command we used before: + +``` +dotnet ef database update +``` + +While it is true that the migrations we created in the project have already been applied, they were applied when the project was configured to use SQLite. Entity Framework Core knows that with this new database configuration, the migrations have not yet been applied, so it applies them to the PostgreSQL database, resulting in the tables being created. You can use a program like [pgAdmin](https://www.pgadmin.org/) to connect to the database and see the tables that were created: + +![pgAdmin showing the tables](pgadmin_aspnetcore_tables_created.png) + +At this point, you can start your application, visit `localhost:5000` in your browser, and create and manipulate `Todo`s just like before, except this time the data is being saved in the PostgreSQL database. Notice how everything works as before, including: + +* Model validation +* Identity authentication and authorization +* etc + +without having to change any code except load a different Entity Framework Core provider in `Startup.cs`. \ No newline at end of file From 551d053ec8031195ec1de01efb49d6e7970ac665 Mon Sep 17 00:00:00 2001 From: Matthew Welke Date: Mon, 19 Feb 2018 17:13:05 -0500 Subject: [PATCH 2/7] Minor fixes in PostgreSQL chapter. --- chapters/alternative-databases/postgresql.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/chapters/alternative-databases/postgresql.md b/chapters/alternative-databases/postgresql.md index 543e7d1..5d552e7 100644 --- a/chapters/alternative-databases/postgresql.md +++ b/chapters/alternative-databases/postgresql.md @@ -1,4 +1,4 @@ -## Postgresql +## PostgreSQL Using PostgreSQL for your application instead of SQLite will allow it to support foreign key relationships with Entity Framework Core, allow it to scale better, and give you access to various PostgreSQL features like the [PostGIS extension](https://postgis.net/). @@ -40,7 +40,7 @@ services.AddEntityFrameworkNpgsql().AddDbContext(options = options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"))); ``` -The connection string `DefaultConnection` will also have to updated to reflect connecting to a PostgreSQL database instead of SQLite. Modify the `appsettings.json` file in the project root to change the following connection string: +The connection string `DefaultConnection` will also have to be updated to reflect connecting to a PostgreSQL database instead of SQLite. Modify the `appsettings.json` file in the project root to change the following connection string: ``` "ConnectionStrings": { @@ -56,7 +56,7 @@ to a new connection string for PostgreSQL: } ``` -### Starting a PostgreSQL +### Starting a PostgreSQL database Setting up PostgreSQL on your development machine is outside of the scope of this book. You can install and start PostgreSQL any way you like, however, a convenient modern way of doing this is using Docker. With [Docker installed](https://docs.docker.com/install/) on your machine, you can create and run a container from the [`Postgres`](https://hub.docker.com/_/postgres/) image, using environment variables to set the username, password, and database used in the connection string set above. To do so, use the following command: @@ -78,7 +78,7 @@ While it is true that the migrations we created in the project have already been ![pgAdmin showing the tables](pgadmin_aspnetcore_tables_created.png) -At this point, you can start your application, visit `localhost:5000` in your browser, and create and manipulate `Todo`s just like before, except this time the data is being saved in the PostgreSQL database. Notice how everything works as before, including: +At this point, you can start your application, visit `localhost:5000` in your browser, and create and manipulate `Todo` items just like before, except this time the data is being saved in the PostgreSQL database. Notice how everything works as before, including: * Model validation * Identity authentication and authorization From 44bb741598e5b262dbc14676ad38c474051f143d Mon Sep 17 00:00:00 2001 From: Matthew Welke Date: Mon, 19 Feb 2018 17:20:42 -0500 Subject: [PATCH 3/7] Remove misinformation re: FKs. --- chapters/alternative-databases/postgresql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/alternative-databases/postgresql.md b/chapters/alternative-databases/postgresql.md index 5d552e7..aa341e7 100644 --- a/chapters/alternative-databases/postgresql.md +++ b/chapters/alternative-databases/postgresql.md @@ -1,6 +1,6 @@ ## PostgreSQL -Using PostgreSQL for your application instead of SQLite will allow it to support foreign key relationships with Entity Framework Core, allow it to scale better, and give you access to various PostgreSQL features like the [PostGIS extension](https://postgis.net/). +Using PostgreSQL for your application instead of SQLite will allow it to scale better and give you access to various PostgreSQL features like the [PostGIS extension](https://postgis.net/). Thanks to the layer of abstraction we get from using Entity Framework Core, modifying our application to use a different database engine is less complex than you would think. We can use our existing models, only having to change the Entity Framework Core provider we use. We will add the [Npgsql EF Core provider](http://www.npgsql.org/efcore/index.html). From f9b66c1cf86a1cf12940bcc14c794276e1882f72 Mon Sep 17 00:00:00 2001 From: Matthew Welke Date: Sat, 14 Apr 2018 15:01:43 -0400 Subject: [PATCH 4/7] Used feedback to clean up. Now in 2nd person perspective, with clearer descriptions of code changes. --- chapters/alternative-databases/README.md | 2 + chapters/alternative-databases/postgresql.md | 41 +++++++++++++------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/chapters/alternative-databases/README.md b/chapters/alternative-databases/README.md index 8e2b9dd..25a1855 100644 --- a/chapters/alternative-databases/README.md +++ b/chapters/alternative-databases/README.md @@ -1,2 +1,4 @@ # Alternative databases Now that you've learned how to create and deploy a basic ASP.NET Core application using SQLite, you can explore other databases you can use. + +This an **optional** chapter, since what you've created with SQLite will work in many situations. In most real world environments, you would use a database like SQL Server, PostgreSQL, or MySQL, which support more advanced querying features and can serve more users at a time. \ No newline at end of file diff --git a/chapters/alternative-databases/postgresql.md b/chapters/alternative-databases/postgresql.md index aa341e7..ce02cac 100644 --- a/chapters/alternative-databases/postgresql.md +++ b/chapters/alternative-databases/postgresql.md @@ -1,18 +1,21 @@ ## PostgreSQL +PostgreSQL is a popular, open-source database. -Using PostgreSQL for your application instead of SQLite will allow it to scale better and give you access to various PostgreSQL features like the [PostGIS extension](https://postgis.net/). +Compared to SQLite, using it will allow your ASP.NET Core app to scale better and give you access to various PostgreSQL features like the [PostGIS extension](https://postgis.net/). -Thanks to the layer of abstraction we get from using Entity Framework Core, modifying our application to use a different database engine is less complex than you would think. We can use our existing models, only having to change the Entity Framework Core provider we use. We will add the [Npgsql EF Core provider](http://www.npgsql.org/efcore/index.html). +Thanks to the layer of abstraction you get from using Entity Framework Core, modifying your application to use a different database is less complex than you would think. Because the user interface wouldn't change, you wouldn't change any code in the `Views`, `Controllers`, or `Services` directories. Despite the database changing, you can also use your existing model classes, so no code needs to change in the `Models` directory either. -### Add provider Nuget package +As you follow the next steps, you'll see that the only code that must change is the code used to hook up the Entity Framework Core provider. You will use the [Npgsql Entity Framework Core provider](http://www.npgsql.org/efcore/index.html). -To add the package, run the following command: +### Add provider NuGet package + +The provider comes as a NuGet package called `Npgsql.EntityFrameworkCore.PostgreSQL`. To add the package, run the following command: ``` dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL ``` -After adding the package, you will notice the project's `.csproj` file being updated to reflect the new list of packages: +After adding the package, you'll notice that the project's `.csproj` file has been updated to reflect the new list of packages: ```xml @@ -26,21 +29,21 @@ After adding the package, you will notice the project's `.csproj` file being upd ### Modify configuration -In the project's `Startup.cs` file, modify the `ConfigureServices` method to replace the following code that enabled the SQLite provider: +Your project's `Startup.cs` file's `ConfigureServices` method currently contains the following code, which hooks up the SQLite provider: ```csharp services.AddDbContext(options => options.UseSqlite(Configuration.GetConnectionString("DefaultConnection"))); ``` -with the following code to instead enable the PostgreSQL provider: +Change it to the following code, which will instead hook up the PostgreSQL provider: ```csharp services.AddEntityFrameworkNpgsql().AddDbContext(options => options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"))); ``` -The connection string `DefaultConnection` will also have to be updated to reflect connecting to a PostgreSQL database instead of SQLite. Modify the `appsettings.json` file in the project root to change the following connection string: +The connection string `DefaultConnection` will also have to be updated to reflect connecting to a different database. Right now, your project's `appsettings.json` file contains the following connection string for SQLite: ``` "ConnectionStrings": { @@ -48,7 +51,7 @@ The connection string `DefaultConnection` will also have to be updated to reflec } ``` -to a new connection string for PostgreSQL: +Change it to the following code to provide a connection string for PostgreSQL: ``` "ConnectionStrings": { @@ -56,29 +59,39 @@ to a new connection string for PostgreSQL: } ``` +The connection string is composed of four parameters: + +- You use `localhost` for the `Server` parameter because you'll be running PostgreSQL on your development machine in this tutorial. +- You use `5432` for the `Port` parameter because this is the default port for PostgreSQL, which you won't be changing in this tutorial. +- You use `username` and `secret` for `User Id` and `Password` respectively, because these are simple example values this tutorial uses. In a real world deployment, you would use more secure credentials and tools like the [Secret Manager](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-2.1&tabs=visual-studio) to store them. + ### Starting a PostgreSQL database -Setting up PostgreSQL on your development machine is outside of the scope of this book. You can install and start PostgreSQL any way you like, however, a convenient modern way of doing this is using Docker. With [Docker installed](https://docs.docker.com/install/) on your machine, you can create and run a container from the [`Postgres`](https://hub.docker.com/_/postgres/) image, using environment variables to set the username, password, and database used in the connection string set above. To do so, use the following command: +Setting up PostgreSQL on your development machine is outside of the scope of this book. You can install and start PostgreSQL any way you like, however, a convenient modern way of doing this is using [Docker](https://www.docker.com/). If you've used virtual machines before, Docker "containers" are a similar concept. Think virtualization but without a hypervisor. The containers get direct access to the kernel of the host machine. + +With [Docker installed](https://docs.docker.com/install/) on your machine, you can create and run a container from the [`Postgres`](https://hub.docker.com/_/postgres/) image. You will use the same parameters from the connection string defined above to create the container, using the following command: ``` docker run -d -e POSTGRES_USER=username -e POSTGRES_PASSWORD=secret -e POSTGRES_DB=todos -p 5432:5432 --name postgres-todos postgres:latest ``` -At this point, the container is running and is exposing port `5432` so that the running ASP.NET Core application and tools like pgAdmin can connect to it at `localhost`. +After creating and starting the container (which is what the `docker run` command does), the container is running in the background and exposing port `5432` so that the running ASP.NET Core application and tools like [pgAdmin](https://www.pgadmin.org/) can connect to it at `localhost`. ### Updating the database -At this point, we can update the database with the same command we used before: +Now that PostgreSQL is running in the background, you can update the database with the same command you used earlier in the tutorial when working with SQLite: ``` dotnet ef database update ``` -While it is true that the migrations we created in the project have already been applied, they were applied when the project was configured to use SQLite. Entity Framework Core knows that with this new database configuration, the migrations have not yet been applied, so it applies them to the PostgreSQL database, resulting in the tables being created. You can use a program like [pgAdmin](https://www.pgadmin.org/) to connect to the database and see the tables that were created: +The reason you must run the migrations again is because this time the connection string defined for the app points to a different database. This new database does not yet have the needed tables created. Running the migrations again at this point in the tutorial prepares the running PostgreSQL database the same way it prepared the SQLite database earlier. + +Now that the migrations have been applied, you can use a program like pgAdmin to connect to the database and see the tables that were created: ![pgAdmin showing the tables](pgadmin_aspnetcore_tables_created.png) -At this point, you can start your application, visit `localhost:5000` in your browser, and create and manipulate `Todo` items just like before, except this time the data is being saved in the PostgreSQL database. Notice how everything works as before, including: +Start your app with `dotnet run` and visit `localhost:5000` in your browser. You'll notice that you can create and manipulate `Todo` items just like before, except this time the data is being saved in the PostgreSQL database. Notice how everything works as before, including: * Model validation * Identity authentication and authorization From 3e498c450bad468102fb542b41358c190ef93e90 Mon Sep 17 00:00:00 2001 From: Matthew Welke Date: Tue, 10 Jul 2018 23:23:47 -0400 Subject: [PATCH 5/7] Changed PostgreSQL chapter to Heroku & PostgreSQL chapter. --- SUMMARY.md | 1 + chapters/alternative-databases/README.md | 4 - chapters/alternative-databases/postgresql.md | 100 -------- .../deploy-to-heroku-with-postgresql.md | 240 ++++++++++++++++++ .../pgadmin_aspnetcore_tables_created.png | Bin 5 files changed, 241 insertions(+), 104 deletions(-) delete mode 100644 chapters/alternative-databases/README.md delete mode 100644 chapters/alternative-databases/postgresql.md create mode 100644 chapters/deploy-the-application/deploy-to-heroku-with-postgresql.md rename chapters/{alternative-databases => deploy-the-application}/pgadmin_aspnetcore_tables_created.png (100%) diff --git a/SUMMARY.md b/SUMMARY.md index 9ed8098..527e9d5 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -31,6 +31,7 @@ * [Integration testing](chapters/automated-testing/integration-testing.md) * [Deploy the application](chapters/deploy-the-application/README.md) * [Deploy to Azure](chapters/deploy-the-application/deploy-to-azure.md) + * [Deploy to Heroku with PostgreSQL](chapters/deploy-the-application/deploy-to-heroku-with-postgresql.md) * [Deploy with Docker](chapters/deploy-the-application/deploy-with-docker.md) * [Alternative databases](chapters/alternative-databases/README.md) * [PostgreSQL](chapters/alternative-databases/postgresql.md) diff --git a/chapters/alternative-databases/README.md b/chapters/alternative-databases/README.md deleted file mode 100644 index 25a1855..0000000 --- a/chapters/alternative-databases/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Alternative databases -Now that you've learned how to create and deploy a basic ASP.NET Core application using SQLite, you can explore other databases you can use. - -This an **optional** chapter, since what you've created with SQLite will work in many situations. In most real world environments, you would use a database like SQL Server, PostgreSQL, or MySQL, which support more advanced querying features and can serve more users at a time. \ No newline at end of file diff --git a/chapters/alternative-databases/postgresql.md b/chapters/alternative-databases/postgresql.md deleted file mode 100644 index ce02cac..0000000 --- a/chapters/alternative-databases/postgresql.md +++ /dev/null @@ -1,100 +0,0 @@ -## PostgreSQL -PostgreSQL is a popular, open-source database. - -Compared to SQLite, using it will allow your ASP.NET Core app to scale better and give you access to various PostgreSQL features like the [PostGIS extension](https://postgis.net/). - -Thanks to the layer of abstraction you get from using Entity Framework Core, modifying your application to use a different database is less complex than you would think. Because the user interface wouldn't change, you wouldn't change any code in the `Views`, `Controllers`, or `Services` directories. Despite the database changing, you can also use your existing model classes, so no code needs to change in the `Models` directory either. - -As you follow the next steps, you'll see that the only code that must change is the code used to hook up the Entity Framework Core provider. You will use the [Npgsql Entity Framework Core provider](http://www.npgsql.org/efcore/index.html). - -### Add provider NuGet package - -The provider comes as a NuGet package called `Npgsql.EntityFrameworkCore.PostgreSQL`. To add the package, run the following command: - -``` -dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL -``` - -After adding the package, you'll notice that the project's `.csproj` file has been updated to reflect the new list of packages: - -```xml - - - - - - - -``` - -### Modify configuration - -Your project's `Startup.cs` file's `ConfigureServices` method currently contains the following code, which hooks up the SQLite provider: - -```csharp -services.AddDbContext(options => - options.UseSqlite(Configuration.GetConnectionString("DefaultConnection"))); -``` - -Change it to the following code, which will instead hook up the PostgreSQL provider: - -```csharp -services.AddEntityFrameworkNpgsql().AddDbContext(options => - options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"))); -``` - -The connection string `DefaultConnection` will also have to be updated to reflect connecting to a different database. Right now, your project's `appsettings.json` file contains the following connection string for SQLite: - -``` -"ConnectionStrings": { - "DefaultConnection": "DataSource=app.db" -} -``` - -Change it to the following code to provide a connection string for PostgreSQL: - -``` -"ConnectionStrings": { - "DefaultConnection": "Server=localhost;Port=5432;User Id=username;Password=secret;Database=todos;" -} -``` - -The connection string is composed of four parameters: - -- You use `localhost` for the `Server` parameter because you'll be running PostgreSQL on your development machine in this tutorial. -- You use `5432` for the `Port` parameter because this is the default port for PostgreSQL, which you won't be changing in this tutorial. -- You use `username` and `secret` for `User Id` and `Password` respectively, because these are simple example values this tutorial uses. In a real world deployment, you would use more secure credentials and tools like the [Secret Manager](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-2.1&tabs=visual-studio) to store them. - -### Starting a PostgreSQL database - -Setting up PostgreSQL on your development machine is outside of the scope of this book. You can install and start PostgreSQL any way you like, however, a convenient modern way of doing this is using [Docker](https://www.docker.com/). If you've used virtual machines before, Docker "containers" are a similar concept. Think virtualization but without a hypervisor. The containers get direct access to the kernel of the host machine. - -With [Docker installed](https://docs.docker.com/install/) on your machine, you can create and run a container from the [`Postgres`](https://hub.docker.com/_/postgres/) image. You will use the same parameters from the connection string defined above to create the container, using the following command: - -``` -docker run -d -e POSTGRES_USER=username -e POSTGRES_PASSWORD=secret -e POSTGRES_DB=todos -p 5432:5432 --name postgres-todos postgres:latest -``` - -After creating and starting the container (which is what the `docker run` command does), the container is running in the background and exposing port `5432` so that the running ASP.NET Core application and tools like [pgAdmin](https://www.pgadmin.org/) can connect to it at `localhost`. - -### Updating the database - -Now that PostgreSQL is running in the background, you can update the database with the same command you used earlier in the tutorial when working with SQLite: - -``` -dotnet ef database update -``` - -The reason you must run the migrations again is because this time the connection string defined for the app points to a different database. This new database does not yet have the needed tables created. Running the migrations again at this point in the tutorial prepares the running PostgreSQL database the same way it prepared the SQLite database earlier. - -Now that the migrations have been applied, you can use a program like pgAdmin to connect to the database and see the tables that were created: - -![pgAdmin showing the tables](pgadmin_aspnetcore_tables_created.png) - -Start your app with `dotnet run` and visit `localhost:5000` in your browser. You'll notice that you can create and manipulate `Todo` items just like before, except this time the data is being saved in the PostgreSQL database. Notice how everything works as before, including: - -* Model validation -* Identity authentication and authorization -* etc - -without having to change any code except load a different Entity Framework Core provider in `Startup.cs`. \ No newline at end of file diff --git a/chapters/deploy-the-application/deploy-to-heroku-with-postgresql.md b/chapters/deploy-the-application/deploy-to-heroku-with-postgresql.md new file mode 100644 index 0000000..2f7860e --- /dev/null +++ b/chapters/deploy-the-application/deploy-to-heroku-with-postgresql.md @@ -0,0 +1,240 @@ +## Deploy to Heroku with PostgreSQL + +Heroku is another platform you can use to easily and quickly deploy your ASP.NET Core application. The [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli) will be used for most of this process. Later, when your application is deployed, Heroku's web portal can be used to inspect your application's state and manage it, including for example changing its environment variables. + +Heroku offers various levels of hosting services. Their "[dyno](https://devcenter.heroku.com/articles/dyno-types)"s refer to an instance of your application running. If you have multiple dynos provisioned, incoming HTTP requests will be load balanced. Their lowest level dyno type is the "free" dyno type. Therefore, following the steps here to deploy to Heroku will not incur any charges to your Heroku account. + +Because of the way Heroku hosts your application, using an [ephemeral filesystem](https://devcenter.heroku.com/articles/dynos#ephemeral-filesystem), you cannot use SQLite for your application's database. Unfortunately, this means the default setup you used if you followed along coding as you read this book, and when you deployed to Azure, won't work. Instead, you'll use PostgreSQL as your database, and you'll use the free tier of the [Heroku Postgres](https://www.heroku.com/postgres) addon. This means that Heroku will provision you access to a shared PostgreSQL database and expose a connection string to your application so that it will know how to connect to the database. + +Don't worry if the idea of using a different database seems scary. One of Entity Framework Core's strengths is that you can substitute providers for each other. Switching to PostgreSQL will be as simple as switching to the PostgreSQL Entity Framework Core provider, and the steps below will walk you through this process. + +### What you'll need + +* Git (use `git --version` to make sure it's installed) +* The Heroku CLI (follow the install instructions at https://devcenter.heroku.com/articles/heroku-cli#download-and-install) +* A Heroku account (accounts are free, and this tutorial will only use free tier services on Heroku) + +### Set up Heroku CLI and create new Heroku app + +After installing the Heroku CLI, use the `heroku login` command to log in. + +After doing so, navigate to the `AspNetCoreTodo` directory on your computer (not the testing projects) and use the `heroku create little-aspnetcorebook-12345` command to create a new Heroku app with a unique name. Replace the `12345` with a unique string of characters so as to not cause a conflict with existing Heroku apps. For example, you might use your name for this value. + +Heroku uses Git as a deployment tool. Now that you created the app, a remote Git repository was set up for you. You'll see this remote repository used later in the steps below to deploy your application. + +Heroku uses "[buildpack](https://devcenter.heroku.com/articles/buildpacks)" to decide which steps to complete to prepare the dyno to run your app. They include setup processes such as downloading and installing SDKs (like `apt-get` on an Ubuntu server). Heroku officially supports multiple platforms such as Ruby on Rails and PHP. For those apps, your application's source code structure is enough for Heroku to decide which official buildpack to use. For ASP.NET Core, since it's not yet an official platform, the community is responsible for creating a buildpack for it and you must manually add this buildpack to your Heroku app. Luckily, [this buildpack](https://github.com/jincod/dotnetcore-buildpack) has been created by the open source community, and you can add it to your Heroku app with the following command: + +``` +heroku buildpacks:set https://github.com/jincod/dotnetcore-buildpack +``` + +Next, you'll modify your application's source code to switch to PostgreSQL. + +### Add PostgreSQL provider NuGet package + +The provider comes as a NuGet package called `Npgsql.EntityFrameworkCore.PostgreSQL`. To add the package, run the following command: + +``` +dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL +``` + +After adding the package, you'll notice that the project's `.csproj` file has been updated to reflect the new list of packages: + +```xml + + + + + + + +``` + +### Modify ApplicationDbContext configuration + +Your project's `Startup.cs` file's `ConfigureServices` method currently contains the following code, which hooks up the SQLite provider: + +```csharp +services.AddDbContext(options => + options.UseSqlite(Configuration.GetConnectionString("DefaultConnection"))); +``` + +Change it to the following code, which will instead hook up the PostgreSQL provider: + +```csharp +services.AddEntityFrameworkNpgsql().AddDbContext(options => + options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"))); +``` + +The connection string `DefaultConnection` will also have to be updated to reflect connecting to a different database. Right now, your project's `appsettings.json` file contains the following connection string for SQLite: + +``` +"ConnectionStrings": { + "DefaultConnection": "DataSource=app.db" +} +``` + +Change it to the following code to provide a connection string for PostgreSQL: + +``` +"ConnectionStrings": { + "DefaultConnection": "Server=localhost;Port=5432;User Id=username;Password=secret;Database=todos;" +} +``` + +The connection string is composed of four parameters: + +- You use `localhost` for the `Server` parameter because you'll be running PostgreSQL on your development machine in this tutorial. +- You use `5432` for the `Port` parameter because this is the default port for PostgreSQL, which you won't be changing in this tutorial. +- You use `username` and `secret` for `User Id` and `Password` respectively, because these are simple example values this tutorial uses. In a real world deployment, you would use more secure credentials and tools like the [Secret Manager](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-2.1&tabs=visual-studio) to store them. + +### Starting a PostgreSQL database + +Setting up PostgreSQL on your development machine is outside of the scope of this book. You can install and start PostgreSQL any way you like. However, a convenient, modern way of doing this is using [Docker](https://www.docker.com/). If you've used virtual machines before, Docker "containers" are a similar concept. Think virtualization but without a hypervisor. The containers get direct access to the kernel of the host machine. + +With [Docker installed](https://docs.docker.com/install/) on your machine, you can create and run a container from the [`Postgres`](https://hub.docker.com/_/postgres/) image. You will use the same parameters from the connection string defined above to create the container, using the following command: + +``` +docker run -d -e POSTGRES_USER=username -e POSTGRES_PASSWORD=secret -e POSTGRES_DB=todos -p 5432:5432 --name postgres-todos postgres:latest +``` + +After creating and starting the container (which is what the `docker run` command does), the container is running in the background and exposing port `5432` so that the running ASP.NET Core application and tools like [pgAdmin](https://www.pgadmin.org/) can connect to it at `localhost`. + +### Updating the database with migrations + +Now that PostgreSQL is running in the background, you can update the database with the same command you used earlier in the tutorial when working with SQLite: + +``` +dotnet ef database update +``` + +The reason you must run the migrations again is because this time the connection string defined for the app points to a different database. This new database does not yet have the needed tables created. Running the migrations again at this point in the tutorial prepares the running PostgreSQL database the same way it prepared the SQLite database earlier. + +Now that the migrations have been applied, you can use a program like pgAdmin to connect to the database and see the tables that were created: + +![pgAdmin showing the tables](pgadmin_aspnetcore_tables_created.png) + +Start your app with `dotnet run` and visit `localhost:5000` in your browser. You'll notice that you can create and manipulate `Todo` items just like before, except this time the data is being saved in the PostgreSQL database. Notice how everything works just like it did before without having to change any code except load a different Entity Framework Core provider in `Startup.cs`. + +### Preparing the application for Heroku Postgres + +Right now, your application reads the value of the `DefaultConnection` configuration value at runtime to learn how to connect to the PostgreSQL database running on your development machine. On Heroku, the environment will be different. Heroku sets an environment variable called `DATABASE_URL` for your application to read. You must change your code to read this environment variable instead of the configuration if it detects that it is running on Heroku. In order to tell your application that it's running on Heroku, you'll configure it to read a the environment variable `ASPNETCORE_ENVIRONMENT`. This environment variable has been set to the value `Development` for you automatically by Visual Studio Code so far. You can configure your application to run in "Heroku mode" if this environment variable's value is set to `Production`. Change the following code in `Startup.cs`: + +```csharp +services.AddEntityFrameworkNpgsql().AddDbContext(options => + options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"))); +``` + +to this: + +```csharp +services.AddEntityFrameworkNpgsql().AddDbContext(options => +{ + var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); + + string connStr; + + // Depending on if in development or production, use either Heroku-provided + // connection string, or development connection string from env var. + if (env == "Development") + { + // Use connection string from file. + connStr = Configuration.GetConnectionString("ApplicationDbContext"); + } + else + { + // Use connection string provided at runtime by Heroku. + var connUrl = Environment.GetEnvironmentVariable("DATABASE_URL"); + + // Parse connection URL to connection string for Npgsql + connUrl = connUrl.Replace("postgres://", string.Empty); + var pgUserPass = connUrl.Split("@")[0]; + var pgHostPortDb = connUrl.Split("@")[1]; + var pgHostPort = pgHostPortDb.Split("/")[0]; + var pgDb = pgHostPortDb.Split("/")[1]; + var pgUser = pgUserPass.Split(":")[0]; + var pgPass = pgUserPass.Split(":")[1]; + var pgHost = pgHostPort.Split(":")[0]; + var pgPort = pgHostPort.Split(":")[1]; + + connStr = $"Server={pgHost};Port={pgPort};User Id={pgUser};Password={pgPass};Database={pgDb}"; + } + + // Whether the connection string came from the local development configuration file + // or from the environment variable from Heroku, use it to set up your DbContext. + options.UseNpgsql(connStr); +}); +``` + +It's a lot more code, but it's a powerful change. This will allow your app to decide as it starts up whether it's running on your local development computer or deployed in production mode on Heroku, and connect to the database meant for it properly in both cases. + +Don't mind the code related to parsing the "connection URL". Some platforms, such as Ruby on Rails, can use this value as is. Unfortunately, you must do a bit of extra work to convert it into a value compatible with Entity Framework Core. Feel free to refactor this parsing code into a utility class elsewhere in your application later if you want to. + +**Before continuing**, you must make sure the `ASPNETCORE_ENVIRONMENT` environment variable is set to `Production` so that your application will correctly connect to the database once it's deployed. You can use Heroku's web portal to do this, but to continue with the CLI theme of the book, use the Heroku CLI to do this instead with the `heroku config:set ASPNETCORE_ENVIRONMENT=Production` command. + +### Set up automatic Entity Framework Core migrations on Heroku + +When your application is deployed to Heroku, you won't have a way to run migrations against it like you did on your local development computer. Instead, you'll change your application's source code to automatically obtain an `ApplicationDbContext` instance when it detects that it is starting up on Heroku, and use that instance to run any pending migrations before the application finishes starting up. + +You'll be exposed to a new C# concept here, called "extension methods". Because the best place to run this code will be in `Program.cs` (because it isn't safe to run it in `Startup.cs`), you will add an extension method to the `IWebHost` interface that you will call as part of the method chain in your application's `Main` method body. Create a file called `Extensions.cs` and add the following code to it: + +```csharp +public static class Extensions +{ + public static IWebHost MigrateDatabase(this IWebHost webHost) + { + // Manually run any pending migrations if configured to do so. + var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); + + if (env == "Production") + { + var serviceScopeFactory = (IServiceScopeFactory)webHost.Services.GetService(typeof(IServiceScopeFactory)); + + using (var scope = serviceScopeFactory.CreateScope()) + { + var services = scope.ServiceProvider; + var dbContext = services.GetRequiredService(); + + dbContext.Database.Migrate(); + } + } + + return webHost; + } +} +``` + +The static method in this class adds a method to the `IWebHost` interface that has no parameters. The `this IWebHost webHost` parameter is what allows the method to be added to the `IWebHost` interface as an extension method. + +The code inside will first check whether the application is running in Production, and therefore running on Heroku. If so, it will obtain a temporary DI scope inside which it will obtain an `ApplicationDbContext` instance and perform the pending migrations. Then, the application will continue to start up. + +Then, change your code in `Program.cs` from: + +```csharp +public static void Main(string[] args) +{ + BuildWebHost(args).Run(); +} +``` + +to + +```csharp +public static void Main(string[] args) +{ + BuildWebHost(args) + .MigrateDatabase() + .Run(); +} + +``` + +This will call your new extension method as the application starts up. + +### Deploy to Heroku + +To deploy your application to Heroku, use `git add` and `git commit` to check in your code changes, and run the `git push heroku master` command. You'll see output in your terminal as Heroku goes through its build process. At the end of this process, your application's public URL will be deployed. You can visit this in your web browser to see your deployed app! + +If you change your application's models or add new models, you can add migrations with the `dotnet ef migrations add` command like before. You can run the migrations locally with the `dotnet ef database update` command like before, and when you deploy your application again, those migrations will run automatically to bring the Heroku Postgres database up to date. + +Keep in mind that once your app is running with live data it isn't typical to automatically run migrations. Instead, you would use [more careful techniques](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/#applying-migrations-at-runtime) that usually include using the Entity Framework Core CLI tools to create scripts. diff --git a/chapters/alternative-databases/pgadmin_aspnetcore_tables_created.png b/chapters/deploy-the-application/pgadmin_aspnetcore_tables_created.png similarity index 100% rename from chapters/alternative-databases/pgadmin_aspnetcore_tables_created.png rename to chapters/deploy-the-application/pgadmin_aspnetcore_tables_created.png From 305f41f5ee83beafd460158b92e8a3f9a8f52484 Mon Sep 17 00:00:00 2001 From: Matthew Welke Date: Tue, 10 Jul 2018 23:27:44 -0400 Subject: [PATCH 6/7] Remove old "alternative databases" reference from TOC. --- SUMMARY.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/SUMMARY.md b/SUMMARY.md index 527e9d5..966bd9c 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -33,6 +33,4 @@ * [Deploy to Azure](chapters/deploy-the-application/deploy-to-azure.md) * [Deploy to Heroku with PostgreSQL](chapters/deploy-the-application/deploy-to-heroku-with-postgresql.md) * [Deploy with Docker](chapters/deploy-the-application/deploy-with-docker.md) -* [Alternative databases](chapters/alternative-databases/README.md) - * [PostgreSQL](chapters/alternative-databases/postgresql.md) * [Conclusion](chapters/conclusion/README.md) From 36cbe1bcb441eb6ada0e23bfab0cca9c5981b858 Mon Sep 17 00:00:00 2001 From: Matthew Welke Date: Tue, 10 Jul 2018 23:30:14 -0400 Subject: [PATCH 7/7] Minor changes. --- .../deploy-the-application/deploy-to-heroku-with-postgresql.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapters/deploy-the-application/deploy-to-heroku-with-postgresql.md b/chapters/deploy-the-application/deploy-to-heroku-with-postgresql.md index 2f7860e..9176a92 100644 --- a/chapters/deploy-the-application/deploy-to-heroku-with-postgresql.md +++ b/chapters/deploy-the-application/deploy-to-heroku-with-postgresql.md @@ -204,7 +204,7 @@ public static class Extensions } ``` -The static method in this class adds a method to the `IWebHost` interface that has no parameters. The `this IWebHost webHost` parameter is what allows the method to be added to the `IWebHost` interface as an extension method. +The static method `MigrateDatabase` in this class adds a method to the `IWebHost` interface that has no parameters. The `this IWebHost webHost` parameter is what allows the method to be added to the `IWebHost` interface as an extension method. The code inside will first check whether the application is running in Production, and therefore running on Heroku. If so, it will obtain a temporary DI scope inside which it will obtain an `ApplicationDbContext` instance and perform the pending migrations. Then, the application will continue to start up.