© Les Jackson 2020
L. JacksonThe Complete ASP.NET Core 3 API Tutorialhttps://doi.org/10.1007/978-1-4842-6255-9_5

5. The “C” in MVC

Les Jackson1 
(1)
Melbourne, VIC, Australia
 

Chapter Summary

In this chapter we’ll go over some high-level theory on the Model–View–Controller (MVC) pattern, detail out our API application architecture, and start to code up our API controller class.

When Done, You Will

  • Understand what the MVC pattern is

  • Understand our API application architecture, including concepts such as
    • Repositories

    • Data transfer objects (DTOs)

    • Database contexts

  • Add a controller class to our API project.

  • Create a Controller Action (or API Endpoint if you prefer) that returns “hard-coded” JSON.

  • Place our solution under source control.

Quick Word on My Dev Setup

I just want to level set here on the current state of my development setup I’m going to use moving forward:
  • I have VS Code open and running.

  • In VS Code I have opened the CommandAPISolution solution folder.

  • This displays my folder and file tree down the left-hand side (containing both our projects).

  • I’m also using the integrated terminal within VS Code to run my commands.

  • The integrated terminal I’m using is “PowerShell” – you can change this; see info box in the following.
    ../images/501438_1_En_5_Chapter/501438_1_En_5_Fig1_HTML.jpg
    Figure 5-1

    My VS Code setup

../images/501438_1_En_5_Chapter/501438_1_En_5_Figa_HTML.jpg You can change the terminal/shell/command-line type within VS Code quite easily.
  1. 1.

    In VS Code hit “F1” (this opens the “command palette” in VS Code).

     
  2. 2.

    Type shell at the resulting prompt, and select “Terminal: Select Default Shell.”

     
  3. 3.

    You can then select from the Terminals that you have installed.

     

Start Coding!

First, let’s just check that everything is set up and working OK from a very basic startup perspective. To do this from a command-line type (ensure that you’re “in” the API project directory – CommandAPI)
dotnet run
You should see the webserver start with output similar to the following.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig2_HTML.jpg
Figure 5-2

Running our API for the first time

You can see that the webserver host has started and is listening on ports 5000 and 5001 for http and https, respectively.

../images/501438_1_En_5_Chapter/501438_1_En_5_Figb_HTML.jpg To change that port allocation, you can edit the launchSettings.json file in the Properties folder; for now though there would be no benefit to that. We’ll talk more about this file when we come to our discussion on setting the runtime environment in Chapter 8.

If you go to a web browser and navigate to

http://localhost:5000

You’ll see the following.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig3_HTML.jpg
Figure 5-3

Hello World!

Not hugely useful, but it does tell us that everything is wired up correctly. Looking in the Configure method of our Startup class, we can see where this response is coming from.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig4_HTML.jpg
Figure 5-4

Where our greeting comes from

../images/501438_1_En_5_Chapter/501438_1_En_5_Figc_HTML.jpg For those of you that have worked with any of the 2.x versions of the .NET Core Framework (for those of you that haven’t, you can ignore this), this will look slightly different to what you may have seen before. As opposed to

  • app.UseEndPoints

    You would have seen

  • app.Run(async)

    The previous version of the framework would also make use of

Stop our host from listening (Ctrl+C on Windows – should be the same for Linux/OSX), and remove the highlighted section of code (shown previously) from our Configure method. Add the highlighted code shown next to our Startup class, making sure to update both the ConfigureServices and Configure methods :
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace CommandAPI
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            //SECTION 1. Add code below
            services.AddControllers();
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                //SECTION 2. Add code below
                endpoints.MapControllers();
            });
        }
    }
}
What does this code do?
  1. 1.

    Registers services to enable the use of “Controllers” throughout our application. As mentioned in the info box, in previous versions of .NET Core Framework, you would have specified services.AddMVC. Don’t worry; we cover what the Model–View–Controller (MVC) pattern is below.

     
  2. 2.

    We “MapControllers” to our endpoints. This means we make use of the Controller services (registered in the ConfigureServices method) as endpoints in the Request Pipeline.

     
Reminder

../images/501438_1_En_5_Chapter/501438_1_En_5_Figd_HTML.jpgThe code for the entire solution can be found here on GitHub:

https://github.com/binarythistle/Complete-ASP-NET-3-API-Tutorial-Book

As we have done before, run the project (ensure you save the file before doing this1)
dotnet run

