.NET Core (Part 1)

Neil HaddleyApril 10, 2021

Creating a REST API Service using Microsoft cross-platform framework.

$ dotnet new webapi

$ dotnet new gitignore

$ dotnet run

Example Controller

Example Controller

Creating a Book class

$ code .

Add Book class

Books REST Controller

Add BooksController class

dotnet run

$ dotnet run

https://localhost:5001/books

https://localhost:5001/books

https://localhost:5001/books/1788395549

https://localhost:5001/books/1788395549

https://localhost:5001/books/1234567890

https://localhost:5001/books/1234567890

Swagger

Notice that by default Swagger is available.

https://localhost:5001/swagger/index.html

https://localhost:5001/swagger/index.html

Startup

Support for Swagger is added in the project's Startup.cs file

Static files

Static files can be added to a wwwroot folder in a Dotnet Core webapi project.

The static files can be image files, html files and javascript files.

To enable the static files add "app.UseStaticFiles();" to Startup.cs as shown below.

app.UseStaticFiles()

app.UseStaticFiles()

React client

The static files can be a React app that calls the REST API exposed by the (same) Dotnet Core project.

Running React/Dotnet Core app

Running React/Dotnet Core app

haddley_power_app_api

The BooksController code can be extended to support POST, PUT and DELETE actions

haddley_power_app_api

haddley_power_app_api

Book.cs

TEXT
1using System;
2
3namespace dotnet_api
4{
5    public class Book
6    {
7        public Book(long id, String title)
8        {
9            this.id = id;
10            this.title = title;
11        }
12
13        public long id { get; set; }
14
15        public string title { get; set; }
16    }
17}

BooksController.cs

TEXT
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Threading.Tasks;
5using Microsoft.AspNetCore.Mvc;
6using Microsoft.Extensions.Logging;
7
8namespace dotnet_api.Controllers
9{
10    [ApiController]
11    [Route("[controller]")]
12    public class BooksController : ControllerBase
13    {
14        private static readonly List<Book> books = new List<Book>()
15        {
16            (new Book(1788395549, "Learning Node.js Development")),
17            (new Book(1788620216, "Hands-On Microservices with Node.js"))
18        };
19
20        private readonly ILogger<BooksController> _logger;
21
22        public BooksController(ILogger<BooksController> logger)
23        {
24            _logger = logger;
25        }
26
27        [HttpGet]
28        public IEnumerable<Book> GetBooks()
29        {
30            return books.ToArray();
31        }
32
33        [HttpGet("{id}")]
34        public ActionResult<Book> GetBooks(long id)
35        {
36            Book book = books.Find(x => (x.id == id));
37            if (book == null)
38            {
39                return NotFound("Book Not Found");
40            }
41            return book;
42        }
43
44
45    }
46}

Startup.cs

TEXT
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Threading.Tasks;
5using Microsoft.AspNetCore.Builder;
6using Microsoft.AspNetCore.Hosting;
7using Microsoft.AspNetCore.HttpsPolicy;
8using Microsoft.AspNetCore.Mvc;
9using Microsoft.Extensions.Configuration;
10using Microsoft.Extensions.DependencyInjection;
11using Microsoft.Extensions.Hosting;
12using Microsoft.Extensions.Logging;
13using Microsoft.OpenApi.Models;
14
15namespace dotnet_api
16{
17    public class Startup
18    {
19        public Startup(IConfiguration configuration)
20        {
21            Configuration = configuration;
22        }
23
24        public IConfiguration Configuration { get; }
25
26        // This method gets called by the runtime. Use this method to add services to the container.
27        public void ConfigureServices(IServiceCollection services)
28        {
29
30            services.AddControllers();
31            services.AddSwaggerGen(c =>
32            {
33                c.SwaggerDoc("v1", new OpenApiInfo { Title = "dotnet_api", Version = "v1" });
34            });
35        }
36
37        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
38        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
39        {
40            if (env.IsDevelopment())
41            {
42                app.UseDeveloperExceptionPage();
43                app.UseSwagger();
44                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "dotnet_api v1"));
45            }
46
47            app.UseHttpsRedirection();
48
49            app.UseRouting();
50
51            app.UseAuthorization();
52
53            app.UseEndpoints(endpoints =>
54            {
55                endpoints.MapControllers();
56            });
57        }
58    }
59}

App.js

TEXT
1import React, { useEffect, useState } from 'react';
2
3function App() {
4
5  const [books, setBooks] = useState([]);
6
7  useEffect(() => {
8
9    console.log("use effect");
10    fetch('/books')
11      .then(
12        (d) => {
13          d.json().then((b) => {
14            setBooks(() => b)
15          });
16        }
17      )
18
19  }
20    , [])
21
22  return (
23
24    <>
25        {books.map(book =>
26            <h4>{book.title}</h4>)}
27    </>
28
29  );
30}
31
32export default App;

