Skip to content

Commit

Permalink
Initial port from aspnet-core-react-template
Browse files Browse the repository at this point in the history
  • Loading branch information
bradymholt committed May 15, 2017
0 parents commit 1a62df8
Show file tree
Hide file tree
Showing 110 changed files with 9,569 additions and 0 deletions.
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
root = true

[*]
end_of_line = lf
charset = utf-8
indent_style = space
trim_trailing_whitespace = true
insert_final_newline = true
indent_size = 2

[*.{js,ts,tsx}]
indent_size = 4
28 changes: 28 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.DS_Store

# dotnet core
bin/
obj/
project.lock.json

api/wwwroot/**
!api/wwwroot/scratch.html
!api/wwwroot/favicon.ico

# node
node_modules/
typings/
npm-debug.log

# client-react
client-react/components/*.js
client-react.test/build
!client-react.test/build/client-react/styles/

# ops
ops/hosts
ops/*.retry

# other
*.js.map

50 changes: 50 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug api/ (server)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceRoot}/api/bin/Debug/netcoreapp1.1/api.dll",
"args": [],
"env": {
"ASPNETCORE_ENVIRONMENT": "Development",
"NODE_PATH": "../node_modules/"
},
"cwd": "${workspaceRoot}/api",
"externalConsole": false,
"stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": "Debug client-web.test/ (Mocha tests)",
"type": "node",
"request": "launch",
"protocol": "inspector",
"program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
"stopOnEntry": false,
"args": [
"--require",
"ignore-styles",
"--recursive",
"client-web.test/build/client-web.test"
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "pretest:client",
"runtimeArgs": [
"--nolazy"
],
"env": {
"NODE_ENV": "development"
},
"sourceMaps": true
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}
11 changes: 11 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/bin": true,
"**/obj": true
}
}
34 changes: 34 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "0.1.0",
"command": "npm",
"isShellCommand": true,
"showOutput": "always",
"suppressTaskName": true,
"tasks": [
{
"taskName": "build",
"args": [
"run",
"build"
],
"isBuildCommand": true
},
{
"taskName": "test",
"args": [
"run",
"test"
],
"isTestCommand": true
},
{
"taskName": "pretest:client",
"args":[
"run",
"pretest:client"
]
}
]
}
116 changes: 116 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# ASP.NET Core / Vue.js SPA Template App

This app is a template application using ASP.NET Core for a REST/JSON API server and Vue.js for a web client.