Now, navigate to the same URL in a web browser (http://localhost:5000), and we should get “nothing.”

Call the Postman

Now is probably a good time to get Postman up and running as it’s a useful tool that allows you to have a more detailed look at what’s going on.

So, if you’ve not done so already, go to the Postman website (www.getpostman.com), and download the version most suitable for your environment, (I use the Windows desktop client, but there’s a Chrome plugin along with desktop versions for other operating systems).

We want to make a request to our API using Postman, so click “New.”
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig5_HTML.jpg
Figure 5-5

Start a New Request in Postman

The select “request.”
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig6_HTML.jpg
Figure 5-6

Create a basic request

Give the request a simple name, for example, “Test Request.”
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig7_HTML.jpg
Figure 5-7

Name your request

You’ll also need to create a “Collection” to house the various API requests you want to create (e.g., GET, POST, etc.):
  1. 1.

    Click “+ Create Collection.”

     
  2. 2.

    Give it a name, for example, “CommandAPI.”

     
  3. 3.

    Select OK (the tick), and ensure you select your newly created collection (not shown).

     
  4. 4.

    Click Save to Command API.

     
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig8_HTML.jpg
Figure 5-8

Request Collection

You should then have a new tab available to populate with the details of your request. Simply type
http://localhost:5000
or
https://localhost:5001
into the “Enter request URL” text box, ensure “GET” is selected from the drop-down next to it, and hit SEND; it should look something like the following.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig9_HTML.jpg
Figure 5-9

GET Request results in Postman

If you’ve clicked Send, then you should see a response of “404 Not Found”; clicking on the headers tab, you can see the headers returned.

We’ll return to Postman a bit later, but it’s just useful to get it up, running, and tested now.

What have we broken?

We’ve not actually broken anything, but we have taken the first steps in setting up our application to use the MVC pattern to provide our API endpoint.

What Is MVC?

I’m guessing if you’re here, you probably have some idea of what the MVC (Model–View–Controller) pattern is. If not, I provide a brief explanation here, but as
  1. 1.

    There are already 1000s of articles on MVC.

     
  2. 2.

    MVC theory is not the primary focus of this tutorial.

     

I won’t go into too much detail. Again, I feel you’ll learn more about MVC by building a solution, rather than reading long textual explanations. I think when we cover off the Application Architecture below, things will make much more sense though.

Model–View–Controller

Put simply, the MVC pattern allows us to separate the concerns of different parts of our application:

  • Model (our Domain Data)

  • View (User Interface)

  • Controller (Requests and Actions)

In fact, to make things even simpler, as we’re developing an API, we won’t even have any View artefacts.2 A high-level representation of this architecture for our API is shown here.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig10_HTML.jpg
Figure 5-10

Our API Application Architecture

It’s also worth noting, in case it wasn’t clear, that the MVC pattern is just that – an application architecture pattern – it is agnostic from technical implementation. As this happens to be a book about a particular technology (.NET Core), we cover how .NET Core implements MVC; however, there are other implementations of the MVC pattern using different frameworks and languages.

Models, Data Transfer Objects, Repositories, and Data Access

You’re probably happy enough with the concept of a Model – it’s just data, right? Yes, that’s simple enough. So, looking at the architecture diagram in Figure 5-10, you’re then wondering what’s a DTO, a Repository, and a DB Context. And I don’t blame you – I struggled with the distinction between these concepts too at first. In fact, we could leave out DTOs and Repositories from our solution and it would work without them. So why include them at all? Great question; let me try and explain.

First, let me answer the “what” before I answer the “why.”

What’s the Distinction?

Let’s step through each of those classes:
  • Model: Represents the internal domain data of our application (the “M” in MVC).

  • Data Transfer Objects (DTOs) : Are the representations of our Domain Models to our external consumers, meaning that we don’t expose internal implementation detail (our Models) to external concerns. This has multiple benefits as we’ll discuss later.

  • Data Access (aka DB Context) : Takes our Models and represents (or “mediates”) them down to a specific persistence layer (e.g., PostgreSQL, SQL Server, etc.). Going forward, I’ll refer to our Data Access class as a “DB Context” which is a technology-specific term taken from “Entity Framework Core” – don’t worry; more on that later in Chapter 7.

  • Repository : Provides a technology agnostic (or persistence ignorant) view of our permanently stored data to our application.

So, what do you take from this? The main concept (which is repeated throughout the book) is that we should be decoupling implementational detail from the interface or contract we want to provide to consumers. But why is that a good thing?

Why Decoupling Is Good?

I’ve kind of alluded to that earlier, and we’ll cover it in more detail when we come to implementing these concepts, but in short decoupling our interfaces (or contracts) from our implementations provides the following benefits:
  • Security: We may not want to expose potentially sensitive data contained in our implementation (think our Model) to our external consumers. Providing an external representation (e.g., a DTO) with sensitive information removed addresses this.

  • Change Agility: Separating out our interface – which should remain consistent so as not to break our “contract” with our consumers – means we can then change our implementation detail without impacting that interface. We then have the confidence to react quickly to market demands without fear of breaking existing agreements. We’ll demonstrate this concept more when we come onto using dependency injection and our repository.

Bringing It Together

In the chapters that follow, we’ll leverage MVC as well as the other concepts discussed earlier to
  • Chapter 5: Create a Controller to manage all our API requests (see our CRUD actions in Chapter 3).

  • Chapter 6: Create a Model to internally represent our resources (in this case our library of command-line prompts)

  • Chapter 6: Create a Repository to provide a technology agnostic view of our persisted data.

  • Chapter 7: Leverage Entity Framework Core to create a DB Context that will allow us to persist our Model down to PostgreSQL.

  • Chapter 9: Create DTO representations of our Model for external use.

Let’s wrap our architectural overview there (again, don’t worry – we’ll deep dive these concepts later) and move on to creating our Controller.

Our Controller

Making sure that you are in the main API project directory (CommandAPI), create a folder named “Controllers” underneath CommandAPI as a subfolder.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig11_HTML.jpg
Figure 5-11

Controllers Folder in our API Project

Inside the Controllers folder you just created, create a file called CommandsController.cs .

Quick Tip

../images/501438_1_En_5_Chapter/501438_1_En_5_Fige_HTML.jpgIf you’re using VS Code, you can create both folders and files from within the VS Code directory explorer. Just make sure when you’re creating either that you have the correct “parent” folder selected.

../images/501438_1_En_5_Chapter/501438_1_En_5_Fig12_HTML.jpg
Figure 5-12

File and folder creation in VS Code

Your directory structure should now look like this.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig13_HTML.jpg
Figure 5-13

Our directory structure

Ensure that you postfix the CommandsController file with a “.cs” extension to denote it’s a C# file.

Both the folder and naming convention of our controller file follow a standard, conventional approach; this makes our applications more readable to other developers; it also allows us to leverage from the principles of “Convention over Configuration.”

Now, to begin with we’re just going to create a simple “action” in our Controller that will return some hard-coded JSON (as opposed to serializing data that will ultimately come from our DB). Again, this just makes sure we have everything wired up correctly.

../images/501438_1_En_5_Chapter/501438_1_En_5_Figf_HTML.jpg A controller “Action” (I may also refer to it as an endpoint) maps to our API CRUD operations as listed in Chapter 3; our first action though will just return a simple hard-coded string.

The code in your CommandsController class should now look like this:
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
namespace CommandAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class CommandsController : ControllerBase
    {
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            return new string[] {"this", "is", "hard", "coded"};
        }
    }
}