index.html

TEXT
1<!DOCTYPE html>
2<html lang="en">
3
4<head>
5	<title>React App</title>
6</head>
7
8<body>
9
10	<noscript>You need to enable JavaScript to run this app.</noscript>
11	<div id="root"></div>
12
13	<script>!function (e) {function r(r) {for (var n, i, l = r[0], p = r[1], f = r[2], c = 0, s = []; c < l.length; c++)i = l[c], Object.prototype.hasOwnProperty.call(o, i) && o[i] && s.push(o[i][0]), o[i] = 0; for (n in p) Object.prototype.hasOwnProperty.call(p, n) && (e[n] = p[n]); for (a && a(r); s.length;)s.shift()(); return u.push.apply(u, f || []), t()} function t() {for (var e, r = 0; r < u.length; r++) {for (var t = u[r], n = !0, l = 1; l < t.length; l++) {var p = t[l]; 0 !== o[p] && (n = !1)} n && (u.splice(r--, 1), e = i(i.s = t[0]))} return e} var n = {}, o = {1: 0}, u = []; function i(r) {if (n[r]) return n[r].exports; var t = n[r] = {i: r, l: !1, exports: {}}; return e[r].call(t.exports, t, t.exports, i), t.l = !0, t.exports} i.m = e, i.c = n, i.d = function (e, r, t) {i.o(e, r) || Object.defineProperty(e, r, {enumerable: !0, get: t})}, i.r = function (e) {"undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {value: "Module"}), Object.defineProperty(e, "__esModule", {value: !0})}, i.t = function (e, r) {if (1 & r && (e = i(e)), 8 & r) return e; if (4 & r && "object" == typeof e && e && e.__esModule) return e; var t = Object.create(null); if (i.r(t), Object.defineProperty(t, "default", {enumerable: !0, value: e}), 2 & r && "string" != typeof e) for (var n in e) i.d(t, n, function (r) {return e[r]}.bind(null, n)); return t}, i.n = function (e) {var r = e && e.__esModule ? function () {return e.default} : function () {return e}; return i.d(r, "a", r), r}, i.o = function (e, r) {return Object.prototype.hasOwnProperty.call(e, r)}, i.p = "/"; var l = this["webpackJsonpnode-spring-client"] = this["webpackJsonpnode-spring-client"] || [], p = l.push.bind(l); l.push = r, l = l.slice(); for (var f = 0; f < l.length; f++)r(l[f]); var a = p; t()}([])</script>
14	<script src="/js/2.bd91be3c.chunk.js"></script>
15	<script src="/js/main.d36b6e09.chunk.js"></script>
16
17</body>
18
19</html>

BookController.cs

TEXT
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Threading.Tasks;
5using Microsoft.AspNetCore.Mvc;
6using Microsoft.Extensions.Logging;
7
8namespace haddley_power_app_api.Controllers
9{
10    [ApiController]
11    [Route("[controller]")]
12    public class BookController : ControllerBase
13    {
14
15        private static readonly List<Book> books = new List<Book>()
16            {
17                (new Book(1788395549, "Learning Node.js Development")),
18                (new Book(1788620216, "Hands-On Microservices with Node.js"))
19            };
20
21        private readonly ILogger<BookController> _logger;
22
23        public BookController(ILogger<BookController> logger)
24        {
25            _logger = logger;
26        }
27
28        [HttpGet]
29        public IEnumerable<Book> GetBooks()
30        {
31            return books.ToArray();
32        }
33
34        [HttpGet("{id}")]
35        public ActionResult<Book> GetBooks(long id)
36        {
37            var itemFound = books.SingleOrDefault(book => book.id == id);
38            if (itemFound == null)
39            {
40                return NotFound("Book Not Found");
41            }
42
43            return itemFound;
44        }
45
46        
47        [HttpPost]
48        public IActionResult Post([FromBody] Book book)
49        {
50            books.Add(book);
51
52            System.Console.WriteLine(book.title);
53
54            return StatusCode(200);
55        }
56
57
58        [HttpPut("{id}")]
59        public IActionResult Put(long id, [FromBody] Book book)
60        {
61            var itemToUpdate = books.SingleOrDefault(book => book.id == id);
62            if (itemToUpdate != null)
63                itemToUpdate.title = book.title;
64
65            return StatusCode(200);
66        }
67
68        [HttpDelete("{id}")]
69        public IActionResult Delete(long id)
70        {
71            var itemToRemove = books.SingleOrDefault(book => book.id == id);
72            if (itemToRemove != null)
73                books.Remove(itemToRemove);
74            return StatusCode(200);
75        }
76
77    }
78
79}