## Overview of Stack
- Server
- ASP.NET Core
- PostgresSQL
- Entity Framework Core w/ EF Migrations
- JSON Web Token (JWT) authorization with OpenIddict
- Docker used for development PostgresSQL database and MailCatcher server
- Client
- Vue.js
- Webpack for asset bundling and HMR (Hot Module Replacement)
- CSS Modules
- Testing
- xUnit for .NET Core
- MailCatcher for development email delivery
- DevOps
- Ansible playbook for provisioning (Nginx reverse proxy, SSL via Let's Encrypt, PostgresSQL backups to S3)
- Ansible playbook for deployment

## Setup

1. Install the following:
- [.NET Core 1.1](https://www.microsoft.com/net/core)
- [Node.js >= v7.8.0](https://nodejs.org/en/download/)
- [Ansible >= 2.0](http://docs.ansible.com/ansible/intro_installation.html)
- [Docker](https://docs.docker.com/engine/installation/)
2. Run `npm install && npm start`
3. Open browser and navigate to [http://localhost:5000](http://localhost:5000).

## Scripts

### `npm install`

When first cloning the repo or adding new dependencies, run this command. This will:

- Install Node dependencies from package.json
- Install .NET Core dependencies from api/api.csproj and api.test/api.test.csproj (using dotnet restore)

### `npm start`

To start the app for development, run this command. This will:

- Run `docker-compose up` to ensure the PostgreSQL and MailCatcher Docker images are up and running
- Run dotnet watch run which will build the app (if changed), watch for changes and start the web server on http://localhost:5000
- Run Webpack dev middleware with HMR via [ASP.NET JavaScriptServices](https://github.com/aspnet/JavaScriptServices)

### `npm run migrate`

After making changes to Entity Framework models in `api/Models/`, run this command to generate and run a migration on the database. A timestamp will be used for the migration name.

### `npm test`

This will run the xUnit tests in api.test/ and the Vue.js tests in client-web.test/.

### `npm run provision:prod`

_Before running this script, you need to create an ops/hosts file first. See the [ops README](ops/) for instructions._

This will run the ops/provision.yml Ansible playbook and provision hosts in ops/hosts inventory file. This prepares the hosts to recieve deployments by doing the following:
- Install Nginx
- Generate a SSL certificate from [Let's Encrypt](https://letsencrypt.org/) and configure Nginx to use it
- Install .Net Core
- Install Supervisor (will run/manage the ASP.NET app)
- Install PostgreSQL
- Setup a cron job to automatically backup the PostgresSQL database, compress it, and upload it to S3.
- Setup UFW (firewall) to lock everything down except inbound SSH and web traffic
- Create a deploy user, directory for deployments and configure Nginx to serve from this directory

### `npm run deploy:prod`

_Before running this script, you need to create a ops/hosts file first. See the [ops README](ops/) for instructions._

This script will:
- Build release Webpack bundles
- Package the .NET Core application in Release mode (dotnet publish)
- Run the ops/deploy.yml Ansible playbook to deploy this app to hosts in /ops/hosts inventory file. This does the following:
- Copies the build assets to the remote host(s)
- Updates the `appsettings.json` file with PostgresSQL credentials specified in ops/hosts file and the app URL (needed for JWT tokens)
- Restarts the app so that changes will be picked up

## Development Email Delivery

This template includes a [MailCatcher](https://mailcatcher.me/) Docker image so that when email is sent during development (i.e. new user registration), it can be viewed
in the MailCacher web interface at [http://localhost:1080/](http://localhost:1080/).

## Visual Studio Code config

This project has [Visual Studio Code](https://code.visualstudio.com/) tasks and debugger launch config located in .vscode/.

### Tasks

- **Command+Shift+B** - Runs the "build" task which builds the api/ project
- **Command+Shift+T** - Runs the "test" task which runs the xUnit tests in api.test/ and Mocha/Enzyme tests in client-react.test/.

### Debug Launcher

With the following debugger launch configs, you can set breakpoints in api/ or the the Mocha tests in client-react.test/ and have full debugging support.

- **Debug api/ (server)** - Runs the vscode debugger (breakpoints) on the api/ .NET Core app
- **Debug client-web.test/ (Mocha tests)** - Runs the vscode debugger on the client-web.test/ Mocha tests

## Credit

The following resources were helpful in setting up this template:

- [Sample for implementing Authentication with a React Flux app and JWTs](https://github.com/auth0-blog/react-flux-jwt-authentication-sample)
- [Angular 2, React, and Knockout apps on ASP.NET Core](http://blog.stevensanderson.com/2016/05/02/angular2-react-knockout-apps-on-aspnet-core/)
- [Setting up ASP.NET v5 (vNext) to use JWT tokens (using OpenIddict)](http://capesean.co.za/blog/asp-net-5-jwt-tokens/)
- [Cross-platform Single Page Applications with ASP.NET Core 1.0, Angular 2 & TypeScript](https://chsakell.com/2016/01/01/cross-platform-single-page-applications-with-asp-net-5-angular-2-typescript/)
- [Stack Overflow - Token Based Authentication in ASP.NET Core](http://stackoverflow.com/questions/30546542/token-based-authentication-in-asp-net-core-refreshed)
- [SPA example of a token based authentication implementation using the Aurelia front end framework and ASP.NET core]( https://github.com/alexandre-spieser/AureliaAspNetCoreAuth)
- [A Real-World React.js Setup for ASP.NET Core and MVC5](https://www.simple-talk.com/dotnet/asp-net/a-real-world-react-js-setup-for-asp-net-core-and-mvc)
- My own perseverance because this took a _lot_ of time to get right 😁
19 changes: 19 additions & 0 deletions api.test/Controller/Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Collections.Generic;
using System.Linq;
using Xunit;
using app = aspnetCoreReactTemplate;

namespace Tests.Controller
{
public class Tests
{
// [Fact]
// public void Index_ReturnsAViewResult_WithAListOfBrainstormSessions()
// {
// var controller = new app.Controllers.ContactsController(null);
// var result = (IEnumerable<app.Models.Contact>)controller.Get();

// Assert.NotEqual(result.Count(), 0);
// }
}
}
14 changes: 14 additions & 0 deletions api.test/ControllerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Xunit;

namespace Tests
{
public class ControllerTests
{
[Fact]
public void Test1()
{
var contact = new aspnetCoreReactTemplate.Models.Contact();
Assert.True(string.IsNullOrEmpty(contact.email));
}
}
}
7 changes: 7 additions & 0 deletions api.test/NuGet.Config
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="NuGet" value="https://api.nuget.org/v3/index.json" />
<add key="aspnet-contrib" value="https://www.myget.org/F/aspnet-contrib/api/v3/index.json" />
</packageSources>
</configuration>
19 changes: 19 additions & 0 deletions api.test/Unit/Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Xunit;
using app = aspnetCoreReactTemplate;

namespace Tests.Unit
{
public class Tests
{
[Fact]
public void TestNewContactProperties()
{
var contact = new app.Models.Contact();

Assert.True(string.IsNullOrEmpty(contact.lastName));
Assert.True(string.IsNullOrEmpty(contact.firstName));
Assert.True(string.IsNullOrEmpty(contact.email));
Assert.True(string.IsNullOrEmpty(contact.phone));
}
}
}
20 changes: 20 additions & 0 deletions api.test/api.test.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
<DebugType>portable</DebugType>
<AssemblyName>api.test</AssemblyName>
<PackageId>api.test</PackageId>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<PackageTargetFallback>$(PackageTargetFallback);dotnet5.4;portable-net451+win8</PackageTargetFallback>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../api/api.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
<PackageReference Include="System.Runtime.Serialization.Primitives" Version="4.3.0" />
<PackageReference Include="xunit" Version="2.2.0" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.0-beta1-build3642" />
</ItemGroup>
</Project>
Loading

0 comments on commit 1a62df8

Please sign in to comment.