├── .gitignore
├── BasicsRefresh.sln
├── LICENSE
├── README.md
└── src
├── ContactsAngular
├── .gitignore
├── ClientApp
│ ├── .editorconfig
│ ├── .gitignore
│ ├── README.md
│ ├── angular.json
│ ├── browserslist
│ ├── e2e
│ │ ├── protractor.conf.js
│ │ ├── src
│ │ │ ├── app.e2e-spec.ts
│ │ │ └── app.po.ts
│ │ └── tsconfig.e2e.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── app
│ │ │ ├── apis
│ │ │ │ └── contactApi.ts
│ │ │ ├── app.component.html
│ │ │ ├── app.component.ts
│ │ │ ├── app.module.ts
│ │ │ ├── app.server.module.ts
│ │ │ ├── contacts
│ │ │ │ ├── contact-list.component.html
│ │ │ │ └── contact-list.component.ts
│ │ │ ├── counter
│ │ │ │ ├── counter.component.html
│ │ │ │ ├── counter.component.spec.ts
│ │ │ │ └── counter.component.ts
│ │ │ ├── fetch-data
│ │ │ │ ├── fetch-data.component.html
│ │ │ │ └── fetch-data.component.ts
│ │ │ ├── home
│ │ │ │ ├── home.component.html
│ │ │ │ └── home.component.ts
│ │ │ └── nav-menu
│ │ │ │ ├── nav-menu.component.css
│ │ │ │ ├── nav-menu.component.html
│ │ │ │ └── nav-menu.component.ts
│ │ ├── assets
│ │ │ └── .gitkeep
│ │ ├── environments
│ │ │ ├── environment.prod.ts
│ │ │ └── environment.ts
│ │ ├── index.html
│ │ ├── karma.conf.js
│ │ ├── main.ts
│ │ ├── polyfills.ts
│ │ ├── styles.css
│ │ ├── test.ts
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.server.json
│ │ ├── tsconfig.spec.json
│ │ └── tslint.json
│ ├── tsconfig.json
│ └── tslint.json
├── ContactsAngular.csproj
├── Controllers
│ └── WeatherForecastController.cs
├── Pages
│ ├── Error.cshtml
│ ├── Error.cshtml.cs
│ └── _ViewImports.cshtml
├── Program.cs
├── Startup.cs
├── WeatherForecast.cs
├── appsettings.Development.json
├── appsettings.json
└── wwwroot
│ └── favicon.ico
├── ContactsApi
├── ContactsApi.csproj
├── Controllers
│ └── ContactsController.cs
├── Data
│ ├── ContactsDbContext.cs
│ └── Migrations
│ │ ├── 20191010112653_Initial.Designer.cs
│ │ ├── 20191010112653_Initial.cs
│ │ └── ContactsDbContextModelSnapshot.cs
├── Middleware
│ ├── RequestResponseLoggingMiddleware.cs
│ └── RequestResponseLoggingMiddlewareExtensions.cs
├── Models
│ └── Contact.cs
├── Program.cs
├── Startup.cs
├── appsettings.Development.json
└── appsettings.json
├── ContactsBlazorServerApp
├── Apis
│ └── ContactsApi.cs
├── App.razor
├── ContactsBlazorServerApp.csproj
├── Data
│ ├── WeatherForecast.cs
│ └── WeatherForecastService.cs
├── Pages
│ ├── ContactList.razor
│ ├── Counter.razor
│ ├── Error.razor
│ ├── FetchData.razor
│ ├── Index.razor
│ └── _Host.cshtml
├── Program.cs
├── Shared
│ ├── MainLayout.razor
│ └── NavMenu.razor
├── Startup.cs
├── _Imports.razor
├── appsettings.Development.json
├── appsettings.json
└── wwwroot
│ ├── css
│ ├── bootstrap
│ │ ├── bootstrap.min.css
│ │ └── bootstrap.min.css.map
│ ├── open-iconic
│ │ ├── FONT-LICENSE
│ │ ├── ICON-LICENSE
│ │ ├── README.md
│ │ └── font
│ │ │ ├── css
│ │ │ └── open-iconic-bootstrap.min.css
│ │ │ └── fonts
│ │ │ ├── open-iconic.eot
│ │ │ ├── open-iconic.otf
│ │ │ ├── open-iconic.svg
│ │ │ ├── open-iconic.ttf
│ │ │ └── open-iconic.woff
│ └── site.css
│ └── favicon.ico
├── ContactsRazorPages
├── Apis
│ └── ContactsApi.cs
├── ContactsRazorPages.csproj
├── Pages
│ ├── Contacts
│ │ ├── Create.cshtml
│ │ ├── Create.cshtml.cs
│ │ ├── Delete.cshtml
│ │ ├── Delete.cshtml.cs
│ │ ├── Details.cshtml
│ │ ├── Details.cshtml.cs
│ │ ├── Edit.cshtml
│ │ ├── Edit.cshtml.cs
│ │ ├── Index.cshtml
│ │ └── Index.cshtml.cs
│ ├── Error.cshtml
│ ├── Error.cshtml.cs
│ ├── Index.cshtml
│ ├── Index.cshtml.cs
│ ├── Privacy.cshtml
│ ├── Privacy.cshtml.cs
│ ├── Shared
│ │ ├── _Layout.cshtml
│ │ └── _ValidationScriptsPartial.cshtml
│ ├── _ViewImports.cshtml
│ └── _ViewStart.cshtml
├── Program.cs
├── Startup.cs
├── appsettings.Development.json
├── appsettings.json
└── wwwroot
│ ├── css
│ └── site.css
│ ├── favicon.ico
│ ├── js
│ └── site.js
│ └── lib
│ ├── bootstrap
│ ├── LICENSE
│ └── dist
│ │ ├── css
│ │ ├── bootstrap-grid.css
│ │ ├── bootstrap-grid.css.map
│ │ ├── bootstrap-grid.min.css
│ │ ├── bootstrap-grid.min.css.map
│ │ ├── bootstrap-reboot.css
│ │ ├── bootstrap-reboot.css.map
│ │ ├── bootstrap-reboot.min.css
│ │ ├── bootstrap-reboot.min.css.map
│ │ ├── bootstrap.css
│ │ ├── bootstrap.css.map
│ │ ├── bootstrap.min.css
│ │ └── bootstrap.min.css.map
│ │ └── js
│ │ ├── bootstrap.bundle.js
│ │ ├── bootstrap.bundle.js.map
│ │ ├── bootstrap.bundle.min.js
│ │ ├── bootstrap.bundle.min.js.map
│ │ ├── bootstrap.js
│ │ ├── bootstrap.js.map
│ │ ├── bootstrap.min.js
│ │ └── bootstrap.min.js.map
│ ├── jquery-validation-unobtrusive
│ ├── LICENSE.txt
│ ├── jquery.validate.unobtrusive.js
│ └── jquery.validate.unobtrusive.min.js
│ ├── jquery-validation
│ ├── LICENSE.md
│ └── dist
│ │ ├── additional-methods.js
│ │ ├── additional-methods.min.js
│ │ ├── jquery.validate.js
│ │ └── jquery.validate.min.js
│ └── jquery
│ ├── LICENSE.txt
│ └── dist
│ ├── jquery.js
│ ├── jquery.min.js
│ └── jquery.min.map
├── ContactsReact
├── .gitignore
├── ClientApp
│ ├── .gitignore
│ ├── README.md
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ └── manifest.json
│ ├── src
│ │ ├── App.js
│ │ ├── App.test.js
│ │ ├── components
│ │ │ ├── ContactList.js
│ │ │ ├── Counter.js
│ │ │ ├── FetchData.js
│ │ │ ├── Home.js
│ │ │ ├── Layout.js
│ │ │ ├── NavMenu.css
│ │ │ ├── NavMenu.js
│ │ │ └── contactsApi.ts
│ │ ├── custom.css
│ │ ├── index.js
│ │ ├── react-app-env.d.ts
│ │ └── registerServiceWorker.js
│ └── tsconfig.json
├── ContactsReact.csproj
├── Controllers
│ └── WeatherForecastController.cs
├── Pages
│ ├── Error.cshtml
│ ├── Error.cshtml.cs
│ └── _ViewImports.cshtml
├── Program.cs
├── Startup.cs
├── WeatherForecast.cs
├── appsettings.Development.json
└── appsettings.json
├── contacts-aurelia
├── .editorconfig
├── .gitignore
├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ └── settings.json
├── README.md
├── aurelia_project
│ ├── aurelia.json
│ ├── generators
│ │ ├── attribute.json
│ │ ├── attribute.ts
│ │ ├── binding-behavior.json
│ │ ├── binding-behavior.ts
│ │ ├── component.json
│ │ ├── component.ts
│ │ ├── element.json
│ │ ├── element.ts
│ │ ├── generator.json
│ │ ├── generator.ts
│ │ ├── task.json
│ │ ├── task.ts
│ │ ├── value-converter.json
│ │ └── value-converter.ts
│ └── tasks
│ │ ├── build.json
│ │ ├── build.ts
│ │ ├── jest.json
│ │ ├── jest.ts
│ │ ├── run.json
│ │ ├── run.ts
│ │ ├── test.json
│ │ └── test.ts
├── config
│ ├── environment.json
│ └── environment.production.json
├── favicon.ico
├── index.ejs
├── package-lock.json
├── package.json
├── src
│ ├── app.html
│ ├── app.ts
│ ├── contact-detail.html
│ ├── contact-detail.ts
│ ├── contact-list.html
│ ├── contact-list.ts
│ ├── contactsApi.ts
│ ├── main.ts
│ ├── no-selection.html
│ ├── no-selection.ts
│ ├── resources
│ │ └── index.ts
│ ├── styles.css
│ └── utility.ts
├── static
│ └── favicon.ico
├── test
│ └── jest-pretest.ts
├── tsconfig.json
├── tslint.json
├── types
│ ├── fetch.d.ts
│ └── system.d.ts
└── webpack.config.js
└── contacts-vue
├── .browserslistrc
├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── public
├── favicon.ico
└── index.html
├── src
├── App.vue
├── apis
│ └── contactsApi.ts
├── assets
│ └── logo.png
├── components
│ ├── ContacList.vue
│ └── HelloWorld.vue
├── main.ts
├── router
│ └── index.ts
├── shims-tsx.d.ts
├── shims-vue.d.ts
└── views
│ ├── About.vue
│ ├── ContactList.vue
│ └── Home.vue
└── tsconfig.json
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Eric Anderson
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ASP.NET-Core-Basics-Refresh
2 | This repository contains the code that goes with set of blog post on the basics of of ASP.NET Core where can be found [here](http://www.elanderson.net/category/asp-net-core/asp-net-basics/).
3 |
4 | ## Expanded
5 | This repo is a fresh start with the same idea as the [ASP.NET Core Basics](https://github.com/elanderson/ASP.NET-Core-Basics), but with a fresh start at the release of ASP.NET Core 3.0. Over time this repo should give a jumping off point to experiment with [Angular](https://angular.io/), [Aurelia](http://aurelia.io/), [React](https://reactjs.org/), [Vue](https://vuejs.org/), and [Blazor](https://blazor.net/) from inside the same soultion using different projects for each framework.
6 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /dist-server
6 | /tmp
7 | /out-tsc
8 |
9 | # dependencies
10 | /node_modules
11 |
12 | # IDEs and editors
13 | /.idea
14 | .project
15 | .classpath
16 | .c9/
17 | *.launch
18 | .settings/
19 | *.sublime-workspace
20 |
21 | # IDE - VSCode
22 | .vscode/*
23 | !.vscode/settings.json
24 | !.vscode/tasks.json
25 | !.vscode/launch.json
26 | !.vscode/extensions.json
27 |
28 | # misc
29 | /.sass-cache
30 | /connect.lock
31 | /coverage
32 | /libpeerconnection.log
33 | npm-debug.log
34 | yarn-error.log
35 | testem.log
36 | /typings
37 |
38 | # System Files
39 | .DS_Store
40 | Thumbs.db
41 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/README.md:
--------------------------------------------------------------------------------
1 | # ContactsAngular
2 |
3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 6.0.0.
4 |
5 | ## Development server
6 |
7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
8 |
9 | ## Code scaffolding
10 |
11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
12 |
13 | ## Build
14 |
15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
16 |
17 | ## Running unit tests
18 |
19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
20 |
21 | ## Running end-to-end tests
22 |
23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
24 |
25 | ## Further help
26 |
27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
28 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/browserslist:
--------------------------------------------------------------------------------
1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 | # For IE 9-11 support, please uncomment the last line of the file and adjust as needed
5 | > 0.5%
6 | last 2 versions
7 | Firefox ESR
8 | not dead
9 | # IE 9-11
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/e2e/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // Protractor configuration file, see link for more information
2 | // https://github.com/angular/protractor/blob/master/lib/config.ts
3 |
4 | const { SpecReporter } = require("jasmine-spec-reporter");
5 |
6 | exports.config = {
7 | allScriptsTimeout: 11000,
8 | specs: ["./src/**/*.e2e-spec.ts"],
9 | capabilities: {
10 | browserName: "chrome"
11 | },
12 | directConnect: true,
13 | baseUrl: "http://localhost:4200/",
14 | framework: "jasmine",
15 | jasmineNodeOpts: {
16 | showColors: true,
17 | defaultTimeoutInterval: 30000,
18 | print: function() {}
19 | },
20 | onPrepare() {
21 | require("ts-node").register({
22 | project: require("path").join(__dirname, "./tsconfig.e2e.json")
23 | });
24 | jasmine
25 | .getEnv()
26 | .addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/e2e/src/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { AppPage } from './app.po';
2 |
3 | describe('App', () => {
4 | let page: AppPage;
5 |
6 | beforeEach(() => {
7 | page = new AppPage();
8 | });
9 |
10 | it('should display welcome message', () => {
11 | page.navigateTo();
12 | expect(page.getMainHeading()).toEqual('Hello, world!');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/e2e/src/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, by, element } from 'protractor';
2 |
3 | export class AppPage {
4 | navigateTo() {
5 | return browser.get('/');
6 | }
7 |
8 | getMainHeading() {
9 | return element(by.css('app-root h1')).getText();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/e2e/tsconfig.e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "module": "commonjs",
6 | "target": "es5",
7 | "types": [
8 | "jasmine",
9 | "jasminewd2",
10 | "node"
11 | ]
12 | }
13 | }
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "contactsangular",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "ng": "ng",
6 | "start": "ng serve",
7 | "build": "ng build",
8 | "build:ssr": "ng run ContactsAngular:server:dev",
9 | "test": "ng test",
10 | "lint": "ng lint",
11 | "e2e": "ng e2e"
12 | },
13 | "private": true,
14 | "dependencies": {
15 | "@angular/animations": "8.0.0",
16 | "@angular/common": "8.0.0",
17 | "@angular/compiler": "8.0.0",
18 | "@angular/core": "8.0.0",
19 | "@angular/forms": "8.0.0",
20 | "@angular/platform-browser": "8.0.0",
21 | "@angular/platform-browser-dynamic": "8.0.0",
22 | "@angular/platform-server": "8.0.0",
23 | "@angular/router": "8.0.0",
24 | "@nguniversal/module-map-ngfactory-loader": "8.0.0-rc.1",
25 | "aspnet-prerendering": "^3.0.1",
26 | "bootstrap": "^4.3.1",
27 | "core-js": "^2.6.5",
28 | "jquery": "3.4.1",
29 | "oidc-client": "^1.9.0",
30 | "popper.js": "^1.14.3",
31 | "rxjs": "^6.4.0",
32 | "zone.js": "~0.9.1"
33 | },
34 | "devDependencies": {
35 | "@angular-devkit/build-angular": "^0.800.6",
36 | "@angular/cli": "8.0.6",
37 | "@angular/compiler-cli": "8.0.0",
38 | "@angular/language-service": "8.0.0",
39 | "@types/jasmine": "~3.3.9",
40 | "@types/jasminewd2": "~2.0.6",
41 | "@types/node": "~11.10.5",
42 | "codelyzer": "^5.0.1",
43 | "jasmine-core": "~3.3.0",
44 | "jasmine-spec-reporter": "~4.2.1",
45 | "karma": "^4.0.0",
46 | "karma-chrome-launcher": "~2.2.0",
47 | "karma-coverage-istanbul-reporter": "~2.0.5",
48 | "karma-jasmine": "~2.0.1",
49 | "karma-jasmine-html-reporter": "^1.4.0",
50 | "typescript": "3.4.5"
51 | },
52 | "optionalDependencies": {
53 | "node-sass": "^4.9.3",
54 | "protractor": "~5.4.0",
55 | "ts-node": "~5.0.1",
56 | "tslint": "~5.9.1"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html'
6 | })
7 | export class AppComponent {
8 | title = 'app';
9 | }
10 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { BrowserModule } from '@angular/platform-browser';
2 | import { NgModule } from '@angular/core';
3 | import { FormsModule } from '@angular/forms';
4 | import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
5 | import { RouterModule } from '@angular/router';
6 |
7 | import { AppComponent } from './app.component';
8 | import { NavMenuComponent } from './nav-menu/nav-menu.component';
9 | import { HomeComponent } from './home/home.component';
10 | import { CounterComponent } from './counter/counter.component';
11 | import { FetchDataComponent } from './fetch-data/fetch-data.component';
12 | import { ContactListComponent } from "./contacts/contact-list.component";
13 | import { contacts } from "./apis/contactApi";
14 |
15 | @NgModule({
16 | declarations: [
17 | AppComponent,
18 | NavMenuComponent,
19 | HomeComponent,
20 | CounterComponent,
21 | FetchDataComponent,
22 | ContactListComponent
23 | ],
24 | imports: [
25 | BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
26 | HttpClientModule,
27 | FormsModule,
28 | RouterModule.forRoot([
29 | { path: '', component: HomeComponent, pathMatch: 'full' },
30 | { path: 'contact-list', component: ContactListComponent },
31 | { path: 'counter', component: CounterComponent },
32 | { path: 'fetch-data', component: FetchDataComponent },
33 | ])
34 | ],
35 | providers: [contacts.ContactsClient],
36 | bootstrap: [AppComponent]
37 | })
38 | export class AppModule { }
39 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/app.server.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { ServerModule } from '@angular/platform-server';
3 | import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader';
4 | import { AppComponent } from './app.component';
5 | import { AppModule } from './app.module';
6 |
7 | @NgModule({
8 | imports: [AppModule, ServerModule, ModuleMapLoaderModule],
9 | bootstrap: [AppComponent]
10 | })
11 | export class AppServerModule { }
12 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/contacts/contact-list.component.html:
--------------------------------------------------------------------------------
1 | Contacts
2 |
3 | Loading...
4 |
5 |
6 |
7 |
8 | Name
9 | Address
10 | City
11 | State
12 | Postal Code
13 | Phone
14 | Email
15 |
16 |
17 |
18 |
19 | {{ contact.name }}
20 | {{ contact.address }}
21 | {{ contact.city }}
22 | {{ contact.state }}
23 | {{ contact.postalCode }}
24 | {{ contact.phone }}
25 | {{ contact.email }}
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/contacts/contact-list.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { contacts as Contacts } from "../apis/contactApi";
3 |
4 | @Component({
5 | selector: 'app-contact-list',
6 | templateUrl: './contact-list.component.html'
7 | })
8 | export class ContactListComponent {
9 | public contacts: Contacts.IContact[];
10 |
11 | constructor(contactsClient : Contacts.ContactsClient) {
12 | contactsClient.getContacts().subscribe(result => {
13 | this.contacts = result;
14 | },
15 | error => console.error(error));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/counter/counter.component.html:
--------------------------------------------------------------------------------
1 | Counter
2 |
3 | This is a simple example of an Angular component.
4 |
5 | Current count: {{ currentCount }}
6 |
7 | Increment
8 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/counter/counter.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { CounterComponent } from './counter.component';
4 |
5 | describe('CounterComponent', () => {
6 | let component: CounterComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ CounterComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(CounterComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should display a title', async(() => {
23 | const titleText = fixture.nativeElement.querySelector('h1').textContent;
24 | expect(titleText).toEqual('Counter');
25 | }));
26 |
27 | it('should start with count 0, then increments by 1 when clicked', async(() => {
28 | const countElement = fixture.nativeElement.querySelector('strong');
29 | expect(countElement.textContent).toEqual('0');
30 |
31 | const incrementButton = fixture.nativeElement.querySelector('button');
32 | incrementButton.click();
33 | fixture.detectChanges();
34 | expect(countElement.textContent).toEqual('1');
35 | }));
36 | });
37 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/counter/counter.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-counter-component',
5 | templateUrl: './counter.component.html'
6 | })
7 | export class CounterComponent {
8 | public currentCount = 0;
9 |
10 | public incrementCounter() {
11 | this.currentCount++;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/fetch-data/fetch-data.component.html:
--------------------------------------------------------------------------------
1 | Weather forecast
2 |
3 | This component demonstrates fetching data from the server.
4 |
5 | Loading...
6 |
7 |
8 |
9 |
10 | Date
11 | Temp. (C)
12 | Temp. (F)
13 | Summary
14 |
15 |
16 |
17 |
18 | {{ forecast.date }}
19 | {{ forecast.temperatureC }}
20 | {{ forecast.temperatureF }}
21 | {{ forecast.summary }}
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/fetch-data/fetch-data.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Inject } from '@angular/core';
2 | import { HttpClient } from '@angular/common/http';
3 |
4 | @Component({
5 | selector: 'app-fetch-data',
6 | templateUrl: './fetch-data.component.html'
7 | })
8 | export class FetchDataComponent {
9 | public forecasts: WeatherForecast[];
10 |
11 | constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
12 | http.get(baseUrl + 'weatherforecast').subscribe(result => {
13 | this.forecasts = result;
14 | }, error => console.error(error));
15 | }
16 | }
17 |
18 | interface WeatherForecast {
19 | date: string;
20 | temperatureC: number;
21 | temperatureF: number;
22 | summary: string;
23 | }
24 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/home/home.component.html:
--------------------------------------------------------------------------------
1 | Hello, world!
2 | Welcome to your new single-page application, built with:
3 |
8 | To help you get started, we've also set up:
9 |
10 | Client-side navigation . For example, click Counter then Back to return here.
11 | Angular CLI integration . In development mode, there's no need to run ng serve
. It runs in the background automatically, so your client-side resources are dynamically built on demand and the page refreshes when you modify any file.
12 | Efficient production builds . In production mode, development-time features are disabled, and your dotnet publish
configuration automatically invokes ng build
to produce minified, ahead-of-time compiled JavaScript files.
13 |
14 | The ClientApp
subdirectory is a standard Angular CLI application. If you open a command prompt in that directory, you can run any ng
command (e.g., ng test
), or use npm
to install extra packages into it.
15 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/home/home.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-home',
5 | templateUrl: './home.component.html',
6 | })
7 | export class HomeComponent {
8 | }
9 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/nav-menu/nav-menu.component.css:
--------------------------------------------------------------------------------
1 | a.navbar-brand {
2 | white-space: normal;
3 | text-align: center;
4 | word-break: break-all;
5 | }
6 |
7 | html {
8 | font-size: 14px;
9 | }
10 | @media (min-width: 768px) {
11 | html {
12 | font-size: 16px;
13 | }
14 | }
15 |
16 | .box-shadow {
17 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
18 | }
19 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/nav-menu/nav-menu.component.html:
--------------------------------------------------------------------------------
1 |
50 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/app/nav-menu/nav-menu.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-nav-menu',
5 | templateUrl: './nav-menu.component.html',
6 | styleUrls: ['./nav-menu.component.css']
7 | })
8 | export class NavMenuComponent {
9 | isExpanded = false;
10 |
11 | collapse() {
12 | this.isExpanded = false;
13 | }
14 |
15 | toggle() {
16 | this.isExpanded = !this.isExpanded;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elanderson/ASP.NET-Core-Basics-Refresh/ce90da48353633653f4c2c194fdc597abe18a150/src/ContactsAngular/ClientApp/src/assets/.gitkeep
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // This file can be replaced during build by using the `fileReplacements` array.
2 | // `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`.
3 | // The list of file replacements can be found in `angular.json`.
4 |
5 | export const environment = {
6 | production: false
7 | };
8 |
9 | /*
10 | * In development mode, to ignore zone related error stack frames such as
11 | * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can
12 | * import the following file, but please comment it out in production mode
13 | * because it will have performance impact when throw error
14 | */
15 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI.
16 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ContactsAngular
6 |
7 |
8 |
9 |
10 |
11 |
12 | Loading...
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | clearContext: false // leave Jasmine Spec Runner output visible in browser
17 | },
18 | coverageIstanbulReporter: {
19 | dir: require('path').join(__dirname, '../coverage'),
20 | reports: ['html', 'lcovonly'],
21 | fixWebpackSourcePaths: true
22 | },
23 | reporters: ['progress', 'kjhtml'],
24 | port: 9876,
25 | colors: true,
26 | logLevel: config.LOG_INFO,
27 | autoWatch: true,
28 | browsers: ['Chrome'],
29 | singleRun: false
30 | });
31 | };
32 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | export function getBaseUrl() {
8 | return document.getElementsByTagName('base')[0].href;
9 | }
10 |
11 | const providers = [
12 | { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] }
13 | ];
14 |
15 | if (environment.production) {
16 | enableProdMode();
17 | }
18 |
19 | platformBrowserDynamic(providers).bootstrapModule(AppModule)
20 | .catch(err => console.log(err));
21 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */
22 | // import 'classlist.js'; // Run `npm install --save classlist.js`.
23 |
24 | /**
25 | * Web Animations `@angular/platform-browser/animations`
26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
28 | */
29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`.
30 |
31 | /**
32 | * By default, zone.js will patch all possible macroTask and DomEvents
33 | * user can disable parts of macroTask/DomEvents patch by setting following flags
34 | * because those flags need to be set before `zone.js` being loaded, and webpack
35 | * will put import in the top of bundle, so user need to create a separate file
36 | * in this directory (for example: zone-flags.ts), and put the following flags
37 | * into that file, and then add the following code before importing zone.js.
38 | * import './zone-flags.ts';
39 | *
40 | * The flags allowed in zone-flags.ts are listed here.
41 | *
42 | * The following flags will work for all browsers.
43 | *
44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
47 | *
48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
50 | *
51 | * (window as any).__Zone_enable_cross_context_check = true;
52 | *
53 | */
54 |
55 | /***************************************************************************************************
56 | * Zone JS is required by default for Angular itself.
57 | */
58 | import 'zone.js/dist/zone'; // Included with Angular CLI.
59 |
60 |
61 | /***************************************************************************************************
62 | * APPLICATION IMPORTS
63 | */
64 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
3 | /* Provide sufficient contrast against white background */
4 | a {
5 | color: #0366d6;
6 | }
7 |
8 | code {
9 | color: #e01a76;
10 | }
11 |
12 | .btn-primary {
13 | color: #fff;
14 | background-color: #1b6ec2;
15 | border-color: #1861ac;
16 | }
17 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/zone-testing';
4 | import { getTestBed } from '@angular/core/testing';
5 | import {
6 | BrowserDynamicTestingModule,
7 | platformBrowserDynamicTesting
8 | } from '@angular/platform-browser-dynamic/testing';
9 |
10 | declare const require: any;
11 |
12 | // First, initialize the Angular testing environment.
13 | getTestBed().initTestEnvironment(
14 | BrowserDynamicTestingModule,
15 | platformBrowserDynamicTesting()
16 | );
17 | // Then we find all the tests.
18 | const context = require.context('./', true, /\.spec\.ts$/);
19 | // And load the modules.
20 | context.keys().map(context);
21 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "types": []
6 | },
7 | "exclude": [
8 | "src/test.ts",
9 | "**/*.spec.ts"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/tsconfig.server.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "module": "commonjs"
5 | },
6 | "angularCompilerOptions": {
7 | "entryModule": "app/app.server.module#AppServerModule"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/spec",
5 | "types": [
6 | "jasmine",
7 | "node"
8 | ]
9 | },
10 | "files": [
11 | "test.ts",
12 | "polyfills.ts"
13 | ],
14 | "include": [
15 | "**/*.spec.ts",
16 | "**/*.d.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/src/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tslint.json",
3 | "rules": {
4 | "directive-selector": [
5 | true,
6 | "attribute",
7 | "app",
8 | "camelCase"
9 | ],
10 | "component-selector": [
11 | true,
12 | "element",
13 | "app",
14 | "kebab-case"
15 | ]
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "baseUrl": "./",
5 | "module": "esnext",
6 | "outDir": "./dist/out-tsc",
7 | "sourceMap": true,
8 | "declaration": false,
9 | "moduleResolution": "node",
10 | "emitDecoratorMetadata": true,
11 | "experimentalDecorators": true,
12 | "target": "es2015",
13 | "typeRoots": [
14 | "node_modules/@types"
15 | ],
16 | "lib": [
17 | "es2017",
18 | "dom"
19 | ]
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ClientApp/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "arrow-return-shorthand": true,
7 | "callable-types": true,
8 | "class-name": true,
9 | "comment-format": [
10 | true,
11 | "check-space"
12 | ],
13 | "curly": true,
14 | "deprecation": {
15 | "severity": "warn"
16 | },
17 | "eofline": true,
18 | "forin": true,
19 | "import-blacklist": [
20 | true,
21 | "rxjs/Rx"
22 | ],
23 | "import-spacing": true,
24 | "indent": [
25 | true,
26 | "spaces"
27 | ],
28 | "interface-over-type-literal": true,
29 | "label-position": true,
30 | "max-line-length": [
31 | true,
32 | 140
33 | ],
34 | "member-access": false,
35 | "member-ordering": [
36 | true,
37 | {
38 | "order": [
39 | "static-field",
40 | "instance-field",
41 | "static-method",
42 | "instance-method"
43 | ]
44 | }
45 | ],
46 | "no-arg": true,
47 | "no-bitwise": true,
48 | "no-console": [
49 | true,
50 | "debug",
51 | "info",
52 | "time",
53 | "timeEnd",
54 | "trace"
55 | ],
56 | "no-construct": true,
57 | "no-debugger": true,
58 | "no-duplicate-super": true,
59 | "no-empty": false,
60 | "no-empty-interface": true,
61 | "no-eval": true,
62 | "no-inferrable-types": [
63 | true,
64 | "ignore-params"
65 | ],
66 | "no-misused-new": true,
67 | "no-non-null-assertion": true,
68 | "no-shadowed-variable": true,
69 | "no-string-literal": false,
70 | "no-string-throw": true,
71 | "no-switch-case-fall-through": true,
72 | "no-trailing-whitespace": true,
73 | "no-unnecessary-initializer": true,
74 | "no-unused-expression": true,
75 | "no-use-before-declare": true,
76 | "no-var-keyword": true,
77 | "object-literal-sort-keys": false,
78 | "one-line": [
79 | true,
80 | "check-open-brace",
81 | "check-catch",
82 | "check-else",
83 | "check-whitespace"
84 | ],
85 | "prefer-const": true,
86 | "quotemark": [
87 | true,
88 | "single"
89 | ],
90 | "radix": true,
91 | "semicolon": [
92 | true,
93 | "always"
94 | ],
95 | "triple-equals": [
96 | true,
97 | "allow-null-check"
98 | ],
99 | "typedef-whitespace": [
100 | true,
101 | {
102 | "call-signature": "nospace",
103 | "index-signature": "nospace",
104 | "parameter": "nospace",
105 | "property-declaration": "nospace",
106 | "variable-declaration": "nospace"
107 | }
108 | ],
109 | "unified-signatures": true,
110 | "variable-name": false,
111 | "whitespace": [
112 | true,
113 | "check-branch",
114 | "check-decl",
115 | "check-operator",
116 | "check-separator",
117 | "check-type"
118 | ],
119 | "no-output-on-prefix": true,
120 | "no-inputs-metadata-property": true,
121 | "no-outputs-metadata-property": true,
122 | "no-host-metadata-property": true,
123 | "no-input-rename": true,
124 | "no-output-rename": true,
125 | "use-lifecycle-interface": true,
126 | "use-pipe-transform-interface": true,
127 | "component-class-suffix": true,
128 | "directive-class-suffix": true
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/ContactsAngular/ContactsAngular.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | true
6 | Latest
7 | false
8 | ClientApp\
9 | $(DefaultItemExcludes);$(SpaRoot)node_modules\**
10 |
11 |
12 | false
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | %(DistFiles.Identity)
48 | PreserveNewest
49 | true
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/src/ContactsAngular/Controllers/WeatherForecastController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Mvc;
6 | using Microsoft.Extensions.Logging;
7 |
8 | namespace ContactsAngular.Controllers
9 | {
10 | [ApiController]
11 | [Route("[controller]")]
12 | public class WeatherForecastController : ControllerBase
13 | {
14 | private static readonly string[] Summaries = new[]
15 | {
16 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
17 | };
18 |
19 | private readonly ILogger _logger;
20 |
21 | public WeatherForecastController(ILogger logger)
22 | {
23 | _logger = logger;
24 | }
25 |
26 | [HttpGet]
27 | public IEnumerable Get()
28 | {
29 | var rng = new Random();
30 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast
31 | {
32 | Date = DateTime.Now.AddDays(index),
33 | TemperatureC = rng.Next(-20, 55),
34 | Summary = Summaries[rng.Next(Summaries.Length)]
35 | })
36 | .ToArray();
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/ContactsAngular/Pages/Error.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ErrorModel
3 | @{
4 | ViewData["Title"] = "Error";
5 | }
6 |
7 | Error.
8 | An error occurred while processing your request.
9 |
10 | @if (Model.ShowRequestId)
11 | {
12 |
13 | Request ID: @Model.RequestId
14 |
15 | }
16 |
17 | Development Mode
18 |
19 | Swapping to the Development environment displays detailed information about the error that occurred.
20 |
21 |
22 | The Development environment shouldn't be enabled for deployed applications.
23 | It can result in displaying sensitive information from exceptions to end users.
24 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
25 | and restarting the app.
26 |
27 |
--------------------------------------------------------------------------------
/src/ContactsAngular/Pages/Error.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.AspNetCore.Mvc.RazorPages;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace ContactsAngular.Pages
11 | {
12 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
13 | public class ErrorModel : PageModel
14 | {
15 | private readonly ILogger _logger;
16 |
17 | public ErrorModel(ILogger logger)
18 | {
19 | _logger = logger;
20 | }
21 |
22 | public string RequestId { get; set; }
23 |
24 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
25 |
26 | public void OnGet()
27 | {
28 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/ContactsAngular/Pages/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using ContactsAngular
2 | @namespace ContactsAngular.Pages
3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
4 |
--------------------------------------------------------------------------------
/src/ContactsAngular/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.Extensions.Configuration;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace ContactsAngular
11 | {
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateWebHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
20 | WebHost.CreateDefaultBuilder(args)
21 | .UseStartup();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/ContactsAngular/Startup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.AspNetCore.HttpsPolicy;
4 | using Microsoft.AspNetCore.SpaServices.AngularCli;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Hosting;
8 |
9 | namespace ContactsAngular
10 | {
11 | public class Startup
12 | {
13 | public Startup(IConfiguration configuration)
14 | {
15 | Configuration = configuration;
16 | }
17 |
18 | public IConfiguration Configuration { get; }
19 |
20 | // This method gets called by the runtime. Use this method to add services to the container.
21 | public void ConfigureServices(IServiceCollection services)
22 | {
23 | services.AddControllersWithViews();
24 | // In production, the Angular files will be served from this directory
25 | services.AddSpaStaticFiles(configuration =>
26 | {
27 | configuration.RootPath = "ClientApp/dist";
28 | });
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, IWebHostEnvironment env)
33 | {
34 | if (env.IsDevelopment())
35 | {
36 | app.UseDeveloperExceptionPage();
37 | }
38 | else
39 | {
40 | app.UseExceptionHandler("/Error");
41 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
42 | app.UseHsts();
43 | }
44 |
45 | app.UseHttpsRedirection();
46 | app.UseStaticFiles();
47 | if (!env.IsDevelopment())
48 | {
49 | app.UseSpaStaticFiles();
50 | }
51 |
52 | app.UseRouting();
53 |
54 | app.UseEndpoints(endpoints =>
55 | {
56 | endpoints.MapControllerRoute(
57 | name: "default",
58 | pattern: "{controller}/{action=Index}/{id?}");
59 | });
60 |
61 | app.UseSpa(spa =>
62 | {
63 | // To learn more about options for serving an Angular SPA from ASP.NET Core,
64 | // see https://go.microsoft.com/fwlink/?linkid=864501
65 |
66 | spa.Options.SourcePath = "ClientApp";
67 |
68 | if (env.IsDevelopment())
69 | {
70 | spa.UseAngularCliServer(npmScript: "start");
71 | }
72 | });
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/ContactsAngular/WeatherForecast.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ContactsAngular
4 | {
5 | public class WeatherForecast
6 | {
7 | public DateTime Date { get; set; }
8 |
9 | public int TemperatureC { get; set; }
10 |
11 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
12 |
13 | public string Summary { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/ContactsAngular/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "System": "Information",
6 | "Microsoft": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/ContactsAngular/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Warning"
5 | }
6 | },
7 | "AllowedHosts": "*"
8 | }
9 |
--------------------------------------------------------------------------------
/src/ContactsAngular/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elanderson/ASP.NET-Core-Basics-Refresh/ce90da48353633653f4c2c194fdc597abe18a150/src/ContactsAngular/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/src/ContactsApi/ContactsApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 | runtime; build; native; contentfiles; analyzers; buildtransitive
10 | all
11 |
12 |
13 |
14 |
15 | all
16 | runtime; build; native; contentfiles; analyzers; buildtransitive
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/ContactsApi/Controllers/ContactsController.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Microsoft.AspNetCore.Mvc;
5 | using Microsoft.EntityFrameworkCore;
6 | using ContactsApi.Data;
7 | using ContactsApi.Models;
8 |
9 | namespace ContactsApi.Controllers
10 | {
11 | [Route("api/[controller]")]
12 | [ApiController]
13 | public class ContactsController : ControllerBase
14 | {
15 | private readonly ContactsDbContext _context;
16 |
17 | public ContactsController(ContactsDbContext context)
18 | {
19 | _context = context;
20 | }
21 |
22 | // GET: api/Contacts
23 | [HttpGet]
24 | public async Task>> GetContacts()
25 | {
26 | return await _context.Contacts.ToListAsync();
27 | }
28 |
29 | // GET: api/Contacts/5
30 | [HttpGet("{id}")]
31 | public async Task> GetContact(int id)
32 | {
33 | var contact = await _context.Contacts.FindAsync(id);
34 |
35 | if (contact == null)
36 | {
37 | return NotFound();
38 | }
39 |
40 | return contact;
41 | }
42 |
43 | // PUT: api/Contacts/5
44 | // To protect from overposting attacks, please enable the specific properties you want to bind to, for
45 | // more details see https://aka.ms/RazorPagesCRUD.
46 | [HttpPut("{id}")]
47 | public async Task PutContact(int id, Contact contact)
48 | {
49 | if (id != contact.Id)
50 | {
51 | return BadRequest();
52 | }
53 |
54 | _context.Entry(contact).State = EntityState.Modified;
55 |
56 | try
57 | {
58 | await _context.SaveChangesAsync();
59 | }
60 | catch (DbUpdateConcurrencyException)
61 | {
62 | if (!ContactExists(id))
63 | {
64 | return NotFound();
65 | }
66 | else
67 | {
68 | throw;
69 | }
70 | }
71 |
72 | return NoContent();
73 | }
74 |
75 | // POST: api/Contacts
76 | // To protect from overposting attacks, please enable the specific properties you want to bind to, for
77 | // more details see https://aka.ms/RazorPagesCRUD.
78 | [HttpPost]
79 | public async Task> PostContact(Contact contact)
80 | {
81 | _context.Contacts.Add(contact);
82 | await _context.SaveChangesAsync();
83 |
84 | return CreatedAtAction("GetContact", new { id = contact.Id }, contact);
85 | }
86 |
87 | // DELETE: api/Contacts/5
88 | [HttpDelete("{id}")]
89 | public async Task> DeleteContact(int id)
90 | {
91 | var contact = await _context.Contacts.FindAsync(id);
92 | if (contact == null)
93 | {
94 | return NotFound();
95 | }
96 |
97 | _context.Contacts.Remove(contact);
98 | await _context.SaveChangesAsync();
99 |
100 | return contact;
101 | }
102 |
103 | private bool ContactExists(int id)
104 | {
105 | return _context.Contacts.Any(e => e.Id == id);
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/ContactsApi/Data/ContactsDbContext.cs:
--------------------------------------------------------------------------------
1 | using ContactsApi.Models;
2 | using Microsoft.EntityFrameworkCore;
3 |
4 | namespace ContactsApi.Data
5 | {
6 | public class ContactsDbContext : DbContext
7 | {
8 | public DbSet Contacts { get; set; }
9 |
10 | public ContactsDbContext(DbContextOptions options) : base(options) { }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/ContactsApi/Data/Migrations/20191010112653_Initial.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | using ContactsApi.Data;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Migrations;
6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
7 |
8 | namespace ContactsApi.Data.Migrations
9 | {
10 | [DbContext(typeof(ContactsDbContext))]
11 | [Migration("20191010112653_Initial")]
12 | partial class Initial
13 | {
14 | protected override void BuildTargetModel(ModelBuilder modelBuilder)
15 | {
16 | #pragma warning disable 612, 618
17 | modelBuilder
18 | .HasAnnotation("ProductVersion", "3.0.0");
19 |
20 | modelBuilder.Entity("ContactsApi.Models.Contact", b =>
21 | {
22 | b.Property("Id")
23 | .ValueGeneratedOnAdd()
24 | .HasColumnType("INTEGER");
25 |
26 | b.Property("Address")
27 | .HasColumnType("TEXT");
28 |
29 | b.Property("City")
30 | .HasColumnType("TEXT");
31 |
32 | b.Property("Email")
33 | .HasColumnType("TEXT");
34 |
35 | b.Property("Name")
36 | .HasColumnType("TEXT");
37 |
38 | b.Property("Phone")
39 | .HasColumnType("TEXT");
40 |
41 | b.Property("PostalCode")
42 | .HasColumnType("TEXT");
43 |
44 | b.Property("State")
45 | .HasColumnType("TEXT");
46 |
47 | b.HasKey("Id");
48 |
49 | b.ToTable("Contacts");
50 | });
51 | #pragma warning restore 612, 618
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/ContactsApi/Data/Migrations/20191010112653_Initial.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore.Migrations;
2 |
3 | namespace ContactsApi.Data.Migrations
4 | {
5 | public partial class Initial : Migration
6 | {
7 | protected override void Up(MigrationBuilder migrationBuilder)
8 | {
9 | migrationBuilder.CreateTable(
10 | name: "Contacts",
11 | columns: table => new
12 | {
13 | Id = table.Column(nullable: false)
14 | .Annotation("Sqlite:Autoincrement", true),
15 | Name = table.Column(nullable: true),
16 | Address = table.Column(nullable: true),
17 | City = table.Column(nullable: true),
18 | State = table.Column(nullable: true),
19 | PostalCode = table.Column(nullable: true),
20 | Phone = table.Column(nullable: true),
21 | Email = table.Column(nullable: true)
22 | },
23 | constraints: table =>
24 | {
25 | table.PrimaryKey("PK_Contacts", x => x.Id);
26 | });
27 | }
28 |
29 | protected override void Down(MigrationBuilder migrationBuilder)
30 | {
31 | migrationBuilder.DropTable(
32 | name: "Contacts");
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/ContactsApi/Data/Migrations/ContactsDbContextModelSnapshot.cs:
--------------------------------------------------------------------------------
1 | //
2 | using ContactsApi.Data;
3 | using Microsoft.EntityFrameworkCore;
4 | using Microsoft.EntityFrameworkCore.Infrastructure;
5 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
6 |
7 | namespace ContactsApi.Data.Migrations
8 | {
9 | [DbContext(typeof(ContactsDbContext))]
10 | partial class ContactsDbContextModelSnapshot : ModelSnapshot
11 | {
12 | protected override void BuildModel(ModelBuilder modelBuilder)
13 | {
14 | #pragma warning disable 612, 618
15 | modelBuilder
16 | .HasAnnotation("ProductVersion", "3.0.0");
17 |
18 | modelBuilder.Entity("ContactsApi.Models.Contact", b =>
19 | {
20 | b.Property("Id")
21 | .ValueGeneratedOnAdd()
22 | .HasColumnType("INTEGER");
23 |
24 | b.Property("Address")
25 | .HasColumnType("TEXT");
26 |
27 | b.Property("City")
28 | .HasColumnType("TEXT");
29 |
30 | b.Property("Email")
31 | .HasColumnType("TEXT");
32 |
33 | b.Property("Name")
34 | .HasColumnType("TEXT");
35 |
36 | b.Property("Phone")
37 | .HasColumnType("TEXT");
38 |
39 | b.Property("PostalCode")
40 | .HasColumnType("TEXT");
41 |
42 | b.Property("State")
43 | .HasColumnType("TEXT");
44 |
45 | b.HasKey("Id");
46 |
47 | b.ToTable("Contacts");
48 | });
49 | #pragma warning restore 612, 618
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/ContactsApi/Middleware/RequestResponseLoggingMiddleware.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Threading.Tasks;
4 | using Microsoft.AspNetCore.Http;
5 | using Microsoft.Extensions.Logging;
6 | using Microsoft.IO;
7 |
8 | namespace ContactsApi.Middleware
9 | {
10 | public class RequestResponseLoggingMiddleware
11 | {
12 | private readonly RequestDelegate _next;
13 | private readonly ILogger _logger;
14 | private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
15 |
16 | public RequestResponseLoggingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
17 | {
18 | _next = next;
19 | _logger = loggerFactory.CreateLogger();
20 | _recyclableMemoryStreamManager = new RecyclableMemoryStreamManager();
21 | }
22 |
23 | public async Task Invoke(HttpContext context)
24 | {
25 | await LogRequest(context);
26 | await LogResponse(context);
27 | }
28 |
29 | private async Task LogRequest(HttpContext context)
30 | {
31 | context.Request.EnableBuffering();
32 |
33 | await using var requestStream = _recyclableMemoryStreamManager.GetStream();
34 | await context.Request.Body.CopyToAsync(requestStream);
35 | _logger.LogInformation($"Http Request Information:{Environment.NewLine}" +
36 | $"Schema:{context.Request.Scheme} " +
37 | $"Host: {context.Request.Host} " +
38 | $"Path: {context.Request.Path} " +
39 | $"QueryString: {context.Request.QueryString} " +
40 | $"Request Body: {ReadStreamInChunks(requestStream)}");
41 | context.Request.Body.Position = 0;
42 | }
43 |
44 | private async Task LogResponse(HttpContext context)
45 | {
46 | var originalBodyStream = context.Response.Body;
47 |
48 | await using var responseBody = _recyclableMemoryStreamManager.GetStream();
49 | context.Response.Body = responseBody;
50 |
51 | await _next(context);
52 |
53 | context.Response.Body.Seek(0, SeekOrigin.Begin);
54 | var text = await new StreamReader(context.Response.Body).ReadToEndAsync();
55 | context.Response.Body.Seek(0, SeekOrigin.Begin);
56 |
57 | _logger.LogInformation($"Http Response Information:{Environment.NewLine}" +
58 | $"Schema:{context.Request.Scheme} " +
59 | $"Host: {context.Request.Host} " +
60 | $"Path: {context.Request.Path} " +
61 | $"QueryString: {context.Request.QueryString} " +
62 | $"Response Body: {text}");
63 |
64 | await responseBody.CopyToAsync(originalBodyStream);
65 | }
66 |
67 | private static string ReadStreamInChunks(Stream stream)
68 | {
69 | const int readChunkBufferLength = 4096;
70 |
71 | stream.Seek(0, SeekOrigin.Begin);
72 |
73 | using var textWriter = new StringWriter();
74 | using var reader = new StreamReader(stream);
75 |
76 | var readChunk = new char[readChunkBufferLength];
77 | int readChunkLength;
78 |
79 | do
80 | {
81 | readChunkLength = reader.ReadBlock(readChunk, 0, readChunkBufferLength);
82 | textWriter.Write(readChunk, 0, readChunkLength);
83 | } while (readChunkLength > 0);
84 |
85 | return textWriter.ToString();
86 | }
87 | }
88 | }
--------------------------------------------------------------------------------
/src/ContactsApi/Middleware/RequestResponseLoggingMiddlewareExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 |
3 | namespace ContactsApi.Middleware
4 | {
5 | public static class RequestResponseLoggingMiddlewareExtensions
6 | {
7 | public static IApplicationBuilder UseRequestResponseLogging(this IApplicationBuilder builder)
8 | {
9 | return builder.UseMiddleware();
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/ContactsApi/Models/Contact.cs:
--------------------------------------------------------------------------------
1 | namespace ContactsApi.Models
2 | {
3 | public class Contact
4 | {
5 | public int Id { get; set; }
6 | public string Name { get; set; }
7 | public string Address { get; set; }
8 | public string City { get; set; }
9 | public string State { get; set; }
10 | public string PostalCode { get; set; }
11 | public string Phone { get; set; }
12 | public string Email { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/ContactsApi/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace ContactsApi
11 | {
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IHostBuilder CreateHostBuilder(string[] args) =>
20 | Host.CreateDefaultBuilder(args)
21 | .ConfigureWebHostDefaults(webBuilder =>
22 | {
23 | webBuilder.UseStartup();
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/ContactsApi/Startup.cs:
--------------------------------------------------------------------------------
1 | using ContactsApi.Data;
2 | using ContactsApi.Middleware;
3 | using Microsoft.AspNetCore.Builder;
4 | using Microsoft.AspNetCore.Hosting;
5 | using Microsoft.EntityFrameworkCore;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.DependencyInjection;
8 | using Microsoft.Extensions.Hosting;
9 |
10 | namespace ContactsApi
11 | {
12 | public class Startup
13 | {
14 | public Startup(IConfiguration configuration)
15 | {
16 | Configuration = configuration;
17 | }
18 |
19 | public IConfiguration Configuration { get; }
20 |
21 | private const string AllowAllCors = "AllowAll";
22 |
23 | // This method gets called by the runtime. Use this method to add services to the container.
24 | public void ConfigureServices(IServiceCollection services)
25 | {
26 | services.AddDbContext(options =>
27 | options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
28 | services.AddControllers();
29 | services.AddOpenApiDocument(document => document.PostProcess = d => d.Info.Title = "Contacts API");
30 |
31 | services.AddCors(options =>
32 | {
33 | options.AddPolicy(AllowAllCors,
34 | builder =>
35 | {
36 | builder.AllowAnyHeader();
37 | builder.AllowAnyMethod();
38 | builder.AllowAnyOrigin();
39 | });
40 | });
41 | }
42 |
43 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
44 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
45 | {
46 | if (env.IsDevelopment())
47 | {
48 | app.UseDeveloperExceptionPage();
49 | }
50 |
51 | app.UseRequestResponseLogging();
52 |
53 | app.UseCors(AllowAllCors);
54 |
55 | app.UseHttpsRedirection();
56 |
57 | app.UseRouting();
58 |
59 | app.UseAuthorization();
60 |
61 | app.UseEndpoints(endpoints =>
62 | {
63 | endpoints.MapControllers();
64 | });
65 |
66 | app.UseOpenApi();
67 | app.UseSwaggerUi3();
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/ContactsApi/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "System": "Information",
6 | "Microsoft": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/ContactsApi/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "ConnectionStrings": {
3 | "DefaultConnection": "DataSource=app.db"
4 | },
5 | "Logging": {
6 | "LogLevel": {
7 | "Default": "Information",
8 | "Microsoft": "Warning",
9 | "Microsoft.Hosting.Lifetime": "Information"
10 | }
11 | },
12 | "AllowedHosts": "*"
13 | }
14 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/App.razor:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Sorry, there's nothing at this address.
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/ContactsBlazorServerApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/Data/WeatherForecast.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ContactsBlazorServerApp.Data
4 | {
5 | public class WeatherForecast
6 | {
7 | public DateTime Date { get; set; }
8 |
9 | public int TemperatureC { get; set; }
10 |
11 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
12 |
13 | public string Summary { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/Data/WeatherForecastService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 |
5 | namespace ContactsBlazorServerApp.Data
6 | {
7 | public class WeatherForecastService
8 | {
9 | private static readonly string[] Summaries = new[]
10 | {
11 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
12 | };
13 |
14 | public Task GetForecastAsync(DateTime startDate)
15 | {
16 | var rng = new Random();
17 | return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
18 | {
19 | Date = startDate.AddDays(index),
20 | TemperatureC = rng.Next(-20, 55),
21 | Summary = Summaries[rng.Next(Summaries.Length)]
22 | }).ToArray());
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/Pages/ContactList.razor:
--------------------------------------------------------------------------------
1 | @page "/contactlist"
2 |
3 | @using Apis
4 | @inject IContactsClient ContactClient
5 |
6 | Contact List
7 |
8 | @if (_contacts == null)
9 | {
10 | Loading...
11 | }
12 | else
13 | {
14 |
15 |
16 |
17 | Name
18 | Address
19 | City
20 | State
21 | Postal Code
22 | Phone
23 | Email
24 |
25 |
26 |
27 | @foreach (var contact in _contacts)
28 | {
29 |
30 | @contact.Name
31 | @contact.Address
32 | @contact.City
33 | @contact.State
34 | @contact.PostalCode
35 | @contact.Phone
36 | @contact.Email
37 |
38 | }
39 |
40 |
41 | }
42 |
43 | @code {
44 | private ICollection _contacts;
45 |
46 | protected override async Task OnInitializedAsync()
47 | {
48 | _contacts = await ContactClient.GetContactsAsync();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/Pages/Counter.razor:
--------------------------------------------------------------------------------
1 | @page "/counter"
2 |
3 | Counter
4 |
5 | Current count: @currentCount
6 |
7 | Click me
8 |
9 | @code {
10 | private int currentCount = 0;
11 |
12 | private void IncrementCount()
13 | {
14 | currentCount++;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/Pages/Error.razor:
--------------------------------------------------------------------------------
1 | @page "/error"
2 |
3 |
4 | Error.
5 | An error occurred while processing your request.
6 |
7 | Development Mode
8 |
9 | Swapping to Development environment will display more detailed information about the error that occurred.
10 |
11 |
12 | The Development environment shouldn't be enabled for deployed applications.
13 | It can result in displaying sensitive information from exceptions to end users.
14 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
15 | and restarting the app.
16 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/Pages/FetchData.razor:
--------------------------------------------------------------------------------
1 | @page "/fetchdata"
2 |
3 | @using ContactsBlazorServerApp.Data
4 | @inject WeatherForecastService ForecastService
5 |
6 | Weather forecast
7 |
8 | This component demonstrates fetching data from a service.
9 |
10 | @if (forecasts == null)
11 | {
12 | Loading...
13 | }
14 | else
15 | {
16 |
17 |
18 |
19 | Date
20 | Temp. (C)
21 | Temp. (F)
22 | Summary
23 |
24 |
25 |
26 | @foreach (var forecast in forecasts)
27 | {
28 |
29 | @forecast.Date.ToShortDateString()
30 | @forecast.TemperatureC
31 | @forecast.TemperatureF
32 | @forecast.Summary
33 |
34 | }
35 |
36 |
37 | }
38 |
39 | @code {
40 | private WeatherForecast[] forecasts;
41 |
42 | protected override async Task OnInitializedAsync()
43 | {
44 | forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/Pages/Index.razor:
--------------------------------------------------------------------------------
1 | @page "/"
2 |
3 | Hello, world!
4 |
5 | Welcome to your new app.
6 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/Pages/_Host.cshtml:
--------------------------------------------------------------------------------
1 | @page "/"
2 | @namespace ContactsBlazorServerApp.Pages
3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
4 | @{
5 | Layout = null;
6 | }
7 |
8 |
9 |
10 |
11 |
12 |
13 | ContactsBlazorServerApp
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | An error has occurred. This application may no longer respond until reloaded.
26 |
27 |
28 | An unhandled exception has occurred. See browser dev tools for details.
29 |
30 |
Reload
31 |
🗙
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/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.Hosting;
10 | using Microsoft.Extensions.Logging;
11 |
12 | namespace ContactsBlazorServerApp
13 | {
14 | public class Program
15 | {
16 | public static void Main(string[] args)
17 | {
18 | CreateHostBuilder(args).Build().Run();
19 | }
20 |
21 | public static IHostBuilder CreateHostBuilder(string[] args) =>
22 | Host.CreateDefaultBuilder(args)
23 | .ConfigureWebHostDefaults(webBuilder =>
24 | {
25 | webBuilder.UseStartup();
26 | });
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/Shared/MainLayout.razor:
--------------------------------------------------------------------------------
1 | @inherits LayoutComponentBase
2 |
3 |
6 |
7 |
8 |
11 |
12 |
13 | @Body
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/Shared/NavMenu.razor:
--------------------------------------------------------------------------------
1 |
7 |
8 |
32 |
33 | @code {
34 | private bool collapseNavMenu = true;
35 |
36 | private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
37 |
38 | private void ToggleNavMenu()
39 | {
40 | collapseNavMenu = !collapseNavMenu;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Apis;
3 | using Microsoft.AspNetCore.Builder;
4 | using Microsoft.AspNetCore.Hosting;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Hosting;
8 | using ContactsBlazorServerApp.Data;
9 |
10 | namespace ContactsBlazorServerApp
11 | {
12 | public class Startup
13 | {
14 | public Startup(IConfiguration configuration)
15 | {
16 | Configuration = configuration;
17 | }
18 |
19 | public IConfiguration Configuration { get; }
20 |
21 | // This method gets called by the runtime. Use this method to add services to the container.
22 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
23 | public void ConfigureServices(IServiceCollection services)
24 | {
25 | services.AddRazorPages()
26 | .AddNewtonsoftJson();
27 | services.AddServerSideBlazor();
28 | services.AddSingleton();
29 | services.AddHttpClient(client => client.BaseAddress = new Uri(Configuration.GetSection("ContactsApi").Value));
30 | }
31 |
32 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
33 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
34 | {
35 | if (env.IsDevelopment())
36 | {
37 | app.UseDeveloperExceptionPage();
38 | }
39 | else
40 | {
41 | app.UseExceptionHandler("/Error");
42 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
43 | app.UseHsts();
44 | }
45 |
46 | app.UseHttpsRedirection();
47 | app.UseStaticFiles();
48 |
49 | app.UseRouting();
50 |
51 | app.UseEndpoints(endpoints =>
52 | {
53 | endpoints.MapBlazorHub();
54 | endpoints.MapFallbackToPage("/_Host");
55 | });
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/_Imports.razor:
--------------------------------------------------------------------------------
1 | @using System.Net.Http
2 | @using Microsoft.AspNetCore.Authorization
3 | @using Microsoft.AspNetCore.Components.Authorization
4 | @using Microsoft.AspNetCore.Components.Forms
5 | @using Microsoft.AspNetCore.Components.Routing
6 | @using Microsoft.AspNetCore.Components.Web
7 | @using Microsoft.JSInterop
8 | @using ContactsBlazorServerApp
9 | @using ContactsBlazorServerApp.Shared
10 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "DetailedErrors": true,
3 | "Logging": {
4 | "LogLevel": {
5 | "Default": "Information",
6 | "Microsoft": "Warning",
7 | "Microsoft.Hosting.Lifetime": "Information"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*",
10 | "ContactsApi": "https://localhost:5001"
11 | }
12 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/wwwroot/css/open-iconic/ICON-LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Waybury
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.
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/wwwroot/css/open-iconic/README.md:
--------------------------------------------------------------------------------
1 | [Open Iconic v1.1.1](http://useiconic.com/open)
2 | ===========
3 |
4 | ### Open Iconic is the open source sibling of [Iconic](http://useiconic.com). It is a hyper-legible collection of 223 icons with a tiny footprint—ready to use with Bootstrap and Foundation. [View the collection](http://useiconic.com/open#icons)
5 |
6 |
7 |
8 | ## What's in Open Iconic?
9 |
10 | * 223 icons designed to be legible down to 8 pixels
11 | * Super-light SVG files - 61.8 for the entire set
12 | * SVG sprite—the modern replacement for icon fonts
13 | * Webfont (EOT, OTF, SVG, TTF, WOFF), PNG and WebP formats
14 | * Webfont stylesheets (including versions for Bootstrap and Foundation) in CSS, LESS, SCSS and Stylus formats
15 | * PNG and WebP raster images in 8px, 16px, 24px, 32px, 48px and 64px.
16 |
17 |
18 | ## Getting Started
19 |
20 | #### For code samples and everything else you need to get started with Open Iconic, check out our [Icons](http://useiconic.com/open#icons) and [Reference](http://useiconic.com/open#reference) sections.
21 |
22 | ### General Usage
23 |
24 | #### Using Open Iconic's SVGs
25 |
26 | We like SVGs and we think they're the way to display icons on the web. Since Open Iconic are just basic SVGs, we suggest you display them like you would any other image (don't forget the `alt` attribute).
27 |
28 | ```
29 |
30 | ```
31 |
32 | #### Using Open Iconic's SVG Sprite
33 |
34 | Open Iconic also comes in a SVG sprite which allows you to display all the icons in the set with a single request. It's like an icon font, without being a hack.
35 |
36 | Adding an icon from an SVG sprite is a little different than what you're used to, but it's still a piece of cake. *Tip: To make your icons easily style able, we suggest adding a general class to the* `` *tag and a unique class name for each different icon in the* `` *tag.*
37 |
38 | ```
39 |
40 |
41 |
42 | ```
43 |
44 | Sizing icons only needs basic CSS. All the icons are in a square format, so just set the `` tag with equal width and height dimensions.
45 |
46 | ```
47 | .icon {
48 | width: 16px;
49 | height: 16px;
50 | }
51 | ```
52 |
53 | Coloring icons is even easier. All you need to do is set the `fill` rule on the `` tag.
54 |
55 | ```
56 | .icon-account-login {
57 | fill: #f00;
58 | }
59 | ```
60 |
61 | To learn more about SVG Sprites, read [Chris Coyier's guide](http://css-tricks.com/svg-sprites-use-better-icon-fonts/).
62 |
63 | #### Using Open Iconic's Icon Font...
64 |
65 |
66 | ##### …with Bootstrap
67 |
68 | You can find our Bootstrap stylesheets in `font/css/open-iconic-bootstrap.{css, less, scss, styl}`
69 |
70 |
71 | ```
72 |
73 | ```
74 |
75 |
76 | ```
77 |
78 | ```
79 |
80 | ##### …with Foundation
81 |
82 | You can find our Foundation stylesheets in `font/css/open-iconic-foundation.{css, less, scss, styl}`
83 |
84 | ```
85 |
86 | ```
87 |
88 |
89 | ```
90 |
91 | ```
92 |
93 | ##### …on its own
94 |
95 | You can find our default stylesheets in `font/css/open-iconic.{css, less, scss, styl}`
96 |
97 | ```
98 |
99 | ```
100 |
101 | ```
102 |
103 | ```
104 |
105 |
106 | ## License
107 |
108 | ### Icons
109 |
110 | All code (including SVG markup) is under the [MIT License](http://opensource.org/licenses/MIT).
111 |
112 | ### Fonts
113 |
114 | All fonts are under the [SIL Licensed](http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web).
115 |
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/wwwroot/css/open-iconic/font/fonts/open-iconic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elanderson/ASP.NET-Core-Basics-Refresh/ce90da48353633653f4c2c194fdc597abe18a150/src/ContactsBlazorServerApp/wwwroot/css/open-iconic/font/fonts/open-iconic.eot
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/wwwroot/css/open-iconic/font/fonts/open-iconic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elanderson/ASP.NET-Core-Basics-Refresh/ce90da48353633653f4c2c194fdc597abe18a150/src/ContactsBlazorServerApp/wwwroot/css/open-iconic/font/fonts/open-iconic.otf
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elanderson/ASP.NET-Core-Basics-Refresh/ce90da48353633653f4c2c194fdc597abe18a150/src/ContactsBlazorServerApp/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/wwwroot/css/open-iconic/font/fonts/open-iconic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elanderson/ASP.NET-Core-Basics-Refresh/ce90da48353633653f4c2c194fdc597abe18a150/src/ContactsBlazorServerApp/wwwroot/css/open-iconic/font/fonts/open-iconic.woff
--------------------------------------------------------------------------------
/src/ContactsBlazorServerApp/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elanderson/ASP.NET-Core-Basics-Refresh/ce90da48353633653f4c2c194fdc597abe18a150/src/ContactsBlazorServerApp/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/src/ContactsRazorPages/ContactsRazorPages.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Contacts/Create.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ContactsRazorPages.Pages.Contacts.CreateModel
3 |
4 | @{
5 | ViewData["Title"] = "Create";
6 | }
7 |
8 | Create
9 |
10 | Contact
11 |
12 |
57 |
58 |
61 |
62 | @section Scripts {
63 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
64 | }
65 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Contacts/Create.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Apis;
3 | using Microsoft.AspNetCore.Mvc;
4 | using Microsoft.AspNetCore.Mvc.RazorPages;
5 |
6 | namespace ContactsRazorPages.Pages.Contacts
7 | {
8 | public class CreateModel : PageModel
9 | {
10 | private readonly IContactsClient _client;
11 |
12 | public CreateModel(IContactsClient client)
13 | {
14 | _client = client;
15 | }
16 |
17 | public IActionResult OnGet()
18 | {
19 | return Page();
20 | }
21 |
22 | [BindProperty]
23 | public Contact Contact { get; set; }
24 |
25 | // To protect from overposting attacks, please enable the specific properties you want to bind to, for
26 | // more details see https://aka.ms/RazorPagesCRUD.
27 | public async Task OnPostAsync()
28 | {
29 | if (!ModelState.IsValid)
30 | {
31 | return Page();
32 | }
33 |
34 | await _client.PostContactAsync(Contact);
35 |
36 | return RedirectToPage("./Index");
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Contacts/Delete.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ContactsRazorPages.Pages.Contacts.DeleteModel
3 |
4 | @{
5 | ViewData["Title"] = "Delete";
6 | }
7 |
8 | Delete
9 |
10 | Are you sure you want to delete this?
11 |
12 |
Contact
13 |
14 |
15 |
16 | @Html.DisplayNameFor(model => model.Contact.Name)
17 |
18 |
19 | @Html.DisplayFor(model => model.Contact.Name)
20 |
21 |
22 | @Html.DisplayNameFor(model => model.Contact.Address)
23 |
24 |
25 | @Html.DisplayFor(model => model.Contact.Address)
26 |
27 |
28 | @Html.DisplayNameFor(model => model.Contact.City)
29 |
30 |
31 | @Html.DisplayFor(model => model.Contact.City)
32 |
33 |
34 | @Html.DisplayNameFor(model => model.Contact.State)
35 |
36 |
37 | @Html.DisplayFor(model => model.Contact.State)
38 |
39 |
40 | @Html.DisplayNameFor(model => model.Contact.PostalCode)
41 |
42 |
43 | @Html.DisplayFor(model => model.Contact.PostalCode)
44 |
45 |
46 | @Html.DisplayNameFor(model => model.Contact.Phone)
47 |
48 |
49 | @Html.DisplayFor(model => model.Contact.Phone)
50 |
51 |
52 | @Html.DisplayNameFor(model => model.Contact.Email)
53 |
54 |
55 | @Html.DisplayFor(model => model.Contact.Email)
56 |
57 |
58 |
59 |
64 |
65 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Contacts/Delete.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Apis;
3 | using Microsoft.AspNetCore.Mvc;
4 | using Microsoft.AspNetCore.Mvc.RazorPages;
5 |
6 | namespace ContactsRazorPages.Pages.Contacts
7 | {
8 | public class DeleteModel : PageModel
9 | {
10 | private readonly IContactsClient _client;
11 |
12 | public DeleteModel(IContactsClient client)
13 | {
14 | _client = client;
15 | }
16 |
17 | [BindProperty]
18 | public Contact Contact { get; set; }
19 |
20 | public async Task OnGetAsync(int? id)
21 | {
22 | if (id == null)
23 | {
24 | return NotFound();
25 | }
26 |
27 | Contact = await _client.GetContactAsync(id.Value);
28 |
29 | if (Contact == null)
30 | {
31 | return NotFound();
32 | }
33 | return Page();
34 | }
35 |
36 | public async Task OnPostAsync(int? id)
37 | {
38 | if (id == null)
39 | {
40 | return NotFound();
41 | }
42 |
43 | await _client.DeleteContactAsync(id.Value);
44 |
45 | return RedirectToPage("./Index");
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Contacts/Details.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ContactsRazorPages.Pages.Contacts.DetailsModel
3 |
4 | @{
5 | ViewData["Title"] = "Details";
6 | }
7 |
8 | Details
9 |
10 |
11 |
Contact
12 |
13 |
14 |
15 | @Html.DisplayNameFor(model => model.Contact.Name)
16 |
17 |
18 | @Html.DisplayFor(model => model.Contact.Name)
19 |
20 |
21 | @Html.DisplayNameFor(model => model.Contact.Address)
22 |
23 |
24 | @Html.DisplayFor(model => model.Contact.Address)
25 |
26 |
27 | @Html.DisplayNameFor(model => model.Contact.City)
28 |
29 |
30 | @Html.DisplayFor(model => model.Contact.City)
31 |
32 |
33 | @Html.DisplayNameFor(model => model.Contact.State)
34 |
35 |
36 | @Html.DisplayFor(model => model.Contact.State)
37 |
38 |
39 | @Html.DisplayNameFor(model => model.Contact.PostalCode)
40 |
41 |
42 | @Html.DisplayFor(model => model.Contact.PostalCode)
43 |
44 |
45 | @Html.DisplayNameFor(model => model.Contact.Phone)
46 |
47 |
48 | @Html.DisplayFor(model => model.Contact.Phone)
49 |
50 |
51 | @Html.DisplayNameFor(model => model.Contact.Email)
52 |
53 |
54 | @Html.DisplayFor(model => model.Contact.Email)
55 |
56 |
57 |
58 |
62 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Contacts/Details.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Apis;
3 | using Microsoft.AspNetCore.Mvc;
4 | using Microsoft.AspNetCore.Mvc.RazorPages;
5 |
6 | namespace ContactsRazorPages.Pages.Contacts
7 | {
8 | public class DetailsModel : PageModel
9 | {
10 | private readonly IContactsClient _client;
11 |
12 | public DetailsModel(IContactsClient client)
13 | {
14 | _client = client;
15 | }
16 |
17 | public Contact Contact { get; set; }
18 |
19 | public async Task OnGetAsync(int? id)
20 | {
21 | if (id == null)
22 | {
23 | return NotFound();
24 | }
25 |
26 | Contact = await _client.GetContactAsync(id.Value);
27 |
28 | if (Contact == null)
29 | {
30 | return NotFound();
31 | }
32 | return Page();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Contacts/Edit.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ContactsRazorPages.Pages.Contacts.EditModel
3 |
4 | @{
5 | ViewData["Title"] = "Edit";
6 | }
7 |
8 | Edit
9 |
10 | Contact
11 |
12 |
58 |
59 |
62 |
63 | @section Scripts {
64 | @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
65 | }
66 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Contacts/Edit.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Apis;
3 | using Microsoft.AspNetCore.Mvc;
4 | using Microsoft.AspNetCore.Mvc.RazorPages;
5 |
6 | namespace ContactsRazorPages.Pages.Contacts
7 | {
8 | public class EditModel : PageModel
9 | {
10 | private readonly IContactsClient _client;
11 |
12 | public EditModel(IContactsClient client)
13 | {
14 | _client = client;
15 | }
16 |
17 | [BindProperty]
18 | public Contact Contact { get; set; }
19 |
20 | public async Task OnGetAsync(int? id)
21 | {
22 | if (id == null)
23 | {
24 | return NotFound();
25 | }
26 |
27 | Contact = await _client.GetContactAsync(id.Value);
28 |
29 | if (Contact == null)
30 | {
31 | return NotFound();
32 | }
33 | return Page();
34 | }
35 |
36 | // To protect from overposting attacks, please enable the specific properties you want to bind to, for
37 | // more details see https://aka.ms/RazorPagesCRUD.
38 | public async Task OnPostAsync()
39 | {
40 | if (!ModelState.IsValid)
41 | {
42 | return Page();
43 | }
44 |
45 | await _client.PutContactAsync(Contact.Id, Contact);
46 |
47 | return RedirectToPage("./Index");
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Contacts/Index.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ContactsRazorPages.Pages.Contacts.IndexModel
3 |
4 | @{
5 | ViewData["Title"] = "Index";
6 | }
7 |
8 | Index
9 |
10 |
11 | Create New
12 |
13 |
14 |
15 |
16 |
17 | @Html.DisplayNameFor(model => model.Contact[0].Name)
18 |
19 |
20 | @Html.DisplayNameFor(model => model.Contact[0].Address)
21 |
22 |
23 | @Html.DisplayNameFor(model => model.Contact[0].City)
24 |
25 |
26 | @Html.DisplayNameFor(model => model.Contact[0].State)
27 |
28 |
29 | @Html.DisplayNameFor(model => model.Contact[0].PostalCode)
30 |
31 |
32 | @Html.DisplayNameFor(model => model.Contact[0].Phone)
33 |
34 |
35 | @Html.DisplayNameFor(model => model.Contact[0].Email)
36 |
37 |
38 |
39 |
40 |
41 | @foreach (var item in Model.Contact) {
42 |
43 |
44 | @Html.DisplayFor(modelItem => item.Name)
45 |
46 |
47 | @Html.DisplayFor(modelItem => item.Address)
48 |
49 |
50 | @Html.DisplayFor(modelItem => item.City)
51 |
52 |
53 | @Html.DisplayFor(modelItem => item.State)
54 |
55 |
56 | @Html.DisplayFor(modelItem => item.PostalCode)
57 |
58 |
59 | @Html.DisplayFor(modelItem => item.Phone)
60 |
61 |
62 | @Html.DisplayFor(modelItem => item.Email)
63 |
64 |
65 | Edit |
66 | Details |
67 | Delete
68 |
69 |
70 | }
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Contacts/Index.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Apis;
5 | using Microsoft.AspNetCore.Mvc.RazorPages;
6 |
7 | namespace ContactsRazorPages.Pages.Contacts
8 | {
9 | public class IndexModel : PageModel
10 | {
11 | private readonly IContactsClient _client;
12 |
13 | public IndexModel(IContactsClient client)
14 | {
15 | _client = client;
16 | }
17 |
18 | public IList Contact { get;set; }
19 |
20 | public async Task OnGetAsync()
21 | {
22 | Contact = (await _client.GetContactsAsync()).ToList();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Error.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ErrorModel
3 | @{
4 | ViewData["Title"] = "Error";
5 | }
6 |
7 | Error.
8 | An error occurred while processing your request.
9 |
10 | @if (Model.ShowRequestId)
11 | {
12 |
13 | Request ID: @Model.RequestId
14 |
15 | }
16 |
17 | Development Mode
18 |
19 | Swapping to the Development environment displays detailed information about the error that occurred.
20 |
21 |
22 | The Development environment shouldn't be enabled for deployed applications.
23 | It can result in displaying sensitive information from exceptions to end users.
24 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
25 | and restarting the app.
26 |
27 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Error.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.AspNetCore.Mvc.RazorPages;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace ContactsRazorPages.Pages
11 | {
12 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
13 | public class ErrorModel : PageModel
14 | {
15 | public string RequestId { get; set; }
16 |
17 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
18 |
19 | private readonly ILogger _logger;
20 |
21 | public ErrorModel(ILogger logger)
22 | {
23 | _logger = logger;
24 | }
25 |
26 | public void OnGet()
27 | {
28 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Index.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model IndexModel
3 | @{
4 | ViewData["Title"] = "Home page";
5 | }
6 |
7 |
11 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Index.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Mvc;
6 | using Microsoft.AspNetCore.Mvc.RazorPages;
7 | using Microsoft.Extensions.Logging;
8 |
9 | namespace ContactsRazorPages.Pages
10 | {
11 | public class IndexModel : PageModel
12 | {
13 | private readonly ILogger _logger;
14 |
15 | public IndexModel(ILogger logger)
16 | {
17 | _logger = logger;
18 | }
19 |
20 | public void OnGet()
21 | {
22 |
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Privacy.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model PrivacyModel
3 | @{
4 | ViewData["Title"] = "Privacy Policy";
5 | }
6 | @ViewData["Title"]
7 |
8 | Use this page to detail your site's privacy policy.
9 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Privacy.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Mvc;
6 | using Microsoft.AspNetCore.Mvc.RazorPages;
7 | using Microsoft.Extensions.Logging;
8 |
9 | namespace ContactsRazorPages.Pages
10 | {
11 | public class PrivacyModel : PageModel
12 | {
13 | private readonly ILogger _logger;
14 |
15 | public PrivacyModel(ILogger logger)
16 | {
17 | _logger = logger;
18 | }
19 |
20 | public void OnGet()
21 | {
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Shared/_Layout.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @ViewData["Title"] - ContactsRazorPages
7 |
8 |
9 |
10 |
11 |
35 |
36 |
37 | @RenderBody()
38 |
39 |
40 |
41 |
46 |
47 |
48 |
49 |
50 |
51 | @RenderSection("Scripts", required: false)
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/Shared/_ValidationScriptsPartial.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using ContactsRazorPages
2 | @namespace ContactsRazorPages.Pages
3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
4 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Pages/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "_Layout";
3 | }
4 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace ContactsRazorPages
11 | {
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IHostBuilder CreateHostBuilder(string[] args) =>
20 | Host.CreateDefaultBuilder(args)
21 | .ConfigureWebHostDefaults(webBuilder =>
22 | {
23 | webBuilder.UseStartup();
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Apis;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.AspNetCore.HttpsPolicy;
9 | using Microsoft.Extensions.Configuration;
10 | using Microsoft.Extensions.DependencyInjection;
11 | using Microsoft.Extensions.Hosting;
12 |
13 | namespace ContactsRazorPages
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 | services.AddRazorPages()
28 | .AddNewtonsoftJson();
29 |
30 | services.AddHttpClient(client => client.BaseAddress = new Uri(Configuration.GetSection("ContactsApi").Value));
31 | }
32 |
33 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
34 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
35 | {
36 | if (env.IsDevelopment())
37 | {
38 | app.UseDeveloperExceptionPage();
39 | }
40 | else
41 | {
42 | app.UseExceptionHandler("/Error");
43 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
44 | app.UseHsts();
45 | }
46 |
47 | app.UseHttpsRedirection();
48 | app.UseStaticFiles();
49 |
50 | app.UseRouting();
51 |
52 | app.UseAuthorization();
53 |
54 | app.UseEndpoints(endpoints =>
55 | {
56 | endpoints.MapRazorPages();
57 | });
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "System": "Information",
6 | "Microsoft": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*",
10 | "ContactsApi": "https://localhost:5001"
11 | }
12 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | /* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | for details on configuring this project to bundle and minify static web assets. */
3 |
4 | a.navbar-brand {
5 | white-space: normal;
6 | text-align: center;
7 | word-break: break-all;
8 | }
9 |
10 | /* Provide sufficient contrast against white background */
11 | a {
12 | color: #0366d6;
13 | }
14 |
15 | .btn-primary {
16 | color: #fff;
17 | background-color: #1b6ec2;
18 | border-color: #1861ac;
19 | }
20 |
21 | .nav-pills .nav-link.active, .nav-pills .show > .nav-link {
22 | color: #fff;
23 | background-color: #1b6ec2;
24 | border-color: #1861ac;
25 | }
26 |
27 | /* Sticky footer styles
28 | -------------------------------------------------- */
29 | html {
30 | font-size: 14px;
31 | }
32 | @media (min-width: 768px) {
33 | html {
34 | font-size: 16px;
35 | }
36 | }
37 |
38 | .border-top {
39 | border-top: 1px solid #e5e5e5;
40 | }
41 | .border-bottom {
42 | border-bottom: 1px solid #e5e5e5;
43 | }
44 |
45 | .box-shadow {
46 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
47 | }
48 |
49 | button.accept-policy {
50 | font-size: 1rem;
51 | line-height: inherit;
52 | }
53 |
54 | /* Sticky footer styles
55 | -------------------------------------------------- */
56 | html {
57 | position: relative;
58 | min-height: 100%;
59 | }
60 |
61 | body {
62 | /* Margin bottom by footer height */
63 | margin-bottom: 60px;
64 | }
65 | .footer {
66 | position: absolute;
67 | bottom: 0;
68 | width: 100%;
69 | white-space: nowrap;
70 | line-height: 60px; /* Vertically center the text there */
71 | }
72 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elanderson/ASP.NET-Core-Basics-Refresh/ce90da48353633653f4c2c194fdc597abe18a150/src/ContactsRazorPages/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/src/ContactsRazorPages/wwwroot/js/site.js:
--------------------------------------------------------------------------------
1 | // Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
2 | // for details on configuring this project to bundle and minify static web assets.
3 |
4 | // Write your Javascript code.
5 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/wwwroot/lib/bootstrap/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2011-2018 Twitter, Inc.
4 | Copyright (c) 2011-2018 The Bootstrap Authors
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 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/wwwroot/lib/bootstrap/dist/css/bootstrap-reboot.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
3 | * Copyright 2011-2019 The Bootstrap Authors
4 | * Copyright 2011-2019 Twitter, Inc.
5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
7 | */*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */
--------------------------------------------------------------------------------
/src/ContactsRazorPages/wwwroot/lib/jquery-validation-unobtrusive/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) .NET Foundation. All rights reserved.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4 | these files except in compliance with the License. You may obtain a copy of the
5 | License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software distributed
10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the
12 | specific language governing permissions and limitations under the License.
13 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/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 |
--------------------------------------------------------------------------------
/src/ContactsRazorPages/wwwroot/lib/jquery/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright JS Foundation and other contributors, https://js.foundation/
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 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "contactsreact",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "babel-eslint": "10.0.1",
7 | "bootstrap": "^4.1.3",
8 | "jquery": "^3.4.1",
9 | "merge": "^1.2.1",
10 | "oidc-client": "^1.9.0",
11 | "react": "^16.0.0",
12 | "react-dom": "^16.0.0",
13 | "react-router-bootstrap": "^0.24.4",
14 | "react-router-dom": "^4.2.2",
15 | "react-scripts": "^3.0.1",
16 | "reactstrap": "^6.3.0",
17 | "rimraf": "^2.6.2"
18 | },
19 | "devDependencies": {
20 | "ajv": "^6.9.1",
21 | "cross-env": "^5.2.0",
22 | "eslint": "^5.12.0",
23 | "eslint-config-react-app": "^4.0.1",
24 | "eslint-plugin-flowtype": "^2.0.0",
25 | "eslint-plugin-import": "^2.14.0",
26 | "eslint-plugin-jsx-a11y": "^6.2.1",
27 | "eslint-plugin-react": "^7.11.1",
28 | "typescript": "^3.5.2"
29 | },
30 | "eslintConfig": {
31 | "extends": "react-app"
32 | },
33 | "scripts": {
34 | "start": "rimraf ./build && react-scripts start",
35 | "build": "react-scripts build",
36 | "test": "cross-env CI=true react-scripts test --env=jsdom",
37 | "eject": "react-scripts eject",
38 | "lint": "eslint ./src/"
39 | },
40 | "browserslist": {
41 | "production": [
42 | ">0.2%",
43 | "not dead",
44 | "not op_mini all"
45 | ],
46 | "development": [
47 | "last 1 chrome version",
48 | "last 1 firefox version",
49 | "last 1 safari version"
50 | ]
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elanderson/ASP.NET-Core-Basics-Refresh/ce90da48353633653f4c2c194fdc597abe18a150/src/ContactsReact/ClientApp/public/favicon.ico
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
23 | ContactsReact
24 |
25 |
26 |
27 | You need to enable JavaScript to run this app.
28 |
29 |
30 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "ContactsReact",
3 | "name": "ContactsReact",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Route } from 'react-router';
3 | import { Layout } from './components/Layout';
4 | import { Home } from './components/Home';
5 | import { FetchData } from './components/FetchData';
6 | import { Counter } from './components/Counter';
7 | import { ContactList } from './components/ContactList';
8 |
9 | import './custom.css'
10 |
11 | export default class App extends Component {
12 | static displayName = App.name;
13 |
14 | render () {
15 | return (
16 |
17 |
18 |
19 |
20 |
21 |
22 | );
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { MemoryRouter } from 'react-router-dom';
4 | import App from './App';
5 |
6 | it('renders without crashing', async () => {
7 | const div = document.createElement('div');
8 | ReactDOM.render(
9 |
10 |
11 | , div);
12 | await new Promise(resolve => setTimeout(resolve, 1000));
13 | });
14 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/src/components/ContactList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { ContactsClient } from './contactsApi';
3 |
4 | export class ContactList extends Component {
5 | static displayName = ContactList.name;
6 |
7 | constructor(props) {
8 | super(props);
9 | this.state = { contacts: [], loading: true };
10 | }
11 |
12 | componentDidMount() {
13 | this.populateContactData();
14 | }
15 |
16 | static renderContactsTable(contacts) {
17 | return (
18 |
19 |
20 |
21 | Name
22 | Address
23 | City
24 | State
25 | Postal Code
26 | Phone
27 | Email
28 |
29 |
30 |
31 | {contacts.map(contact =>
32 |
33 | {contact.name}
34 | {contact.address}
35 | {contact.city}
36 | {contact.state}
37 | {contact.postalCode}
38 | {contact.phone}
39 | {contact.email}
40 |
41 | )}
42 |
43 |
44 | );
45 | }
46 |
47 | render() {
48 | let contents = this.state.loading
49 | ? Loading...
50 | : ContactList.renderContactsTable(this.state.contacts);
51 |
52 | return (
53 |
54 |
Contacts
55 | {contents}
56 |
57 | );
58 | }
59 |
60 | async populateContactData() {
61 | let client = new ContactsClient();
62 | client.getContacts()
63 | .then(data => this.setState({ contacts: data, loading: false }));
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/src/components/Counter.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | export class Counter extends Component {
4 | static displayName = Counter.name;
5 |
6 | constructor(props) {
7 | super(props);
8 | this.state = { currentCount: 0 };
9 | this.incrementCounter = this.incrementCounter.bind(this);
10 | }
11 |
12 | incrementCounter() {
13 | this.setState({
14 | currentCount: this.state.currentCount + 1
15 | });
16 | }
17 |
18 | render() {
19 | return (
20 |
21 |
Counter
22 |
23 |
This is a simple example of a React component.
24 |
25 |
Current count: {this.state.currentCount}
26 |
27 |
Increment
28 |
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/src/components/FetchData.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | export class FetchData extends Component {
4 | static displayName = FetchData.name;
5 |
6 | constructor(props) {
7 | super(props);
8 | this.state = { forecasts: [], loading: true };
9 | }
10 |
11 | componentDidMount() {
12 | this.populateWeatherData();
13 | }
14 |
15 | static renderForecastsTable(forecasts) {
16 | return (
17 |
18 |
19 |
20 | Date
21 | Temp. (C)
22 | Temp. (F)
23 | Summary
24 |
25 |
26 |
27 | {forecasts.map(forecast =>
28 |
29 | {forecast.date}
30 | {forecast.temperatureC}
31 | {forecast.temperatureF}
32 | {forecast.summary}
33 |
34 | )}
35 |
36 |
37 | );
38 | }
39 |
40 | render() {
41 | let contents = this.state.loading
42 | ? Loading...
43 | : FetchData.renderForecastsTable(this.state.forecasts);
44 |
45 | return (
46 |
47 |
Weather forecast
48 |
This component demonstrates fetching data from the server.
49 | {contents}
50 |
51 | );
52 | }
53 |
54 | async populateWeatherData() {
55 | const response = await fetch('weatherforecast');
56 | const data = await response.json();
57 | this.setState({ forecasts: data, loading: false });
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/src/components/Home.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | export class Home extends Component {
4 | static displayName = Home.name;
5 |
6 | render () {
7 | return (
8 |
9 |
Hello, world!
10 |
Welcome to your new single-page application, built with:
11 |
16 |
To help you get started, we have also set up:
17 |
18 | Client-side navigation . For example, click Counter then Back to return here.
19 | Development server integration . In development mode, the development server from create-react-app
runs in the background automatically, so your client-side resources are dynamically built on demand and the page refreshes when you modify any file.
20 | Efficient production builds . In production mode, development-time features are disabled, and your dotnet publish
configuration produces minified, efficiently bundled JavaScript files.
21 |
22 |
The ClientApp
subdirectory is a standard React application based on the create-react-app
template. If you open a command prompt in that directory, you can run npm
commands such as npm test
or npm install
.
23 |
24 | );
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/src/components/Layout.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Container } from 'reactstrap';
3 | import { NavMenu } from './NavMenu';
4 |
5 | export class Layout extends Component {
6 | static displayName = Layout.name;
7 |
8 | render () {
9 | return (
10 |
11 |
12 |
13 | {this.props.children}
14 |
15 |
16 | );
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/src/components/NavMenu.css:
--------------------------------------------------------------------------------
1 | a.navbar-brand {
2 | white-space: normal;
3 | text-align: center;
4 | word-break: break-all;
5 | }
6 |
7 | html {
8 | font-size: 14px;
9 | }
10 | @media (min-width: 768px) {
11 | html {
12 | font-size: 16px;
13 | }
14 | }
15 |
16 | .box-shadow {
17 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
18 | }
19 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/src/components/NavMenu.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Collapse, Container, Navbar, NavbarBrand, NavbarToggler, NavItem, NavLink } from 'reactstrap';
3 | import { Link } from 'react-router-dom';
4 | import './NavMenu.css';
5 |
6 | export class NavMenu extends Component {
7 | static displayName = NavMenu.name;
8 |
9 | constructor (props) {
10 | super(props);
11 |
12 | this.toggleNavbar = this.toggleNavbar.bind(this);
13 | this.state = {
14 | collapsed: true
15 | };
16 | }
17 |
18 | toggleNavbar () {
19 | this.setState({
20 | collapsed: !this.state.collapsed
21 | });
22 | }
23 |
24 | render () {
25 | return (
26 |
27 |
28 |
29 | ContactsReact
30 |
31 |
32 |
33 |
34 | Home
35 |
36 |
37 | Contacts
38 |
39 |
40 | Counter
41 |
42 |
43 | Fetch data
44 |
45 |
46 |
47 |
48 |
49 |
50 | );
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/src/custom.css:
--------------------------------------------------------------------------------
1 | /* Provide sufficient contrast against white background */
2 | a {
3 | color: #0366d6;
4 | }
5 |
6 | code {
7 | color: #E01A76;
8 | }
9 |
10 | .btn-primary {
11 | color: #fff;
12 | background-color: #1b6ec2;
13 | border-color: #1861ac;
14 | }
15 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/src/index.js:
--------------------------------------------------------------------------------
1 | import 'bootstrap/dist/css/bootstrap.css';
2 | import React from 'react';
3 | import ReactDOM from 'react-dom';
4 | import { BrowserRouter } from 'react-router-dom';
5 | import App from './App';
6 | import registerServiceWorker from './registerServiceWorker';
7 |
8 | const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href');
9 | const rootElement = document.getElementById('root');
10 |
11 | ReactDOM.render(
12 |
13 |
14 | ,
15 | rootElement);
16 |
17 | registerServiceWorker();
18 |
19 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/src/ContactsReact/ClientApp/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "module": "esnext",
16 | "moduleResolution": "node",
17 | "resolveJsonModule": true,
18 | "isolatedModules": true,
19 | "noEmit": true,
20 | "jsx": "preserve"
21 | },
22 | "include": [
23 | "src"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/src/ContactsReact/ContactsReact.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | true
6 | Latest
7 | false
8 | ClientApp\
9 | $(DefaultItemExcludes);$(SpaRoot)node_modules\**
10 |
11 |
12 |
13 |
14 |
15 | all
16 | runtime; build; native; contentfiles; analyzers; buildtransitive
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | %(DistFiles.Identity)
47 | PreserveNewest
48 | true
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/ContactsReact/Controllers/WeatherForecastController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Mvc;
6 | using Microsoft.Extensions.Logging;
7 |
8 | namespace ContactsReact.Controllers
9 | {
10 | [ApiController]
11 | [Route("[controller]")]
12 | public class WeatherForecastController : ControllerBase
13 | {
14 | private static readonly string[] Summaries = new[]
15 | {
16 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
17 | };
18 |
19 | private readonly ILogger _logger;
20 |
21 | public WeatherForecastController(ILogger logger)
22 | {
23 | _logger = logger;
24 | }
25 |
26 | [HttpGet]
27 | public IEnumerable Get()
28 | {
29 | var rng = new Random();
30 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast
31 | {
32 | Date = DateTime.Now.AddDays(index),
33 | TemperatureC = rng.Next(-20, 55),
34 | Summary = Summaries[rng.Next(Summaries.Length)]
35 | })
36 | .ToArray();
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/ContactsReact/Pages/Error.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model ErrorModel
3 | @{
4 | ViewData["Title"] = "Error";
5 | }
6 |
7 | Error.
8 | An error occurred while processing your request.
9 |
10 | @if (Model.ShowRequestId)
11 | {
12 |
13 | Request ID: @Model.RequestId
14 |
15 | }
16 |
17 | Development Mode
18 |
19 | Swapping to the Development environment displays detailed information about the error that occurred.
20 |
21 |
22 | The Development environment shouldn't be enabled for deployed applications.
23 | It can result in displaying sensitive information from exceptions to end users.
24 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
25 | and restarting the app.
26 |
27 |
--------------------------------------------------------------------------------
/src/ContactsReact/Pages/Error.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.AspNetCore.Mvc.RazorPages;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace ContactsReact.Pages
11 | {
12 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
13 | public class ErrorModel : PageModel
14 | {
15 | private readonly ILogger _logger;
16 |
17 | public ErrorModel(ILogger logger)
18 | {
19 | _logger = logger;
20 | }
21 |
22 | public string RequestId { get; set; }
23 |
24 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
25 |
26 | public void OnGet()
27 | {
28 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/ContactsReact/Pages/_ViewImports.cshtml:
--------------------------------------------------------------------------------
1 | @using ContactsReact
2 | @namespace ContactsReact.Pages
3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
4 |
--------------------------------------------------------------------------------
/src/ContactsReact/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.Extensions.Configuration;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace ContactsReact
11 | {
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateWebHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
20 | WebHost.CreateDefaultBuilder(args)
21 | .UseStartup();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/ContactsReact/Startup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.AspNetCore.HttpsPolicy;
4 | using Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Hosting;
8 |
9 | namespace ContactsReact
10 | {
11 | public class Startup
12 | {
13 | public Startup(IConfiguration configuration)
14 | {
15 | Configuration = configuration;
16 | }
17 |
18 | public IConfiguration Configuration { get; }
19 |
20 | // This method gets called by the runtime. Use this method to add services to the container.
21 | public void ConfigureServices(IServiceCollection services)
22 | {
23 |
24 | services.AddControllersWithViews();
25 |
26 | // In production, the React files will be served from this directory
27 | services.AddSpaStaticFiles(configuration =>
28 | {
29 | configuration.RootPath = "ClientApp/build";
30 | });
31 | }
32 |
33 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
34 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
35 | {
36 | if (env.IsDevelopment())
37 | {
38 | app.UseDeveloperExceptionPage();
39 | }
40 | else
41 | {
42 | app.UseExceptionHandler("/Error");
43 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
44 | app.UseHsts();
45 | }
46 |
47 | app.UseHttpsRedirection();
48 | app.UseStaticFiles();
49 | app.UseSpaStaticFiles();
50 |
51 | app.UseRouting();
52 |
53 | app.UseEndpoints(endpoints =>
54 | {
55 | endpoints.MapControllerRoute(
56 | name: "default",
57 | pattern: "{controller}/{action=Index}/{id?}");
58 | });
59 |
60 | app.UseSpa(spa =>
61 | {
62 | spa.Options.SourcePath = "ClientApp";
63 |
64 | if (env.IsDevelopment())
65 | {
66 | spa.UseReactDevelopmentServer(npmScript: "start");
67 | }
68 | });
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/ContactsReact/WeatherForecast.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ContactsReact
4 | {
5 | public class WeatherForecast
6 | {
7 | public DateTime Date { get; set; }
8 |
9 | public int TemperatureC { get; set; }
10 |
11 | public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
12 |
13 | public string Summary { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/ContactsReact/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "System": "Information",
6 | "Microsoft": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/ContactsReact/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Warning"
5 | }
6 | },
7 | "AllowedHosts": "*"
8 | }
9 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: http://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Unix-style newlines with a newline ending every file
7 | [*]
8 | end_of_line = lf
9 | insert_final_newline = true
10 | # 2 space indentation
11 | indent_style = space
12 | indent_size = 2
13 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # You may want to customise this file depending on your Operating System
3 | # and the editor that you use.
4 | #
5 | # We recommend that you use a Global Gitignore for files that are not related
6 | # to the project. (https://help.github.com/articles/ignoring-files/#create-a-global-gitignore)
7 |
8 | # OS
9 | #
10 | # Ref: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
11 | # Ref: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
12 | # Ref: https://github.com/github/gitignore/blob/master/Global/Linux.gitignore
13 | .DS_STORE
14 | Thumbs.db
15 |
16 | # Editors
17 | #
18 | # Ref: https://github.com/github/gitignore/blob/master/Global
19 | # Ref: https://github.com/github/gitignore/blob/master/Global/JetBrains.gitignore
20 | # Ref: https://github.com/github/gitignore/blob/master/Global/VisualStudioCode.gitignore
21 | .idea
22 | .vscode/*
23 | !.vscode/settings.json
24 | !.vscode/tasks.json
25 | !.vscode/launch.json
26 | !.vscode/extensions.json
27 |
28 | # Dependencies
29 | node_modules
30 |
31 | # Compiled files
32 | /scripts
33 | /src/environment.js
34 | /src/environment.ts
35 | /dist
36 | /test/coverage-jest
37 | /test/coverage-karma
38 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "AureliaEffect.aurelia",
4 | "msjsdiag.debugger-for-chrome",
5 | "steoates.autoimport",
6 | "EditorConfig.EditorConfig",
7 | "christian-kohler.path-intellisense",
8 | "behzad88.Aurelia"
9 | ]
10 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Chrome",
6 | "type": "chrome",
7 | "request": "launch",
8 | "url": "http://localhost:8080",
9 | "webRoot": "${workspaceRoot}/src",
10 | "userDataDir": "${workspaceRoot}/.chrome",
11 | "sourceMapPathOverrides": {
12 | "webpack:///./src/*": "${webRoot}/*"
13 | }
14 | }
15 | ]
16 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules/typescript/lib",
3 | "html.suggest.angular1": false,
4 | "html.suggest.ionic": false
5 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/README.md:
--------------------------------------------------------------------------------
1 | # `contacts-aurelia`
2 |
3 | This project is bootstrapped by [aurelia-cli](https://github.com/aurelia/cli).
4 |
5 | For more information, go to https://aurelia.io/docs/cli/webpack
6 |
7 | ## Run dev app
8 |
9 | Run `npm start`, then open `http://localhost:8080`
10 |
11 | You can change the standard webpack configurations from CLI easily with something like this: `npm start -- --open --port 8888`. However, it is better to change the respective npm scripts or `webpack.config.js` with these options, as per your need.
12 |
13 | To enable Webpack Bundle Analyzer, do `npm run analyze` (production build).
14 |
15 | To enable hot module reload, do `npm start -- --hmr`.
16 |
17 | To change dev server port, do `npm start -- --port 8888`.
18 |
19 | To change dev server host, do `npm start -- --host 127.0.0.1`
20 |
21 | **PS:** You could mix all the flags as well, `npm start -- --host 127.0.0.1 --port 7070 --open --hmr`
22 |
23 | For long time aurelia-cli user, you can still use `au run` with those arguments like `au run --env prod --open --hmr`. But `au run` now simply executes `npm start` command.
24 |
25 | ## Build for production
26 |
27 | Run `npm run build`, or the old way `au build --env prod`.
28 |
29 | ## Unit tests
30 |
31 | Run `au test` (or `au jest`).
32 |
33 | To run in watch mode, `au test --watch` or `au jest --watch`.
34 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/aurelia.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "contacts-aurelia",
3 | "type": "project:application",
4 | "paths": {
5 | "root": "src",
6 | "resources": "resources",
7 | "elements": "resources/elements",
8 | "attributes": "resources/attributes",
9 | "valueConverters": "resources/value-converters",
10 | "bindingBehaviors": "resources/binding-behaviors"
11 | },
12 | "transpiler": {
13 | "id": "typescript",
14 | "fileExtension": ".ts"
15 | },
16 | "build": {
17 | "options": {
18 | "server": "dev",
19 | "extractCss": "prod",
20 | "coverage": false
21 | }
22 | },
23 | "platform": {
24 | "hmr": false,
25 | "open": false,
26 | "port": 8080,
27 | "host": "localhost",
28 | "output": "dist"
29 | },
30 | "packageManager": "npm"
31 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/generators/attribute.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "attribute",
3 | "description": "Creates a custom attribute class and places it in the project resources."
4 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/generators/attribute.ts:
--------------------------------------------------------------------------------
1 | import {inject} from 'aurelia-dependency-injection';
2 | import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
3 |
4 | @inject(Project, CLIOptions, UI)
5 | export default class AttributeGenerator {
6 | constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
7 |
8 | async execute() {
9 | const name = await this.ui.ensureAnswer(
10 | this.options.args[0],
11 | 'What would you like to call the custom attribute?'
12 | );
13 |
14 | let fileName = this.project.makeFileName(name);
15 | let className = this.project.makeClassName(name);
16 |
17 | this.project.attributes.add(
18 | ProjectItem.text(`${fileName}.ts`, this.generateSource(className))
19 | );
20 |
21 | await this.project.commitChanges();
22 | await this.ui.log(`Created ${fileName}.`);
23 | }
24 |
25 | generateSource(className) {
26 | return `import {autoinject} from 'aurelia-framework';
27 |
28 | @autoinject()
29 | export class ${className}CustomAttribute {
30 | constructor(private element: Element) { }
31 |
32 | valueChanged(newValue, oldValue) {
33 | //
34 | }
35 | }
36 | `;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/generators/binding-behavior.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "binding-behavior",
3 | "description": "Creates a binding behavior class and places it in the project resources."
4 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/generators/binding-behavior.ts:
--------------------------------------------------------------------------------
1 | import {inject} from 'aurelia-dependency-injection';
2 | import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
3 |
4 | @inject(Project, CLIOptions, UI)
5 | export default class BindingBehaviorGenerator {
6 | constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
7 |
8 | async execute() {
9 | const name = await this.ui.ensureAnswer(
10 | this.options.args[0],
11 | 'What would you like to call the binding behavior?'
12 | );
13 |
14 | let fileName = this.project.makeFileName(name);
15 | let className = this.project.makeClassName(name);
16 |
17 | this.project.bindingBehaviors.add(
18 | ProjectItem.text(`${fileName}.ts`, this.generateSource(className))
19 | );
20 |
21 | await this.project.commitChanges();
22 | await this.ui.log(`Created ${fileName}.`);
23 | }
24 |
25 | generateSource(className) {
26 | return `export class ${className}BindingBehavior {
27 | bind(binding, source) {
28 | //
29 | }
30 |
31 | unbind(binding, source) {
32 | //
33 | }
34 | }
35 | `
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/generators/component.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "component",
3 | "description": "Creates a custom component class and template (view model and view), placing them in the project source folder (or optionally in sub folders)."
4 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/generators/component.ts:
--------------------------------------------------------------------------------
1 | import { inject } from 'aurelia-dependency-injection';
2 | import { Project, ProjectItem, CLIOptions, UI } from 'aurelia-cli';
3 |
4 | var path = require('path');
5 |
6 | @inject(Project, CLIOptions, UI)
7 | export default class ElementGenerator {
8 | constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
9 |
10 | async execute() {
11 | const name = await this.ui.ensureAnswer(
12 | this.options.args[0],
13 | 'What would you like to call the component?'
14 | );
15 |
16 | const subFolders = await this.ui.ensureAnswer(
17 | this.options.args[1],
18 | 'What sub-folder would you like to add it to?\nIf it doesn\'t exist it will be created for you.\n\nDefault folder is the source folder (src).', "."
19 | );
20 |
21 | let fileName = this.project.makeFileName(name);
22 | let className = this.project.makeClassName(name);
23 |
24 | this.project.root.add(
25 | ProjectItem.text(path.join(subFolders, fileName + '.ts'), this.generateJSSource(className)),
26 | ProjectItem.text(path.join(subFolders, fileName + '.html'), this.generateHTMLSource(className))
27 | );
28 |
29 | await this.project.commitChanges();
30 | await this.ui.log(`Created ${name} in the '${path.join(this.project.root.name, subFolders)}' folder`);
31 | }
32 |
33 | generateJSSource(className) {
34 | return `export class ${className} {
35 | message: string;
36 |
37 | constructor() {
38 | this.message = 'Hello world';
39 | }
40 | }
41 | `
42 | }
43 |
44 | generateHTMLSource(className) {
45 | return `
46 | \${message}
47 |
48 | `
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/generators/element.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "element",
3 | "description": "Creates a custom element class and template, placing them in the project resources."
4 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/generators/element.ts:
--------------------------------------------------------------------------------
1 | import {inject} from 'aurelia-dependency-injection';
2 | import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
3 |
4 | @inject(Project, CLIOptions, UI)
5 | export default class ElementGenerator {
6 | constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
7 |
8 | async execute() {
9 | const name = await this.ui.ensureAnswer(
10 | this.options.args[0],
11 | 'What would you like to call the custom element?'
12 | );
13 |
14 | let fileName = this.project.makeFileName(name);
15 | let className = this.project.makeClassName(name);
16 |
17 | this.project.elements.add(
18 | ProjectItem.text(`${fileName}.ts`, this.generateJSSource(className)),
19 | ProjectItem.text(`${fileName}.html`, this.generateHTMLSource(className))
20 | );
21 |
22 | await this.project.commitChanges();
23 | await this.ui.log(`Created ${fileName}.`);
24 | }
25 |
26 | generateJSSource(className) {
27 | return `import {bindable} from 'aurelia-framework';
28 |
29 | export class ${className} {
30 | @bindable value;
31 |
32 | valueChanged(newValue, oldValue) {
33 | //
34 | }
35 | }
36 | `;
37 | }
38 |
39 | generateHTMLSource(className) {
40 | return `
41 | \${value}
42 |
43 | `;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/generators/generator.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "generator",
3 | "description": "Creates a generator class and places it in the project generators folder."
4 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/generators/generator.ts:
--------------------------------------------------------------------------------
1 | import {inject} from 'aurelia-dependency-injection';
2 | import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
3 |
4 | @inject(Project, CLIOptions, UI)
5 | export default class GeneratorGenerator {
6 | constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
7 |
8 | async execute() {
9 | const name = await this.ui.ensureAnswer(
10 | this.options.args[0],
11 | 'What would you like to call the generator?'
12 | );
13 |
14 | let fileName = this.project.makeFileName(name);
15 | let className = this.project.makeClassName(name);
16 |
17 | this.project.generators.add(
18 | ProjectItem.text(`${fileName}.ts`, this.generateSource(className))
19 | );
20 |
21 | await this.project.commitChanges()
22 | await this.ui.log(`Created ${fileName}.`);
23 | }
24 |
25 | generateSource(className) {
26 | return `import {inject} from 'aurelia-dependency-injection';
27 | import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
28 |
29 | @inject(Project, CLIOptions, UI)
30 | export default class ${className}Generator {
31 | constructor(project, options, ui) {
32 | this.project = project;
33 | this.options = options;
34 | this.ui = ui;
35 | }
36 |
37 | execute() {
38 | return this.ui
39 | .ensureAnswer(this.options.args[0], 'What would you like to call the new item?')
40 | .then(name => {
41 | let fileName = this.project.makeFileName(name);
42 | let className = this.project.makeClassName(name);
43 |
44 | this.project.elements.add(
45 | ProjectItem.text(\`\${fileName}.ts\`, this.generateSource(className))
46 | );
47 |
48 | return this.project.commitChanges()
49 | .then(() => this.ui.log(\`Created \${fileName}.\`));
50 | });
51 | }
52 |
53 | generateSource(className) {
54 | return \`import {bindable} from 'aurelia-framework';
55 |
56 | export class \${className} {
57 | @bindable value;
58 |
59 | valueChanged(newValue, oldValue) {
60 | //
61 | }
62 | }
63 | \`
64 | }
65 | }
66 | `;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/generators/task.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "task",
3 | "description": "Creates a task and places it in the project tasks folder."
4 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/generators/task.ts:
--------------------------------------------------------------------------------
1 | import {inject} from 'aurelia-dependency-injection';
2 | import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
3 |
4 | @inject(Project, CLIOptions, UI)
5 | export default class TaskGenerator {
6 | constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
7 |
8 | async execute() {
9 | const name = await this.ui.ensureAnswer(
10 | this.options.args[0],
11 | 'What would you like to call the task?'
12 | );
13 |
14 | let fileName = this.project.makeFileName(name);
15 | let functionName = this.project.makeFunctionName(name);
16 |
17 | this.project.tasks.add(
18 | ProjectItem.text(`${fileName}.ts`, this.generateSource(functionName))
19 | );
20 |
21 | await this.project.commitChanges();
22 | await this.ui.log(`Created ${fileName}.`);
23 | }
24 |
25 | generateSource(functionName) {
26 | return `import * as gulp from 'gulp';
27 | import * as project from '../aurelia.json';
28 |
29 | export default function ${functionName}() {
30 | return gulp.src(project.paths.???)
31 | .pipe(gulp.dest(project.paths.output));
32 | }
33 | `;
34 |
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/generators/value-converter.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "value-converter",
3 | "description": "Creates a value converter class and places it in the project resources."
4 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/generators/value-converter.ts:
--------------------------------------------------------------------------------
1 | import {inject} from 'aurelia-dependency-injection';
2 | import {Project, ProjectItem, CLIOptions, UI} from 'aurelia-cli';
3 |
4 | @inject(Project, CLIOptions, UI)
5 | export default class ValueConverterGenerator {
6 | constructor(private project: Project, private options: CLIOptions, private ui: UI) { }
7 |
8 | async execute() {
9 | const name = await this.ui.ensureAnswer(
10 | this.options.args[0],
11 | 'What would you like to call the value converter?'
12 | );
13 |
14 | let fileName = this.project.makeFileName(name);
15 | let className = this.project.makeClassName(name);
16 |
17 | this.project.valueConverters.add(
18 | ProjectItem.text(`${fileName}.ts`, this.generateSource(className))
19 | );
20 |
21 | await this.project.commitChanges();
22 | await this.ui.log(`Created ${fileName}.`);
23 | }
24 |
25 | generateSource(className) {
26 | return `export class ${className}ValueConverter {
27 | toView(value) {
28 | //
29 | }
30 |
31 | fromView(value) {
32 | //
33 | }
34 | }
35 | `;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/tasks/build.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "build",
3 | "description": "Builds and processes all application assets. It is an alias of the `npm run build:dev`, you may use either of those; see README for more details.",
4 | "flags": [
5 | {
6 | "name": "analyze",
7 | "description": "Enable Webpack Bundle Analyzer. Typically paired with --env prod",
8 | "type": "boolean"
9 | },
10 | {
11 | "name": "env",
12 | "description": "Sets the build environment.",
13 | "type": "string"
14 | },
15 | {
16 | "name": "watch",
17 | "description": "Watches source files for changes and refreshes the bundles automatically.",
18 | "type": "boolean"
19 | }
20 | ]
21 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/tasks/build.ts:
--------------------------------------------------------------------------------
1 | import { NPM } from 'aurelia-cli';
2 |
3 | export default function() {
4 | console.log('`au build` is an alias of the `npm run build:dev`, you may use either of those; see README for more details.');
5 | const args = process.argv.slice(3);
6 | return (new NPM()).run('run', ['build:dev', '--', ... cleanArgs(args)]);
7 | }
8 |
9 | // Cleanup --env prod to --env.production
10 | // for backwards compatibility
11 | function cleanArgs(args) {
12 | const cleaned = [];
13 | for (let i = 0, ii = args.length; i < ii; i++) {
14 | if (args[i] === '--env' && i < ii - 1) {
15 | const env = args[++i].toLowerCase();
16 | if (env.startsWith('prod')) {
17 | cleaned.push('--env.production');
18 | } else if (env.startsWith('test')) {
19 | cleaned.push('--tests');
20 | }
21 | } else {
22 | cleaned.push(args[i]);
23 | }
24 | }
25 | return cleaned;
26 | }
27 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/tasks/jest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jest",
3 | "description": "Runs Jest and reports the results.",
4 | "flags": [
5 | {
6 | "name": "watch",
7 | "description": "Watches test files for changes and re-runs the tests automatically.",
8 | "type": "boolean"
9 | }
10 | ]
11 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/tasks/jest.ts:
--------------------------------------------------------------------------------
1 | export {default} from './test';
2 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/tasks/run.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "run",
3 | "description": "Builds the application and serves up the assets via a local web server, watching files for changes as you work. It is an alias of the `npm start`, you may use either of those; see README for more details.",
4 | "flags": [
5 | {
6 | "name": "analyze",
7 | "description": "Enable Webpack Bundle Analyzer. Typically paired with --env prod",
8 | "type": "boolean"
9 | },
10 | {
11 | "name": "env",
12 | "description": "Sets the build environment.",
13 | "type": "string"
14 | },
15 | {
16 | "name": "hmr",
17 | "description": "Enable Hot Module Reload",
18 | "type": "boolean"
19 | },
20 | {
21 | "name": "port",
22 | "description": "Set port number of the dev server",
23 | "type": "string"
24 | },
25 | {
26 | "name": "host",
27 | "description": "Set host address of the dev server, the accessible URL",
28 | "type": "string"
29 | },
30 | {
31 | "name": "open",
32 | "description": "Open the default browser at the application location.",
33 | "type": "boolean"
34 | }
35 | ]
36 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/tasks/run.ts:
--------------------------------------------------------------------------------
1 | import { NPM } from 'aurelia-cli';
2 | import * as kill from 'tree-kill';
3 | import { platform } from '../aurelia.json';
4 |
5 | const npm = new NPM();
6 |
7 | function run() {
8 | console.log('`au run` is an alias of the `npm start`, you may use either of those; see README for more details.');
9 | const args = process.argv.slice(3);
10 | return npm.run('start', ['--', ... cleanArgs(args)]);
11 | }
12 |
13 | // Cleanup --env prod to --env.production
14 | // for backwards compatibility
15 | function cleanArgs(args) {
16 | let host;
17 | const cleaned = [];
18 |
19 | for (let i = 0, ii = args.length; i < ii; i++) {
20 | if (args[i] === '--env' && i < ii - 1) {
21 | const env = args[++i].toLowerCase();
22 | if (env.startsWith('prod')) {
23 | cleaned.push('--env.production');
24 | } else if (env.startsWith('test')) {
25 | cleaned.push('--tests');
26 | }
27 | } else if (args[i] === '--host' && i < ii -1) {
28 | host = args[++i];
29 | } else {
30 | cleaned.push(args[i]);
31 | }
32 | }
33 |
34 | // Deal with --host before webpack-dev-server calls webpack config.
35 | // Because of https://discourse.aurelia.io/t/changing-platform-host-in-aurelia-json-doesnt-change-the-host-ip/3043/10?u=huochunpeng
36 | if (!host) host = platform.host;
37 | if (host) cleaned.push('--host', host);
38 | return cleaned;
39 | }
40 |
41 | const shutdownAppServer = () => {
42 | if (npm && npm.proc) {
43 | kill(npm.proc.pid);
44 | }
45 | };
46 |
47 | export { run as default, shutdownAppServer };
48 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/tasks/test.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test",
3 | "description": "Runs Jest and reports the results.",
4 | "flags": [
5 | {
6 | "name": "watch",
7 | "description": "Watches test files for changes and re-runs the tests automatically.",
8 | "type": "boolean"
9 | }
10 | ]
11 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/aurelia_project/tasks/test.ts:
--------------------------------------------------------------------------------
1 | import * as jest from 'jest-cli';
2 | import * as path from 'path';
3 | import * as packageJson from '../../package.json';
4 |
5 | import { CLIOptions } from 'aurelia-cli';
6 |
7 | export default (cb) => {
8 | let options = packageJson.jest;
9 |
10 | if (CLIOptions.hasFlag('watch')) {
11 | Object.assign(options, { watchAll: true});
12 | }
13 |
14 |
15 | jest.runCLI(options, [path.resolve(__dirname, '../../')]).then(({ results }) => {
16 | if (results.numFailedTests || results.numFailedTestSuites) {
17 | cb('Tests Failed');
18 | } else {
19 | cb();
20 | }
21 | });
22 | };
23 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/config/environment.json:
--------------------------------------------------------------------------------
1 | {
2 | "debug": true,
3 | "testing": true
4 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/config/environment.production.json:
--------------------------------------------------------------------------------
1 | {
2 | "debug": false,
3 | "testing": false
4 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elanderson/ASP.NET-Core-Basics-Refresh/ce90da48353633653f4c2c194fdc597abe18a150/src/contacts-aurelia/favicon.ico
--------------------------------------------------------------------------------
/src/contacts-aurelia/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- htmlWebpackPlugin.options.metadata.title %>
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "contacts-aurelia",
3 | "description": "An Aurelia client application.",
4 | "version": "0.1.0",
5 | "repository": {
6 | "type": "???",
7 | "url": "???"
8 | },
9 | "license": "MIT",
10 | "dependencies": {
11 | "aurelia-animator-css": "^1.0.4",
12 | "aurelia-bootstrapper": "^2.3.2",
13 | "aurelia-fetch-client": "^1.8.2",
14 | "bootstrap": "^4.4.1",
15 | "font-awesome": "^4.7.0"
16 | },
17 | "devDependencies": {
18 | "aurelia-cli": "^1.2.3",
19 | "aurelia-testing": "^1.0.0",
20 | "aurelia-tools": "^2.0.0",
21 | "gulp": "^4.0.0",
22 | "minimatch": "^3.0.4",
23 | "through2": "^3.0.0",
24 | "vinyl-fs": "^3.0.3",
25 | "promise-polyfill": "^8.1.0",
26 | "ts-loader": "^5.2.1",
27 | "ts-node": "^7.0.1",
28 | "@types/node": "^10.11.6",
29 | "@types/lodash": "^4.14.117",
30 | "@types/webpack": "^4.4.15",
31 | "typescript": "^3.1.2",
32 | "html-webpack-plugin": "^3.2.0",
33 | "copy-webpack-plugin": "^5.0.0",
34 | "mini-css-extract-plugin": "^0.4.3",
35 | "aurelia-webpack-plugin": "^3.0.0",
36 | "duplicate-package-checker-webpack-plugin": "^3.0.0",
37 | "clean-webpack-plugin": "^1.0.1",
38 | "webpack": "^4.27.0",
39 | "webpack-cli": "^3.1.2",
40 | "webpack-dev-server": "^3.1.9",
41 | "expose-loader": "^0.7.5",
42 | "style-loader": "^0.23.1",
43 | "url-loader": "^1.1.2",
44 | "css-loader": "^1.0.0",
45 | "file-loader": "^2.0.0",
46 | "app-settings-loader": "^1.0.2",
47 | "json-loader": "^0.5.7",
48 | "html-loader": "^0.5.5",
49 | "istanbul-instrumenter-loader": "^3.0.1",
50 | "webpack-bundle-analyzer": "^3.0.4",
51 | "tree-kill": "^1.2.1",
52 | "jest": "^24.1.0",
53 | "jest-cli": "^24.1.0",
54 | "jest-transform-stub": "^2.0.0",
55 | "aurelia-loader-nodejs": "^1.0.1",
56 | "aurelia-pal-nodejs": "^1.2.0",
57 | "ts-jest": "^24.0.0",
58 | "@types/jest": "^24.0.9"
59 | },
60 | "scripts": {
61 | "build": "webpack --env.production --extractCss",
62 | "start": "webpack-dev-server --extractCss",
63 | "build:dev": "webpack --extractCss",
64 | "analyze": "webpack --env.production --analyze",
65 | "test": "au test"
66 | },
67 | "engines": {
68 | "node": ">=8.9.0"
69 | },
70 | "jest": {
71 | "moduleNameMapper": {
72 | "^aurelia-binding$": "/node_modules/aurelia-binding"
73 | },
74 | "modulePaths": [
75 | "/src",
76 | "/node_modules"
77 | ],
78 | "moduleFileExtensions": [
79 | "ts",
80 | "js",
81 | "json"
82 | ],
83 | "transform": {
84 | "^.+\\.(css|less|sass|scss|styl|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "jest-transform-stub",
85 | "^.+\\.ts$": "ts-jest"
86 | },
87 | "testRegex": "\\.spec\\.(ts|js)$",
88 | "setupFiles": [
89 | "/test/jest-pretest.ts"
90 | ],
91 | "testEnvironment": "node",
92 | "collectCoverage": true,
93 | "collectCoverageFrom": [
94 | "src/**/*.{js,ts}",
95 | "!**/*.spec.{js,ts}",
96 | "!**/node_modules/**",
97 | "!**/test/**"
98 | ],
99 | "coverageDirectory": "/test/coverage-jest",
100 | "coverageReporters": [
101 | "json",
102 | "lcov",
103 | "text",
104 | "html"
105 | ]
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Contacts
9 |
10 |
11 |
12 |
18 |
19 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/src/app.ts:
--------------------------------------------------------------------------------
1 | import {PLATFORM} from 'aurelia-pal';
2 |
3 | export class App {
4 | router: any;
5 |
6 | configureRouter(config, router){
7 | config.title = 'Contacts';
8 | config.map([
9 | { route: '', moduleId: PLATFORM.moduleName('no-selection'), title: 'Select' },
10 | { route: 'contacts/:id', moduleId: PLATFORM.moduleName('contact-detail'), name:'contacts' }
11 | ]);
12 |
13 | this.router = router;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/src/contact-detail.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
29 |
30 | Save
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/src/contact-detail.ts:
--------------------------------------------------------------------------------
1 | import {inject} from 'aurelia-framework';
2 | import {ContactsClient, Contact} from './contactsApi';
3 | import {areEqual} from './utility';
4 |
5 | @inject(ContactsClient)
6 | export class ContactDetail {
7 | api: ContactsClient;
8 | routeConfig: any;
9 | contact: Contact;
10 | originalContact: any;
11 |
12 | constructor(api){
13 | this.api = api;
14 | }
15 |
16 | activate(params, routeConfig) {
17 | this.routeConfig = routeConfig;
18 |
19 | return this.api.getContact(params.id).then(contact => {
20 | this.contact = contact;
21 | this.routeConfig.navModel.setTitle(contact.name);
22 | this.originalContact = JSON.parse(JSON.stringify(contact));
23 | });
24 | }
25 |
26 | get canSave() {
27 | return true;
28 | }
29 |
30 | save() {
31 | this.api.postContact(this.contact).then(contact => {
32 | this.contact = contact;
33 | this.routeConfig.navModel.setTitle(contact.name);
34 | this.originalContact = JSON.parse(JSON.stringify(contact));
35 | });
36 | }
37 |
38 | canDeactivate() {
39 | if (!areEqual(this.originalContact, this.contact)){
40 | return confirm('You have unsaved changes. Are you sure you wish to leave?');
41 | }
42 |
43 | return true;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/src/contact-list.html:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/src/contact-list.ts:
--------------------------------------------------------------------------------
1 | import {ContactsClient, Contact} from './contactsApi';
2 | import {inject} from 'aurelia-framework';
3 |
4 | @inject(ContactsClient)
5 | export class ContactList {
6 | contacts: Contact[];
7 | api: ContactsClient;
8 | selectedId: any;
9 |
10 | constructor(api: ContactsClient) {
11 | this.api = api;
12 | this.contacts = [];
13 | }
14 |
15 | created() {
16 | this.api.getContacts().then(contacts => this.contacts = contacts);
17 | }
18 |
19 | select(contact) {
20 | this.selectedId = contact.id;
21 | return true;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/src/main.ts:
--------------------------------------------------------------------------------
1 | import { HttpClient } from 'aurelia-fetch-client';
2 | import {Aurelia} from 'aurelia-framework'
3 | import * as environment from '../config/environment.json';
4 | import {PLATFORM} from 'aurelia-pal';
5 | import 'bootstrap/dist/css/bootstrap.css';
6 | import 'font-awesome/css/font-awesome.css';
7 | import { ContactsClient } from 'contactsApi';
8 |
9 | export function configure(aurelia: Aurelia) {
10 | aurelia.use
11 | .standardConfiguration()
12 | .feature(PLATFORM.moduleName('resources/index'))
13 | .instance(ContactsClient, new ContactsClient("https://localhost:5001", aurelia.container.get(HttpClient)));
14 |
15 | aurelia.use.developmentLogging(environment.debug ? 'debug' : 'warn');
16 |
17 | if (environment.testing) {
18 | aurelia.use.plugin(PLATFORM.moduleName('aurelia-testing'));
19 | }
20 |
21 | aurelia.start().then(() => aurelia.setRoot(PLATFORM.moduleName('app')));
22 | }
23 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/src/no-selection.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
${message}
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/src/no-selection.ts:
--------------------------------------------------------------------------------
1 | export class NoSelection {
2 | message: string;
3 |
4 | constructor() {
5 | this.message = "Please Select a Contact.";
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/src/resources/index.ts:
--------------------------------------------------------------------------------
1 | import {FrameworkConfiguration} from 'aurelia-framework';
2 |
3 | export function configure(config: FrameworkConfiguration) {
4 | //config.globalResources([]);
5 | }
6 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/src/styles.css:
--------------------------------------------------------------------------------
1 | body { padding-top: 70px; }
2 |
3 | section {
4 | margin: 0 20px;
5 | }
6 |
7 | a:focus {
8 | outline: none;
9 | }
10 |
11 | .navbar-nav li.loader {
12 | margin: 12px 24px 0 6px;
13 | }
14 |
15 | .no-selection {
16 | margin: 20px;
17 | }
18 |
19 | .contact-list {
20 | overflow-y: auto;
21 | border: 1px solid #ddd;
22 | padding: 10px;
23 | }
24 |
25 | .panel {
26 | margin: 20px;
27 | }
28 |
29 | .button-bar {
30 | right: 0;
31 | left: 0;
32 | bottom: 0;
33 | border-top: 1px solid #ddd;
34 | background: white;
35 | }
36 |
37 | .button-bar > button {
38 | float: right;
39 | margin: 20px;
40 | }
41 |
42 | li.list-group-item {
43 | list-style: none;
44 | }
45 |
46 | li.list-group-item > a {
47 | text-decoration: none;
48 | }
49 |
50 | li.list-group-item.active > a {
51 | color: white;
52 | }
53 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/src/utility.ts:
--------------------------------------------------------------------------------
1 | export function areEqual(obj1, obj2) {
2 | return Object.keys(obj1).every((key) => obj2.hasOwnProperty(key) && (obj1[key] === obj2[key]));
3 | };
--------------------------------------------------------------------------------
/src/contacts-aurelia/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elanderson/ASP.NET-Core-Basics-Refresh/ce90da48353633653f4c2c194fdc597abe18a150/src/contacts-aurelia/static/favicon.ico
--------------------------------------------------------------------------------
/src/contacts-aurelia/test/jest-pretest.ts:
--------------------------------------------------------------------------------
1 | import 'aurelia-polyfills';
2 | import {Options} from 'aurelia-loader-nodejs';
3 | import {globalize} from 'aurelia-pal-nodejs';
4 | import * as path from 'path';
5 | Options.relativeToDir = path.join(__dirname, 'unit');
6 | globalize();
7 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "module": "esnext",
5 | "skipLibCheck": true,
6 | "typeRoots": [
7 | "./node_modules/@types"
8 | ],
9 | "removeComments": true,
10 | "emitDecoratorMetadata": true,
11 | "experimentalDecorators": true,
12 | "sourceMap": true,
13 | "target": "es5",
14 | "lib": [
15 | "es2015",
16 | "dom"
17 | ],
18 | "moduleResolution": "node",
19 | "baseUrl": "src",
20 | "resolveJsonModule": true,
21 | "allowJs": true
22 | },
23 | "include": [
24 | "./src/**/*.ts",
25 | "./test/**/*.ts",
26 | "./types/**/*.d.ts"
27 | ],
28 | "atom": {
29 | "rewriteTsconfig": false
30 | }
31 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "no-empty": true
4 | }
5 | }
--------------------------------------------------------------------------------
/src/contacts-aurelia/types/fetch.d.ts:
--------------------------------------------------------------------------------
1 | declare module "isomorphic-fetch" {
2 | export = fetch;
3 | }
4 |
--------------------------------------------------------------------------------
/src/contacts-aurelia/types/system.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'system' {
2 | import fetch = require('isomorphic-fetch');
3 | import * as Aurelia from 'aurelia-framework';
4 |
5 | /*
6 | * List your dynamically imported modules to get typing support
7 | */
8 | interface System {
9 | import(name: string): Promise;
10 | import(name: 'aurelia-framework'): Promise;
11 | import(name: 'isomorphic-fetch'): Promise;
12 | }
13 |
14 | global {
15 | var System: System;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/contacts-vue/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 |
--------------------------------------------------------------------------------
/src/contacts-vue/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,ts,tsx,vue}]
2 | indent_style = space
3 | indent_size = 2
4 | trim_trailing_whitespace = true
5 | insert_final_newline = true
6 |
--------------------------------------------------------------------------------
/src/contacts-vue/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | 'extends': [
7 | 'plugin:vue/essential',
8 | '@vue/standard',
9 | '@vue/typescript'
10 | ],
11 | rules: {
12 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
13 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
14 | },
15 | parserOptions: {
16 | parser: '@typescript-eslint/parser'
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/contacts-vue/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/src/contacts-vue/README.md:
--------------------------------------------------------------------------------
1 | # contacts-vue
2 |
3 | ## Project setup
4 | ```
5 | npm install
6 | ```
7 |
8 | ### Compiles and hot-reloads for development
9 | ```
10 | npm run serve
11 | ```
12 |
13 | ### Compiles and minifies for production
14 | ```
15 | npm run build
16 | ```
17 |
18 | ### Lints and fixes files
19 | ```
20 | npm run lint
21 | ```
22 |
23 | ### Customize configuration
24 | See [Configuration Reference](https://cli.vuejs.org/config/).
25 |
--------------------------------------------------------------------------------
/src/contacts-vue/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/src/contacts-vue/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "contacts-vue",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "core-js": "^3.4.4",
12 | "vue": "^2.6.10",
13 | "vue-class-component": "^7.0.2",
14 | "vue-property-decorator": "^8.3.0",
15 | "vue-router": "^3.1.3"
16 | },
17 | "devDependencies": {
18 | "@vue/cli-plugin-babel": "^4.1.0",
19 | "@vue/cli-plugin-eslint": "^4.1.0",
20 | "@vue/cli-plugin-router": "^4.1.0",
21 | "@vue/cli-plugin-typescript": "^4.1.0",
22 | "@vue/cli-service": "^4.1.0",
23 | "@vue/eslint-config-standard": "^4.0.0",
24 | "@vue/eslint-config-typescript": "^4.0.0",
25 | "eslint": "^5.16.0",
26 | "eslint-plugin-vue": "^5.0.0",
27 | "typescript": "~3.5.3",
28 | "vue-template-compiler": "^2.6.10"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/contacts-vue/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elanderson/ASP.NET-Core-Basics-Refresh/ce90da48353633653f4c2c194fdc597abe18a150/src/contacts-vue/public/favicon.ico
--------------------------------------------------------------------------------
/src/contacts-vue/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | contacts-vue
9 |
10 |
11 |
12 | We're sorry but contacts-vue doesn't work properly without JavaScript enabled. Please enable it to continue.
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/contacts-vue/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Home |
5 | Contacts |
6 | About
7 |
8 |
9 |
10 |
11 |
12 |
34 |
--------------------------------------------------------------------------------
/src/contacts-vue/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/elanderson/ASP.NET-Core-Basics-Refresh/ce90da48353633653f4c2c194fdc597abe18a150/src/contacts-vue/src/assets/logo.png
--------------------------------------------------------------------------------
/src/contacts-vue/src/components/ContacList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Name
7 | Address
8 | City
9 | State
10 | Postal Code
11 | Phone
12 | Email
13 |
14 |
15 |
16 |
17 | {{contact.name}}
18 | {{contact.address}}
19 | {{contact.city}}
20 | {{contact.state}}
21 | {{contact.postalCode}}
22 | {{contact.phone}}
23 | {{contact.email}}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
45 |
46 |
48 |
--------------------------------------------------------------------------------
/src/contacts-vue/src/components/HelloWorld.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
5 | For a guide and recipes on how to configure / customize this project,
6 | check out the
7 | vue-cli documentation .
8 |
9 |
Installed CLI Plugins
10 |
16 |
Essential Links
17 |
24 |
Ecosystem
25 |
32 |
33 |
34 |
35 |
43 |
44 |
45 |
61 |
--------------------------------------------------------------------------------
/src/contacts-vue/src/main.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 |
5 | Vue.config.productionTip = false
6 |
7 | new Vue({
8 | router,
9 | render: h => h(App)
10 | }).$mount('#app')
11 |
--------------------------------------------------------------------------------
/src/contacts-vue/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueRouter from 'vue-router'
3 | import Home from '../views/Home.vue'
4 | import ContactList from '../views/ContactList.vue'
5 |
6 | Vue.use(VueRouter)
7 |
8 | const routes = [
9 | {
10 | path: '/',
11 | name: 'home',
12 | component: Home
13 | },
14 | {
15 | path: '/contactList',
16 | name: 'contactList',
17 | component: ContactList
18 | },
19 | {
20 | path: '/about',
21 | name: 'about',
22 | // route level code-splitting
23 | // this generates a separate chunk (about.[hash].js) for this route
24 | // which is lazy-loaded when the route is visited.
25 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
26 | }
27 | ]
28 |
29 | const router = new VueRouter({
30 | mode: 'history',
31 | base: process.env.BASE_URL,
32 | routes
33 | })
34 |
35 | export default router
36 |
--------------------------------------------------------------------------------
/src/contacts-vue/src/shims-tsx.d.ts:
--------------------------------------------------------------------------------
1 | import Vue, { VNode } from 'vue'
2 |
3 | declare global {
4 | namespace JSX {
5 | // tslint:disable no-empty-interface
6 | interface Element extends VNode {}
7 | // tslint:disable no-empty-interface
8 | interface ElementClass extends Vue {}
9 | interface IntrinsicElements {
10 | [elem: string]: any
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/contacts-vue/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import Vue from 'vue'
3 | export default Vue
4 | }
5 |
--------------------------------------------------------------------------------
/src/contacts-vue/src/views/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
This is an about page
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/contacts-vue/src/views/ContactList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
18 |
--------------------------------------------------------------------------------
/src/contacts-vue/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
19 |
--------------------------------------------------------------------------------
/src/contacts-vue/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "strict": true,
6 | "jsx": "preserve",
7 | "importHelpers": true,
8 | "moduleResolution": "node",
9 | "experimentalDecorators": true,
10 | "esModuleInterop": true,
11 | "allowSyntheticDefaultImports": true,
12 | "sourceMap": true,
13 | "baseUrl": ".",
14 | "types": [
15 | "webpack-env"
16 | ],
17 | "paths": {
18 | "@/*": [
19 | "src/*"
20 | ]
21 | },
22 | "lib": [
23 | "esnext",
24 | "dom",
25 | "dom.iterable",
26 | "scripthost"
27 | ]
28 | },
29 | "include": [
30 | "src/**/*.ts",
31 | "src/**/*.tsx",
32 | "src/**/*.vue",
33 | "tests/**/*.ts",
34 | "tests/**/*.tsx"
35 | ],
36 | "exclude": [
37 | "node_modules"
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------