Again, if you don’t fancy typing this in, the code is available here on GitHub: https://github.com/binarythistle/Complete-ASP-NET-3-API-Tutorial-Book

We’ll come onto what all this means next, but first lets’ build it.

Ensure that you don’t have the server running from our recent example (Ctrl + C to terminate), save the file, then type
dotnet build
This command just compiles (or builds) the code. If you have any errors, it’ll call them out here; assuming all’s well (which is should be), you should see the following.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig14_HTML.jpg
Figure 5-14

Successful API run

Now, run the app.

Learning Opportunity

../images/501438_1_En_5_Chapter/501438_1_En_5_Figg_HTML.jpgI’m deliberately not going to detail that command going forward now; you should be picking this stuff up as we move on. If in doubt, refer to earlier in the chapter on how to run your code (as opposed to building it as we’ve just done).

Go to Postman (or a web browser if you like), and in the URL box, type

http://localhost:5000/api/commands

Ensure that “Get” is selected in the drop-down (in Postman), then click “Send”; you should see something like this.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig15_HTML.jpg
Figure 5-15

Our first API endpoint response

  1. 1.

    This is the hard-coded json string returned.

     
  2. 2.

    We have a 200 OK HTTP response (basically everything is good).

     

I guess technically you could say that we have implemented an API that services a simple “GET” request! Excellent, but I’m sure most of you want to take the example a little further.

Back to Our Code

