├── samples
├── Chapter1
│ └── FooApi
│ │ ├── Host
│ │ ├── wwwroot
│ │ │ ├── js
│ │ │ │ ├── site.min.js
│ │ │ │ └── site.js
│ │ │ ├── favicon.ico
│ │ │ ├── lib
│ │ │ │ ├── bootstrap
│ │ │ │ │ ├── dist
│ │ │ │ │ │ ├── fonts
│ │ │ │ │ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ │ │ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ │ │ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ │ │ │ │ └── glyphicons-halflings-regular.woff2
│ │ │ │ │ │ └── js
│ │ │ │ │ │ │ └── npm.js
│ │ │ │ │ ├── .bower.json
│ │ │ │ │ └── LICENSE
│ │ │ │ ├── jquery
│ │ │ │ │ ├── .bower.json
│ │ │ │ │ └── LICENSE.txt
│ │ │ │ ├── jquery-validation
│ │ │ │ │ ├── .bower.json
│ │ │ │ │ └── LICENSE.md
│ │ │ │ └── jquery-validation-unobtrusive
│ │ │ │ │ ├── .bower.json
│ │ │ │ │ └── jquery.validate.unobtrusive.min.js
│ │ │ ├── css
│ │ │ │ ├── site.min.css
│ │ │ │ └── site.css
│ │ │ └── images
│ │ │ │ ├── banner2.svg
│ │ │ │ └── banner1.svg
│ │ ├── appsettings.json
│ │ ├── appsettings.Development.json
│ │ ├── Host.csproj
│ │ ├── Program.cs
│ │ ├── bundleconfig.json
│ │ └── Startup.cs
│ │ ├── FooApi
│ │ ├── Models
│ │ │ └── Bar.cs
│ │ ├── FooApi.csproj
│ │ ├── Controllers
│ │ │ └── FooController.cs
│ │ └── FooConfiguration.cs
│ │ ├── FunctionalTests
│ │ ├── FunctionalTests.csproj
│ │ ├── Scenarios
│ │ │ └── FooController.cs
│ │ └── Seedwork
│ │ │ └── FooFixture.cs
│ │ └── FooApi.sln
├── Chapter2
│ └── FooApi
│ │ ├── Host
│ │ ├── wwwroot
│ │ │ ├── js
│ │ │ │ ├── site.min.js
│ │ │ │ └── site.js
│ │ │ ├── favicon.ico
│ │ │ ├── lib
│ │ │ │ ├── bootstrap
│ │ │ │ │ ├── dist
│ │ │ │ │ │ ├── fonts
│ │ │ │ │ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ │ │ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ │ │ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ │ │ │ │ └── glyphicons-halflings-regular.woff2
│ │ │ │ │ │ └── js
│ │ │ │ │ │ │ └── npm.js
│ │ │ │ │ ├── .bower.json
│ │ │ │ │ └── LICENSE
│ │ │ │ ├── jquery
│ │ │ │ │ ├── .bower.json
│ │ │ │ │ └── LICENSE.txt
│ │ │ │ ├── jquery-validation
│ │ │ │ │ ├── .bower.json
│ │ │ │ │ └── LICENSE.md
│ │ │ │ └── jquery-validation-unobtrusive
│ │ │ │ │ ├── .bower.json
│ │ │ │ │ └── jquery.validate.unobtrusive.min.js
│ │ │ ├── css
│ │ │ │ ├── site.min.css
│ │ │ │ └── site.css
│ │ │ └── images
│ │ │ │ ├── banner2.svg
│ │ │ │ └── banner1.svg
│ │ ├── appsettings.json
│ │ ├── appsettings.Development.json
│ │ ├── Host.csproj
│ │ ├── Program.cs
│ │ ├── bundleconfig.json
│ │ └── Startup.cs
│ │ ├── FooApi
│ │ ├── Models
│ │ │ └── Bar.cs
│ │ ├── FooApi.csproj
│ │ ├── Controllers
│ │ │ └── FooController.cs
│ │ └── FooConfiguration.cs
│ │ ├── FunctionalTests
│ │ ├── FunctionalTests.csproj
│ │ ├── Seedwork
│ │ │ └── FooFixture.cs
│ │ └── Scenarios
│ │ │ └── FooController.cs
│ │ └── FooApi.sln
├── Chapter3
│ └── FooApi
│ │ ├── Host
│ │ ├── wwwroot
│ │ │ ├── js
│ │ │ │ ├── site.min.js
│ │ │ │ └── site.js
│ │ │ ├── favicon.ico
│ │ │ ├── lib
│ │ │ │ ├── bootstrap
│ │ │ │ │ ├── dist
│ │ │ │ │ │ ├── fonts
│ │ │ │ │ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ │ │ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ │ │ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ │ │ │ │ └── glyphicons-halflings-regular.woff2
│ │ │ │ │ │ └── js
│ │ │ │ │ │ │ └── npm.js
│ │ │ │ │ ├── .bower.json
│ │ │ │ │ └── LICENSE
│ │ │ │ ├── jquery
│ │ │ │ │ ├── .bower.json
│ │ │ │ │ └── LICENSE.txt
│ │ │ │ ├── jquery-validation
│ │ │ │ │ ├── .bower.json
│ │ │ │ │ └── LICENSE.md
│ │ │ │ └── jquery-validation-unobtrusive
│ │ │ │ │ ├── .bower.json
│ │ │ │ │ └── jquery.validate.unobtrusive.min.js
│ │ │ ├── css
│ │ │ │ ├── site.min.css
│ │ │ │ └── site.css
│ │ │ └── images
│ │ │ │ ├── banner2.svg
│ │ │ │ └── banner1.svg
│ │ ├── appsettings.json
│ │ ├── appsettings.Development.json
│ │ ├── Host.csproj
│ │ ├── Program.cs
│ │ ├── bundleconfig.json
│ │ └── Startup.cs
│ │ ├── FooApi
│ │ ├── Models
│ │ │ └── Bar.cs
│ │ ├── FooApi.csproj
│ │ ├── Controllers
│ │ │ └── FooController.cs
│ │ └── FooConfiguration.cs
│ │ ├── FunctionalTests
│ │ ├── FunctionalTests.csproj
│ │ ├── Seedwork
│ │ │ ├── FooFixture.cs
│ │ │ └── MyTestsAuthenticationHandler.cs
│ │ └── Scenarios
│ │ │ └── FooController.cs
│ │ └── FooApi.sln
└── Chapter4
│ └── FooApi
│ ├── Host
│ ├── wwwroot
│ │ ├── js
│ │ │ ├── site.min.js
│ │ │ └── site.js
│ │ ├── favicon.ico
│ │ ├── lib
│ │ │ ├── bootstrap
│ │ │ │ ├── dist
│ │ │ │ │ ├── fonts
│ │ │ │ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ │ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ │ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ │ │ │ └── glyphicons-halflings-regular.woff2
│ │ │ │ │ └── js
│ │ │ │ │ │ └── npm.js
│ │ │ │ ├── .bower.json
│ │ │ │ └── LICENSE
│ │ │ ├── jquery
│ │ │ │ ├── .bower.json
│ │ │ │ └── LICENSE.txt
│ │ │ ├── jquery-validation
│ │ │ │ ├── .bower.json
│ │ │ │ └── LICENSE.md
│ │ │ └── jquery-validation-unobtrusive
│ │ │ │ ├── .bower.json
│ │ │ │ └── jquery.validate.unobtrusive.min.js
│ │ ├── css
│ │ │ ├── site.min.css
│ │ │ └── site.css
│ │ └── images
│ │ │ └── banner2.svg
│ ├── appsettings.json
│ ├── appsettings.Development.json
│ ├── Host.csproj
│ ├── bundleconfig.json
│ ├── Program.cs
│ └── Startup.cs
│ ├── FooApi
│ ├── Models
│ │ ├── Bar.cs
│ │ └── FooDbContext.cs
│ ├── FooApi.csproj
│ ├── Controllers
│ │ └── FooController.cs
│ ├── Migrations
│ │ ├── 20180307192205_Initial.cs
│ │ ├── FooDbContextModelSnapshot.cs
│ │ └── 20180307192205_Initial.Designer.cs
│ ├── FooConfiguration.cs
│ └── IWebHostExtensions.cs
│ ├── FunctionalTests
│ ├── Seedwork
│ │ ├── ResetDatabaseAttribute.cs
│ │ ├── MyTestsAuthenticationHandler.cs
│ │ └── FooFixture.cs
│ ├── FunctionalTests.csproj
│ └── Scenarios
│ │ └── FooController.cs
│ └── FooApi.sln
├── LICENSE
├── README.en.md
├── README.md
├── .gitignore
└── chapters
└── es
└── chapter2.md
/samples/Chapter1/FooApi/Host/wwwroot/js/site.min.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/js/site.min.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/js/site.min.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/js/site.min.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/js/site.js:
--------------------------------------------------------------------------------
1 | // Write your JavaScript code.
2 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/js/site.js:
--------------------------------------------------------------------------------
1 | // Write your JavaScript code.
2 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/js/site.js:
--------------------------------------------------------------------------------
1 | // Write your JavaScript code.
2 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/js/site.js:
--------------------------------------------------------------------------------
1 | // Write your JavaScript code.
2 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter1/FooApi/Host/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter2/FooApi/Host/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter3/FooApi/Host/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter4/FooApi/Host/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter1/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter1/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter1/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter2/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter2/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter2/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter3/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter3/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter3/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter4/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter4/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter4/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/FooApi/Models/Bar.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace FooApi.Models
6 | {
7 | public class Bar
8 | {
9 | public int Id { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter1/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/FooApi/Models/Bar.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace FooApi.Models
6 | {
7 | public class Bar
8 | {
9 | public int Id { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter2/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/FooApi/Models/Bar.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace FooApi.Models
6 | {
7 | public class Bar
8 | {
9 | public int Id { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter3/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FooApi/Models/Bar.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace FooApi.Models
6 | {
7 | public class Bar
8 | {
9 | public int Id { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Xabaril/ManualEffectiveTestingHttpAPI/HEAD/samples/Chapter4/FooApi/Host/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Debug",
6 | "System": "Information",
7 | "Microsoft": "Information"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Debug",
6 | "System": "Information",
7 | "Microsoft": "Information"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Debug",
6 | "System": "Information",
7 | "Microsoft": "Information"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "IncludeScopes": false,
4 | "LogLevel": {
5 | "Default": "Debug",
6 | "System": "Information",
7 | "Microsoft": "Information"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/css/site.min.css:
--------------------------------------------------------------------------------
1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}.carousel-caption p{font-size:20px;line-height:1.4}.carousel-inner .item img[src$=".svg"]{width:100%}#qrCode{margin:15px}@media screen and (max-width:767px){.carousel-caption{display:none}}
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/css/site.min.css:
--------------------------------------------------------------------------------
1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}.carousel-caption p{font-size:20px;line-height:1.4}.carousel-inner .item img[src$=".svg"]{width:100%}#qrCode{margin:15px}@media screen and (max-width:767px){.carousel-caption{display:none}}
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/css/site.min.css:
--------------------------------------------------------------------------------
1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}.carousel-caption p{font-size:20px;line-height:1.4}.carousel-inner .item img[src$=".svg"]{width:100%}#qrCode{margin:15px}@media screen and (max-width:767px){.carousel-caption{display:none}}
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/css/site.min.css:
--------------------------------------------------------------------------------
1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}.carousel-caption p{font-size:20px;line-height:1.4}.carousel-inner .item img[src$=".svg"]{width:100%}#qrCode{margin:15px}@media screen and (max-width:767px){.carousel-caption{display:none}}
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/FooApi/FooApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FunctionalTests/Seedwork/ResetDatabaseAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using Xunit.Sdk;
3 |
4 | namespace FunctionalTests.Seedwork
5 | {
6 | public class ResetDatabaseAttribute : BeforeAfterTestAttribute
7 | {
8 | public override void Before(MethodInfo methodUnderTest)
9 | {
10 | FooFixture.ResetDatabase();
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/FooApi/FooApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/FooApi/FooApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FooApi/Models/FooDbContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 |
6 | namespace FooApi.Models
7 | {
8 | public class FooDbContext : DbContext
9 | {
10 | public DbSet Bars { get; set; }
11 |
12 | public FooDbContext(DbContextOptions options) : base(options)
13 | {
14 |
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/FooApi/Controllers/FooController.cs:
--------------------------------------------------------------------------------
1 | using FooApi.Models;
2 | using Microsoft.AspNetCore.Mvc;
3 |
4 | namespace FooApi.Controllers
5 | {
6 | [Route("api/[controller]")]
7 | public class FooController : Controller
8 | {
9 | [HttpGet("")]
10 | public IActionResult Get(int id)
11 | {
12 | var bar = new Bar() { Id = id };
13 |
14 | return Ok(bar);
15 | }
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FooApi/FooApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/Host.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/Host.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/Host.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/Host.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/lib/bootstrap/dist/js/npm.js:
--------------------------------------------------------------------------------
1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
2 | require('../../js/transition.js')
3 | require('../../js/alert.js')
4 | require('../../js/button.js')
5 | require('../../js/carousel.js')
6 | require('../../js/collapse.js')
7 | require('../../js/dropdown.js')
8 | require('../../js/modal.js')
9 | require('../../js/tooltip.js')
10 | require('../../js/popover.js')
11 | require('../../js/scrollspy.js')
12 | require('../../js/tab.js')
13 | require('../../js/affix.js')
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/lib/bootstrap/dist/js/npm.js:
--------------------------------------------------------------------------------
1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
2 | require('../../js/transition.js')
3 | require('../../js/alert.js')
4 | require('../../js/button.js')
5 | require('../../js/carousel.js')
6 | require('../../js/collapse.js')
7 | require('../../js/dropdown.js')
8 | require('../../js/modal.js')
9 | require('../../js/tooltip.js')
10 | require('../../js/popover.js')
11 | require('../../js/scrollspy.js')
12 | require('../../js/tab.js')
13 | require('../../js/affix.js')
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/lib/bootstrap/dist/js/npm.js:
--------------------------------------------------------------------------------
1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
2 | require('../../js/transition.js')
3 | require('../../js/alert.js')
4 | require('../../js/button.js')
5 | require('../../js/carousel.js')
6 | require('../../js/collapse.js')
7 | require('../../js/dropdown.js')
8 | require('../../js/modal.js')
9 | require('../../js/tooltip.js')
10 | require('../../js/popover.js')
11 | require('../../js/scrollspy.js')
12 | require('../../js/tab.js')
13 | require('../../js/affix.js')
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/lib/bootstrap/dist/js/npm.js:
--------------------------------------------------------------------------------
1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
2 | require('../../js/transition.js')
3 | require('../../js/alert.js')
4 | require('../../js/button.js')
5 | require('../../js/carousel.js')
6 | require('../../js/collapse.js')
7 | require('../../js/dropdown.js')
8 | require('../../js/modal.js')
9 | require('../../js/tooltip.js')
10 | require('../../js/popover.js')
11 | require('../../js/scrollspy.js')
12 | require('../../js/tab.js')
13 | require('../../js/affix.js')
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/FooApi/Controllers/FooController.cs:
--------------------------------------------------------------------------------
1 | using FooApi.Models;
2 | using Microsoft.AspNetCore.Mvc;
3 |
4 | namespace FooApi.Controllers
5 | {
6 | [Route("api/v{version:apiVersion}/[controller]")]
7 | public class FooController : Controller
8 | {
9 | [HttpGet()]
10 | public IActionResult Get(int id)
11 | {
12 | var bar = new Bar() { Id = id };
13 |
14 | return Ok(bar);
15 | }
16 |
17 | [HttpPost()]
18 | public IActionResult Post([FromBody]Bar bar)
19 | {
20 | return CreatedAtAction(nameof(Get), new { id = bar.Id });
21 | }
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/lib/jquery/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery",
3 | "main": "dist/jquery.js",
4 | "license": "MIT",
5 | "ignore": [
6 | "package.json"
7 | ],
8 | "keywords": [
9 | "jquery",
10 | "javascript",
11 | "browser",
12 | "library"
13 | ],
14 | "homepage": "https://github.com/jquery/jquery-dist",
15 | "version": "2.2.0",
16 | "_release": "2.2.0",
17 | "_resolution": {
18 | "type": "version",
19 | "tag": "2.2.0",
20 | "commit": "6fc01e29bdad0964f62ef56d01297039cdcadbe5"
21 | },
22 | "_source": "git://github.com/jquery/jquery-dist.git",
23 | "_target": "2.2.0",
24 | "_originalSource": "jquery"
25 | }
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/lib/jquery/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery",
3 | "main": "dist/jquery.js",
4 | "license": "MIT",
5 | "ignore": [
6 | "package.json"
7 | ],
8 | "keywords": [
9 | "jquery",
10 | "javascript",
11 | "browser",
12 | "library"
13 | ],
14 | "homepage": "https://github.com/jquery/jquery-dist",
15 | "version": "2.2.0",
16 | "_release": "2.2.0",
17 | "_resolution": {
18 | "type": "version",
19 | "tag": "2.2.0",
20 | "commit": "6fc01e29bdad0964f62ef56d01297039cdcadbe5"
21 | },
22 | "_source": "git://github.com/jquery/jquery-dist.git",
23 | "_target": "2.2.0",
24 | "_originalSource": "jquery"
25 | }
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/lib/jquery/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery",
3 | "main": "dist/jquery.js",
4 | "license": "MIT",
5 | "ignore": [
6 | "package.json"
7 | ],
8 | "keywords": [
9 | "jquery",
10 | "javascript",
11 | "browser",
12 | "library"
13 | ],
14 | "homepage": "https://github.com/jquery/jquery-dist",
15 | "version": "2.2.0",
16 | "_release": "2.2.0",
17 | "_resolution": {
18 | "type": "version",
19 | "tag": "2.2.0",
20 | "commit": "6fc01e29bdad0964f62ef56d01297039cdcadbe5"
21 | },
22 | "_source": "git://github.com/jquery/jquery-dist.git",
23 | "_target": "2.2.0",
24 | "_originalSource": "jquery"
25 | }
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/lib/jquery/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery",
3 | "main": "dist/jquery.js",
4 | "license": "MIT",
5 | "ignore": [
6 | "package.json"
7 | ],
8 | "keywords": [
9 | "jquery",
10 | "javascript",
11 | "browser",
12 | "library"
13 | ],
14 | "homepage": "https://github.com/jquery/jquery-dist",
15 | "version": "2.2.0",
16 | "_release": "2.2.0",
17 | "_resolution": {
18 | "type": "version",
19 | "tag": "2.2.0",
20 | "commit": "6fc01e29bdad0964f62ef56d01297039cdcadbe5"
21 | },
22 | "_source": "git://github.com/jquery/jquery-dist.git",
23 | "_target": "2.2.0",
24 | "_originalSource": "jquery"
25 | }
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/FooApi/FooConfiguration.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | namespace FooApi
8 | {
9 | public static class FooConfiguration
10 | {
11 | public static IServiceCollection ConfigureServices(IServiceCollection services) =>
12 | services
13 | .AddMvc()
14 | .Services;
15 |
16 | public static void Configure(IApplicationBuilder app, Func configureHost) =>
17 | configureHost(app)
18 | .UseMvc();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Logging;
10 |
11 | namespace Host
12 | {
13 | public class Program
14 | {
15 | public static void Main(string[] args)
16 | {
17 | BuildWebHost(args).Run();
18 | }
19 |
20 | public static IWebHost BuildWebHost(string[] args) =>
21 | WebHost.CreateDefaultBuilder(args)
22 | .UseStartup()
23 | .Build();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Logging;
10 |
11 | namespace Host
12 | {
13 | public class Program
14 | {
15 | public static void Main(string[] args)
16 | {
17 | BuildWebHost(args).Run();
18 | }
19 |
20 | public static IWebHost BuildWebHost(string[] args) =>
21 | WebHost.CreateDefaultBuilder(args)
22 | .UseStartup()
23 | .Build();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Logging;
10 |
11 | namespace Host
12 | {
13 | public class Program
14 | {
15 | public static void Main(string[] args)
16 | {
17 | BuildWebHost(args).Run();
18 | }
19 |
20 | public static IWebHost BuildWebHost(string[] args) =>
21 | WebHost.CreateDefaultBuilder(args)
22 | .UseStartup()
23 | .Build();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/bundleconfig.json:
--------------------------------------------------------------------------------
1 | // Configure bundling and minification for the project.
2 | // More info at https://go.microsoft.com/fwlink/?LinkId=808241
3 | [
4 | {
5 | "outputFileName": "wwwroot/css/site.min.css",
6 | // An array of relative input file paths. Globbing patterns supported
7 | "inputFiles": [
8 | "wwwroot/css/site.css"
9 | ]
10 | },
11 | {
12 | "outputFileName": "wwwroot/js/site.min.js",
13 | "inputFiles": [
14 | "wwwroot/js/site.js"
15 | ],
16 | // Optionally specify minification options
17 | "minify": {
18 | "enabled": true,
19 | "renameLocals": true
20 | },
21 | // Optionally generate .map file
22 | "sourceMap": false
23 | }
24 | ]
25 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/bundleconfig.json:
--------------------------------------------------------------------------------
1 | // Configure bundling and minification for the project.
2 | // More info at https://go.microsoft.com/fwlink/?LinkId=808241
3 | [
4 | {
5 | "outputFileName": "wwwroot/css/site.min.css",
6 | // An array of relative input file paths. Globbing patterns supported
7 | "inputFiles": [
8 | "wwwroot/css/site.css"
9 | ]
10 | },
11 | {
12 | "outputFileName": "wwwroot/js/site.min.js",
13 | "inputFiles": [
14 | "wwwroot/js/site.js"
15 | ],
16 | // Optionally specify minification options
17 | "minify": {
18 | "enabled": true,
19 | "renameLocals": true
20 | },
21 | // Optionally generate .map file
22 | "sourceMap": false
23 | }
24 | ]
25 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/bundleconfig.json:
--------------------------------------------------------------------------------
1 | // Configure bundling and minification for the project.
2 | // More info at https://go.microsoft.com/fwlink/?LinkId=808241
3 | [
4 | {
5 | "outputFileName": "wwwroot/css/site.min.css",
6 | // An array of relative input file paths. Globbing patterns supported
7 | "inputFiles": [
8 | "wwwroot/css/site.css"
9 | ]
10 | },
11 | {
12 | "outputFileName": "wwwroot/js/site.min.js",
13 | "inputFiles": [
14 | "wwwroot/js/site.js"
15 | ],
16 | // Optionally specify minification options
17 | "minify": {
18 | "enabled": true,
19 | "renameLocals": true
20 | },
21 | // Optionally generate .map file
22 | "sourceMap": false
23 | }
24 | ]
25 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/bundleconfig.json:
--------------------------------------------------------------------------------
1 | // Configure bundling and minification for the project.
2 | // More info at https://go.microsoft.com/fwlink/?LinkId=808241
3 | [
4 | {
5 | "outputFileName": "wwwroot/css/site.min.css",
6 | // An array of relative input file paths. Globbing patterns supported
7 | "inputFiles": [
8 | "wwwroot/css/site.css"
9 | ]
10 | },
11 | {
12 | "outputFileName": "wwwroot/js/site.min.js",
13 | "inputFiles": [
14 | "wwwroot/js/site.js"
15 | ],
16 | // Optionally specify minification options
17 | "minify": {
18 | "enabled": true,
19 | "renameLocals": true
20 | },
21 | // Optionally generate .map file
22 | "sourceMap": false
23 | }
24 | ]
25 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/FunctionalTests/FunctionalTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/FooApi/Controllers/FooController.cs:
--------------------------------------------------------------------------------
1 | using FooApi.Models;
2 | using Microsoft.AspNetCore.Authorization;
3 | using Microsoft.AspNetCore.Mvc;
4 |
5 | namespace FooApi.Controllers
6 | {
7 | [Route("api/v{version:apiVersion}/[controller]")]
8 | public class FooController : Controller
9 | {
10 | [HttpGet()]
11 | [Authorize("GetPolicy")]
12 | public IActionResult Get(int id)
13 | {
14 | var bar = new Bar() { Id = id };
15 |
16 | return Ok(bar);
17 | }
18 |
19 | [HttpPost()]
20 | [Authorize("PostPolicy")]
21 | public IActionResult Post([FromBody]Bar bar)
22 | {
23 | return CreatedAtAction(nameof(Get), new { id = bar.Id });
24 | }
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 50px;
3 | padding-bottom: 20px;
4 | }
5 |
6 | /* Wrapping element */
7 | /* Set some basic padding to keep content from hitting the edges */
8 | .body-content {
9 | padding-left: 15px;
10 | padding-right: 15px;
11 | }
12 |
13 | /* Carousel */
14 | .carousel-caption p {
15 | font-size: 20px;
16 | line-height: 1.4;
17 | }
18 |
19 | /* Make .svg files in the carousel display properly in older browsers */
20 | .carousel-inner .item img[src$=".svg"] {
21 | width: 100%;
22 | }
23 |
24 | /* QR code generator */
25 | #qrCode {
26 | margin: 15px;
27 | }
28 |
29 | /* Hide/rearrange for smaller screens */
30 | @media screen and (max-width: 767px) {
31 | /* Hide captions */
32 | .carousel-caption {
33 | display: none;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 50px;
3 | padding-bottom: 20px;
4 | }
5 |
6 | /* Wrapping element */
7 | /* Set some basic padding to keep content from hitting the edges */
8 | .body-content {
9 | padding-left: 15px;
10 | padding-right: 15px;
11 | }
12 |
13 | /* Carousel */
14 | .carousel-caption p {
15 | font-size: 20px;
16 | line-height: 1.4;
17 | }
18 |
19 | /* Make .svg files in the carousel display properly in older browsers */
20 | .carousel-inner .item img[src$=".svg"] {
21 | width: 100%;
22 | }
23 |
24 | /* QR code generator */
25 | #qrCode {
26 | margin: 15px;
27 | }
28 |
29 | /* Hide/rearrange for smaller screens */
30 | @media screen and (max-width: 767px) {
31 | /* Hide captions */
32 | .carousel-caption {
33 | display: none;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 50px;
3 | padding-bottom: 20px;
4 | }
5 |
6 | /* Wrapping element */
7 | /* Set some basic padding to keep content from hitting the edges */
8 | .body-content {
9 | padding-left: 15px;
10 | padding-right: 15px;
11 | }
12 |
13 | /* Carousel */
14 | .carousel-caption p {
15 | font-size: 20px;
16 | line-height: 1.4;
17 | }
18 |
19 | /* Make .svg files in the carousel display properly in older browsers */
20 | .carousel-inner .item img[src$=".svg"] {
21 | width: 100%;
22 | }
23 |
24 | /* QR code generator */
25 | #qrCode {
26 | margin: 15px;
27 | }
28 |
29 | /* Hide/rearrange for smaller screens */
30 | @media screen and (max-width: 767px) {
31 | /* Hide captions */
32 | .carousel-caption {
33 | display: none;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using FooApi.Models;
7 | using Microsoft.AspNetCore;
8 | using Microsoft.AspNetCore.Hosting;
9 | using Microsoft.Extensions.Configuration;
10 | using Microsoft.Extensions.Logging;
11 |
12 | namespace Host
13 | {
14 | public class Program
15 | {
16 | public static void Main(string[] args)
17 | {
18 | BuildWebHost(args)
19 | .MigrateDbContext((ctx,sp)=> { })
20 | .Run();
21 | }
22 |
23 | public static IWebHost BuildWebHost(string[] args) =>
24 | WebHost.CreateDefaultBuilder(args)
25 | .UseStartup()
26 | .Build();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 50px;
3 | padding-bottom: 20px;
4 | }
5 |
6 | /* Wrapping element */
7 | /* Set some basic padding to keep content from hitting the edges */
8 | .body-content {
9 | padding-left: 15px;
10 | padding-right: 15px;
11 | }
12 |
13 | /* Carousel */
14 | .carousel-caption p {
15 | font-size: 20px;
16 | line-height: 1.4;
17 | }
18 |
19 | /* Make .svg files in the carousel display properly in older browsers */
20 | .carousel-inner .item img[src$=".svg"] {
21 | width: 100%;
22 | }
23 |
24 | /* QR code generator */
25 | #qrCode {
26 | margin: 15px;
27 | }
28 |
29 | /* Hide/rearrange for smaller screens */
30 | @media screen and (max-width: 767px) {
31 | /* Hide captions */
32 | .carousel-caption {
33 | display: none;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/FunctionalTests/FunctionalTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/FunctionalTests/FunctionalTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/FunctionalTests/Scenarios/FooController.cs:
--------------------------------------------------------------------------------
1 | using FooApi;
2 | using FunctionalTests.Seedwork;
3 | using Microsoft.AspNetCore.Builder;
4 | using Microsoft.AspNetCore.Hosting;
5 | using Microsoft.AspNetCore.TestHost;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using System.Threading.Tasks;
8 | using Xunit;
9 |
10 | namespace FunctionalTests.Scenarios
11 | {
12 | [Collection("Foo")]
13 | public class foo_api_should
14 | {
15 | private readonly FooFixture Given;
16 |
17 | public foo_api_should(FooFixture fooFixture)
18 | {
19 | Given = fooFixture;
20 | }
21 |
22 | [Fact]
23 | public async Task get_bar_when_requested()
24 | {
25 | var response = await Given.FooServer.CreateRequest("api/foo")
26 | .GetAsync();
27 |
28 | response.EnsureSuccessStatusCode();
29 | }
30 | }
31 |
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/FooApi/FooConfiguration.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Mvc;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 |
8 | namespace FooApi
9 | {
10 | public static class FooConfiguration
11 | {
12 | public static IServiceCollection ConfigureServices(IServiceCollection services) =>
13 | services
14 | .AddApiVersioning(setup=>
15 | {
16 | setup.AssumeDefaultVersionWhenUnspecified = true;
17 | setup.DefaultApiVersion = new ApiVersion(1, 0);
18 | })
19 | .AddMvc()
20 | .Services;
21 |
22 | public static void Configure(IApplicationBuilder app, Func configureHost) =>
23 | configureHost(app)
24 | .UseMvc();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FunctionalTests/FunctionalTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp2.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FooApi/Controllers/FooController.cs:
--------------------------------------------------------------------------------
1 | using FooApi.Models;
2 | using Microsoft.AspNetCore.Authorization;
3 | using Microsoft.AspNetCore.Mvc;
4 | using System.Threading.Tasks;
5 |
6 | namespace FooApi.Controllers
7 | {
8 | [Route("api/v{version:apiVersion}/[controller]")]
9 | public class FooController : Controller
10 | {
11 | private readonly FooDbContext context;
12 |
13 | public FooController(FooDbContext context)
14 | {
15 | this.context = context;
16 | }
17 |
18 | [HttpGet()]
19 | [Authorize("GetPolicy")]
20 | public async Task Get(int id)
21 | {
22 | var bar = await context.Bars.FindAsync(id);
23 |
24 | return Ok(bar);
25 | }
26 |
27 | [HttpPost()]
28 | [Authorize("PostPolicy")]
29 | public async Task Post([FromBody]Bar bar)
30 | {
31 | await context.AddAsync(bar);
32 | return CreatedAtAction(nameof(Get), new { id = bar.Id });
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/lib/jquery-validation/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-validation",
3 | "homepage": "http://jqueryvalidation.org/",
4 | "repository": {
5 | "type": "git",
6 | "url": "git://github.com/jzaefferer/jquery-validation.git"
7 | },
8 | "authors": [
9 | "Jörn Zaefferer "
10 | ],
11 | "description": "Form validation made easy",
12 | "main": "dist/jquery.validate.js",
13 | "keywords": [
14 | "forms",
15 | "validation",
16 | "validate"
17 | ],
18 | "license": "MIT",
19 | "ignore": [
20 | "**/.*",
21 | "node_modules",
22 | "bower_components",
23 | "test",
24 | "demo",
25 | "lib"
26 | ],
27 | "dependencies": {
28 | "jquery": ">= 1.7.2"
29 | },
30 | "version": "1.14.0",
31 | "_release": "1.14.0",
32 | "_resolution": {
33 | "type": "version",
34 | "tag": "1.14.0",
35 | "commit": "c1343fb9823392aa9acbe1c3ffd337b8c92fed48"
36 | },
37 | "_source": "git://github.com/jzaefferer/jquery-validation.git",
38 | "_target": ">=1.8",
39 | "_originalSource": "jquery-validation"
40 | }
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/lib/jquery-validation/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-validation",
3 | "homepage": "http://jqueryvalidation.org/",
4 | "repository": {
5 | "type": "git",
6 | "url": "git://github.com/jzaefferer/jquery-validation.git"
7 | },
8 | "authors": [
9 | "Jörn Zaefferer "
10 | ],
11 | "description": "Form validation made easy",
12 | "main": "dist/jquery.validate.js",
13 | "keywords": [
14 | "forms",
15 | "validation",
16 | "validate"
17 | ],
18 | "license": "MIT",
19 | "ignore": [
20 | "**/.*",
21 | "node_modules",
22 | "bower_components",
23 | "test",
24 | "demo",
25 | "lib"
26 | ],
27 | "dependencies": {
28 | "jquery": ">= 1.7.2"
29 | },
30 | "version": "1.14.0",
31 | "_release": "1.14.0",
32 | "_resolution": {
33 | "type": "version",
34 | "tag": "1.14.0",
35 | "commit": "c1343fb9823392aa9acbe1c3ffd337b8c92fed48"
36 | },
37 | "_source": "git://github.com/jzaefferer/jquery-validation.git",
38 | "_target": ">=1.8",
39 | "_originalSource": "jquery-validation"
40 | }
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/lib/jquery-validation/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-validation",
3 | "homepage": "http://jqueryvalidation.org/",
4 | "repository": {
5 | "type": "git",
6 | "url": "git://github.com/jzaefferer/jquery-validation.git"
7 | },
8 | "authors": [
9 | "Jörn Zaefferer "
10 | ],
11 | "description": "Form validation made easy",
12 | "main": "dist/jquery.validate.js",
13 | "keywords": [
14 | "forms",
15 | "validation",
16 | "validate"
17 | ],
18 | "license": "MIT",
19 | "ignore": [
20 | "**/.*",
21 | "node_modules",
22 | "bower_components",
23 | "test",
24 | "demo",
25 | "lib"
26 | ],
27 | "dependencies": {
28 | "jquery": ">= 1.7.2"
29 | },
30 | "version": "1.14.0",
31 | "_release": "1.14.0",
32 | "_resolution": {
33 | "type": "version",
34 | "tag": "1.14.0",
35 | "commit": "c1343fb9823392aa9acbe1c3ffd337b8c92fed48"
36 | },
37 | "_source": "git://github.com/jzaefferer/jquery-validation.git",
38 | "_target": ">=1.8",
39 | "_originalSource": "jquery-validation"
40 | }
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/lib/jquery-validation/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-validation",
3 | "homepage": "http://jqueryvalidation.org/",
4 | "repository": {
5 | "type": "git",
6 | "url": "git://github.com/jzaefferer/jquery-validation.git"
7 | },
8 | "authors": [
9 | "Jörn Zaefferer "
10 | ],
11 | "description": "Form validation made easy",
12 | "main": "dist/jquery.validate.js",
13 | "keywords": [
14 | "forms",
15 | "validation",
16 | "validate"
17 | ],
18 | "license": "MIT",
19 | "ignore": [
20 | "**/.*",
21 | "node_modules",
22 | "bower_components",
23 | "test",
24 | "demo",
25 | "lib"
26 | ],
27 | "dependencies": {
28 | "jquery": ">= 1.7.2"
29 | },
30 | "version": "1.14.0",
31 | "_release": "1.14.0",
32 | "_resolution": {
33 | "type": "version",
34 | "tag": "1.14.0",
35 | "commit": "c1343fb9823392aa9acbe1c3ffd337b8c92fed48"
36 | },
37 | "_source": "git://github.com/jzaefferer/jquery-validation.git",
38 | "_target": ">=1.8",
39 | "_originalSource": "jquery-validation"
40 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Xabaril
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FooApi/Migrations/20180307192205_Initial.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.Metadata;
2 | using Microsoft.EntityFrameworkCore.Migrations;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace FooApi.Migrations
7 | {
8 | public partial class Initial : Migration
9 | {
10 | protected override void Up(MigrationBuilder migrationBuilder)
11 | {
12 | migrationBuilder.CreateTable(
13 | name: "Bars",
14 | columns: table => new
15 | {
16 | Id = table.Column(nullable: false)
17 | .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn)
18 | },
19 | constraints: table =>
20 | {
21 | table.PrimaryKey("PK_Bars", x => x.Id);
22 | });
23 | }
24 |
25 | protected override void Down(MigrationBuilder migrationBuilder)
26 | {
27 | migrationBuilder.DropTable(
28 | name: "Bars");
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/lib/bootstrap/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bootstrap",
3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
4 | "keywords": [
5 | "css",
6 | "js",
7 | "less",
8 | "mobile-first",
9 | "responsive",
10 | "front-end",
11 | "framework",
12 | "web"
13 | ],
14 | "homepage": "http://getbootstrap.com",
15 | "license": "MIT",
16 | "moduleType": "globals",
17 | "main": [
18 | "less/bootstrap.less",
19 | "dist/js/bootstrap.js"
20 | ],
21 | "ignore": [
22 | "/.*",
23 | "_config.yml",
24 | "CNAME",
25 | "composer.json",
26 | "CONTRIBUTING.md",
27 | "docs",
28 | "js/tests",
29 | "test-infra"
30 | ],
31 | "dependencies": {
32 | "jquery": "1.9.1 - 3"
33 | },
34 | "version": "3.3.7",
35 | "_release": "3.3.7",
36 | "_resolution": {
37 | "type": "version",
38 | "tag": "v3.3.7",
39 | "commit": "0b9c4a4007c44201dce9a6cc1a38407005c26c86"
40 | },
41 | "_source": "https://github.com/twbs/bootstrap.git",
42 | "_target": "v3.3.7",
43 | "_originalSource": "bootstrap",
44 | "_direct": true
45 | }
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/lib/bootstrap/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bootstrap",
3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
4 | "keywords": [
5 | "css",
6 | "js",
7 | "less",
8 | "mobile-first",
9 | "responsive",
10 | "front-end",
11 | "framework",
12 | "web"
13 | ],
14 | "homepage": "http://getbootstrap.com",
15 | "license": "MIT",
16 | "moduleType": "globals",
17 | "main": [
18 | "less/bootstrap.less",
19 | "dist/js/bootstrap.js"
20 | ],
21 | "ignore": [
22 | "/.*",
23 | "_config.yml",
24 | "CNAME",
25 | "composer.json",
26 | "CONTRIBUTING.md",
27 | "docs",
28 | "js/tests",
29 | "test-infra"
30 | ],
31 | "dependencies": {
32 | "jquery": "1.9.1 - 3"
33 | },
34 | "version": "3.3.7",
35 | "_release": "3.3.7",
36 | "_resolution": {
37 | "type": "version",
38 | "tag": "v3.3.7",
39 | "commit": "0b9c4a4007c44201dce9a6cc1a38407005c26c86"
40 | },
41 | "_source": "https://github.com/twbs/bootstrap.git",
42 | "_target": "v3.3.7",
43 | "_originalSource": "bootstrap",
44 | "_direct": true
45 | }
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/lib/bootstrap/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bootstrap",
3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
4 | "keywords": [
5 | "css",
6 | "js",
7 | "less",
8 | "mobile-first",
9 | "responsive",
10 | "front-end",
11 | "framework",
12 | "web"
13 | ],
14 | "homepage": "http://getbootstrap.com",
15 | "license": "MIT",
16 | "moduleType": "globals",
17 | "main": [
18 | "less/bootstrap.less",
19 | "dist/js/bootstrap.js"
20 | ],
21 | "ignore": [
22 | "/.*",
23 | "_config.yml",
24 | "CNAME",
25 | "composer.json",
26 | "CONTRIBUTING.md",
27 | "docs",
28 | "js/tests",
29 | "test-infra"
30 | ],
31 | "dependencies": {
32 | "jquery": "1.9.1 - 3"
33 | },
34 | "version": "3.3.7",
35 | "_release": "3.3.7",
36 | "_resolution": {
37 | "type": "version",
38 | "tag": "v3.3.7",
39 | "commit": "0b9c4a4007c44201dce9a6cc1a38407005c26c86"
40 | },
41 | "_source": "https://github.com/twbs/bootstrap.git",
42 | "_target": "v3.3.7",
43 | "_originalSource": "bootstrap",
44 | "_direct": true
45 | }
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/lib/bootstrap/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bootstrap",
3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
4 | "keywords": [
5 | "css",
6 | "js",
7 | "less",
8 | "mobile-first",
9 | "responsive",
10 | "front-end",
11 | "framework",
12 | "web"
13 | ],
14 | "homepage": "http://getbootstrap.com",
15 | "license": "MIT",
16 | "moduleType": "globals",
17 | "main": [
18 | "less/bootstrap.less",
19 | "dist/js/bootstrap.js"
20 | ],
21 | "ignore": [
22 | "/.*",
23 | "_config.yml",
24 | "CNAME",
25 | "composer.json",
26 | "CONTRIBUTING.md",
27 | "docs",
28 | "js/tests",
29 | "test-infra"
30 | ],
31 | "dependencies": {
32 | "jquery": "1.9.1 - 3"
33 | },
34 | "version": "3.3.7",
35 | "_release": "3.3.7",
36 | "_resolution": {
37 | "type": "version",
38 | "tag": "v3.3.7",
39 | "commit": "0b9c4a4007c44201dce9a6cc1a38407005c26c86"
40 | },
41 | "_source": "https://github.com/twbs/bootstrap.git",
42 | "_target": "v3.3.7",
43 | "_originalSource": "bootstrap",
44 | "_direct": true
45 | }
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2016 Twitter, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2016 Twitter, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2016 Twitter, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2016 Twitter, Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/lib/jquery-validation/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright Jörn Zaefferer
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/lib/jquery-validation/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright Jörn Zaefferer
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/lib/jquery-validation/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright Jörn Zaefferer
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/lib/jquery-validation/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | =====================
3 |
4 | Copyright Jörn Zaefferer
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FooApi/Migrations/FooDbContextModelSnapshot.cs:
--------------------------------------------------------------------------------
1 | //
2 | using FooApi.Models;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage;
8 | using System;
9 |
10 | namespace FooApi.Migrations
11 | {
12 | [DbContext(typeof(FooDbContext))]
13 | partial class FooDbContextModelSnapshot : ModelSnapshot
14 | {
15 | protected override void BuildModel(ModelBuilder modelBuilder)
16 | {
17 | #pragma warning disable 612, 618
18 | modelBuilder
19 | .HasAnnotation("ProductVersion", "2.0.1-rtm-125")
20 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
21 |
22 | modelBuilder.Entity("FooApi.Models.Bar", b =>
23 | {
24 | b.Property("Id")
25 | .ValueGeneratedOnAdd();
26 |
27 | b.HasKey("Id");
28 |
29 | b.ToTable("Bars");
30 | });
31 | #pragma warning restore 612, 618
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/FunctionalTests/Seedwork/FooFixture.cs:
--------------------------------------------------------------------------------
1 | using FooApi;
2 | using Microsoft.AspNetCore.Builder;
3 | using Microsoft.AspNetCore.Hosting;
4 | using Microsoft.AspNetCore.TestHost;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Text;
9 | using Xunit;
10 |
11 | namespace FunctionalTests.Seedwork
12 | {
13 | public class FooFixture
14 | {
15 | public TestServer FooServer { get; private set; }
16 |
17 | public FooFixture()
18 | {
19 | var hostBuilder = new WebHostBuilder()
20 | .UseStartup();
21 |
22 | FooServer = new TestServer(hostBuilder);
23 | }
24 | }
25 |
26 | [CollectionDefinition("Foo")]
27 | public class FooFixtureCollection : ICollectionFixture
28 | {
29 | }
30 |
31 | class TestStartup
32 | {
33 | public void ConfigureServices(IServiceCollection services)
34 | {
35 | FooConfiguration.ConfigureServices(services);
36 | }
37 |
38 | public void Configure(IApplicationBuilder app)
39 | {
40 | FooConfiguration.Configure(app, host => host);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/FunctionalTests/Seedwork/FooFixture.cs:
--------------------------------------------------------------------------------
1 | using FooApi;
2 | using Microsoft.AspNetCore.Builder;
3 | using Microsoft.AspNetCore.Hosting;
4 | using Microsoft.AspNetCore.TestHost;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Text;
9 | using Xunit;
10 |
11 | namespace FunctionalTests.Seedwork
12 | {
13 | public class FooFixture
14 | {
15 | public TestServer FooServer { get; private set; }
16 |
17 | public FooFixture()
18 | {
19 | var hostBuilder = new WebHostBuilder()
20 | .UseStartup();
21 |
22 | FooServer = new TestServer(hostBuilder);
23 | }
24 | }
25 |
26 | [CollectionDefinition("Foo")]
27 | public class FooFixtureCollection
28 | : ICollectionFixture
29 | {
30 | }
31 |
32 | class TestStartup
33 | {
34 | public void ConfigureServices(IServiceCollection services)
35 | {
36 | FooConfiguration.ConfigureServices(services);
37 | }
38 |
39 | public void Configure(IApplicationBuilder app)
40 | {
41 | FooConfiguration.Configure(app, host => host);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FooApi/Migrations/20180307192205_Initial.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using FooApi.Models;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Metadata;
6 | using Microsoft.EntityFrameworkCore.Migrations;
7 | using Microsoft.EntityFrameworkCore.Storage;
8 | using System;
9 |
10 | namespace FooApi.Migrations
11 | {
12 | [DbContext(typeof(FooDbContext))]
13 | [Migration("20180307192205_Initial")]
14 | partial class Initial
15 | {
16 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
17 | {
18 | #pragma warning disable 612, 618
19 | modelBuilder
20 | .HasAnnotation("ProductVersion", "2.0.1-rtm-125")
21 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
22 |
23 | modelBuilder.Entity("FooApi.Models.Bar", b =>
24 | {
25 | b.Property("Id")
26 | .ValueGeneratedOnAdd();
27 |
28 | b.HasKey("Id");
29 |
30 | b.ToTable("Bars");
31 | });
32 | #pragma warning restore 612, 618
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/lib/jquery-validation-unobtrusive/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-validation-unobtrusive",
3 | "version": "3.2.6",
4 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive",
5 | "description": "Add-on to jQuery Validation to enable unobtrusive validation options in data-* attributes.",
6 | "main": [
7 | "jquery.validate.unobtrusive.js"
8 | ],
9 | "ignore": [
10 | "**/.*",
11 | "*.json",
12 | "*.md",
13 | "*.txt",
14 | "gulpfile.js"
15 | ],
16 | "keywords": [
17 | "jquery",
18 | "asp.net",
19 | "mvc",
20 | "validation",
21 | "unobtrusive"
22 | ],
23 | "authors": [
24 | "Microsoft"
25 | ],
26 | "license": "http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm",
27 | "repository": {
28 | "type": "git",
29 | "url": "git://github.com/aspnet/jquery-validation-unobtrusive.git"
30 | },
31 | "dependencies": {
32 | "jquery-validation": ">=1.8",
33 | "jquery": ">=1.8"
34 | },
35 | "_release": "3.2.6",
36 | "_resolution": {
37 | "type": "version",
38 | "tag": "v3.2.6",
39 | "commit": "13386cd1b5947d8a5d23a12b531ce3960be1eba7"
40 | },
41 | "_source": "git://github.com/aspnet/jquery-validation-unobtrusive.git",
42 | "_target": "3.2.6",
43 | "_originalSource": "jquery-validation-unobtrusive"
44 | }
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/lib/jquery-validation-unobtrusive/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-validation-unobtrusive",
3 | "version": "3.2.6",
4 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive",
5 | "description": "Add-on to jQuery Validation to enable unobtrusive validation options in data-* attributes.",
6 | "main": [
7 | "jquery.validate.unobtrusive.js"
8 | ],
9 | "ignore": [
10 | "**/.*",
11 | "*.json",
12 | "*.md",
13 | "*.txt",
14 | "gulpfile.js"
15 | ],
16 | "keywords": [
17 | "jquery",
18 | "asp.net",
19 | "mvc",
20 | "validation",
21 | "unobtrusive"
22 | ],
23 | "authors": [
24 | "Microsoft"
25 | ],
26 | "license": "http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm",
27 | "repository": {
28 | "type": "git",
29 | "url": "git://github.com/aspnet/jquery-validation-unobtrusive.git"
30 | },
31 | "dependencies": {
32 | "jquery-validation": ">=1.8",
33 | "jquery": ">=1.8"
34 | },
35 | "_release": "3.2.6",
36 | "_resolution": {
37 | "type": "version",
38 | "tag": "v3.2.6",
39 | "commit": "13386cd1b5947d8a5d23a12b531ce3960be1eba7"
40 | },
41 | "_source": "git://github.com/aspnet/jquery-validation-unobtrusive.git",
42 | "_target": "3.2.6",
43 | "_originalSource": "jquery-validation-unobtrusive"
44 | }
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/lib/jquery-validation-unobtrusive/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-validation-unobtrusive",
3 | "version": "3.2.6",
4 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive",
5 | "description": "Add-on to jQuery Validation to enable unobtrusive validation options in data-* attributes.",
6 | "main": [
7 | "jquery.validate.unobtrusive.js"
8 | ],
9 | "ignore": [
10 | "**/.*",
11 | "*.json",
12 | "*.md",
13 | "*.txt",
14 | "gulpfile.js"
15 | ],
16 | "keywords": [
17 | "jquery",
18 | "asp.net",
19 | "mvc",
20 | "validation",
21 | "unobtrusive"
22 | ],
23 | "authors": [
24 | "Microsoft"
25 | ],
26 | "license": "http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm",
27 | "repository": {
28 | "type": "git",
29 | "url": "git://github.com/aspnet/jquery-validation-unobtrusive.git"
30 | },
31 | "dependencies": {
32 | "jquery-validation": ">=1.8",
33 | "jquery": ">=1.8"
34 | },
35 | "_release": "3.2.6",
36 | "_resolution": {
37 | "type": "version",
38 | "tag": "v3.2.6",
39 | "commit": "13386cd1b5947d8a5d23a12b531ce3960be1eba7"
40 | },
41 | "_source": "git://github.com/aspnet/jquery-validation-unobtrusive.git",
42 | "_target": "3.2.6",
43 | "_originalSource": "jquery-validation-unobtrusive"
44 | }
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/lib/jquery-validation-unobtrusive/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-validation-unobtrusive",
3 | "version": "3.2.6",
4 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive",
5 | "description": "Add-on to jQuery Validation to enable unobtrusive validation options in data-* attributes.",
6 | "main": [
7 | "jquery.validate.unobtrusive.js"
8 | ],
9 | "ignore": [
10 | "**/.*",
11 | "*.json",
12 | "*.md",
13 | "*.txt",
14 | "gulpfile.js"
15 | ],
16 | "keywords": [
17 | "jquery",
18 | "asp.net",
19 | "mvc",
20 | "validation",
21 | "unobtrusive"
22 | ],
23 | "authors": [
24 | "Microsoft"
25 | ],
26 | "license": "http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm",
27 | "repository": {
28 | "type": "git",
29 | "url": "git://github.com/aspnet/jquery-validation-unobtrusive.git"
30 | },
31 | "dependencies": {
32 | "jquery-validation": ">=1.8",
33 | "jquery": ">=1.8"
34 | },
35 | "_release": "3.2.6",
36 | "_resolution": {
37 | "type": "version",
38 | "tag": "v3.2.6",
39 | "commit": "13386cd1b5947d8a5d23a12b531ce3960be1eba7"
40 | },
41 | "_source": "git://github.com/aspnet/jquery-validation-unobtrusive.git",
42 | "_target": "3.2.6",
43 | "_originalSource": "jquery-validation-unobtrusive"
44 | }
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using FooApi;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.DependencyInjection;
10 |
11 | namespace Host
12 | {
13 | public class Startup
14 | {
15 | public Startup(IConfiguration configuration)
16 | {
17 | Configuration = configuration;
18 | }
19 |
20 | public IConfiguration Configuration { get; }
21 |
22 | // This method gets called by the runtime. Use this method to add services to the container.
23 | public void ConfigureServices(IServiceCollection services)
24 | {
25 | FooConfiguration
26 | .ConfigureServices(services)
27 | .AddAuthentication()
28 | .AddJwtBearer();
29 | }
30 |
31 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
32 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
33 | {
34 | FooConfiguration.Configure(app, host =>
35 | host.UseStaticFiles()
36 | .UseAuthentication()
37 | .UseExceptionHandler("/Home/Error"));
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/FunctionalTests/Seedwork/FooFixture.cs:
--------------------------------------------------------------------------------
1 | using Acheve.AspNetCore.TestHost.Security;
2 | using FooApi;
3 | using Microsoft.AspNetCore.Builder;
4 | using Microsoft.AspNetCore.Hosting;
5 | using Microsoft.AspNetCore.TestHost;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Text;
10 | using Xunit;
11 |
12 | namespace FunctionalTests.Seedwork
13 | {
14 | public class FooFixture
15 | {
16 | public TestServer FooServer { get; private set; }
17 |
18 | public FooFixture()
19 | {
20 | var hostBuilder = new WebHostBuilder()
21 | .UseStartup();
22 |
23 | FooServer = new TestServer(hostBuilder);
24 | }
25 | }
26 |
27 | [CollectionDefinition("Foo")]
28 | public class FooFixtureCollection
29 | : ICollectionFixture
30 | {
31 | }
32 |
33 | class TestStartup
34 | {
35 | public void ConfigureServices(IServiceCollection services)
36 | {
37 | FooConfiguration.ConfigureServices(services)
38 | .AddAuthentication(defaultScheme: "TestServer")
39 | .AddTestServerAuthentication();
40 | }
41 |
42 | public void Configure(IApplicationBuilder app)
43 | {
44 | FooConfiguration.Configure(app, host => host.UseAuthentication());
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/FooApi/FooConfiguration.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Mvc;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 |
8 | namespace FooApi
9 | {
10 | public static class FooConfiguration
11 | {
12 | public static IServiceCollection ConfigureServices(IServiceCollection services) =>
13 | services
14 | .AddApiVersioning(setup=>
15 | {
16 | setup.AssumeDefaultVersionWhenUnspecified = true;
17 | setup.DefaultApiVersion = new ApiVersion(1, 0);
18 | })
19 | .AddAuthorization(setup=>
20 | {
21 | setup.AddPolicy("GetPolicy", requirements =>
22 | {
23 | requirements.RequireClaim("Permission", new string[] { "Read" });
24 | });
25 |
26 | setup.AddPolicy("PostPolicy", requirements =>
27 | {
28 | requirements.RequireClaim("Permission", new string[] { "Write" });
29 | });
30 | })
31 | .AddMvc()
32 | .Services;
33 |
34 | public static void Configure(IApplicationBuilder app, Func configureHost) =>
35 | configureHost(app)
36 | .UseMvc();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FooApi/FooConfiguration.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Mvc;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 |
8 | namespace FooApi
9 | {
10 | public static class FooConfiguration
11 | {
12 | public static IServiceCollection ConfigureServices(IServiceCollection services) =>
13 | services
14 | .AddApiVersioning(setup=>
15 | {
16 | setup.AssumeDefaultVersionWhenUnspecified = true;
17 | setup.DefaultApiVersion = new ApiVersion(1, 0);
18 | })
19 | .AddAuthorization(setup=>
20 | {
21 | setup.AddPolicy("GetPolicy", requirements =>
22 | {
23 | requirements.RequireClaim("Permission", new string[] { "Read" });
24 | });
25 |
26 | setup.AddPolicy("PostPolicy", requirements =>
27 | {
28 | requirements.RequireClaim("Permission", new string[] { "Write" });
29 | });
30 | })
31 | .AddMvc()
32 | .Services;
33 |
34 | public static void Configure(IApplicationBuilder app, Func configureHost) =>
35 | configureHost(app)
36 | .UseMvc();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FooApi/IWebHostExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Microsoft.Extensions.Logging;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 |
8 | namespace Microsoft.AspNetCore.Hosting
9 | {
10 | public static class IWebHostExtensions
11 | {
12 | public static IWebHost MigrateDbContext(this IWebHost webHost, Action seeder) where TContext : DbContext
13 | {
14 | using (var scope = webHost.Services.CreateScope())
15 | {
16 | var services = scope.ServiceProvider;
17 |
18 | var logger = services.GetRequiredService>();
19 |
20 | var context = services.GetService();
21 |
22 | try
23 | {
24 | logger.LogInformation($"Migrating database associated with context {typeof(TContext).Name}");
25 |
26 | context.Database
27 | .Migrate();
28 |
29 | seeder(context, services);
30 |
31 | logger.LogInformation($"Migrated database associated with context {typeof(TContext).Name}");
32 | }
33 | catch (Exception ex)
34 | {
35 | logger.LogError(ex, $"An error occurred while migrating the database used on context {typeof(TContext).Name}");
36 | }
37 | }
38 |
39 | return webHost;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using FooApi;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.DependencyInjection;
10 |
11 | namespace Host
12 | {
13 | public class Startup
14 | {
15 | public Startup(IConfiguration configuration)
16 | {
17 | Configuration = configuration;
18 | }
19 |
20 | public IConfiguration Configuration { get; }
21 |
22 | // This method gets called by the runtime. Use this method to add services to the container.
23 | public void ConfigureServices(IServiceCollection services)
24 | {
25 | FooConfiguration
26 | .ConfigureServices(services);
27 | }
28 |
29 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
30 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
31 | {
32 | FooConfiguration.Configure(app, host =>
33 | {
34 | if (env.IsDevelopment())
35 | {
36 | host.UseBrowserLink();
37 | host.UseDeveloperExceptionPage();
38 | }
39 | else
40 | {
41 | host.UseExceptionHandler("/Home/Error");
42 | }
43 |
44 | host.UseStaticFiles();
45 |
46 | return host;
47 | });
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using FooApi;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.DependencyInjection;
10 |
11 | namespace Host
12 | {
13 | public class Startup
14 | {
15 | public Startup(IConfiguration configuration)
16 | {
17 | Configuration = configuration;
18 | }
19 |
20 | public IConfiguration Configuration { get; }
21 |
22 | // This method gets called by the runtime. Use this method to add services to the container.
23 | public void ConfigureServices(IServiceCollection services)
24 | {
25 | FooConfiguration
26 | .ConfigureServices(services);
27 | }
28 |
29 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
30 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
31 | {
32 | FooConfiguration.Configure(app, host =>
33 | {
34 | if (env.IsDevelopment())
35 | {
36 | host.UseBrowserLink();
37 | host.UseDeveloperExceptionPage();
38 | }
39 | else
40 | {
41 | host.UseExceptionHandler("/Home/Error");
42 | }
43 |
44 | host.UseStaticFiles();
45 |
46 | return host;
47 | });
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/FunctionalTests/Seedwork/MyTestsAuthenticationHandler.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Authentication;
2 | using Microsoft.Extensions.Logging;
3 | using Microsoft.Extensions.Options;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Security.Claims;
7 | using System.Text;
8 | using System.Text.Encodings.Web;
9 | using System.Threading.Tasks;
10 |
11 | namespace FunctionalTests.Seedwork
12 | {
13 | public class MyTestsAuthenticationHandler
14 | : AuthenticationHandler
15 | {
16 | public MyTestsAuthenticationHandler(IOptionsMonitor options,
17 | ILoggerFactory logger,
18 | UrlEncoder encoder,
19 | ISystemClock clock)
20 | : base(options, logger, encoder, clock)
21 | {
22 | }
23 |
24 | protected override Task HandleAuthenticateAsync()
25 | {
26 | var claims = new List()
27 | {
28 | new Claim(ClaimTypes.Name,"HttpAPITesting"),
29 | new Claim("Permission","Read")
30 | };
31 |
32 | var identity = new ClaimsIdentity(
33 | claims: claims,
34 | authenticationType: Scheme.Name,
35 | nameType: ClaimTypes.Name,
36 | roleType: ClaimTypes.Role);
37 |
38 | var ticket = new AuthenticationTicket(
39 | new ClaimsPrincipal(identity),
40 | new AuthenticationProperties(),
41 | Scheme.Name);
42 |
43 | return Task.FromResult(AuthenticateResult.Success(ticket));
44 | }
45 | }
46 |
47 | public class MyTestOptions
48 | : AuthenticationSchemeOptions
49 | {
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FunctionalTests/Seedwork/MyTestsAuthenticationHandler.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Authentication;
2 | using Microsoft.Extensions.Logging;
3 | using Microsoft.Extensions.Options;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Security.Claims;
7 | using System.Text;
8 | using System.Text.Encodings.Web;
9 | using System.Threading.Tasks;
10 |
11 | namespace FunctionalTests.Seedwork
12 | {
13 | public class MyTestsAuthenticationHandler
14 | : AuthenticationHandler
15 | {
16 | public MyTestsAuthenticationHandler(IOptionsMonitor options,
17 | ILoggerFactory logger,
18 | UrlEncoder encoder,
19 | ISystemClock clock)
20 | : base(options, logger, encoder, clock)
21 | {
22 | }
23 |
24 | protected override Task HandleAuthenticateAsync()
25 | {
26 | var claims = new List()
27 | {
28 | new Claim(ClaimTypes.Name,"HttpAPITesting"),
29 | new Claim("Permission","Read")
30 | };
31 |
32 | var identity = new ClaimsIdentity(
33 | claims: claims,
34 | authenticationType: Scheme.Name,
35 | nameType: ClaimTypes.Name,
36 | roleType: ClaimTypes.Role);
37 |
38 | var ticket = new AuthenticationTicket(
39 | new ClaimsPrincipal(identity),
40 | new AuthenticationProperties(),
41 | Scheme.Name);
42 |
43 | return Task.FromResult(AuthenticateResult.Success(ticket));
44 | }
45 | }
46 |
47 | public class MyTestOptions
48 | : AuthenticationSchemeOptions
49 | {
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/lib/jquery/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright jQuery Foundation and other contributors, https://jquery.org/
2 |
3 | This software consists of voluntary contributions made by many
4 | individuals. For exact contribution history, see the revision history
5 | available at https://github.com/jquery/jquery
6 |
7 | The following license applies to all parts of this software except as
8 | documented below:
9 |
10 | ====
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining
13 | a copy of this software and associated documentation files (the
14 | "Software"), to deal in the Software without restriction, including
15 | without limitation the rights to use, copy, modify, merge, publish,
16 | distribute, sublicense, and/or sell copies of the Software, and to
17 | permit persons to whom the Software is furnished to do so, subject to
18 | the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be
21 | included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | ====
32 |
33 | All files located in the node_modules and external directories are
34 | externally maintained libraries used by this software which have their
35 | own licenses; we recommend you read them, as their terms may differ from
36 | the terms above.
37 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/lib/jquery/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright jQuery Foundation and other contributors, https://jquery.org/
2 |
3 | This software consists of voluntary contributions made by many
4 | individuals. For exact contribution history, see the revision history
5 | available at https://github.com/jquery/jquery
6 |
7 | The following license applies to all parts of this software except as
8 | documented below:
9 |
10 | ====
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining
13 | a copy of this software and associated documentation files (the
14 | "Software"), to deal in the Software without restriction, including
15 | without limitation the rights to use, copy, modify, merge, publish,
16 | distribute, sublicense, and/or sell copies of the Software, and to
17 | permit persons to whom the Software is furnished to do so, subject to
18 | the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be
21 | included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | ====
32 |
33 | All files located in the node_modules and external directories are
34 | externally maintained libraries used by this software which have their
35 | own licenses; we recommend you read them, as their terms may differ from
36 | the terms above.
37 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/lib/jquery/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright jQuery Foundation and other contributors, https://jquery.org/
2 |
3 | This software consists of voluntary contributions made by many
4 | individuals. For exact contribution history, see the revision history
5 | available at https://github.com/jquery/jquery
6 |
7 | The following license applies to all parts of this software except as
8 | documented below:
9 |
10 | ====
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining
13 | a copy of this software and associated documentation files (the
14 | "Software"), to deal in the Software without restriction, including
15 | without limitation the rights to use, copy, modify, merge, publish,
16 | distribute, sublicense, and/or sell copies of the Software, and to
17 | permit persons to whom the Software is furnished to do so, subject to
18 | the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be
21 | included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | ====
32 |
33 | All files located in the node_modules and external directories are
34 | externally maintained libraries used by this software which have their
35 | own licenses; we recommend you read them, as their terms may differ from
36 | the terms above.
37 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/lib/jquery/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright jQuery Foundation and other contributors, https://jquery.org/
2 |
3 | This software consists of voluntary contributions made by many
4 | individuals. For exact contribution history, see the revision history
5 | available at https://github.com/jquery/jquery
6 |
7 | The following license applies to all parts of this software except as
8 | documented below:
9 |
10 | ====
11 |
12 | Permission is hereby granted, free of charge, to any person obtaining
13 | a copy of this software and associated documentation files (the
14 | "Software"), to deal in the Software without restriction, including
15 | without limitation the rights to use, copy, modify, merge, publish,
16 | distribute, sublicense, and/or sell copies of the Software, and to
17 | permit persons to whom the Software is furnished to do so, subject to
18 | the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be
21 | included in all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 |
31 | ====
32 |
33 | All files located in the node_modules and external directories are
34 | externally maintained libraries used by this software which have their
35 | own licenses; we recommend you read them, as their terms may differ from
36 | the terms above.
37 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/FunctionalTests/Scenarios/FooController.cs:
--------------------------------------------------------------------------------
1 | using FooApi.Controllers;
2 | using FooApi.Models;
3 | using FunctionalTests.Seedwork;
4 | using Microsoft.AspNetCore.TestHost;
5 | using System.Threading.Tasks;
6 | using Xunit;
7 |
8 | namespace FunctionalTests.Scenarios
9 | {
10 | [Collection("Foo")]
11 | public class foo_api_should
12 | {
13 | private readonly FooFixture Given;
14 |
15 | public foo_api_should(FooFixture fooFixture)
16 | {
17 | Given = fooFixture;
18 | }
19 |
20 | [Fact]
21 | public async Task get_bar_when_requested()
22 | {
23 | var response = await Given.FooServer
24 | .CreateHttpApiRequest(foo=>foo.Get(1),new { version = 1 })
25 | .GetAsync();
26 |
27 | response.EnsureSuccessStatusCode();
28 | }
29 |
30 | [Fact]
31 | public async Task post_new_bar()
32 | {
33 | var bar = new Bar() { Id = 1 };
34 | var response = await Given.FooServer
35 | .CreateHttpApiRequest(foo => foo.Post(bar), new { version = 1 })
36 | .PostAsync();
37 |
38 | response.EnsureSuccessStatusCode();
39 | }
40 | }
41 |
42 |
43 | static class FooAPI
44 | {
45 | static string BASEURI = "api/v1/foo";
46 |
47 | public static class Get
48 | {
49 | public static string Bar(int id)
50 | {
51 | return $"{BASEURI }?id={id}";
52 | }
53 | }
54 |
55 | public static class Post
56 | {
57 | public static string Bar()
58 | {
59 | return BASEURI;
60 | }
61 | }
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using FooApi;
6 | using FooApi.Models;
7 | using Microsoft.AspNetCore.Builder;
8 | using Microsoft.AspNetCore.Hosting;
9 | using Microsoft.EntityFrameworkCore;
10 | using Microsoft.Extensions.Configuration;
11 | using Microsoft.Extensions.DependencyInjection;
12 |
13 | namespace Host
14 | {
15 | public class Startup
16 | {
17 | public Startup(IConfiguration configuration)
18 | {
19 | Configuration = configuration;
20 | }
21 |
22 | public IConfiguration Configuration { get; }
23 |
24 | // This method gets called by the runtime. Use this method to add services to the container.
25 | public void ConfigureServices(IServiceCollection services)
26 | {
27 | FooConfiguration
28 | .ConfigureServices(services)
29 | .AddDbContext(options =>
30 | {
31 | options.UseSqlServer(@"Server=LRUIZ-LAPTOP\SQLEXPRESS;Database=Foo;Integrated Security=true", sqlOptions =>
32 | {
33 | sqlOptions.MigrationsAssembly(typeof(Bar).Assembly.GetName().Name);
34 | });
35 | })
36 | .AddAuthentication()
37 | .AddJwtBearer();
38 | }
39 |
40 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
41 | public void Configure(IApplicationBuilder app, IHostingEnvironment env)
42 | {
43 | FooConfiguration.Configure(app, host =>
44 | host.UseStaticFiles()
45 | .UseAuthentication()
46 | .UseExceptionHandler("/Home/Error"));
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/FooApi.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2027
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FooApi", "FooApi\FooApi.csproj", "{B6308A12-C556-4A53-9F94-AB43424D2EB7}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Host", "Host\Host.csproj", "{1B7B0FF8-C0AE-4482-80E3-B9E190440E92}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunctionalTests", "FunctionalTests\FunctionalTests.csproj", "{4CF7F430-B5E9-46BA-8802-37D3AF425BF2}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {2C32CA1E-766F-4927-B9CB-DFC7ECE759D1}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/FooApi.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2027
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FooApi", "FooApi\FooApi.csproj", "{B6308A12-C556-4A53-9F94-AB43424D2EB7}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Host", "Host\Host.csproj", "{1B7B0FF8-C0AE-4482-80E3-B9E190440E92}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunctionalTests", "FunctionalTests\FunctionalTests.csproj", "{4CF7F430-B5E9-46BA-8802-37D3AF425BF2}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {2C32CA1E-766F-4927-B9CB-DFC7ECE759D1}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/FooApi.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2027
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FooApi", "FooApi\FooApi.csproj", "{B6308A12-C556-4A53-9F94-AB43424D2EB7}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Host", "Host\Host.csproj", "{1B7B0FF8-C0AE-4482-80E3-B9E190440E92}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunctionalTests", "FunctionalTests\FunctionalTests.csproj", "{4CF7F430-B5E9-46BA-8802-37D3AF425BF2}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {2C32CA1E-766F-4927-B9CB-DFC7ECE759D1}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FooApi.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2027
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FooApi", "FooApi\FooApi.csproj", "{B6308A12-C556-4A53-9F94-AB43424D2EB7}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Host", "Host\Host.csproj", "{1B7B0FF8-C0AE-4482-80E3-B9E190440E92}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunctionalTests", "FunctionalTests\FunctionalTests.csproj", "{4CF7F430-B5E9-46BA-8802-37D3AF425BF2}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {B6308A12-C556-4A53-9F94-AB43424D2EB7}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {1B7B0FF8-C0AE-4482-80E3-B9E190440E92}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {4CF7F430-B5E9-46BA-8802-37D3AF425BF2}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {2C32CA1E-766F-4927-B9CB-DFC7ECE759D1}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/README.en.md:
--------------------------------------------------------------------------------
1 | # Effective testing of our HTTP APIs in .NET Core
2 |
3 | When we decided to write about "Effective Testing of our HTTP APIs in .NET Core" we did not think about writing in depth about it. It is probably that with some blog entries we would have managed to share our ideas and extend a clear message across the readers. But in the end, the desire to share experiences and different solutions to common problems in our day to day, seems to take up a bit more than we thought. Therefore, we built this short manual, which we hope will serve to introduce you to the path of **functional testing** of our "HTTP APIs built with .NET Core 2.X".
4 |
5 | ## Introduction
6 |
7 | You may have asked yourself, "Why functional tests on our HTTP API if I already have unit tests?" Well, the answer is quite simple, "because they are complementary". That is, having unit tests in our software developments does not prevent us from doing this kind of functional tests. Unit tests are fast and allow us to test different casuistics of our components in an isolated way.
8 |
9 | On the contrary, the functional tests presented here are not so fast, but they allow us to test together the different components or parts that make up our solution and they end up beign a good indicator of code coverage.
10 |
11 | Until recently, running these tests involved some work to make them be part of the normal development cycle of a programmer (coding, construction and tests). With the arrival of *TestServer* (available in both .NET Core and Full Framework with Web Api 2.X) this process has been simplified and we have the possibility to run this type of tests similarly to unit tests and therefore included them within the development flow that we usually follows.
12 |
13 | ## Content
14 |
15 | The content of this manual is open and we will try to keep it as up-to-date as possible. Something that of course is not always easy for the delivery cycles of new features that we have in **.NET Core** project. In principle, we will be based on **.NET Core 2.X** specifically version **2.0**, the latest released version when this manual was being written.
16 |
17 | ## Table of Contents
18 |
19 | 1. [Introduction to TestServer](chapters/en/chapter1.md)
20 | 2. [Routes and parameters](chapters/en/chapter2.md)
21 | 3. [Authorization](chapters/en/chapter3.md)
22 | 4. [Working with data](chapters/en/chapter4.md)
23 |
24 | Each **chapter** has the **code** associated with the explanation of it. You can find them in the **samples** folder.
25 |
26 | ## Acknowledgements
27 |
28 | To all the people who have contributed to the writing and revision of this manual, especially to:
29 |
30 | 1. Unai Zorrilla Castro
31 | 2. Luis Ruiz Pavon
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pruebas efectivas de nuestras HTTP APIs en .NET Core
2 |
3 | Cuando decidimos escribir acerca "Testing efectivo de HTTP API en .NET Core" no teníamos pensado extendernos mucho. Es probable que con algunas entradas de blog hubieramos conseguido compartir nuestras ideas y trasmitir el mensaje de una forma relativamente clara. Pero al final, las ganas de compartir experiencias y diferentes soluciones a problemas comunes en nuestro día a día parece que ocupa mucho más de lo que nosotros pensabamos. Por eso, construimos este pequeño manual, que esperemos os sirva para introduciros en el camino del **testing funcional** de nuestras "HTTP APIs construidas con .NET Core 2.X".
4 |
5 | ## Introducción
6 |
7 | Es probable que usted al leer esto se pregunte, "¿Porqué pruebas funcionales sobre nuestro HTTP API si ya tengo tests unitarios?" Pues bien, la respuesta es sencilla, porque son complementarias. Es decir, tener pruebas unitarias en nuestros desarrollos de software en este caso desarrollo de HTTP API, no impide que hagamos este tipo de pruebas funcionales. Las pruebas unitarias, son aisladas y muy rápidas (o así deberían ser) y nos permiten probar diferentes casuísticas de nuestros componentes de forma aislada.
8 |
9 | Por el contrario, las pruebas funcionales como aquí presentamos no son tan rápidas pero nos permiten probar en conjunto los diferentes componentes que forman nuestra solución, dándonos además un buen índice de cobertura de código.
10 |
11 | Hasta hace relativamente poco, ejecutar estas pruebas implicaba un cierto trabajo de despliegue, haciendo que las mismas no formaran finalmente parte del ciclo normal de un desarrollador (código, construcción y pruebas) por el setup requerido para ejecutarlas. Con la llegada de *TestServer* (*recuerde que no solamente está disponible en .NET Core sino también en Full FX con Web Api 2.X*), este proceso se ha simplificado y tenemos ya la posibilidad de correr este tipo de pruebas como si de pruebas unitarias se tratara y por lo tanto incluirlas dentro de ese flujo de desarrollo que todos solemos seguir.
12 |
13 | ## Contenido
14 |
15 | El contenido de este manual es abierto y trataremos de que esté siempre lo más actualizado posible. Algo que por supuesto no siempre es sencillo por los ciclos de entrega de nuevas características que tenemos en **.NET Core**. En principio, nos basaremos en **.NET Core 2.X**, en concreto con la versión **2.0**, la última versión release cuando este manual se estaba escribiendo.
16 |
17 | ## Índice en castellano
18 |
19 | 1. [Introducción a TestServer](chapters/es/chapter1.md)
20 | 2. [Rutas y parámetros](chapters/es/chapter2.md)
21 | 3. [Autorización](chapters/es/chapter3.md)
22 | 4. [Trabajando con datos](chapters/es/chapter4.md)
23 |
24 | ## English Index
25 |
26 | 1. [Introduction to TestServer](chapters/en/chapter1.md)
27 |
28 |
29 | Cada capítulo lleva asociado el código relativo a la explicación del mismo. Puede encontrarlos dentro de la carpeta **samples**.
30 |
31 | ## Agradecimientos
32 |
33 | A todas las personas que han contribuido a la escritura y revisión de este manual:
34 |
35 | 1. Unai Zorrilla Castro (@unaizorrilla)
36 | 2. Luis Ruiz Pavon (@lurumad)
37 | 3. Jorge Rodriguez Galán (@jrgcubano)
38 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FunctionalTests/Seedwork/FooFixture.cs:
--------------------------------------------------------------------------------
1 | using Acheve.AspNetCore.TestHost.Security;
2 | using FooApi;
3 | using FooApi.Models;
4 | using Microsoft.AspNetCore.Builder;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.AspNetCore.TestHost;
7 | using Microsoft.EntityFrameworkCore;
8 | using Microsoft.Extensions.DependencyInjection;
9 | using Respawn;
10 | using System;
11 | using System.Threading.Tasks;
12 | using Xunit;
13 |
14 | namespace FunctionalTests.Seedwork
15 | {
16 | public class FooFixture
17 | {
18 | private static Checkpoint CheckPoint = new Checkpoint();
19 | public TestServer FooServer { get; private set; }
20 |
21 | public FooFixture()
22 | {
23 | var hostBuilder = new WebHostBuilder()
24 | .UseStartup();
25 |
26 | FooServer = new TestServer(hostBuilder);
27 |
28 | FooServer.Host.MigrateDbContext((ctx,sp)=> { });
29 |
30 | CheckPoint.TablesToIgnore = new[] { "__EFMigrationsHistory" };
31 | }
32 |
33 | public async Task ExecuteScopeAsync(Func action)
34 | {
35 | using (var scope = FooServer.Host.Services.GetService().CreateScope())
36 | {
37 | await action(scope.ServiceProvider);
38 | }
39 | }
40 |
41 | public async Task ExecuteDbContextAsync(Func action)
42 | {
43 | await ExecuteScopeAsync(sp => action(sp.GetService()));
44 | }
45 |
46 | public static void ResetDatabase()
47 | {
48 | CheckPoint.Reset(@"Server=LRUIZ-LAPTOP\SQLEXPRESS;Database=Foo;Integrated Security=true").Wait();
49 | }
50 |
51 | public async Task ABarInTheDatabase()
52 | {
53 | var bar = new Bar();
54 | await ExecuteDbContextAsync(async context =>
55 | {
56 | await context.AddAsync(bar);
57 | await context.SaveChangesAsync();
58 | });
59 | return bar;
60 | }
61 | }
62 |
63 | [CollectionDefinition("Foo")]
64 | public class FooFixtureCollection
65 | : ICollectionFixture
66 | {
67 | }
68 |
69 | class TestStartup
70 | {
71 | public void ConfigureServices(IServiceCollection services)
72 | {
73 | FooConfiguration.ConfigureServices(services)
74 | .AddDbContext(options =>
75 | {
76 | options.UseSqlServer(@"Server=LRUIZ-LAPTOP\SQLEXPRESS;Database=Foo;Integrated Security=true", sqlOptions =>
77 | {
78 | sqlOptions.MigrationsAssembly(typeof(Bar).Assembly.GetName().Name);
79 | });
80 | })
81 | .AddAuthentication(defaultScheme: "TestServer")
82 | .AddTestServerAuthentication();
83 | }
84 |
85 | public void Configure(IApplicationBuilder app)
86 | {
87 | FooConfiguration.Configure(app, host => host.UseAuthentication());
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/FunctionalTests/Scenarios/FooController.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using FooApi.Controllers;
3 | using FooApi.Models;
4 | using FunctionalTests.Seedwork;
5 | using Microsoft.AspNetCore.TestHost;
6 | using System.Collections.Generic;
7 | using System.Net;
8 | using System.Security.Claims;
9 | using System.Threading.Tasks;
10 | using Xunit;
11 |
12 | namespace FunctionalTests.Scenarios
13 | {
14 | [Collection("Foo")]
15 | public class foo_api_should
16 | {
17 | private readonly FooFixture Given;
18 |
19 | public foo_api_should(FooFixture fooFixture)
20 | {
21 | Given = fooFixture;
22 | }
23 |
24 | [Fact]
25 | public async Task get_bar_when_requested()
26 | {
27 | var response = await Given.FooServer
28 | .CreateHttpApiRequest(foo=>foo.Get(1),new { version = 1 })
29 | .WithIdentity(new List() { new Claim("Permission","Read")})
30 | .GetAsync();
31 |
32 | response.EnsureSuccessStatusCode();
33 | }
34 |
35 | [Fact]
36 | public async Task get_forbideen_if_not_authenticated_when_requested()
37 | {
38 | var response = await Given.FooServer
39 | .CreateHttpApiRequest(foo => foo.Get(1), new { version = 1 })
40 | .WithIdentity(new List() { new Claim("Permission", "NonReadClaim") })
41 | .GetAsync();
42 |
43 | response.StatusCode
44 | .Should()
45 | .Be(HttpStatusCode.Forbidden);
46 | }
47 |
48 | [Fact]
49 | public async Task post_new_bar()
50 | {
51 | var bar = new Bar() { Id = 1 };
52 | var response = await Given.FooServer
53 | .CreateHttpApiRequest(foo => foo.Post(bar), new { version = 1 })
54 | .WithIdentity(new List() { new Claim("Permission", "Write") })
55 | .PostAsync();
56 |
57 | response.EnsureSuccessStatusCode();
58 | }
59 |
60 | [Fact]
61 | public async Task post_get_forbidden_if_not_authenticated_when_requested()
62 | {
63 | var bar = new Bar() { Id = 1 };
64 | var response = await Given.FooServer
65 | .CreateHttpApiRequest(foo => foo.Post(bar), new { version = 1 })
66 | .WithIdentity(new List() { new Claim("Permission", "NonWriteClaim") })
67 | .PostAsync();
68 |
69 | response.StatusCode
70 | .Should()
71 | .Be(HttpStatusCode.Forbidden);
72 | }
73 | }
74 |
75 |
76 | static class FooAPI
77 | {
78 | static string BASEURI = "api/v1/foo";
79 |
80 | public static class Get
81 | {
82 | public static string Bar(int id)
83 | {
84 | return $"{BASEURI }?id={id}";
85 | }
86 | }
87 |
88 | public static class Post
89 | {
90 | public static string Bar()
91 | {
92 | return BASEURI;
93 | }
94 | }
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/FunctionalTests/Scenarios/FooController.cs:
--------------------------------------------------------------------------------
1 | using FluentAssertions;
2 | using FooApi.Controllers;
3 | using FooApi.Models;
4 | using FunctionalTests.Seedwork;
5 | using Microsoft.AspNetCore.TestHost;
6 | using Newtonsoft.Json;
7 | using System.Collections.Generic;
8 | using System.Net;
9 | using System.Security.Claims;
10 | using System.Threading.Tasks;
11 | using Xunit;
12 |
13 | namespace FunctionalTests.Scenarios
14 | {
15 | [Collection("Foo")]
16 | public class foo_api_should
17 | {
18 | private readonly FooFixture Given;
19 |
20 | public foo_api_should(FooFixture fooFixture)
21 | {
22 | Given = fooFixture;
23 | }
24 |
25 | [Fact]
26 | [ResetDatabase]
27 | public async Task get_bar_when_requested()
28 | {
29 | var bar = await Given.ABarInTheDatabase();
30 | var response = await Given.FooServer
31 | .CreateHttpApiRequest(foo=>foo.Get(bar.Id),new { version = 1 })
32 | .WithIdentity(new List() { new Claim("Permission","Read")})
33 | .GetAsync();
34 |
35 | response.EnsureSuccessStatusCode();
36 | var json = await response.Content.ReadAsStringAsync();
37 | var result = JsonConvert.DeserializeObject(json);
38 | result.Id.Should().Be(bar.Id);
39 | }
40 |
41 | [Fact]
42 | public async Task get_forbideen_if_not_authenticated_when_requested()
43 | {
44 | var response = await Given.FooServer
45 | .CreateHttpApiRequest(foo => foo.Get(1), new { version = 1 })
46 | .WithIdentity(new List() { new Claim("Permission", "NonReadClaim") })
47 | .GetAsync();
48 |
49 | response.StatusCode
50 | .Should()
51 | .Be(HttpStatusCode.Forbidden);
52 | }
53 |
54 | [Fact]
55 | public async Task post_new_bar()
56 | {
57 | var bar = new Bar() { Id = 1 };
58 | var response = await Given.FooServer
59 | .CreateHttpApiRequest(foo => foo.Post(bar), new { version = 1 })
60 | .WithIdentity(new List() { new Claim("Permission", "Write") })
61 | .PostAsync();
62 |
63 | response.EnsureSuccessStatusCode();
64 | }
65 |
66 | [Fact]
67 | public async Task post_get_forbidden_if_not_authenticated_when_requested()
68 | {
69 | var bar = new Bar() { Id = 1 };
70 | var response = await Given.FooServer
71 | .CreateHttpApiRequest(foo => foo.Post(bar), new { version = 1 })
72 | .WithIdentity(new List() { new Claim("Permission", "NonWriteClaim") })
73 | .PostAsync();
74 |
75 | response.StatusCode
76 | .Should()
77 | .Be(HttpStatusCode.Forbidden);
78 | }
79 | }
80 |
81 |
82 | static class FooAPI
83 | {
84 | static string BASEURI = "api/v1/foo";
85 |
86 | public static class Get
87 | {
88 | public static string Bar(int id)
89 | {
90 | return $"{BASEURI }?id={id}";
91 | }
92 | }
93 |
94 | public static class Post
95 | {
96 | public static string Bar()
97 | {
98 | return BASEURI;
99 | }
100 | }
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | ** Unobtrusive validation support library for jQuery and jQuery Validate
3 | ** Copyright (C) Microsoft Corporation. All rights reserved.
4 | */
5 | !function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function m(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=p.unobtrusive.options||{},m=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),m("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),m("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),m("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var u,p=a.validator,v="unobtrusiveValidation";p.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=m(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){p.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=m(this);a&&a.attachValidation()})}},u=p.unobtrusive.adapters,u.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},u.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},u.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},u.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},p.addMethod("__dummy__",function(a,e,n){return!0}),p.addMethod("regex",function(a,e,n){var t;return this.optional(e)?!0:(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),p.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),p.methods.extension?(u.addSingleVal("accept","mimtype"),u.addSingleVal("extension","extension")):u.addSingleVal("extension","extension","accept"),u.addSingleVal("regex","pattern"),u.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),u.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),u.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),u.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),u.add("required",function(a){("INPUT"!==a.element.tagName.toUpperCase()||"CHECKBOX"!==a.element.type.toUpperCase())&&e(a,"required",!0)}),u.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),u.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),a(function(){p.unobtrusive.parse(document)})}(jQuery);
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | ** Unobtrusive validation support library for jQuery and jQuery Validate
3 | ** Copyright (C) Microsoft Corporation. All rights reserved.
4 | */
5 | !function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function m(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=p.unobtrusive.options||{},m=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),m("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),m("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),m("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var u,p=a.validator,v="unobtrusiveValidation";p.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=m(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){p.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=m(this);a&&a.attachValidation()})}},u=p.unobtrusive.adapters,u.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},u.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},u.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},u.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},p.addMethod("__dummy__",function(a,e,n){return!0}),p.addMethod("regex",function(a,e,n){var t;return this.optional(e)?!0:(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),p.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),p.methods.extension?(u.addSingleVal("accept","mimtype"),u.addSingleVal("extension","extension")):u.addSingleVal("extension","extension","accept"),u.addSingleVal("regex","pattern"),u.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),u.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),u.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),u.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),u.add("required",function(a){("INPUT"!==a.element.tagName.toUpperCase()||"CHECKBOX"!==a.element.type.toUpperCase())&&e(a,"required",!0)}),u.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),u.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),a(function(){p.unobtrusive.parse(document)})}(jQuery);
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | ** Unobtrusive validation support library for jQuery and jQuery Validate
3 | ** Copyright (C) Microsoft Corporation. All rights reserved.
4 | */
5 | !function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function m(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=p.unobtrusive.options||{},m=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),m("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),m("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),m("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var u,p=a.validator,v="unobtrusiveValidation";p.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=m(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){p.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=m(this);a&&a.attachValidation()})}},u=p.unobtrusive.adapters,u.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},u.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},u.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},u.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},p.addMethod("__dummy__",function(a,e,n){return!0}),p.addMethod("regex",function(a,e,n){var t;return this.optional(e)?!0:(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),p.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),p.methods.extension?(u.addSingleVal("accept","mimtype"),u.addSingleVal("extension","extension")):u.addSingleVal("extension","extension","accept"),u.addSingleVal("regex","pattern"),u.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),u.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),u.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),u.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),u.add("required",function(a){("INPUT"!==a.element.tagName.toUpperCase()||"CHECKBOX"!==a.element.type.toUpperCase())&&e(a,"required",!0)}),u.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),u.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),a(function(){p.unobtrusive.parse(document)})}(jQuery);
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | ** Unobtrusive validation support library for jQuery and jQuery Validate
3 | ** Copyright (C) Microsoft Corporation. All rights reserved.
4 | */
5 | !function(a){function e(a,e,n){a.rules[e]=n,a.message&&(a.messages[e]=a.message)}function n(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function t(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function r(a){return a.substr(0,a.lastIndexOf(".")+1)}function i(a,e){return 0===a.indexOf("*.")&&(a=a.replace("*.",e)),a}function o(e,n){var r=a(this).find("[data-valmsg-for='"+t(n[0].name)+"']"),i=r.attr("data-valmsg-replace"),o=i?a.parseJSON(i)!==!1:null;r.removeClass("field-validation-valid").addClass("field-validation-error"),e.data("unobtrusiveContainer",r),o?(r.empty(),e.removeClass("input-validation-error").appendTo(r)):e.hide()}function d(e,n){var t=a(this).find("[data-valmsg-summary=true]"),r=t.find("ul");r&&r.length&&n.errorList.length&&(r.empty(),t.addClass("validation-summary-errors").removeClass("validation-summary-valid"),a.each(n.errorList,function(){a("").html(this.message).appendTo(r)}))}function s(e){var n=e.data("unobtrusiveContainer");if(n){var t=n.attr("data-valmsg-replace"),r=t?a.parseJSON(t):null;n.addClass("field-validation-valid").removeClass("field-validation-error"),e.removeData("unobtrusiveContainer"),r&&n.empty()}}function l(e){var n=a(this),t="__jquery_unobtrusive_validation_form_reset";if(!n.data(t)){n.data(t,!0);try{n.data("validator").resetForm()}finally{n.removeData(t)}n.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors"),n.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}}function m(e){var n=a(e),t=n.data(v),r=a.proxy(l,e),i=p.unobtrusive.options||{},m=function(n,t){var r=i[n];r&&a.isFunction(r)&&r.apply(e,t)};return t||(t={options:{errorClass:i.errorClass||"input-validation-error",errorElement:i.errorElement||"span",errorPlacement:function(){o.apply(e,arguments),m("errorPlacement",arguments)},invalidHandler:function(){d.apply(e,arguments),m("invalidHandler",arguments)},messages:{},rules:{},success:function(){s.apply(e,arguments),m("success",arguments)}},attachValidation:function(){n.off("reset."+v,r).on("reset."+v,r).validate(this.options)},validate:function(){return n.validate(),n.valid()}},n.data(v,t)),t}var u,p=a.validator,v="unobtrusiveValidation";p.unobtrusive={adapters:[],parseElement:function(e,n){var t,r,i,o=a(e),d=o.parents("form")[0];d&&(t=m(d),t.options.rules[e.name]=r={},t.options.messages[e.name]=i={},a.each(this.adapters,function(){var n="data-val-"+this.name,t=o.attr(n),s={};void 0!==t&&(n+="-",a.each(this.params,function(){s[this]=o.attr(n+this)}),this.adapt({element:e,form:d,message:t,params:s,rules:r,messages:i}))}),a.extend(r,{__dummy__:!0}),n||t.attachValidation())},parse:function(e){var n=a(e),t=n.parents().addBack().filter("form").add(n.find("form")).has("[data-val=true]");n.find("[data-val=true]").each(function(){p.unobtrusive.parseElement(this,!0)}),t.each(function(){var a=m(this);a&&a.attachValidation()})}},u=p.unobtrusive.adapters,u.add=function(a,e,n){return n||(n=e,e=[]),this.push({name:a,params:e,adapt:n}),this},u.addBool=function(a,n){return this.add(a,function(t){e(t,n||a,!0)})},u.addMinMax=function(a,n,t,r,i,o){return this.add(a,[i||"min",o||"max"],function(a){var i=a.params.min,o=a.params.max;i&&o?e(a,r,[i,o]):i?e(a,n,i):o&&e(a,t,o)})},u.addSingleVal=function(a,n,t){return this.add(a,[n||"val"],function(r){e(r,t||a,r.params[n])})},p.addMethod("__dummy__",function(a,e,n){return!0}),p.addMethod("regex",function(a,e,n){var t;return this.optional(e)?!0:(t=new RegExp(n).exec(a),t&&0===t.index&&t[0].length===a.length)}),p.addMethod("nonalphamin",function(a,e,n){var t;return n&&(t=a.match(/\W/g),t=t&&t.length>=n),t}),p.methods.extension?(u.addSingleVal("accept","mimtype"),u.addSingleVal("extension","extension")):u.addSingleVal("extension","extension","accept"),u.addSingleVal("regex","pattern"),u.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url"),u.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range"),u.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength"),u.add("equalto",["other"],function(n){var o=r(n.element.name),d=n.params.other,s=i(d,o),l=a(n.form).find(":input").filter("[name='"+t(s)+"']")[0];e(n,"equalTo",l)}),u.add("required",function(a){("INPUT"!==a.element.tagName.toUpperCase()||"CHECKBOX"!==a.element.type.toUpperCase())&&e(a,"required",!0)}),u.add("remote",["url","type","additionalfields"],function(o){var d={url:o.params.url,type:o.params.type||"GET",data:{}},s=r(o.element.name);a.each(n(o.params.additionalfields||o.element.name),function(e,n){var r=i(n,s);d.data[r]=function(){var e=a(o.form).find(":input").filter("[name='"+t(r)+"']");return e.is(":checkbox")?e.filter(":checked").val()||e.filter(":hidden").val()||"":e.is(":radio")?e.filter(":checked").val()||"":e.val()}}),e(o,"remote",d)}),u.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&e(a,"minlength",a.params.min),a.params.nonalphamin&&e(a,"nonalphamin",a.params.nonalphamin),a.params.regex&&e(a,"regex",a.params.regex)}),a(function(){p.unobtrusive.parse(document)})}(jQuery);
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
--------------------------------------------------------------------------------
/chapters/es/chapter2.md:
--------------------------------------------------------------------------------
1 |
2 | # Rutas y parámetros
3 |
4 | Si ha llegado hasta aquí ya tendrá un esqueleto fundamental sobre el que iremos profundizando. Con el fin de ir trabajando sobre algo cada vez mas similar a lo que se encontrará en sus proyectos reales iremos ampliando el ejemplo base agregando nuevas funcionalidades en las que iremos tratando diferentes casuísticas. En este caso hablaremos sobre como gestionar las rutas de nuestros controladores en nuestros tests y como trabajar con los parámetros asociados a las diferentes acciones a las que invoquemos.
5 |
6 | Para ilustrar los diferentes elementos vamos a aumentar el código de nuestro HTTP API, con el fin de que podamos reflejar diferentes elementos. Los cambios introducidos implican agregar los siguienes paquetes a nusetro *FooApi*.
7 |
8 | ```PowerShell
9 | Install-Package Microsoft.AspNetCore.Mvc.Versioning
10 | ```
11 |
12 | ```csharp
13 | [Route("api/v{version:apiVersion}/[controller]")]
14 | public class FooController
15 | :Controller
16 | {
17 | [HttpGet()]
18 | public IActionResult Get(int id)
19 | {
20 | var bar = new Bar() { Id = id };
21 |
22 | return Ok(bar);
23 | }
24 |
25 | [HttpPost()]
26 | public IActionResult Post([FromBody]Bar bar)
27 | {
28 | return CreatedAtAction(nameof(Get), new { id = bar.Id });
29 | }
30 | }
31 | ```
32 |
33 | Al código de partida hemos agregado un nuevo método asi como un cambio en la ruta para reflejar versionado de nuestro API. Con estos cambios nso vamos a nuestros tests y podemos reescribirlos tambien como sigue:
34 |
35 | ```csharp
36 | [Collection("Foo")]
37 | public class foo_api_should
38 | {
39 | private readonly FooFixture Given;
40 |
41 | public foo_api_should(FooFixture fooFixture)
42 | {
43 | Given = fooFixture;
44 | }
45 |
46 | [Fact]
47 | public async Task get_bar_when_requested()
48 | {
49 | var response = await Given.FooServer.CreateRequest("api/v1/foo?id=1")
50 | .GetAsync();
51 |
52 | response.EnsureSuccessStatusCode();
53 | }
54 |
55 | [Fact]
56 | public async Task post_new_bar()
57 | {
58 | var response = await Given.FooServer.CreateRequest("api/v1/foo")
59 | .And(message =>
60 | {
61 | var content = JsonConvert.SerializeObject(new Bar() { Id = 1 });
62 | message.Content = new StringContent(content,Encoding.UTF8,"application/json");
63 |
64 | }).PostAsync();
65 |
66 | response.EnsureSuccessStatusCode();
67 | }
68 | }
69 | ```
70 |
71 | Como puede observar, ahora que ya tenemos un par de test simples ya hay algunas cosas que nos hacen ver que tendremos algunos *code smells*. El primero de ellos se refiere al propio uso de las rutas, en ambos tests estamos repitiendo la ruta utilizada *api/v1/foo* y eso nos puede implicar como se imaginará problemas con en cualquier otro sitio donde tengamos magic strings y código repetido.
72 |
73 | Un primer intento para arreglar esto suele basarse en la creación de una pequeña clase dónde podamos gestionar estas rutas, como podria ser la siguiente, que por supuesto tambien es susceptible de ser mejorada:
74 |
75 | ```csharp
76 | static class FooAPI
77 | {
78 | static string BASEURI = "api/v1/foo";
79 |
80 | public static class Get
81 | {
82 | public static string Bar(int id)
83 | {
84 | return $"{BASEURI}?id={id}";
85 | }
86 | }
87 |
88 | public static class Post
89 | {
90 | public static string Bar()
91 | {
92 | return BASEURI;
93 | }
94 | }
95 | }
96 | ```
97 |
98 | Ahora en nuestros tests, eliminaremos las *magic strings* en favor del uso de estas clases:
99 |
100 | ```csharp
101 | [Fact]
102 | public async Task get_bar_when_requested()
103 | {
104 | var response = await Given.FooServer.CreateRequest(FooAPI.Get.Bar(1))
105 | .GetAsync();
106 |
107 | response.EnsureSuccessStatusCode();
108 | }
109 |
110 | [Fact]
111 | public async Task post_new_bar()
112 | {
113 | var response = await Given.FooServer.CreateRequest(FooAPI.Post.Bar())
114 | .And(message =>
115 | {
116 | var content = JsonConvert.SerializeObject(new Bar() { Id = 1 });
117 | message.Content = new StringContent(content,Encoding.UTF8,"application/json");
118 |
119 | }).PostAsync();
120 |
121 | response.EnsureSuccessStatusCode();
122 | }
123 | ```
124 | Otro de los elementos con el que nos encontramos es que en todos los métodos donde estemos pasando tipos complejos como es el caso de nuestro **Bar** tendremos que andar repitiendo el trabajo de serialización. Esto al igual que hemos hecho con las rutas tambien podria refactorizarse usando Builders y disponiéndolos en nuestro *Given*, no obstante intentaremos presentar el uso de una librería,*Acheve.TestHost*, que nos podria ayudar a simplificar nuestros tests. Instalaremos por lo tanto esta librería en nuestro proyecto de tests
125 |
126 |
127 | ```PowerShell
128 | Install-Package Acheve.TestHost
129 | ```
130 |
131 | Esta librería nos aporta un nuevo método de extensión para nuestro *TestServer* llamado *CreateHttpApiRequest* gracias al cual podremos tener nuestros tests anteriores de una forma mas simple. En este momento *CreateHttpApiRequest* solamente es válido para HTTP API usando Attribute Routing, por lo tanto no funcionará de forma correcta para API HTTP que se basen en *conventional routes*. Ahora podemos utilizar este método *CreateHttpApiRequest* y librarnos de tener que conocer las rutas y como los difernetes elementos se mapean a los diferentes segmentos que podamos tener en las mismas asi como el trabajo de serialización de nuestros objetos puesto que el se encarga de todos estos aspectos.
132 |
133 | ```csharp
134 | [Fact]
135 | public async Task get_bar_when_requested()
136 | {
137 | var response = await Given.FooServer
138 | .CreateHttpApiRequest(foo=>foo.Get(1),new { version = 1 })
139 | .GetAsync();
140 |
141 | response.EnsureSuccessStatusCode();
142 | }
143 |
144 | [Fact]
145 | public async Task post_new_bar()
146 | {
147 | var bar = new Bar() { Id = 1 };
148 | var response = await Given.FooServer
149 | .CreateHttpApiRequest(foo => foo.Post(bar), new { version = 1 })
150 | .PostAsync();
151 |
152 | response.EnsureSuccessStatusCode();
153 | }
154 | ```
155 |
156 | Fíjese como se usa el tipo anónimo para especificar aquellos *tokens* que no pueden ser obtenidos de la propia definición de la acción llamada en nuestro controlador.
157 |
158 | # Conclusiones
159 |
160 | En este capítulo hemos visto como enfrentarnos al manejo de las diferentes rutas de nuestro controladores en los tests de nuestras HTTP API para simplificar nuestros tests e intentar luchar contra diferentes *code smell* que nos pueden aparecer.
161 |
162 | > [Continuar la lectura](./chapter3.md)
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/images/banner2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/images/banner2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/images/banner2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/samples/Chapter4/FooApi/Host/wwwroot/images/banner2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/samples/Chapter1/FooApi/Host/wwwroot/images/banner1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/samples/Chapter2/FooApi/Host/wwwroot/images/banner1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/samples/Chapter3/FooApi/Host/wwwroot/images/banner1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------