OK so that’s great, but what did we actually do? Let’s go back to our code and pick it apart.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig16_HTML.jpg
Figure 5-16

Deep dive on our first controller action

1. Using Directives

We included two using directives here:
  • System.Collections.Generic (supports IEnumerable)

  • Microsoft.AspNetCore.Mvc (supports pretty much everything else detailed below)

2. Inherit from Controller Base

Our Controller class inherits from ControllerBase (it does not provide View support which we don’t need). You can inherit from Controller also if you like, but as you can probably guess, this provides additional support for Views that we just don’t need.
ControllerBase is further detailed on Microsoft Build.3

3. Set Up Routing

As you will have seen when you used Postman to issue a GET request to our API, you had to navigate to
http://localhost:5000/api/commands
The URI convention for an API controllers is
http://<server_address>/api/<controller_name>

where we use the route pattern /api/<controller_name> following the main part of the URI.

To enable this, we have “decorated” our CommandsController class with a [Route] attribute:
 [Route("api/[controller]")]

../images/501438_1_En_5_Chapter/501438_1_En_5_Figh_HTML.jpg You’ll notice that when we talk about the name of our controller from a route perspective, we use “Commands” as opposed to the fuller “CommandsController”.

Indeed, the name of our controller really is “Commands”; the use of the “Controller” postfix in our class definition is an example of configuration over convention. Basically, it makes the code easier to read if we use this convention, that is, we know it’s a controller class.

Warning!

../images/501438_1_En_5_Chapter/501438_1_En_5_Figi_HTML.jpg We have specified our route using the [controller] “wildcard,” which dynamically derives that segment of the route from the name of our controller (minus the “Controller” portion) as we’ve explained before. So, in our case, this gives us the route:

api/commands

What this means is that if you change the name of your Controller for whatever reason, the route will change also. This may have quite unexpected consequences for our consumers, in effect breaking our contract - so be careful!

You can “rectify” this behavior by hardcoding the name of your route as so it would become

[Route("api/commands")]

I’ll leave the semi-dynamically declared route for now as I think that is what you’ll most likely see out there in the field, but feel free to change to the hard-coded approach if you’re more comfortable with that.

4. APIController Attribute

Decorating our class with this attribute provides the following out-of-the-box behaviors for our controller:
  • Attribute Routing

  • Automatic HTTP 400 Error responses (e.g., 400 Bad Request, 405 Not Allowed, etc.)

  • Default Binding Sources (more on these later)

  • Problem details for error status codes

It’s not mandatory to use it but highly recommended, as the default behaviors it provides are really useful; for a further deep dive on this, refer to the Microsoft documentation.4

5. HttpGet Attribute

Cast your mind back to the start of the tutorial, and you’ll remember that we specified our standard CRUD actions for our API and that each of those actions aligns to a particular http verb, for example, GET, POST, PUT, etc.

Decorating our first simple action with [HttpGet] is really just specifying which verb our action responds to.

You can test this by changing the verb type in Postman to “POST” and calling our API again. As we have no defined action in our API Controller that responds to POST, we’ll receive a 4xx HTTP error response.

../images/501438_1_En_5_Chapter/501438_1_En_5_Figj_HTML.jpg As mentioned before, the Verb Attribute (e.g., GET) in combination with the route (e.g., api/commands) should be unique for each action (endpoint) within our API.

If you take a look back to our full list of the API endpoints in Chapter 3, you’ll notice that this is indeed the case.

6. Our Controller Action

This is quite an expansive area,5 and there are multiple ways you can write your controller actions. I’ve just opted for the “ActionResult” return type which was introduced as part of .NET Core 2.1.

In short, you’ll have an ActionResult return type for each API CRUD action, so we’ll end up with six by the time we’re finished.

Synchronous vs. Asynchronous?

In the recent example, our controller actions are synchronous, meaning that when they get called by a client (e.g., Postman), they will wait until a result is returned and in doing so occupy a thread (think of a thread as a small slice of a CPU’s time). Once a result is returned, that thread is then released (back to a thread pool) where it can be reused by some other operation.

The problem with synchronous operations is that if there is enough of them (think a high traffic API), eventually all the available threads will be used from the thread pool, blocking further operations from running. That is where asynchronous Controller Actions would come in.

An asynchronous controller action will not wait for a long-running operation (e.g., complex Database query or call over the network) to complete and will hand the thread back to the pool while it waits. When the long-running operation does eventually have a result for us, a thread is reacquired by the controller action to complete the operation.

In short, asynchronous operations are really about scalability and not (as is sometimes claimed) speed. Just using an asynchronous controller action does nothing to improve the time the I/O operation (e.g., database query) takes to complete. It does, however, improve the situation where we may run out of threads (due to blocking) which has positive implications for scaling. There is also some nice usability implications when applied to User Interface design (have you ever used an application that “freezes” when performing a long-running operation?).

I did debate whether to use asynchronous controller actions in our example; however, in keeping with the “Thin and Wide” approach of the book, I thought it would introduce unnecessary complexity that would detract from the core thrust of the book, so I have omitted for now.

This section has already taken up enough space, so let’s move on!

Source Control

OK this has been quite a long chapter, and we’ve covered a lot of ground. Before we wrap it up, I want to introduce the concept of source control.

What is source control?

Source control is really about the following two concepts:
  1. 1.

    Tracking (and rolling back) changes in code

     
  2. 2.

    Coordinating those changes when there are multiple developers/contributors to the code (referred to as Continuous Integration; we’ll deep dive into this in Chapter 12)

     
The general idea is that throughout a code project’s life cycle, many changes will be made to the source code, and we really need a way to track those changes, for reasons including but not limited to
  • Requirements Traceability: Ensuring that the changes relate back to a requested feature/bug fix.

  • Release Notes: Wrapping up our changes so we can publish new release notes for our app.

  • Rolling Back: If we know what changed (and we broke something), we can either (a) fix it or (b) roll back the change – a source control system allows us to do that.

On top of tracking changes, the other primary reason for using a source control solution is to coordinate the changes to the codebase when multiple developers are working on it. If you’re the only person working on your code, you’re not going to really conflict with yourself (well not usually anyway). What about when you have more than one person making changes to the same codebase? How can that happen without things like overwriting each other’s changes? Again, this is where a source control solution comes in to play – it coordinates those changes and identifies conflicts should they arise.

Now, we’re not going to delve too deep into the workings of source control, but we are going to put our project “under source control” for two reasons:
  1. 1.

    To introduce you to the concept

     
  2. 2.

    So we can automatically deploy our app to production via a CI/CD6 pipeline – more in Chapter 12

     

Git and GitHub

Now, there are various source control solutions out there, but by far the most common is Git (and those based around Git), to such an extent that “source control” and Git are almost synonyms. Think about “vacuum cleaners” and “Hoover” (or perhaps now Dyson), and you’ll get the picture.

What’s the difference?

Git is the source control system that
  • You can have running on your local machine to track local code changes

  • You can have running on a server to manage parallel, distributed team changes

While you can use Git in a distributed team environment, there are a number of companies that have taken it further placing “Git in the Cloud,” with such examples as
  • GitHub (probably the most well-recognized – and now acquired by Microsoft)

  • Bitbucket (from Atlassian – the makers of Jira and Confluence)

  • Gitlabs

We’re going to use both Git (locally on our machine) and GitHub as part of this tutorial (as mentioned in Chapter 2).

Setting Up Your Local Git Repo

If you followed along in Chapter 2, you should already have Git up and running locally; if not, or you’re unsure, pop back to Chapter 2, and take a look.

At a terminal/command line in the main solution directory, (CommandAPISolution), type (if your API app is still running you may want to stop it by hitting Ctrl + c)
git init

This should initialize a local Git repository in the solution directory that will track the code changes in a hidden folder called .git (note the period “.” prefixing “git”).

Now type
git status
This will show you all the “untracked” files in your directory (basically files that are not under source control); at this stage, that is everything.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig17_HTML.jpg
Figure 5-17

Untracked files in our new Git Repo

.gitignore file

Before we start to track our solution files (and bring them under source control), there are certain files that you shouldn’t bring under source control, in particular, files that are “generated” as the result of a build, primarily as they are surplus to requirements (they’re not “source” files’!).

In order to “ignore” these file types, you create a file in your “root” solution directory called .gitignore, (again note the period “.” at the beginning). Now this can become quite a personal choice on what you want to include or not, but I have provided an example that you can use (or ignore altogether – excuse the pun!):
*.swp
*.*~
project.lock.json
.DS_Store
*.pyc
# Visual Studio Code
.VS Code
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
msbuild.log
msbuild.err
msbuild.wrn
# Visual Studio
.vs/
# Compiled Source
*.com
*.class
*.dll
*.exe
*.o
*.so
So if you want to use a .gitignore file (I recommend it – you don’t want to put compiled assets in a source repository), create one, and pop it in the root of your solution directory, as I’ve done here (this shows the file in VS Code).
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig18_HTML.jpg
Figure 5-18

Our .gitignore file

Type git status again, and you should see this file now as one of the “untracked” files also.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig19_HTML.jpg
Figure 5-19

Untracked .gitignore file

Track and Commit Your Files

OK, we want to track “everything” (except those files ignored!); to do so, type (ensure you put the trailing period “.”)
git add .
Followed by
git status
You should see the following.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig20_HTML.jpg
Figure 5-20

Tracked Files ready for Commit

These files are being tracked and are “staged” for commit.

Finally, we want to “commit” the changes (essentially lock them in) by typing
git commit -m "Initial Commit"
This commits the code with a note (or “message”; hence the -m switch) about that particular commit. You typically use this to describe the changes or additions you have made to the code (more about this later); you should see the following.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig21_HTML.jpg
Figure 5-21

Committed Files

A quick additional git status and you should see the following.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig22_HTML.jpg
Figure 5-22

No further changes have occurred

Celebration Checkpoint

../images/501438_1_En_5_Chapter/501438_1_En_5_Figk_HTML.jpgGood job! We have basically placed our solution under local source control and have committed all our “changes” to our master branch in our first commit.

../images/501438_1_En_5_Chapter/501438_1_En_5_Figl_HTML.jpg If this is the first time you’ve seen or used Git, I’d suggest you pause reading here and do a bit of Googling to find some additional resources. It’s a fairly big subject on its own, and I don’t want to cover it in depth here, mainly because I’d be repeating noncore content.

I will of course cover the necessary amount of Git to get the job done in this tutorial; further reading is purely optional!

The Git website also allows you to download the full Pro Git ebook; you can find that here: https://git-scm.com/book/en/v2

Set Up Your GitHub Repo

OK so the last section took you through the creation of a local Git repository, and that’s fine for tracking code changes on your local machine. However, if you’re working as part of a larger team, or even as an individual programmer, and want to make use of Azure DevOps (as we will in Chapters 12, 13, and 14), we need to configure a “remote Git repository” that we will
  • Push to from our local machine.

  • Link to an Azure DevOps Build Pipeline to kick off the build process.

Jump over to https://github.com (and if you haven’t already – sign up for an account); you should see your own landing page once you’ve created an account/logged in; here’s mine.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig23_HTML.jpg
Figure 5-23

GitHub Landing Page

Create a GitHub Repository

In the top right-hand corner of the site, click on your face (or whatever the default image is if you’re not a narcissist like me), and select “Your repositories.”
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig24_HTML.jpg
Figure 5-24

Select your repositories

Then click “New” and you should see the “Create a new repository” screen.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig25_HTML.jpg
Figure 5-25

Create your repository

Give the repository a name (I just called mine CommandAPI, but you can call it anything you like), and select either Public or Private. For this tutorial, I strongly recommend selecting Public, primarily as that’s the option I’ve developed this tutorial with – and I know it works with the later sections of the book. Indeed, the option you select here is important as it has impacts when we come to set up our CI/CD pipeline in Chapter 12.

Then click “Create Repository”; you should see the following.
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig26_HTML.jpg
Figure 5-26

GitHub repository created

This page details how you can now link and push your local repository to this remote one (the section I’ve circled). So copy that text, and paste it into your terminal window (you need to make sure you’re still in the root solution folder we were working in previously).
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig27_HTML.jpg
Figure 5-27

Add remote repo and push your local repo

Les’ Personal Anecdote

../images/501438_1_En_5_Chapter/501438_1_En_5_Figm_HTML.jpgYou may get asked to authenticate to GitHub when you issue the second command: git push -u origin master.

I’ve had some issues with this on Windows until I updated the “Git Credential Manager for Windows”; after I updated, it was all smooth sailing. Google “Git Credential Manager for Windows” if you’re having authentication issues, and install the latest version!

So What Just Happened?

Well, in short

  • We “registered” our remote GitHub repo with our local repo (first command).

  • We then pushed our local repo up to GitHub (second command).

Note

The first command line only needs to be issued once; the second one we’ll be using more throughout the rest of the tutorial.

If you refresh your GitHub repository page, instead of seeing the instructions you just issued, you should see our solution!
../images/501438_1_En_5_Chapter/501438_1_En_5_Fig28_HTML.jpg
Figure 5-28

Our code is now on GitHub

You’ll notice “Initial Commit” as a comment against every file and folder – seem familiar?

Well that’s it for this chapter – great job!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.233.72