├── .github
└── workflows
│ ├── codeql-analysis.yml
│ └── ossar-analysis.yml
├── .gitignore
├── .idea
└── .idea.AspDotnetVueJs
│ └── .idea
│ ├── codeStyles
│ └── codeStyleConfig.xml
│ ├── dictionaries
│ └── highlander.xml
│ ├── encodings.xml
│ ├── indexLayout.xml
│ ├── inspectionProfiles
│ └── Project_Default.xml
│ ├── jsLibraryMappings.xml
│ ├── jsLinters
│ └── eslint.xml
│ ├── misc.xml
│ ├── reactTemplatesPlugin.xml
│ ├── vagrant.xml
│ └── vcs.xml
├── AspDotnetVueJs.nuspec
├── AspDotnetVueJs.sln
├── CodeStyle.xml
├── LICENSE
├── README.md
├── appveyor.yml
└── content
├── .babelrc
├── .dockerignore
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .template.config
└── template.json
├── AspDotnetVueJs.csproj
├── ClientApp
├── app.js
├── build
│ ├── base.config.js
│ ├── publishingLoader.html
│ └── webpack.config.js
├── components
│ ├── App.vue
│ ├── elements
│ │ ├── CounterDisplay.vue
│ │ └── DataTable.vue
│ ├── layouts
│ │ ├── CardContainer.vue
│ │ ├── HeaderLayout.vue
│ │ └── ViewLayout.vue
│ └── views
│ │ ├── Counter.vue
│ │ ├── Home.vue
│ │ ├── NotFound.vue
│ │ └── WeatherForecast.vue
├── favicon.ico
├── icons.js
├── index.html
├── models
│ └── WeatherForecast.js
├── router
│ ├── index.js
│ └── routes.js
├── services
│ └── forecast-service.js
├── static
│ └── ie-polyfill.min.js
├── store
│ ├── index.js
│ ├── modules
│ │ ├── counter.js
│ │ └── weather.js
│ └── mutation-types.js
├── styles
│ ├── base
│ │ ├── global.sass
│ │ └── normalize.scss
│ ├── main.sass
│ ├── tools
│ │ └── variables.sass
│ └── vendors
│ │ └── element.scss
└── utils
│ └── helpers
│ ├── functions.js
│ ├── notification.js
│ ├── table-column-composer.js
│ └── vuex-logger.js
├── Controllers
└── WeatherController.cs
├── Dockerfile
├── Extensions
└── ServiceCollectionExtensions.cs
├── Models
└── WeatherForecast.cs
├── Program.cs
├── Properties
└── launchSettings.json
├── Providers
├── IWeatherProvider.cs
└── WeatherProviderFake.cs
├── Startup.cs
├── appsettings.Development.json
├── appsettings.json
├── package.json
└── wwwroot
└── .gitkeep
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ master ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ master ]
20 | schedule:
21 | - cron: '17 15 * * 0'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: [ 'csharp', 'javascript' ]
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
37 | # Learn more:
38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
39 |
40 | steps:
41 | - name: Checkout repository
42 | uses: actions/checkout@v2
43 |
44 | # Initializes the CodeQL tools for scanning.
45 | - name: Initialize CodeQL
46 | uses: github/codeql-action/init@v1
47 | with:
48 | languages: ${{ matrix.language }}
49 | # If you wish to specify custom queries, you can do so here or in a config file.
50 | # By default, queries listed here will override any specified in a config file.
51 | # Prefix the list here with "+" to use these queries and those in the config file.
52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
53 |
54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
55 | # If this step fails, then you should remove it and run the build manually (see below)
56 | - name: Autobuild
57 | uses: github/codeql-action/autobuild@v1
58 |
59 | # ℹ️ Command-line programs to run using the OS shell.
60 | # 📚 https://git.io/JvXDl
61 |
62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
63 | # and modify them (or add more) to build your code if your project
64 | # uses a compiled language
65 |
66 | #- run: |
67 | # make bootstrap
68 | # make release
69 |
70 | - name: Perform CodeQL Analysis
71 | uses: github/codeql-action/analyze@v1
72 |
--------------------------------------------------------------------------------
/.github/workflows/ossar-analysis.yml:
--------------------------------------------------------------------------------
1 | # This workflow integrates a collection of open source static analysis tools
2 | # with GitHub code scanning. For documentation, or to provide feedback, visit
3 | # https://github.com/github/ossar-action
4 | name: OSSAR
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | # The branches below must be a subset of the branches above
11 | branches: [ master ]
12 | schedule:
13 | - cron: '24 16 * * 6'
14 |
15 | jobs:
16 | OSSAR-Scan:
17 | # OSSAR runs on windows-latest.
18 | # ubuntu-latest and macos-latest support coming soon
19 | runs-on: windows-latest
20 |
21 | steps:
22 | - name: Checkout repository
23 | uses: actions/checkout@v2
24 |
25 | # Ensure a compatible version of dotnet is installed.
26 | # The [Microsoft Security Code Analysis CLI](https://aka.ms/mscadocs) is built with dotnet v3.1.201.
27 | # A version greater than or equal to v3.1.201 of dotnet must be installed on the agent in order to run this action.
28 | # GitHub hosted runners already have a compatible version of dotnet installed and this step may be skipped.
29 | # For self-hosted runners, ensure dotnet version 3.1.201 or later is installed by including this action:
30 | # - name: Install .NET
31 | # uses: actions/setup-dotnet@v1
32 | # with:
33 | # dotnet-version: '3.1.x'
34 |
35 | # Run open source static analysis tools
36 | - name: Run OSSAR
37 | uses: github/ossar-action@v1
38 | id: ossar
39 |
40 | # Upload results to the Security tab
41 | - name: Upload OSSAR results
42 | uses: github/codeql-action/upload-sarif@v1
43 | with:
44 | sarif_file: ${{ steps.ossar.outputs.sarifFile }}
45 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | npm-debug.log
4 |
5 | VueJs.Picnic.CSharp/wwwroot/**/*
6 | VueJs.PicnicTable.CSharp/wwwroot/**/*
7 |
8 | ## Personal temp folder
9 | tmp/**/*
10 | pack_template/**/*
11 |
12 | ## Others
13 | # /Properties/launchSettings.json
14 |
15 | ## Ignore Visual Studio temporary files, build results, and
16 | ## files generated by popular Visual Studio add-ons.
17 |
18 | # User-specific files
19 | *.suo
20 | *.user
21 | *.userosscache
22 | *.sln.docstates
23 |
24 | # User-specific files (MonoDevelop/Xamarin Studio)
25 | *.userprefs
26 |
27 | # Build results
28 | [Dd]ebug/
29 | [Dd]ebugPublic/
30 | [Rr]elease/
31 | [Rr]eleases/
32 | x64/
33 | x86/
34 | bld/
35 | bin/
36 | Bin/
37 | obj/
38 | Obj/
39 |
40 | # Visual Studio 2015 cache/options directory
41 | .vs/
42 | /wwwroot/dist/**
43 |
44 | # Workaround for https://github.com/aspnet/JavaScriptServices/issues/235
45 | !/wwwroot/dist/_placeholder.txt
46 |
47 | /yarn.lock
48 |
49 | # MSTest test Results
50 | [Tt]est[Rr]esult*/
51 | [Bb]uild[Ll]og.*
52 |
53 | # NUNIT
54 | *.VisualState.xml
55 | TestResult.xml
56 |
57 | # Build Results of an ATL Project
58 | [Dd]ebugPS/
59 | [Rr]eleasePS/
60 | dlldata.c
61 |
62 | # DNX
63 | project.lock.json
64 | artifacts/
65 |
66 | *_i.c
67 | *_p.c
68 | *_i.h
69 | *.ilk
70 | *.meta
71 | *.obj
72 | *.pch
73 | *.pdb
74 | *.pgc
75 | *.pgd
76 | *.rsp
77 | *.sbr
78 | *.tlb
79 | *.tli
80 | *.tlh
81 | *.tmp
82 | *.tmp_proj
83 | *.log
84 | *.vspscc
85 | *.vssscc
86 | .builds
87 | *.pidb
88 | *.svclog
89 | *.scc
90 |
91 | # Chutzpah Test files
92 | _Chutzpah*
93 |
94 | # Visual C++ cache files
95 | ipch/
96 | *.aps
97 | *.ncb
98 | *.opendb
99 | *.opensdf
100 | *.sdf
101 | *.cachefile
102 |
103 | # Visual Studio profiler
104 | *.psess
105 | *.vsp
106 | *.vspx
107 | *.sap
108 |
109 | # TFS 2012 Local Workspace
110 | $tf/
111 |
112 | # Guidance Automation Toolkit
113 | *.gpState
114 |
115 | # ReSharper is a .NET coding add-in
116 | _ReSharper*/
117 | *.[Rr]e[Ss]harper
118 | *.DotSettings.user
119 |
120 | # JustCode is a .NET coding add-in
121 | .JustCode
122 |
123 | # TeamCity is a build add-in
124 | _TeamCity*
125 |
126 | # DotCover is a Code Coverage Tool
127 | *.dotCover
128 |
129 | # NCrunch
130 | _NCrunch_*
131 | .*crunch*.local.xml
132 | nCrunchTemp_*
133 |
134 | # MightyMoose
135 | *.mm.*
136 | AutoTest.Net/
137 |
138 | # Web workbench (sass)
139 | .sass-cache/
140 |
141 | # Installshield output folder
142 | [Ee]xpress/
143 |
144 | # DocProject is a documentation generator add-in
145 | DocProject/buildhelp/
146 | DocProject/Help/*.HxT
147 | DocProject/Help/*.HxC
148 | DocProject/Help/*.hhc
149 | DocProject/Help/*.hhk
150 | DocProject/Help/*.hhp
151 | DocProject/Help/Html2
152 | DocProject/Help/html
153 |
154 | # Click-Once directory
155 | publish/
156 |
157 | # Publish Web Output
158 | *.[Pp]ublish.xml
159 | *.azurePubxml
160 | # TODO: Comment the next line if you want to checkin your web deploy settings
161 | # but database connection strings (with potential passwords) will be unencrypted
162 | *.pubxml
163 | *.publishproj
164 |
165 | # NuGet Packages
166 | *.nupkg
167 | # The packages folder can be ignored because of Package Restore
168 | **/packages/*
169 | # except build/, which is used as an MSBuild target.
170 | !**/packages/build/
171 | # Uncomment if necessary however generally it will be regenerated when needed
172 | #!**/packages/repositories.config
173 |
174 | # Microsoft Azure Build Output
175 | csx/
176 | *.build.csdef
177 |
178 | # Microsoft Azure Emulator
179 | ecf/
180 | rcf/
181 |
182 | # Microsoft Azure ApplicationInsights config file
183 | ApplicationInsights.config
184 |
185 | # Windows Store app package directory
186 | AppPackages/
187 | BundleArtifacts/
188 |
189 | # Visual Studio cache files
190 | # files ending in .cache can be ignored
191 | *.[Cc]ache
192 | # but keep track of directories ending in .cache
193 | !*.[Cc]ache/
194 |
195 | # Others
196 | ClientBin/
197 | ~$*
198 | *~
199 | *.dbmdl
200 | *.dbproj.schemaview
201 | *.pfx
202 | *.publishsettings
203 | orleans.codegen.cs
204 |
205 | # Workaround for https://github.com/aspnet/JavaScriptServices/issues/235
206 | /node_modules/**
207 | !/node_modules/_placeholder.txt
208 |
209 | # RIA/Silverlight projects
210 | Generated_Code/
211 |
212 | # Backup & report files from converting an old project file
213 | # to a newer Visual Studio version. Backup files are not needed,
214 | # because we have git ;-)
215 | _UpgradeReport_Files/
216 | Backup*/
217 | UpgradeLog*.XML
218 | UpgradeLog*.htm
219 |
220 | # SQL Server files
221 | *.mdf
222 | *.ldf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 |
238 | # Visual Studio 6 build log
239 | *.plg
240 |
241 | # Visual Studio 6 workspace options file
242 | *.opt
243 |
244 | # Visual Studio LightSwitch build output
245 | **/*.HTMLClient/GeneratedArtifacts
246 | **/*.DesktopClient/GeneratedArtifacts
247 | **/*.DesktopClient/ModelManifest.xml
248 | **/*.Server/GeneratedArtifacts
249 | **/*.Server/ModelManifest.xml
250 | _Pvt_Extensions
251 |
252 | # Paket dependency manager
253 | .paket/paket.exe
254 |
255 | # FAKE - F# Make
256 | .fake/
257 |
258 | .vscode/
259 | /content/wwwroot
260 |
--------------------------------------------------------------------------------
/.idea/.idea.AspDotnetVueJs/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/.idea.AspDotnetVueJs/.idea/dictionaries/highlander.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | paiva
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/.idea.AspDotnetVueJs/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/.idea.AspDotnetVueJs/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/.idea.AspDotnetVueJs/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/.idea.AspDotnetVueJs/.idea/jsLibraryMappings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/.idea.AspDotnetVueJs/.idea/jsLinters/eslint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/.idea.AspDotnetVueJs/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/.idea.AspDotnetVueJs/.idea/reactTemplatesPlugin.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/.idea.AspDotnetVueJs/.idea/vagrant.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/.idea.AspDotnetVueJs/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/AspDotnetVueJs.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | aspdotnet-vuejs
5 | Highlander Paiva
6 | hvpaiva
7 |
8 | Template for ASP.NET Core 2.2 WebApi + Vue.js Client app with webpack and hot reloading
9 |
10 |
11 |
12 |
13 | {{version}}
14 |
15 | https://github.com/hvpaiva/aspdotnet-vuejs
16 | https://github.com/hvpaiva/aspdotnet-vuejs/blob/master/LICENSE
17 | web template vuejs aspnet dotnet webapi vuex elementui
18 |
19 |
20 |
24 |
25 |
--------------------------------------------------------------------------------
/AspDotnetVueJs.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspDotnetVueJs", "content\AspDotnetVueJs.csproj", "{8F165E5B-8BA1-4858-B79F-C2FE04050F42}"
4 | EndProject
5 | Global
6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
7 | Debug|Any CPU = Debug|Any CPU
8 | Release|Any CPU = Release|Any CPU
9 | EndGlobalSection
10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
11 | {8F165E5B-8BA1-4858-B79F-C2FE04050F42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
12 | {8F165E5B-8BA1-4858-B79F-C2FE04050F42}.Debug|Any CPU.Build.0 = Debug|Any CPU
13 | {8F165E5B-8BA1-4858-B79F-C2FE04050F42}.Release|Any CPU.ActiveCfg = Release|Any CPU
14 | {8F165E5B-8BA1-4858-B79F-C2FE04050F42}.Release|Any CPU.Build.0 = Release|Any CPU
15 | EndGlobalSection
16 | EndGlobal
17 |
--------------------------------------------------------------------------------
/CodeStyle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
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 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | GROUP_PROPERTY_FIELD_WITH_GETTER_SETTER
61 | KEEP
62 |
63 |
64 | TREAT_LAMBDA_INITIALIZED_FIELDS_AS_METHODS
65 | KEEP
66 |
67 |
68 | OVERRIDDEN_METHODS
69 | KEEP
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Highlander Paiva
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.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://www.nuget.org/packages/aspdotnet-vuejs/)
2 | [](https://ci.appveyor.com/project/hvpaiva/aspdotnet-vuejs/branch/master)
3 |
4 | #
Dotnet Core 3.0 + VueJs
5 |
6 | This project main idea is to provide an easy way to start a new project using .Net Core WebAPI in server side and VueJs in the client side. For this goal, we setup the main configuration to enable this integration using some utilities as hot reloading and some frontend libraries as Element-UI and FontAwesome.
7 |
8 | Our goal is to provide a simple SPA with minimum dependencies and performance issues. The VueJs is configured with Vuex and Vue Router, but this can be removed if you don't feel it meets your requirement. The same goes for the component library. In this template, we also provide examples with the main functionalits.
9 |
10 | This template is inspired and adapted from [Mark Pieszak's project](https://github.com/MarkPieszak/aspnetcore-Vue-starter) and [Nordes' project](https://github.com/Nordes/HoNoSoFt.DotNet.Web.Spa.ProjectTemplates).
11 |
12 | # Table Of Contents
13 | - [Table Of Contents](#table-of-contents)
14 | - [Technology inside](#technology-inside)
15 | - [Installation](#installation)
16 | - [Update your installation?](#update-your-installation)
17 | - [Uninstallation](#uninstallation)
18 | - [Develop](#develop)
19 | - [Publishing your application](#publishing-your-application)
20 | - [Before publishing](#before-publishing)
21 | - [Publishing](#publishing)
22 | - [Extra if you use NginX](#extra-if-you-use-nginx)
23 | - [Docker](#docker)
24 | - [Docker - Build yourself](#docker---build-yourself)
25 | - [Some Automation](#some-automation)
26 | - [Kestrel serving using Gzip compression](#kestrel-serving-using-gzip-compression)
27 | - [Base components](#base-components)
28 | - [Webpack build](#webpack-build)
29 | - [Vuex](#vuex)
30 | - [Look'n feel](#lookn-feel)
31 | - [Element UI](#element-ui)
32 |
38 | - [License](#license)
39 |
40 |
41 | ## Technology inside
42 |
43 | - .Net Core 3.0
44 | - VueJs
45 | - Webpack 4
46 | - Element UI
47 | - Babel
48 | - Vuex
49 | - Vue-router
50 | - Eslint (airbnb + vuejs-recomended)
51 | - Swagger *
52 | - Vue-i18n *
53 | - Vee-validate *
54 | - LiveReload *
55 |
56 | \* Work In Progress. Available in future releases.
57 |
58 | ## Installation
59 | To download and install the template, just type:
60 |
61 | ```bash
62 | > dotnet new -i aspdotnet-vuejs
63 | ```
64 |
65 | > You can see a list of installed templates by using the `dotnet new -l` command.
66 |
67 | Then to create your project you will simply use the command bellow in the directory:
68 |
69 | ```bash
70 | > dotnet new vue
71 | ```
72 |
73 | This will automatically run `dotnet restore`. But it can be changed in template configurations.
74 | See `dotnet new vue -h` before using the previous command.
75 |
76 | > The solution and project name will be the name of the directory.
77 |
78 | ### Update your installation
79 | To update your installation, you will just need to repeat the installation process.
80 | As long as the version number are not equals, you won't have any unexpected behaviour.
81 |
82 | ### Uninstallation
83 |
84 | Type the following command from the shell:
85 |
86 | ```bash
87 | > dotnet new -u aspdotnet-vuejs
88 | ```
89 |
90 | ## Develop
91 |
92 | To start developing your application, just use the .Net CLI command:
93 |
94 | ```bash
95 | > dotnet run YourAplication.csproj
96 | ```
97 |
98 | > You can just type `dotnet run` in the project directory or configure your IDE to run.
99 | > In this last case just don't forget to pass the `ASPNETCORE_ENVIRONMENT=Development` environment variable.
100 |
101 | This will also run all node dependencies like `npm i`.
102 |
103 | > The application will be started in _Development_ mode with hot reloading
104 | > enabled at `https://localhost:5001` and `http://localhost:5000`.
105 |
106 | ## Publishing your application
107 | ### Before publishing
108 | You need to ensure that your wwwroot **is empty** before starting the process.
109 |
110 | ### Publishing
111 | Simply use the normal way of publishing using .Net Core CLI
112 |
113 | ```bash
114 | > dotnet publish YourProject.csproj -c release -o ./publish/
115 | ```
116 |
117 | > You can also add all the other parameter from the dotnet cli.
118 | > Please [visit the MSDN site](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?tabs=netcore21) to know more about it.
119 |
120 | This will do a rebuild of your project and then after it will use the special target to rebuild your client (vuejs) in production mode.
121 |
122 | ### Extra if you use NginX
123 | If you are publishing behind a NginX server, you might need more configuration.
124 |
125 | Let's say you have your base site `http://www.example.com` and that in your NginX configuration you would like to have your dotnet app within `http://www.example.com/myApp`. You will need in such a scenario to set the base uri for the index.html. Instead of doing that manually between development and production, you have the file `./build/base.prod.config.js` which contains a possible override.
126 |
127 | Simply set your override like the following:
128 |
129 | ```javascript
130 | module.exports = {
131 | baseUriPath: '/myApp/'
132 | }
133 | ```
134 |
135 | When you will publish next time, the path will then be taken into account and it will sets automatically the base uri path.
136 |
137 | ## Docker
138 | The project already add some [docker container](https://hub.docker.com/r/hvpaiva/aspdotnet-vuejs/) available through the Docker Hub. You can pull the image if you want. It will make the sample available locally. The image is using the Alpine version so it only uses a small footprint.
139 |
140 | ### Docker - Build yourself
141 | Since containers in docker are quite popular, a `Dockerfile` is also included within the template root folder. Don't forget the `.dockerignore` where some files are being ignored in order to avoid some unwanted file to be copied before publishing.
142 |
143 | > Ensure that you have Docker installed.
144 |
145 | ## Some Automation
146 |
147 | ### Kestrel serving using Gzip compression
148 | The code is having built-in the Gzip compression on the HTTPs. It's good to use that code especially if you use Kestrel. Otherwise, if you use IIS, please remove that specific code found in the `Startup.cs`. Normally, IIS offer it's own compression module which is more performant.
149 |
150 | ### Base components
151 | There's some automation regarding the `Components` available within _./ClientApp/components/**/*_.
152 | All the file starting with the keyword `base` are going to be declared as global and the name of the component to be used anywhere will be defined in _snake case_ without the `base` keyword.
153 |
154 | **Example:** `baseHelloWorld` will be registered as `hello-world` and you are going to be able to use it in your Vue Template.
155 |
156 | ```html
157 |
158 |
159 | works!
160 |
161 |
162 | ```
163 |
164 | > There's a real example within the project for the card component for each page. The name of the component is `baseCard.vue`.
165 |
166 | ### Webpack build
167 | The css is not generated while you are in development mode. They are going to be created only when you will use the `dotnet publish` command or as an alternative, you can also go and type `npm run build -- --prod` which will launch the production build with the minification and extraction of the files.
168 |
169 | > **Important:** Currently, webpack clean the entire wwwroot folder within the .Net project. So, if you have static files, move them within the _./ClientApp/static/_ folder.
170 |
171 | ## Look'n feel
172 |
173 | ### Element UI
174 | To help make the development faster, we provide the installation of the component library [Element-UI](http://element.eleme.io/#/en-US). The documentation of this library can be founded in his site.
175 |
176 | > It can be removed normally in `main.js` if you don't need.
177 |
178 |
179 |
203 |
204 | ## License
205 | 
206 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | image: Visual Studio 2017
2 |
3 | version: 3.0.{build}
4 |
5 | install:
6 | # - ps: (new-object Net.WebClient).DownloadString("https://raw.github.com/madskristensen/ExtensionScripts/master/AppVeyor/vsix.ps1") | iex
7 |
8 | before_build:
9 | - ps: write-host Build v. $env:appveyor_build_version
10 | - nuget restore
11 | # - ps: Vsix-IncrementVsixVersion | Vsix-UpdateBuildVersion
12 |
13 | dotnet_csproj:
14 | patch: true
15 | file: '**\*.csproj'
16 | version: '{version}'
17 | package_version: '{version}'
18 | assembly_version: '{version}'
19 | file_version: '{version}'
20 | informational_version: '{version}'
21 |
22 | build_script:
23 | - msbuild /p:configuration=Release /p:DeployExtension=false /p:ZipPackageCompressionLevel=normal /v:m
24 | - ps: (Get-Content AspDotnetVueJs.nuspec).replace('{{version}}', $env:appveyor_build_version ) | Set-Content AspDotnetVueJs.nuspec
25 | - nuget pack
26 | #Nuget auto-packaging can also be done cref: https://www.appveyor.com/docs/deployment/nuget/
27 |
28 | after_build:
29 | - ps: Get-ChildItem .\*.nupkg | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
30 | - ps: Get-ChildItem .\*.nupkg | % { dotnet new -i $_.FullName }
31 | - ps: mkdir demo.dotnetvue
32 | - ps: cd demo.dotnetvue
33 | - ps: dotnet new vuejs
34 | - npm install
35 | - ps: dotnet publish demo.dotnetvue.csproj -c release -r win-x86 -o ./output --self-contained
36 |
37 | artifacts:
38 | - path: demo.dotnetvue\output
39 | name: dotnet-vuejs
40 |
41 |
--------------------------------------------------------------------------------
/content/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-env"
4 | ],
5 | "plugins": [
6 | "@babel/plugin-transform-runtime",
7 | "@babel/plugin-transform-async-to-generator",
8 | "@babel/plugin-syntax-dynamic-import",
9 | "@babel/plugin-syntax-import-meta",
10 | "@babel/plugin-proposal-class-properties",
11 | "@babel/plugin-proposal-json-strings",
12 | [
13 | "@babel/plugin-proposal-decorators",
14 | {
15 | "legacy": true
16 | }
17 | ],
18 | "@babel/plugin-proposal-function-sent",
19 | "@babel/plugin-proposal-export-namespace-from",
20 | "@babel/plugin-proposal-numeric-separator",
21 | "@babel/plugin-proposal-throw-expressions"
22 | ],
23 | "comments": false
24 | }
25 |
--------------------------------------------------------------------------------
/content/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | obj/
3 | bin/
4 |
5 | wwwroot/**
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | .dockerignore
14 |
--------------------------------------------------------------------------------
/content/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | charset = utf-8
3 | end_of_line = lf
4 | trim_trailing_whitespace = false
5 | insert_final_newline = false
6 | indent_style = space
7 | indent_size = 4
8 |
9 | # Microsoft .NET properties
10 | csharp_new_line_before_members_in_object_initializers = false
11 | csharp_preferred_modifier_order = public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
12 | csharp_style_var_elsewhere = true:hint
13 | csharp_style_var_for_built_in_types = true:hint
14 | csharp_style_var_when_type_is_apparent = true:hint
15 | dotnet_style_predefined_type_for_locals_parameters_members = true:hint
16 | dotnet_style_predefined_type_for_member_access = true:hint
17 | dotnet_style_qualification_for_event = false:warning
18 | dotnet_style_qualification_for_field = false:warning
19 | dotnet_style_qualification_for_method = false:warning
20 | dotnet_style_qualification_for_property = false:warning
21 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:hint
22 |
23 | # ReSharper properties
24 | resharper_autodetect_indent_settings = true
25 | resharper_use_indent_from_vs = false
26 |
27 | # ReSharper inspection severities
28 | resharper_bad_attribute_brackets_spaces_highlighting = warning
29 | resharper_bad_braces_spaces_highlighting = warning
30 | resharper_bad_colon_spaces_highlighting = warning
31 | resharper_bad_comma_spaces_highlighting = warning
32 | resharper_bad_control_braces_line_breaks_highlighting = warning
33 | resharper_bad_declaration_braces_indent_highlighting = warning
34 | resharper_bad_declaration_braces_line_breaks_highlighting = warning
35 | resharper_bad_empty_braces_line_breaks_highlighting = warning
36 | resharper_bad_expression_braces_indent_highlighting = warning
37 | resharper_bad_expression_braces_line_breaks_highlighting = warning
38 | resharper_bad_generic_brackets_spaces_highlighting = warning
39 | resharper_bad_indent_highlighting = warning
40 | resharper_bad_linq_line_breaks_highlighting = warning
41 | resharper_bad_list_line_breaks_highlighting = warning
42 | resharper_bad_member_access_spaces_highlighting = warning
43 | resharper_bad_namespace_braces_indent_highlighting = warning
44 | resharper_bad_parens_line_breaks_highlighting = warning
45 | resharper_bad_parens_spaces_highlighting = warning
46 | resharper_bad_preprocessor_indent_highlighting = warning
47 | resharper_bad_semicolon_spaces_highlighting = warning
48 | resharper_bad_spaces_after_keyword_highlighting = warning
49 | resharper_bad_square_brackets_spaces_highlighting = warning
50 | resharper_bad_switch_braces_indent_highlighting = warning
51 | resharper_bad_symbol_spaces_highlighting = warning
52 | resharper_class_never_instantiated_global_highlighting = none
53 | resharper_incorrect_blank_lines_near_braces_highlighting = warning
54 | resharper_missing_blank_lines_highlighting = warning
55 | resharper_missing_indent_highlighting = warning
56 | resharper_missing_linebreak_highlighting = warning
57 | resharper_missing_space_highlighting = warning
58 | resharper_multiple_spaces_highlighting = warning
59 | resharper_multiple_statements_on_one_line_highlighting = warning
60 | resharper_multiple_type_members_on_one_line_highlighting = warning
61 | resharper_outdent_is_off_prev_level_highlighting = warning
62 | resharper_redundant_blank_lines_highlighting = warning
63 | resharper_redundant_linebreak_highlighting = warning
64 | resharper_redundant_space_highlighting = warning
65 | resharper_tabs_and_spaces_mismatch_highlighting = warning
66 | resharper_tabs_outside_indent_highlighting = warning
67 | resharper_unused_member_global_highlighting = none
68 | resharper_unused_parameter_global_highlighting = none
69 | resharper_web_config_module_not_resolved_highlighting = warning
70 | resharper_web_config_type_not_resolved_highlighting = warning
71 | resharper_web_config_wrong_module_highlighting = warning
72 | resharper_wrong_indent_size_highlighting = warning
73 |
74 | [{*.sht, *.html, *.shtm, *.shtml, *.ng, *.htm}]
75 | indent_style = tab
76 | tab_width = 4
77 |
78 | [*.svg]
79 | indent_style = tab
80 | tab_width = 4
81 |
82 | [{.babelrc, .stylelintrc, jest.config, *.uplugin, *.uproject, *.bowerrc, *.jsb3, *.jsb2, *.json}]
83 | indent_style = tab
84 | tab_width = 4
85 |
86 | [{*.targets, *.overridetasks, *.tasks}]
87 | indent_style = tab
88 | tab_width = 4
89 |
90 | [{*.csproj, *.ccproj, *.androidproj}]
91 | indent_style = tab
92 | tab_width = 4
93 |
94 | [{*.vcxitems, *.vcxproj}]
95 | indent_style = tab
96 | tab_width = 4
97 |
98 | [*.css]
99 | indent_style = tab
100 | tab_width = 4
101 |
102 | [*.less]
103 | indent_style = space
104 | indent_size = 2
105 |
106 | [*.sass]
107 | indent_style = tab
108 | tab_width = 4
109 |
110 | [*.scss]
111 | indent_style = tab
112 | tab_width = 4
113 |
114 | [{*.cjs, *.js}]
115 | indent_style = tab
116 | tab_width = 4
117 |
118 | [{*.ats, *.ts}]
119 | indent_style = tab
120 | tab_width = 4
121 |
122 | [{tsconfig.lib.json, tsconfig.spec.json, tsconfig.app.json, tsconfig.json, tsconfig.e2e.json}]
123 | indent_style = tab
124 | tab_width = 4
125 |
126 | [*.js.map]
127 | indent_style = tab
128 | tab_width = 4
129 |
130 | [{*.pug, *.jade}]
131 | indent_style = tab
132 | tab_width = 4
133 |
134 | [*.vue]
135 | indent_style = tab
136 | tab_width = 4
137 |
138 | [{*.yml, *.yaml}]
139 | indent_style = space
140 | indent_size = 2
141 |
142 | [.eslintrc]
143 | indent_style = tab
144 | tab_width = 4
145 |
146 | [*.{appxmanifest, asax, ascx, aspx, build, config, cs, cshtml, csproj, dbml, discomap, dtd, fs, fsi, fsscript, fsx, htm, html, jsproj, lsproj, master, ml, mli, njsproj, nuspec, proj, props, razor, resw, resx, skin, StyleCop, targets, tasks, vb, vbproj, xaml, xamlx, xml, xoml, xsd}]
147 | indent_style = space
148 | indent_size = 4
149 | tab_width = 4
150 |
--------------------------------------------------------------------------------
/content/.eslintignore:
--------------------------------------------------------------------------------
1 | ######################################################
2 | # https://eslint.org/docs/user-guide/configuring
3 | ######################################################
4 | # /node_modules/* and /bower_components/* in the project root are ignored by default
5 | # Ignore built files except build/index.js
6 | /ClientApp/static/**/*.js
7 |
8 | # !build/index.js ... if i would like to ignore all except that... then it's the way
9 |
--------------------------------------------------------------------------------
/content/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parserOptions: {
4 | parser: "babel-eslint",
5 | sourceType: "module"
6 | },
7 | "extends": [
8 | "airbnb",
9 | "plugin:vue/recommended"
10 | ],
11 | plugins: [
12 | 'vue'
13 | ],
14 | 'rules': {
15 | 'arrow-parens': 0,
16 | 'generator-star-spacing': 0,
17 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
18 | 'no-console': process.env.NODE_ENV === 'production' ? 2 : 0,
19 | 'comma-dangle': ['error', 'never'],
20 | 'no-shadow': 0,
21 | 'no-param-reassign': ["error", { "props": true, "ignorePropertyModificationsFor": ["state"] }],
22 | 'object-curly-newline': ["error", { "consistent": true }],
23 | 'unicode-bom': 0,
24 | 'import/no-unresolved': 0,
25 | 'vue/script-indent': ['error', "tab", { 'baseIndent': 0 , "switchCase": 1}],
26 | 'vue/html-indent': ['error', "tab", { 'baseIndent': 1 }],
27 | 'no-tabs': 0,
28 | "indent": ["error", "tab", { "SwitchCase": 1 }],
29 | "no-mixed-operators": 0,
30 | "import/prefer-default-export": 0,
31 | "no-use-before-define": 0,
32 | "no-plusplus": 0,
33 | "no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
34 | }
35 | };
36 |
--------------------------------------------------------------------------------
/content/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | npm-debug.log
4 |
5 | # /Properties/launchSettings.json
6 |
7 | package-lock.json
8 |
9 | ## Ignore Visual Studio temporary files, build results, and
10 | ## files generated by popular Visual Studio add-ons.
11 |
12 | # User-specific files
13 | *.suo
14 | *.user
15 | *.userosscache
16 | *.sln.docstates
17 |
18 | # User-specific files (MonoDevelop/Xamarin Studio)
19 | *.userprefs
20 |
21 | # Build results
22 | [Dd]ebug/
23 | [Dd]ebugPublic/
24 | [Rr]elease/
25 | [Rr]eleases/
26 | x64/
27 | x86/
28 | bld/
29 | bin/
30 | Bin/
31 | obj/
32 | Obj/
33 |
34 | # Visual Studio 2015 cache/options directory
35 | .vs/
36 | /wwwroot/dist/**
37 |
38 | # Workaround for https://github.com/aspnet/JavaScriptServices/issues/235
39 | !/wwwroot/dist/_placeholder.txt
40 |
41 | /yarn.lock
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUNIT
48 | *.VisualState.xml
49 | TestResult.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # DNX
57 | project.lock.json
58 | artifacts/
59 |
60 | *_i.c
61 | *_p.c
62 | *_i.h
63 | *.ilk
64 | *.meta
65 | *.obj
66 | *.pch
67 | *.pdb
68 | *.pgc
69 | *.pgd
70 | *.rsp
71 | *.sbr
72 | *.tlb
73 | *.tli
74 | *.tlh
75 | *.tmp
76 | *.tmp_proj
77 | *.log
78 | *.vspscc
79 | *.vssscc
80 | .builds
81 | *.pidb
82 | *.svclog
83 | *.scc
84 |
85 | # Chutzpah Test files
86 | _Chutzpah*
87 |
88 | # Visual C++ cache files
89 | ipch/
90 | *.aps
91 | *.ncb
92 | *.opendb
93 | *.opensdf
94 | *.sdf
95 | *.cachefile
96 |
97 | # Visual Studio profiler
98 | *.psess
99 | *.vsp
100 | *.vspx
101 | *.sap
102 |
103 | # TFS 2012 Local Workspace
104 | $tf/
105 |
106 | # Guidance Automation Toolkit
107 | *.gpState
108 |
109 | # ReSharper is a .NET coding add-in
110 | _ReSharper*/
111 | *.[Rr]e[Ss]harper
112 | *.DotSettings.user
113 |
114 | # JustCode is a .NET coding add-in
115 | .JustCode
116 |
117 | # TeamCity is a build add-in
118 | _TeamCity*
119 |
120 | # DotCover is a Code Coverage Tool
121 | *.dotCover
122 |
123 | # NCrunch
124 | _NCrunch_*
125 | .*crunch*.local.xml
126 | nCrunchTemp_*
127 |
128 | # MightyMoose
129 | *.mm.*
130 | AutoTest.Net/
131 |
132 | # Web workbench (sass)
133 | .sass-cache/
134 |
135 | # Installshield output folder
136 | [Ee]xpress/
137 |
138 | # DocProject is a documentation generator add-in
139 | DocProject/buildhelp/
140 | DocProject/Help/*.HxT
141 | DocProject/Help/*.HxC
142 | DocProject/Help/*.hhc
143 | DocProject/Help/*.hhk
144 | DocProject/Help/*.hhp
145 | DocProject/Help/Html2
146 | DocProject/Help/html
147 |
148 | # Click-Once directory
149 | publish/
150 |
151 | # Publish Web Output
152 | *.[Pp]ublish.xml
153 | *.azurePubxml
154 | # TODO: Comment the next line if you want to checkin your web deploy settings
155 | # but database connection strings (with potential passwords) will be unencrypted
156 | *.pubxml
157 | *.publishproj
158 |
159 | # NuGet Packages
160 | *.nupkg
161 | # The packages folder can be ignored because of Package Restore
162 | **/packages/*
163 | # except build/, which is used as an MSBuild target.
164 | !**/packages/build/
165 | # Uncomment if necessary however generally it will be regenerated when needed
166 | #!**/packages/repositories.config
167 |
168 | # Microsoft Azure Build Output
169 | csx/
170 | *.build.csdef
171 |
172 | # Microsoft Azure Emulator
173 | ecf/
174 | rcf/
175 |
176 | # Microsoft Azure ApplicationInsights config file
177 | ApplicationInsights.config
178 |
179 | # Windows Store app package directory
180 | AppPackages/
181 | BundleArtifacts/
182 |
183 | # Visual Studio cache files
184 | # files ending in .cache can be ignored
185 | *.[Cc]ache
186 | # but keep track of directories ending in .cache
187 | !*.[Cc]ache/
188 |
189 | # Others
190 | ClientBin/
191 | ~$*
192 | *~
193 | *.dbmdl
194 | *.dbproj.schemaview
195 | *.pfx
196 | *.publishsettings
197 | orleans.codegen.cs
198 |
199 | # Workaround for https://github.com/aspnet/JavaScriptServices/issues/235
200 | /node_modules/**
201 | !/node_modules/_placeholder.txt
202 |
203 | # RIA/Silverlight projects
204 | Generated_Code/
205 |
206 | # Backup & report files from converting an old project file
207 | # to a newer Visual Studio version. Backup files are not needed,
208 | # because we have git ;-)
209 | _UpgradeReport_Files/
210 | Backup*/
211 | UpgradeLog*.XML
212 | UpgradeLog*.htm
213 |
214 | # SQL Server files
215 | *.mdf
216 | *.ldf
217 |
218 | # Business Intelligence projects
219 | *.rdl.data
220 | *.bim.layout
221 | *.bim_*.settings
222 |
223 | # Microsoft Fakes
224 | FakesAssemblies/
225 |
226 | # GhostDoc plugin setting file
227 | *.GhostDoc.xml
228 |
229 | # Node.js Tools for Visual Studio
230 | .ntvs_analysis.dat
231 |
232 | # Visual Studio 6 build log
233 | *.plg
234 |
235 | # Visual Studio 6 workspace options file
236 | *.opt
237 |
238 | # Visual Studio LightSwitch build output
239 | **/*.HTMLClient/GeneratedArtifacts
240 | **/*.DesktopClient/GeneratedArtifacts
241 | **/*.DesktopClient/ModelManifest.xml
242 | **/*.Server/GeneratedArtifacts
243 | **/*.Server/ModelManifest.xml
244 | _Pvt_Extensions
245 |
246 | # Paket dependency manager
247 | .paket/paket.exe
248 |
249 | # FAKE - F# Make
250 | .fake/
251 |
252 | .vscode/
253 |
--------------------------------------------------------------------------------
/content/.template.config/template.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/template",
3 | "author": "Highlander Paiva",
4 | "classifications": [ "Web", "WebAPI", "SPA" ],
5 | "groupIdentity": "AspDotnetVueJs",
6 | "identity": "AspDotnetVueJs",
7 | "name": "ASP.NET Core with VueJs",
8 | "preferNameDirectory": true,
9 | "primaryOutputs": [
10 | {
11 | "path": "AspDotnetVueJs.csproj"
12 | }
13 | ],
14 | "shortName": "vue",
15 | "sourceName": "AspDotnetVueJs",
16 | "sources": [
17 | {
18 | "source": "./",
19 | "target": "./",
20 | "exclude": [
21 | ".template.config/**"
22 | ],
23 | "modifiers": [
24 | {
25 | "condition": "(TargetFrameworkOverride == '')",
26 | "exclude": [
27 | "app.config"
28 | ]
29 | },
30 | {
31 | "condition": "(ExcludeLaunchSettings)",
32 | "exclude": [
33 | "Properties/launchSettings.json"
34 | ]
35 | }
36 | ]
37 | }
38 | ],
39 | "symbols": {
40 | "ExcludeLaunchSettings": {
41 | "type": "parameter",
42 | "datatype": "bool",
43 | "defaultValue": "false",
44 | "description": "Whether to exclude launchSettings.json from the generated template."
45 | },
46 | "HttpPort": {
47 | "type": "parameter",
48 | "datatype": "integer",
49 | "description": "Port number to use for the HTTP endpoint in launchSettings.json."
50 | },
51 | "HttpPortGenerated": {
52 | "type": "generated",
53 | "generator": "port"
54 | },
55 | "HttpPortReplacer": {
56 | "type": "generated",
57 | "generator": "coalesce",
58 | "parameters": {
59 | "sourceVariableName": "HttpPort",
60 | "fallbackVariableName": "HttpPortGenerated"
61 | },
62 | "replaces": "8080"
63 | },
64 | "HttpsPort": {
65 | "type": "parameter",
66 | "datatype": "integer",
67 | "description": "Port number to use for the HTTPS endpoint in launchSettings.json. This option is only applicable when the parameter no-https is not used (no-https will be ignored if either IndividualAuth or OrganizationalAuth is used)."
68 | },
69 | "HttpsPortGenerated": {
70 | "type": "generated",
71 | "generator": "port",
72 | "parameters": {
73 | "low": 44300,
74 | "high": 44399
75 | }
76 | },
77 | "HttpsPortReplacer": {
78 | "type": "generated",
79 | "generator": "coalesce",
80 | "parameters": {
81 | "sourceVariableName": "HttpsPort",
82 | "fallbackVariableName": "HttpsPortGenerated"
83 | },
84 | "replaces": "44300"
85 | },
86 | "TargetFrameworkOverride": {
87 | "type": "parameter",
88 | "description": "Overrides the target framework",
89 | "replaces": "TargetFrameworkOverride",
90 | "datatype": "string",
91 | "defaultValue": ""
92 | },
93 | "Framework": {
94 | "type": "parameter",
95 | "description": "The target framework for the project.",
96 | "datatype": "choice",
97 | "choices": [
98 | {
99 | "choice": "netcoreapp2.2",
100 | "description": "Target netcoreapp2.2"
101 | }
102 | ],
103 | "replaces": "netcoreapp2.2",
104 | "defaultValue": "netcoreapp2.2"
105 | },
106 | "HostIdentifier": {
107 | "type": "bind",
108 | "binding": "HostIdentifier"
109 | },
110 | "skipRestore": {
111 | "type": "parameter",
112 | "datatype": "bool",
113 | "description": "If specified, skips the automatic restore of the project on create.",
114 | "defaultValue": "false"
115 | },
116 | "NoHttps": {
117 | "type": "parameter",
118 | "datatype": "bool",
119 | "defaultValue": "false",
120 | "description": "Whether to turn off HTTPS. This option only applies if Individual, IndividualB2C, SingleOrg, or MultiOrg aren't used for --auth."
121 | }
122 | },
123 | "tags": {
124 | "language": "C#",
125 | "type": "project"
126 | },
127 |
128 |
129 | "precedence": 100,
130 | "guids": [
131 | "6B3E8EE8-92E3-41CE-A356-A5F880EEA367"
132 | ],
133 | "postActions": [
134 | {
135 | "condition": "(!skipRestore)",
136 | "description": "Restore NuGet packages required by this project.",
137 | "manualInstructions": [
138 | {
139 | "text": "Run 'dotnet restore'"
140 | }
141 | ],
142 | "actionId": "210D431B-A78B-4D2F-B762-4ED3E3EA9025",
143 | "continueOnError": true
144 | }
145 | ]
146 | }
147 |
--------------------------------------------------------------------------------
/content/AspDotnetVueJs.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0
5 | true
6 | $(DefaultItemExcludes);$(SpaRoot)node_modules\**
7 |
8 |
9 | false
10 | AspDotnetVueJs
11 |
12 |
13 |
14 | true
15 | $(NoWarn);1591
16 |
17 |
18 |
19 | obj\Debug\netcoreapp3.0\AspDotnetVueJs.xml
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | <_ContentIncludedByDefault Remove="wwwroot\dist\0.js" />
42 | <_ContentIncludedByDefault Remove="wwwroot\dist\0.js.map" />
43 | <_ContentIncludedByDefault Remove="wwwroot\dist\1.js" />
44 | <_ContentIncludedByDefault Remove="wwwroot\dist\1.js.map" />
45 | <_ContentIncludedByDefault Remove="wwwroot\dist\fonts\element-icons.2fad952a.woff" />
46 | <_ContentIncludedByDefault Remove="wwwroot\dist\fonts\element-icons.6f0a7632.ttf" />
47 | <_ContentIncludedByDefault Remove="wwwroot\dist\main.js" />
48 | <_ContentIncludedByDefault Remove="wwwroot\dist\main.js.map" />
49 | <_ContentIncludedByDefault Remove="wwwroot\dist\vendor.js" />
50 | <_ContentIncludedByDefault Remove="wwwroot\dist\vendor.js.map" />
51 | <_ContentIncludedByDefault Remove="wwwroot\favicon.ico" />
52 | <_ContentIncludedByDefault Remove="wwwroot\index.html" />
53 | <_ContentIncludedByDefault Remove="wwwroot\static\ie-polyfill.min.js" />
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | %(DistFiles.Identity)
83 | PreserveNewest
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/content/ClientApp/app.js:
--------------------------------------------------------------------------------
1 | // Core imports
2 | import Vue from 'vue';
3 | import upperFirst from 'lodash/upperFirst';
4 | import camelCase from 'lodash/camelCase';
5 | import router from './router/index';
6 | import store from './store';
7 | import App from './components/App';
8 | import { FontAwesomeIcon } from './icons';
9 |
10 | // 3th imports
11 | import { sync } from 'vuex-router-sync';
12 | import axios from 'axios';
13 | import ElementUI from 'element-ui';
14 | import locale from 'element-ui/lib/locale/lang/en';
15 |
16 | // CSS imports
17 | import './styles/main.sass';
18 |
19 | // Configurations
20 | Vue.use(ElementUI, { locale });
21 | Vue.component('icon', FontAwesomeIcon);
22 | Vue.prototype.$http = axios;
23 | sync(store, router);
24 |
25 | // Mode details on: https://vuejs.org/v2/guide/components-registration.html
26 | const requireComponent = require.context(
27 | // The relative path of the components folder
28 | './components',
29 | // Whether or not to look in subfolders
30 | true,
31 | // The regular expression used to match base component filenames
32 | /base[A-Z]\w+\.(vue|js)$/
33 | );
34 |
35 | requireComponent.keys().forEach(fileName => {
36 | // Get component config
37 | const componentConfig = requireComponent(fileName);
38 |
39 | // Get PascalCase name of component
40 | const componentName = upperFirst(
41 | camelCase(
42 | // Strip the leading `./` and extension from the filename
43 | fileName.replace(/base/, '').replace(/^\.\/(.*)\.\w+$/, '$1')
44 | )
45 | );
46 |
47 | // Register component globally
48 | Vue.component(
49 | componentName,
50 | // Look for the component options on `.default`, which will
51 | // exist if the component was exported with `export default`,
52 | // otherwise fall back to module's root.
53 | componentConfig.default || componentConfig
54 | );
55 | });
56 |
57 | new Vue({ // eslint-disable-line
58 | el: '#app',
59 | store,
60 | router,
61 | ...App
62 | });
63 |
--------------------------------------------------------------------------------
/content/ClientApp/build/base.config.js:
--------------------------------------------------------------------------------
1 | const productionConfig = require('../../appsettings.json');
2 | const devConfig = require('../../appsettings.Development.json');
3 |
4 | const environment = process.env.NODE_ENV;
5 | const isProduction = environment === 'production';
6 |
7 | const CurrentEnvironment = isProduction
8 | ? productionConfig
9 | : devConfig;
10 |
11 | const has = Object.prototype.hasOwnProperty;
12 |
13 | module.exports = {
14 |
15 | environment,
16 |
17 | isProduction,
18 |
19 | baseUriPath: has.call(CurrentEnvironment, 'BaseUriPath')
20 | && CurrentEnvironment.BaseUriPath !== ''
21 | ? CurrentEnvironment.BaseUriPath
22 | : '/',
23 |
24 | generateMapFiles: has.call(CurrentEnvironment, 'GenerateMapFiles')
25 | ? CurrentEnvironment.GenerateMapFiles
26 | : false
27 | };
28 |
--------------------------------------------------------------------------------
/content/ClientApp/build/publishingLoader.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Webpack - Building in progress...
4 |
75 |
76 |
77 |
78 |
79 |
80 | Building Frontend...
81 |
86 |
87 |
88 |
89 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/content/ClientApp/build/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const fs = require('fs');
3 | const webpack = require('webpack');
4 | const CopyWebpackPlugin = require('copy-webpack-plugin');
5 | const VueLoaderPlugin = require('vue-loader/lib/plugin');
6 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');
7 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
8 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
9 | const HtmlWebpackPlugin = require('html-webpack-plugin');
10 | const rimraf = require('rimraf');
11 | const BaseConfig = require('./base.config');
12 | const AppConfig = require('../../appsettings');
13 | const LaunchConfig = require('../../Properties/launchSettings');
14 |
15 | const rootDir = path.resolve(__dirname, '../..');
16 |
17 | const bundleOutputDir = path.resolve(rootDir, './wwwroot/dist');
18 |
19 | console.info(`Building for production: ${BaseConfig.isProduction}`);
20 | rimraf.sync(path.resolve(rootDir, 'wwwroot/**/*'), { silent: true });
21 |
22 | if (!BaseConfig.isProduction) {
23 | fs.createReadStream(path.resolve(rootDir, 'ClientApp/build/publishingLoader.html'))
24 | .pipe(fs.createWriteStream(path.resolve(rootDir, 'wwwroot/index.html')));
25 | }
26 |
27 | console.info(BaseConfig);
28 |
29 | module.exports = {
30 | name: 'app',
31 | devServer: {
32 | proxy: {
33 | '^/api': {
34 | target: LaunchConfig.profiles.AspDotnetVueJS.applicationUrl,
35 | ws: true,
36 | changeOrigin: true
37 | }
38 | }
39 | },
40 | mode: BaseConfig.isProduction ? 'production' : 'development',
41 | stats: BaseConfig.isProduction ? 'errors-only' : 'normal',
42 | entry: { main: path.resolve(rootDir, './ClientApp/app.js') },
43 | resolve: {
44 | extensions: ['.js', '.vue'],
45 | alias: {
46 | components: path.resolve(rootDir, './ClientApp/components')
47 | }
48 | },
49 | optimization: {
50 | splitChunks: {
51 | cacheGroups: {
52 | commons: {
53 | chunks: 'initial',
54 | name: 'site',
55 | minChunks: 2,
56 | maxInitialRequests: 5,
57 | minSize: 0
58 | },
59 | vendor: {
60 | test: /node_modules/,
61 | chunks: 'initial',
62 | name: 'vendor',
63 | priority: 10,
64 | enforce: true
65 | }
66 | }
67 | },
68 | minimizer: [
69 | new UglifyJsPlugin(
70 | {
71 | cache: true,
72 | parallel: true,
73 | sourceMap: !BaseConfig.isProduction
74 | }
75 | ),
76 | new OptimizeCSSAssetsPlugin({})
77 | ],
78 | nodeEnv: BaseConfig.isProduction ? 'production' : 'development'
79 | },
80 | output: {
81 | path: path.resolve(rootDir, './wwwroot/dist'),
82 | filename: !BaseConfig.isProduction ? '[name].js' : '[name].[hash].js',
83 | // publicPath: In production we don't use webpack hot reload, so it should be alright.
84 | // the usage of the at the beginning is for the basePath to be properly used. See
85 | // BaseConfig.baseUriPath. The webpack hot reload require the official URI path or you
86 | // will get errors in your console.
87 | publicPath: BaseConfig.isProduction ? `.${BaseConfig.baseUriPath}/dist/` : '/dist/'
88 | },
89 | module: {
90 | rules: [
91 | // this will apply to `.vue`
92 | {
93 | test: /\.vue$/,
94 | loader: 'vue-loader'
95 | },
96 | // this will apply to both plain `.js` files
97 | // AND `
28 |
29 |
48 |
--------------------------------------------------------------------------------
/content/ClientApp/components/elements/CounterDisplay.vue:
--------------------------------------------------------------------------------
1 |
2 | #counter-display
3 | .display
4 | .title {{ title.toUpperCase() }}
5 | .counter {{ value }}
6 |
7 | .controls(v-if="hasControl")
8 | el-button(type="primary" icon="el-icon-minus" @click="decrementCounter()")
9 | el-button(type="secondary" icon="el-icon-delete" @click="resetCounter()")
10 | el-button(type="primary" icon="el-icon-plus" @click="incrementCounter()")
11 |
12 |
13 |
14 |
51 |
52 |
89 |
--------------------------------------------------------------------------------
/content/ClientApp/components/elements/DataTable.vue:
--------------------------------------------------------------------------------
1 |
2 | #data-table
3 |
4 | h3.title-section(v-if="title") {{ title }}
5 |
6 | el-table(
7 | ref="multipleTable"
8 | v-loading="loader"
9 | :data="data"
10 | :height="height"
11 | @select-all="handleSelectionChange"
12 | @select="handleSelectionChange",
13 | )
14 | .columns(v-for="(column, index) in columns" :key="index")
15 | el-table-column(
16 | :type="column.type"
17 | :label="column.label"
18 | :width="column.width"
19 | :property="column.property"
20 | :show-overflow-tooltip="column.showOverflowTooltip"
21 | )
22 |
23 | el-pagination.pagination( v-if="pagination"
24 | :total="totalInServer"
25 | :page-size="numDataPerPage"
26 | @current-change="updatePage"
27 | :current-page.sync="actualPage"
28 | :layout="paginationLayout"
29 | @prev-click="prevPage"
30 | @next-click="nextPage"
31 | @size-change="sizeChange"
32 | )
33 |
34 |
35 |
136 |
137 |
152 |
--------------------------------------------------------------------------------
/content/ClientApp/components/layouts/CardContainer.vue:
--------------------------------------------------------------------------------
1 |
2 | #card-container
3 | el-card
4 | h3.title {{ title }}
5 | slot
6 |
7 |
8 |
9 |
21 |
22 |
30 |
--------------------------------------------------------------------------------
/content/ClientApp/components/layouts/HeaderLayout.vue:
--------------------------------------------------------------------------------
1 |
2 | #header-layout
3 | h2.title {{ title }}
4 | el-menu(mode="horizontal" :default-active='activeRouter' :router="true")
5 | el-menu-item(
6 | v-for="(route, index) in displayedRoutes"
7 | :key="index"
8 | :index="route.name"
9 | :route="route"
10 | )
11 | icon.menu-icon(:icon="route.icon")
12 | | {{ route.display }}
13 |
14 |
15 |
46 |
47 |
61 |
--------------------------------------------------------------------------------
/content/ClientApp/components/layouts/ViewLayout.vue:
--------------------------------------------------------------------------------
1 |
2 | #view-layout
3 | slot
4 |
5 |
6 |
7 |
12 |
13 |
17 |
--------------------------------------------------------------------------------
/content/ClientApp/components/views/Counter.vue:
--------------------------------------------------------------------------------
1 |
2 | #counter
3 |
4 | card-container(title="Counter")
5 |
6 | el-row(:gutter="20")
7 | el-col(:span="24")
8 |
9 | p This is a simple example of a Vue.js component & Vuex
10 |
11 | el-row(:gutter="20")
12 | el-col(:span="12")
13 |
14 | counter-display(
15 | :value="counter"
16 | :has-control="true"
17 | title="Current count (Vuex)"
18 | @on-increment="incrementCounter"
19 | @on-reset="resetCounter"
20 | @on-decrement="decrementCounter"
21 | )
22 |
23 | el-col(:span="12")
24 |
25 | counter-display(:value="autoCount" title="Auto count")
26 |
27 |
28 |
29 |
73 |
74 |
80 |
--------------------------------------------------------------------------------
/content/ClientApp/components/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 | #home
3 | card-container(title="Home page")
4 |
5 | el-row(:gutter="20")
6 | el-col(:span="24")
7 |
8 | p Powered by:
9 |
10 | ul
11 | li
12 | a(href="https://get.asp.net/")
13 | icon(:icon="['fab', 'microsoft']")
14 | | ASP.NET Core
15 | | and
16 | a(href="https://msdn.microsoft.com/en-us/library/67ef8sbd.aspx")
17 | | C#
18 | | for cross-platform server-side code.
19 |
20 | li
21 | a(href="https://vuejs.org/")
22 | icon(:icon="['fab', 'vuejs']")
23 | | Vue.js
24 | | for client-side code.
25 |
26 | li
27 | a(href="https://webpack.js.org/") Webpack
28 | | for building and bundling client-side resources.
29 |
30 | li
31 | a(href="https://fontawesome.com")
32 | icon(:icon="['fab', 'font-awesome']")
33 | | Font Awesome
34 | | for the icons
35 |
36 | li
37 | a(href="http://element.eleme.io") Element-ui
38 | | for the components library
39 |
40 | li API sample data from the dotnet controller.
41 |
42 | p To help you get started, we've also set up:
43 |
44 | ul
45 | li
46 | strong Client-side navigation.
47 | | For example, click
48 | em Counter
49 | | then
50 | em Back
51 | | to return here.
52 |
53 | li
54 | strong Webpack dev middleware.
55 | | In development mode, there's no need to run the
56 | code webpack
57 | | build tool. Your client-side resources are dynamically built on demand.
58 | | Updates are available as soon as you modify any file.
59 |
60 | li
61 | strong Hot module replacement.
62 | | In development mode, you don't even need to reload the page after
63 | | making most changes. Within seconds of saving changes to files, your
64 | | Vue.js app will be rebuilt and a new instance injected is into the page.
65 |
66 | li
67 | strong Code splitting and lazy loading.
68 | | Vue.js components may optionally be bundled individually and
69 | | loaded on demand. For example, the code and template for 'Counter'
70 | | is not loaded until you navigate to it..
71 |
72 | li
73 | strong Efficient production builds.
74 | | In production mode, development-time features are disabled,
75 | | and the
76 | code webpack
77 | | build tool produces minified static CSS and JavaScript files.
78 |
79 |
80 |
89 |
90 |
92 |
--------------------------------------------------------------------------------
/content/ClientApp/components/views/NotFound.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | #not-found
4 | .shrug
5 | p.title
6 | b 404 - Page not found.
7 | span.left-arm ¯\_
8 | | (ツ)
9 | span.right-arm _/¯
10 | h6 The page you trying to reach may not exist.
11 | el-button(type="text" @click="goToHome") Go back to home
12 |
13 |
14 |
15 |
26 |
27 |
90 |
--------------------------------------------------------------------------------
/content/ClientApp/components/views/WeatherForecast.vue:
--------------------------------------------------------------------------------
1 |
2 | #weather-forecast
3 |
4 | card-container(title="Weather forecast")
5 |
6 | el-row(:gutter="20")
7 | el-col(:span="24")
8 |
9 | p This component demonstrates fetching data from the server.
10 |
11 | el-row(:gutter="20")
12 | el-col(:span="24")
13 |
14 | data-table(
15 | :data="forecasts",
16 | :total-in-server="tableOptions.totalInServer"
17 | :columns="columns"
18 | :current-page="tableOptions.currentPage"
19 | :numPerPage="tableOptions.pageSize"
20 | :loader="loader"
21 | @current-page="loadPage"
22 | @size-table="size"
23 | )
24 |
25 |
26 |
27 |
83 |
84 |
86 |
--------------------------------------------------------------------------------
/content/ClientApp/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hvpaiva/aspdotnet-vuejs/e7bf3c5ed78e95f0f5a9a392b8dc32fdfdbe9b16/content/ClientApp/favicon.ico
--------------------------------------------------------------------------------
/content/ClientApp/icons.js:
--------------------------------------------------------------------------------
1 | import { library } from '@fortawesome/fontawesome-svg-core';
2 | // Official documentation available at: https://github.com/FortAwesome/vue-fontawesome
3 | import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
4 |
5 | // If not present, it won't be visible within the application. Considering that you
6 | // don't want all the icons for no reason. This is a good way to avoid importing too many
7 | // unnecessary things.
8 | library.add(
9 | require('@fortawesome/free-solid-svg-icons').faGraduationCap,
10 | require('@fortawesome/free-solid-svg-icons').faList,
11 | require('@fortawesome/free-solid-svg-icons').faSpinner,
12 | require('@fortawesome/free-solid-svg-icons').faHome,
13 | // Brands
14 | require('@fortawesome/free-brands-svg-icons').faMicrosoft,
15 | require('@fortawesome/free-brands-svg-icons').faVuejs,
16 | require('@fortawesome/free-brands-svg-icons').faFontAwesome
17 | );
18 |
19 | export {
20 | FontAwesomeIcon
21 | }
22 |
--------------------------------------------------------------------------------
/content/ClientApp/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <%= appName %>
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/content/ClientApp/models/WeatherForecast.js:
--------------------------------------------------------------------------------
1 | const WeatherForecast = {
2 | dateFormatted: null,
3 | temperatureC: null,
4 | temperatureF: null,
5 | summary: null
6 | };
7 |
8 | export default WeatherForecast;
9 |
--------------------------------------------------------------------------------
/content/ClientApp/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import VueRouter from 'vue-router';
3 | import routes from './routes';
4 |
5 | Vue.use(VueRouter);
6 |
7 | const router = new VueRouter({
8 | mode: 'history',
9 | routes
10 | });
11 |
12 | export default router;
13 |
--------------------------------------------------------------------------------
/content/ClientApp/router/routes.js:
--------------------------------------------------------------------------------
1 | import Home from '../components/views/Home';
2 | import NotFound from '../components/views/NotFound';
3 |
4 | const routes = [
5 | {
6 | name: 'home',
7 | path: '/',
8 | component: Home,
9 | display: 'Home',
10 | icon: 'home'
11 | },
12 | {
13 | name: 'counter',
14 | path: '/counter',
15 | component: () => import('../components/views/Counter'),
16 | display: 'Counter',
17 | icon: 'graduation-cap'
18 | },
19 | {
20 | name: 'weather',
21 | path: '/weather',
22 | component: () => import('../components/views/WeatherForecast'),
23 | display: 'Weather forecast',
24 | icon: 'list'
25 | },
26 | { name: '404', path: '/404', component: NotFound },
27 | { name: 'catchAll', path: '*', redirect: '/404' }
28 | ];
29 |
30 | export default routes;
31 |
--------------------------------------------------------------------------------
/content/ClientApp/services/forecast-service.js:
--------------------------------------------------------------------------------
1 | import Axios from 'axios';
2 |
3 | const ForecastService = {
4 |
5 | fetch: async (to, from) => Axios.get(
6 | `/api/weather/forecasts?from=${from}&to=${to}`
7 | )
8 | };
9 |
10 | export default ForecastService;
11 |
--------------------------------------------------------------------------------
/content/ClientApp/static/ie-polyfill.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * @overview es6-promise - a tiny implementation of Promises/A+.
3 | * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
4 | * @license Licensed under MIT license
5 | * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE
6 | * @version 3.2.1
7 | */
8 |
9 | (function(){"use strict";function t(t){return"function"==typeof t||"object"==typeof t&&null!==t}function e(t){return"function"==typeof t}function n(t){G=t}function r(t){Q=t}function o(){return function(){process.nextTick(a)}}function i(){return function(){B(a)}}function s(){var t=0,e=new X(a),n=document.createTextNode("");return e.observe(n,{characterData:!0}),function(){n.data=t=++t%2}}function u(){var t=new MessageChannel;return t.port1.onmessage=a,function(){t.port2.postMessage(0)}}function c(){return function(){setTimeout(a,1)}}function a(){for(var t=0;J>t;t+=2){var e=tt[t],n=tt[t+1];e(n),tt[t]=void 0,tt[t+1]=void 0}J=0}function f(){try{var t=require,e=t("vertx");return B=e.runOnLoop||e.runOnContext,i()}catch(n){return c()}}function l(t,e){var n=this,r=new this.constructor(p);void 0===r[rt]&&k(r);var o=n._state;if(o){var i=arguments[o-1];Q(function(){x(o,r,i,n._result)})}else E(n,r,t,e);return r}function h(t){var e=this;if(t&&"object"==typeof t&&t.constructor===e)return t;var n=new e(p);return g(n,t),n}function p(){}function _(){return new TypeError("You cannot resolve a promise with itself")}function d(){return new TypeError("A promises callback cannot return that same promise.")}function v(t){try{return t.then}catch(e){return ut.error=e,ut}}function y(t,e,n,r){try{t.call(e,n,r)}catch(o){return o}}function m(t,e,n){Q(function(t){var r=!1,o=y(n,e,function(n){r||(r=!0,e!==n?g(t,n):S(t,n))},function(e){r||(r=!0,j(t,e))},"Settle: "+(t._label||" unknown promise"));!r&&o&&(r=!0,j(t,o))},t)}function b(t,e){e._state===it?S(t,e._result):e._state===st?j(t,e._result):E(e,void 0,function(e){g(t,e)},function(e){j(t,e)})}function w(t,n,r){n.constructor===t.constructor&&r===et&&constructor.resolve===nt?b(t,n):r===ut?j(t,ut.error):void 0===r?S(t,n):e(r)?m(t,n,r):S(t,n)}function g(e,n){e===n?j(e,_()):t(n)?w(e,n,v(n)):S(e,n)}function A(t){t._onerror&&t._onerror(t._result),T(t)}function S(t,e){t._state===ot&&(t._result=e,t._state=it,0!==t._subscribers.length&&Q(T,t))}function j(t,e){t._state===ot&&(t._state=st,t._result=e,Q(A,t))}function E(t,e,n,r){var o=t._subscribers,i=o.length;t._onerror=null,o[i]=e,o[i+it]=n,o[i+st]=r,0===i&&t._state&&Q(T,t)}function T(t){var e=t._subscribers,n=t._state;if(0!==e.length){for(var r,o,i=t._result,s=0;si;i++)e.resolve(t[i]).then(n,r)}:function(t,e){e(new TypeError("You must pass an array to race."))})}function F(t){var e=this,n=new e(p);return j(n,t),n}function D(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function K(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}function L(t){this[rt]=O(),this._result=this._state=void 0,this._subscribers=[],p!==t&&("function"!=typeof t&&D(),this instanceof L?C(this,t):K())}function N(t,e){this._instanceConstructor=t,this.promise=new t(p),this.promise[rt]||k(this.promise),I(e)?(this._input=e,this.length=e.length,this._remaining=e.length,this._result=new Array(this.length),0===this.length?S(this.promise,this._result):(this.length=this.length||0,this._enumerate(),0===this._remaining&&S(this.promise,this._result))):j(this.promise,U())}function U(){return new Error("Array Methods must be provided an Array")}function W(){var t;if("undefined"!=typeof global)t=global;else if("undefined"!=typeof self)t=self;else try{t=Function("return this")()}catch(e){throw new Error("polyfill failed because global object is unavailable in this environment")}var n=t.Promise;(!n||"[object Promise]"!==Object.prototype.toString.call(n.resolve())||n.cast)&&(t.Promise=pt)}var z;z=Array.isArray?Array.isArray:function(t){return"[object Array]"===Object.prototype.toString.call(t)};var B,G,H,I=z,J=0,Q=function(t,e){tt[J]=t,tt[J+1]=e,J+=2,2===J&&(G?G(a):H())},R="undefined"!=typeof window?window:void 0,V=R||{},X=V.MutationObserver||V.WebKitMutationObserver,Z="undefined"==typeof self&&"undefined"!=typeof process&&"[object process]"==={}.toString.call(process),$="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,tt=new Array(1e3);H=Z?o():X?s():$?u():void 0===R&&"function"==typeof require?f():c();var et=l,nt=h,rt=Math.random().toString(36).substring(16),ot=void 0,it=1,st=2,ut=new M,ct=new M,at=0,ft=Y,lt=q,ht=F,pt=L;L.all=ft,L.race=lt,L.resolve=nt,L.reject=ht,L._setScheduler=n,L._setAsap=r,L._asap=Q,L.prototype={constructor:L,then:et,"catch":function(t){return this.then(null,t)}};var _t=N;N.prototype._enumerate=function(){for(var t=this.length,e=this._input,n=0;this._state===ot&&t>n;n++)this._eachEntry(e[n],n)},N.prototype._eachEntry=function(t,e){var n=this._instanceConstructor,r=n.resolve;if(r===nt){var o=v(t);if(o===et&&t._state!==ot)this._settledAt(t._state,e,t._result);else if("function"!=typeof o)this._remaining--,this._result[e]=t;else if(n===pt){var i=new n(p);w(i,t,o),this._willSettleAt(i,e)}else this._willSettleAt(new n(function(e){e(t)}),e)}else this._willSettleAt(r(t),e)},N.prototype._settledAt=function(t,e,n){var r=this.promise;r._state===ot&&(this._remaining--,t===st?j(r,n):this._result[e]=n),0===this._remaining&&S(r,this._result)},N.prototype._willSettleAt=function(t,e){var n=this;E(t,void 0,function(t){n._settledAt(it,e,t)},function(t){n._settledAt(st,e,t)})};var dt=W,vt={Promise:pt,polyfill:dt};"function"==typeof define&&define.amd?define(function(){return vt}):"undefined"!=typeof module&&module.exports?module.exports=vt:"undefined"!=typeof this&&(this.ES6Promise=vt),dt()}).call(this);
10 |
11 | /*!
12 | * @overview fetch - The fetch() function is a Promise-based mechanism for programmatically making web requests in the browser.
13 | * @license Licensed under MIT license
14 | * See https://raw.githubusercontent.com/github/fetch/master/LICENSE
15 | * @version 3.0.0
16 | */
17 | var support={searchParams:"URLSearchParams"in self,iterable:"Symbol"in self&&"iterator"in Symbol,blob:"FileReader"in self&&"Blob"in self&&function(){try{return new Blob,!0}catch(e){return!1}}(),formData:"FormData"in self,arrayBuffer:"ArrayBuffer"in self};function isDataView(e){return e&&DataView.prototype.isPrototypeOf(e)}if(support.arrayBuffer)var viewClasses=["[object Int8Array]","[object Uint8Array]","[object Uint8ClampedArray]","[object Int16Array]","[object Uint16Array]","[object Int32Array]","[object Uint32Array]","[object Float32Array]","[object Float64Array]"],isArrayBufferView=ArrayBuffer.isView||function(e){return e&&viewClasses.indexOf(Object.prototype.toString.call(e))>-1};function normalizeName(e){if("string"!=typeof e&&(e=String(e)),/[^a-z0-9\-#$%&'*+.^_`|~]/i.test(e))throw new TypeError("Invalid character in header field name");return e.toLowerCase()}function normalizeValue(e){return"string"!=typeof e&&(e=String(e)),e}function iteratorFor(e){var t={next:function(){var t=e.shift();return{done:void 0===t,value:t}}};return support.iterable&&(t[Symbol.iterator]=function(){return t}),t}function Headers(e){this.map={},e instanceof Headers?e.forEach(function(e,t){this.append(t,e)},this):Array.isArray(e)?e.forEach(function(e){this.append(e[0],e[1])},this):e&&Object.getOwnPropertyNames(e).forEach(function(t){this.append(t,e[t])},this)}function consumed(e){if(e.bodyUsed)return Promise.reject(new TypeError("Already read"));e.bodyUsed=!0}function fileReaderReady(e){return new Promise(function(t,r){e.onload=function(){t(e.result)},e.onerror=function(){r(e.error)}})}function readBlobAsArrayBuffer(e){var t=new FileReader,r=fileReaderReady(t);return t.readAsArrayBuffer(e),r}function readBlobAsText(e){var t=new FileReader,r=fileReaderReady(t);return t.readAsText(e),r}function readArrayBufferAsText(e){for(var t=new Uint8Array(e),r=new Array(t.length),o=0;o-1?t:e}function Request(e,t){var r=(t=t||{}).body;if(e instanceof Request){if(e.bodyUsed)throw new TypeError("Already read");this.url=e.url,this.credentials=e.credentials,t.headers||(this.headers=new Headers(e.headers)),this.method=e.method,this.mode=e.mode,this.signal=e.signal,r||null==e._bodyInit||(r=e._bodyInit,e.bodyUsed=!0)}else this.url=String(e);if(this.credentials=t.credentials||this.credentials||"same-origin",!t.headers&&this.headers||(this.headers=new Headers(t.headers)),this.method=normalizeMethod(t.method||this.method||"GET"),this.mode=t.mode||this.mode||null,this.signal=t.signal||this.signal,this.referrer=null,("GET"===this.method||"HEAD"===this.method)&&r)throw new TypeError("Body not allowed for GET or HEAD requests");this._initBody(r)}function decode(e){var t=new FormData;return e.trim().split("&").forEach(function(e){if(e){var r=e.split("="),o=r.shift().replace(/\+/g," "),s=r.join("=").replace(/\+/g," ");t.append(decodeURIComponent(o),decodeURIComponent(s))}}),t}function parseHeaders(e){var t=new Headers;return e.replace(/\r?\n[\t ]+/g," ").split(/\r?\n/).forEach(function(e){var r=e.split(":"),o=r.shift().trim();if(o){var s=r.join(":").trim();t.append(o,s)}}),t}function Response(e,t){t||(t={}),this.type="default",this.status=void 0===t.status?200:t.status,this.ok=this.status>=200&&this.status<300,this.statusText="statusText"in t?t.statusText:"OK",this.headers=new Headers(t.headers),this.url=t.url||"",this._initBody(e)}Request.prototype.clone=function(){return new Request(this,{body:this._bodyInit})},Body.call(Request.prototype),Body.call(Response.prototype),Response.prototype.clone=function(){return new Response(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new Headers(this.headers),url:this.url})},Response.error=function(){var e=new Response(null,{status:0,statusText:""});return e.type="error",e};var redirectStatuses=[301,302,303,307,308];Response.redirect=function(e,t){if(-1===redirectStatuses.indexOf(t))throw new RangeError("Invalid status code");return new Response(null,{status:t,headers:{location:e}})};var DOMException=self.DOMException;try{new DOMException}catch(e){(DOMException=function(e,t){this.message=e,this.name=t;var r=Error(e);this.stack=r.stack}).prototype=Object.create(Error.prototype),DOMException.prototype.constructor=DOMException}function fetch(e,t){return new Promise(function(r,o){var s=new Request(e,t);if(s.signal&&s.signal.aborted)return o(new DOMException("Aborted","AbortError"));var n=new XMLHttpRequest;function i(){n.abort()}n.onload=function(){var e={status:n.status,statusText:n.statusText,headers:parseHeaders(n.getAllResponseHeaders()||"")};e.url="responseURL"in n?n.responseURL:e.headers.get("X-Request-URL");var t="response"in n?n.response:n.responseText;r(new Response(t,e))},n.onerror=function(){o(new TypeError("Network request failed"))},n.ontimeout=function(){o(new TypeError("Network request failed"))},n.onabort=function(){o(new DOMException("Aborted","AbortError"))},n.open(s.method,s.url,!0),"include"===s.credentials?n.withCredentials=!0:"omit"===s.credentials&&(n.withCredentials=!1),"responseType"in n&&support.blob&&(n.responseType="blob"),s.headers.forEach(function(e,t){n.setRequestHeader(t,e)}),s.signal&&(s.signal.addEventListener("abort",i),n.onreadystatechange=function(){4===n.readyState&&s.signal.removeEventListener("abort",i)}),n.send(void 0===s._bodyInit?null:s._bodyInit)})}fetch.polyfill=!0,self.fetch||(self.fetch=fetch,self.Headers=Headers,self.Request=Request,self.Response=Response);
--------------------------------------------------------------------------------
/content/ClientApp/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Vuex from 'vuex';
3 |
4 | import logger from '../utils/helpers/vuex-logger';
5 | import counter from './modules/counter';
6 | import weather from './modules/weather';
7 |
8 | Vue.use(Vuex);
9 |
10 | const debugMode = process.env.NODE_ENV !== 'production';
11 |
12 | export default new Vuex.Store({
13 | modules: {
14 | counter,
15 | weather
16 | },
17 | strict: debugMode,
18 | plugins: debugMode ? [logger()] : []
19 | });
20 |
--------------------------------------------------------------------------------
/content/ClientApp/store/modules/counter.js:
--------------------------------------------------------------------------------
1 | import { DECREMENT_COUNTER, INCREMENT_COUNTER, RESET_COUNTER } from '../mutation-types';
2 |
3 | export const COUNTER_OPERATIONS = {
4 | INCREMENT: 0,
5 | DECREMENT: 1,
6 | RESET: 2
7 | };
8 |
9 | const INITIAL_STATE = {
10 | counter: 0
11 | };
12 |
13 | const state = Object.assign({}, INITIAL_STATE);
14 |
15 | const getters = {
16 | counter: state => state.counter
17 | };
18 |
19 | const mutations = {
20 | [INCREMENT_COUNTER]: state => state.counter++,
21 |
22 | [DECREMENT_COUNTER]: state => state.counter--,
23 |
24 | [RESET_COUNTER]: state => {
25 | state.counter = INITIAL_STATE.counter;
26 | }
27 | };
28 |
29 | const actions = {
30 | operation: ({ commit }, operation) => {
31 | switch (operation) {
32 | case COUNTER_OPERATIONS.INCREMENT:
33 | commit(INCREMENT_COUNTER);
34 | break;
35 | case COUNTER_OPERATIONS.DECREMENT:
36 | commit(DECREMENT_COUNTER);
37 | break;
38 | case COUNTER_OPERATIONS.RESET:
39 | commit(RESET_COUNTER);
40 | break;
41 | default:
42 | console.error('No operation defined.');
43 | }
44 | }
45 | };
46 |
47 | export default {
48 | state,
49 | getters,
50 | mutations,
51 | actions
52 | };
53 |
--------------------------------------------------------------------------------
/content/ClientApp/store/modules/weather.js:
--------------------------------------------------------------------------------
1 | import {
2 | SET_CURRENT_PAGE,
3 | SET_FORECASTS, SET_PAGE_SIZE,
4 | SET_TOTAL_IN_SERVER
5 | } from '../mutation-types';
6 | import ForecastService from '../../services/forecast-service';
7 |
8 | const from = () => (state.tableOptions.currentPage - 1) * state.tableOptions.pageSize;
9 |
10 | const to = () => from() + state.tableOptions.pageSize;
11 |
12 | const INITIAL_STATE = {
13 | forecasts: [],
14 | tableOptions: {
15 | currentPage: 1,
16 | totalInServer: 0,
17 | pageSize: 10
18 | }
19 | };
20 |
21 | const state = Object.assign({}, INITIAL_STATE);
22 |
23 | const getters = {
24 | forecasts: state => state.forecasts,
25 |
26 | hasForecasts: state => state.forecasts.length !== 0,
27 |
28 | tableOptions: state => state.tableOptions
29 | };
30 |
31 | const mutations = {
32 | [SET_FORECASTS]: (state, forecasts) => {
33 | state.forecasts = forecasts;
34 | },
35 |
36 | [SET_TOTAL_IN_SERVER]: (state, totalInServer) => {
37 | state.tableOptions.totalInServer = totalInServer;
38 | },
39 |
40 | [SET_PAGE_SIZE]: (state, pageSize) => {
41 | state.tableOptions.pageSize = pageSize;
42 | },
43 |
44 | [SET_CURRENT_PAGE]: (state, currentPage) => {
45 | state.tableOptions.currentPage = currentPage;
46 | }
47 | };
48 |
49 | const actions = {
50 | fetchForecasts: async ({ commit }, page) => {
51 | commit(SET_CURRENT_PAGE, page);
52 |
53 | const response = await ForecastService.fetch(to(), from());
54 | commit(SET_FORECASTS, response.data.forecasts);
55 | commit(SET_TOTAL_IN_SERVER, response.data.total);
56 | },
57 |
58 | changePageSize: ({ commit }, pageSize) => {
59 | commit(SET_PAGE_SIZE, pageSize);
60 | }
61 | };
62 |
63 | export default {
64 | state,
65 | getters,
66 | mutations,
67 | actions
68 | };
69 |
--------------------------------------------------------------------------------
/content/ClientApp/store/mutation-types.js:
--------------------------------------------------------------------------------
1 | export const INCREMENT_COUNTER = 'INCREMENT_COUNTER';
2 | export const DECREMENT_COUNTER = 'DECREMENT_COUNTER';
3 | export const RESET_COUNTER = 'RESET_COUNTER';
4 | export const SET_FORECASTS = 'SET_FORECASTS';
5 | export const SET_TOTAL_IN_SERVER = 'SET_TOTAL_IN_SERVER';
6 | export const SET_PAGE_SIZE = 'SET_PAGE_SIZE';
7 | export const SET_CURRENT_PAGE = 'SET_CURRENT_PAGE';
8 |
--------------------------------------------------------------------------------
/content/ClientApp/styles/base/global.sass:
--------------------------------------------------------------------------------
1 | @import "../tools/variables"
2 |
3 | body
4 | width: 100%
5 | min-height: 100vh
6 |
7 | a
8 | color: $--color-primary
9 |
--------------------------------------------------------------------------------
/content/ClientApp/styles/base/normalize.scss:
--------------------------------------------------------------------------------
1 | /* ==========================================================================
2 | Normalize.scss settings
3 | ========================================================================== */
4 | /**
5 | * Includes legacy browser support IE6/7
6 | *
7 | * Set to false if you want to drop support for IE6 and IE7
8 | */
9 |
10 | $legacy_browser_support: false !default;
11 |
12 | /* Base
13 | ========================================================================== */
14 |
15 | /**
16 | * 1. Set default font family to sans-serif.
17 | * 2. Prevent iOS and IE text size adjust after device orientation change,
18 | * without disabling user zoom.
19 | * 3. Corrects text resizing oddly in IE 6/7 when body `font-size` is set using
20 | * `em` units.
21 | */
22 |
23 | html {
24 | font-family: sans-serif; /* 1 */
25 | -ms-text-size-adjust: 100%; /* 2 */
26 | -webkit-text-size-adjust: 100%; /* 2 */
27 | @if $legacy_browser_support {
28 | *font-size: 100%; /* 3 */
29 | }
30 | }
31 |
32 | /**
33 | * Remove default margin.
34 | */
35 |
36 | body {
37 | margin: 0;
38 | }
39 |
40 | /* HTML5 display definitions
41 | ========================================================================== */
42 |
43 | /**
44 | * Correct `block` display not defined for any HTML5 element in IE 8/9.
45 | * Correct `block` display not defined for `details` or `summary` in IE 10/11
46 | * and Firefox.
47 | * Correct `block` display not defined for `main` in IE 11.
48 | */
49 |
50 | article,
51 | aside,
52 | details,
53 | figcaption,
54 | figure,
55 | footer,
56 | header,
57 | hgroup,
58 | main,
59 | menu,
60 | nav,
61 | section,
62 | summary {
63 | display: block;
64 | }
65 |
66 | /**
67 | * 1. Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.
68 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
69 | */
70 |
71 | audio,
72 | canvas,
73 | progress,
74 | video {
75 | display: inline-block; /* 1 */
76 | vertical-align: baseline; /* 2 */
77 | @if $legacy_browser_support {
78 | *display: inline;
79 | *zoom: 1;
80 | }
81 | }
82 |
83 | /**
84 | * Prevents modern browsers from displaying `audio` without controls.
85 | * Remove excess height in iOS 5 devices.
86 | */
87 |
88 | audio:not([controls]) {
89 | display: none;
90 | height: 0;
91 | }
92 |
93 | /**
94 | * Address `[hidden]` styling not present in IE 8/9/10.
95 | * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
96 | */
97 |
98 | [hidden],
99 | template {
100 | display: none;
101 | }
102 |
103 | /* Links
104 | ========================================================================== */
105 |
106 | /**
107 | * Remove the gray background color from active links in IE 10.
108 | */
109 |
110 | a {
111 | background-color: transparent;
112 | }
113 |
114 | /**
115 | * Improve readability of focused elements when they are also in an
116 | * active/hover state.
117 | */
118 |
119 | a {
120 | &:active, &:hover {
121 | outline: 0;
122 | };
123 | }
124 |
125 | /* Text-level semantics
126 | ========================================================================== */
127 |
128 | /**
129 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
130 | */
131 |
132 | abbr[title] {
133 | border-bottom: 1px dotted;
134 | }
135 |
136 | /**
137 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
138 | */
139 |
140 | b,
141 | strong {
142 | font-weight: bold;
143 | }
144 |
145 | @if $legacy_browser_support {
146 | blockquote {
147 | margin: 1em 40px;
148 | }
149 | }
150 |
151 | /**
152 | * Address styling not present in Safari and Chrome.
153 | */
154 |
155 | dfn {
156 | font-style: italic;
157 | }
158 |
159 | /**
160 | * Address variable `h1` font-size and margin within `section` and `article`
161 | * contexts in Firefox 4+, Safari, and Chrome.
162 | */
163 |
164 | h1 {
165 | font-size: 2em;
166 | margin: 0.67em 0;
167 | }
168 |
169 | @if $legacy_browser_support {
170 | h2 {
171 | font-size: 1.5em;
172 | margin: 0.83em 0;
173 | }
174 |
175 | h3 {
176 | font-size: 1.17em;
177 | margin: 1em 0;
178 | }
179 |
180 | h4 {
181 | font-size: 1em;
182 | margin: 1.33em 0;
183 | }
184 |
185 | h5 {
186 | font-size: 0.83em;
187 | margin: 1.67em 0;
188 | }
189 |
190 | h6 {
191 | font-size: 0.67em;
192 | margin: 2.33em 0;
193 | }
194 | }
195 |
196 | /**
197 | * Addresses styling not present in IE 8/9.
198 | */
199 |
200 | mark {
201 | background: #ff0;
202 | color: #000;
203 | }
204 |
205 | @if $legacy_browser_support {
206 |
207 | /**
208 | * Addresses margins set differently in IE 6/7.
209 | */
210 |
211 | p,
212 | pre {
213 | *margin: 1em 0;
214 | }
215 |
216 | /*
217 | * Addresses CSS quotes not supported in IE 6/7.
218 | */
219 |
220 | q {
221 | *quotes: none;
222 | }
223 |
224 | /*
225 | * Addresses `quotes` property not supported in Safari 4.
226 | */
227 |
228 | q:before,
229 | q:after {
230 | content: '';
231 | content: none;
232 | }
233 | }
234 |
235 | /**
236 | * Address inconsistent and variable font size in all browsers.
237 | */
238 |
239 | small {
240 | font-size: 80%;
241 | }
242 |
243 | /**
244 | * Prevent `sub` and `sup` affecting `line-height` in all browsers.
245 | */
246 |
247 | sub,
248 | sup {
249 | font-size: 75%;
250 | line-height: 0;
251 | position: relative;
252 | vertical-align: baseline;
253 | }
254 |
255 | sup {
256 | top: -0.5em;
257 | }
258 |
259 | sub {
260 | bottom: -0.25em;
261 | }
262 |
263 | @if $legacy_browser_support {
264 |
265 | /* ==========================================================================
266 | Lists
267 | ========================================================================== */
268 |
269 | /*
270 | * Addresses margins set differently in IE 6/7.
271 | */
272 |
273 | dl,
274 | menu,
275 | ol,
276 | ul {
277 | *margin: 1em 0;
278 | }
279 |
280 | dd {
281 | *margin: 0 0 0 40px;
282 | }
283 |
284 | /*
285 | * Addresses paddings set differently in IE 6/7.
286 | */
287 |
288 | menu,
289 | ol,
290 | ul {
291 | *padding: 0 0 0 40px;
292 | }
293 |
294 | /*
295 | * Corrects list images handled incorrectly in IE 7.
296 | */
297 |
298 | nav ul,
299 | nav ol {
300 | *list-style: none;
301 | *list-style-image: none;
302 | }
303 |
304 | }
305 |
306 | /* Embedded content
307 | ========================================================================== */
308 |
309 | /**
310 | * 1. Remove border when inside `a` element in IE 8/9/10.
311 | * 2. Improves image quality when scaled in IE 7.
312 | */
313 |
314 | img {
315 | border: 0;
316 | @if $legacy_browser_support {
317 | *-ms-interpolation-mode: bicubic; /* 2 */
318 | }
319 | }
320 |
321 | /**
322 | * Correct overflow not hidden in IE 9/10/11.
323 | */
324 |
325 | svg:not(:root) {
326 | overflow: hidden;
327 | }
328 |
329 | /* Grouping content
330 | ========================================================================== */
331 |
332 | /**
333 | * Address margin not present in IE 8/9 and Safari.
334 | */
335 |
336 | figure {
337 | margin: 1em 40px;
338 | }
339 |
340 | /**
341 | * Address differences between Firefox and other browsers.
342 | */
343 |
344 | hr {
345 | box-sizing: content-box;
346 | height: 0;
347 | }
348 |
349 | /**
350 | * Contain overflow in all browsers.
351 | */
352 |
353 | pre {
354 | overflow: auto;
355 | }
356 |
357 | /**
358 | * Address odd `em`-unit font size rendering in all browsers.
359 | * Correct font family set oddly in IE 6, Safari 4/5, and Chrome.
360 | */
361 |
362 | code,
363 | kbd,
364 | pre,
365 | samp {
366 | font-family: monospace, monospace;
367 | @if $legacy_browser_support {
368 | _font-family: 'courier new', monospace;
369 | }
370 | font-size: 1em;
371 | }
372 |
373 | /* Forms
374 | ========================================================================== */
375 |
376 | /**
377 | * Known limitation: by default, Chrome and Safari on OS X allow very limited
378 | * styling of `select`, unless a `border` property is set.
379 | */
380 |
381 | /**
382 | * 1. Correct color not being inherited.
383 | * Known issue: affects color of disabled elements.
384 | * 2. Correct font properties not being inherited.
385 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
386 | * 4. Improves appearance and consistency in all browsers.
387 | */
388 |
389 | button,
390 | input,
391 | optgroup,
392 | select,
393 | textarea {
394 | color: inherit; /* 1 */
395 | font: inherit; /* 2 */
396 | margin: 0; /* 3 */
397 | @if $legacy_browser_support {
398 | vertical-align: baseline; /* 3 */
399 | *vertical-align: middle; /* 3 */
400 | }
401 | }
402 |
403 | /**
404 | * Address `overflow` set to `hidden` in IE 8/9/10/11.
405 | */
406 |
407 | button {
408 | overflow: visible;
409 | }
410 |
411 | /**
412 | * Address inconsistent `text-transform` inheritance for `button` and `select`.
413 | * All other form control elements do not inherit `text-transform` values.
414 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
415 | * Correct `select` style inheritance in Firefox.
416 | */
417 |
418 | button,
419 | select {
420 | text-transform: none;
421 | }
422 |
423 | /**
424 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
425 | * and `video` controls.
426 | * 2. Correct inability to style clickable `input` types in iOS.
427 | * 3. Improve usability and consistency of cursor style between image-type
428 | * `input` and others.
429 | * 4. Removes inner spacing in IE 7 without affecting normal text inputs.
430 | * Known issue: inner spacing remains in IE 6.
431 | */
432 |
433 | button,
434 | html input[type="button"], /* 1 */
435 | input[type="reset"],
436 | input[type="submit"] {
437 | -webkit-appearance: button; /* 2 */
438 | cursor: pointer; /* 3 */
439 | @if $legacy_browser_support {
440 | *overflow: visible; /* 4 */
441 | }
442 | }
443 |
444 | /**
445 | * Re-set default cursor for disabled elements.
446 | */
447 |
448 | button[disabled],
449 | html input[disabled] {
450 | cursor: default;
451 | }
452 |
453 | /**
454 | * Remove inner padding and border in Firefox 4+.
455 | */
456 |
457 | button::-moz-focus-inner,
458 | input::-moz-focus-inner {
459 | border: 0;
460 | padding: 0;
461 | }
462 |
463 | /**
464 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in
465 | * the UA stylesheet.
466 | */
467 |
468 | input {
469 | line-height: normal;
470 | }
471 |
472 | /**
473 | * 1. Address box sizing set to `content-box` in IE 8/9/10.
474 | * 2. Remove excess padding in IE 8/9/10.
475 | * Known issue: excess padding remains in IE 6.
476 | */
477 |
478 | input[type="checkbox"],
479 | input[type="radio"] {
480 | box-sizing: border-box; /* 1 */
481 | padding: 0; /* 2 */
482 | @if $legacy_browser_support {
483 | *height: 13px; /* 3 */
484 | *width: 13px; /* 3 */
485 | }
486 | }
487 |
488 | /**
489 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain
490 | * `font-size` values of the `input`, it causes the cursor style of the
491 | * decrement button to change from `default` to `text`.
492 | */
493 |
494 | input[type="number"]::-webkit-inner-spin-button,
495 | input[type="number"]::-webkit-outer-spin-button {
496 | height: auto;
497 | }
498 |
499 | /**
500 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
501 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
502 | */
503 |
504 | input[type="search"] {
505 | -webkit-appearance: textfield; /* 1 */
506 | box-sizing: content-box; /* 2 */
507 | }
508 |
509 | /**
510 | * Remove inner padding and search cancel button in Safari and Chrome on OS X.
511 | * Safari (but not Chrome) clips the cancel button when the search input has
512 | * padding (and `textfield` appearance).
513 | */
514 |
515 | input[type="search"]::-webkit-search-cancel-button,
516 | input[type="search"]::-webkit-search-decoration {
517 | -webkit-appearance: none;
518 | }
519 |
520 | /**
521 | * Define consistent border, margin, and padding.
522 | */
523 |
524 | fieldset {
525 | border: 1px solid #c0c0c0;
526 | margin: 0 2px;
527 | padding: 0.35em 0.625em 0.75em;
528 | }
529 |
530 | /**
531 | * 1. Correct `color` not being inherited in IE 8/9/10/11.
532 | * 2. Remove padding so people aren't caught out if they zero out fieldsets.
533 | * 3. Corrects text not wrapping in Firefox 3.
534 | * 4. Corrects alignment displayed oddly in IE 6/7.
535 | */
536 |
537 | legend {
538 | border: 0; /* 1 */
539 | padding: 0; /* 2 */
540 | @if $legacy_browser_support {
541 | white-space: normal; /* 3 */
542 | *margin-left: -7px; /* 4 */
543 | }
544 | }
545 |
546 | /**
547 | * Remove default vertical scrollbar in IE 8/9/10/11.
548 | */
549 |
550 | textarea {
551 | overflow: auto;
552 | }
553 |
554 | /**
555 | * Don't inherit the `font-weight` (applied by a rule above).
556 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
557 | */
558 |
559 | optgroup {
560 | font-weight: bold;
561 | }
562 |
563 | /* Tables
564 | ========================================================================== */
565 |
566 | /**
567 | * Remove most spacing between table cells.
568 | */
569 |
570 | table {
571 | border-collapse: collapse;
572 | border-spacing: 0;
573 | }
574 |
575 | td,
576 | th {
577 | padding: 0;
578 | }
579 |
--------------------------------------------------------------------------------
/content/ClientApp/styles/main.sass:
--------------------------------------------------------------------------------
1 | // tooling: variables, mixins, functions
2 | @import "./tools/variables"
3 |
4 | // base application styles
5 | @import "./base/normalize"
6 | @import "./base/global"
7 |
8 | // 3th imports or overrides
9 | @import "./vendors/element"
10 |
--------------------------------------------------------------------------------
/content/ClientApp/styles/tools/variables.sass:
--------------------------------------------------------------------------------
1 | /* theme color */
2 | $--color-primary: teal
3 |
4 | @import "~element-ui/packages/theme-chalk/src/common/var"
5 |
--------------------------------------------------------------------------------
/content/ClientApp/styles/vendors/element.scss:
--------------------------------------------------------------------------------
1 | $--font-path: '~element-ui/lib/theme-chalk/fonts';
2 |
3 | @import "~element-ui/packages/theme-chalk/src/index";
4 |
--------------------------------------------------------------------------------
/content/ClientApp/utils/helpers/functions.js:
--------------------------------------------------------------------------------
1 | export const find = (list, f) => list.filter(f)[0];
2 |
3 | export const deepCopy = (obj, cache = []) => {
4 | if (obj === null || typeof obj !== 'object') {
5 | return obj;
6 | }
7 |
8 | const hit = find(cache, c => c.original === obj);
9 | if (hit) {
10 | return hit.copy;
11 | }
12 |
13 | const copy = Array.isArray(obj) ? [] : {};
14 |
15 | cache.push({
16 | original: obj,
17 | copy
18 | });
19 |
20 | Object.keys(obj).forEach(key => {
21 | copy[key] = deepCopy(obj[key], cache);
22 | });
23 |
24 | return copy;
25 | };
26 |
27 | export const forEachValue = (obj, fn) => {
28 | Object.keys(obj).forEach(key => fn(obj[key], key));
29 | };
30 |
31 | export const isObject = (obj) => obj !== null && typeof obj === 'object';
32 |
33 | export const isPromise = (val) => val && typeof val.then === 'function';
34 |
35 | export const assert = (condition, msg) => {
36 | if (!condition) throw new Error(`[vuex] ${msg}`);
37 | };
38 |
39 | export const repeat = (str, times) => (new Array(times + 1)).join(str);
40 |
41 | export const pad = (num, maxLength) => repeat('0', maxLength - num.toString().length) + num;
42 |
--------------------------------------------------------------------------------
/content/ClientApp/utils/helpers/notification.js:
--------------------------------------------------------------------------------
1 | export class Notification {
2 | /**
3 | * Show success notification
4 | *
5 | * @param {Object} vueInstance - Vue instance
6 | * @param {String} message - Message which to display on Notification
7 | */
8 | static success(vueInstance, message) {
9 | vueInstance.$notify({
10 | type: 'success',
11 | title: 'Success',
12 | message,
13 | duration: 3500
14 | });
15 | }
16 |
17 | /**
18 | * Show error notification
19 | *
20 | * @param {Object} vueInstance - Vue instance
21 | * @param {String} message - Message which to display on Notification
22 | */
23 | static error(vueInstance, message) {
24 | vueInstance.$notify({
25 | type: 'error',
26 | title: 'Something went wrong',
27 | message,
28 | duration: 5000
29 | });
30 | }
31 |
32 | /**
33 | * Show warn notification
34 | *
35 | * @param {Object} vueInstance - Vue instance
36 | * @param {String} message - Message which to display on Notification
37 | */
38 | static warning(vueInstance, message) {
39 | vueInstance.$notify({
40 | type: 'warning',
41 | title: 'Something went wrong',
42 | message,
43 | duration: 5000
44 | });
45 | }
46 |
47 | /**
48 | * Show info notification
49 | *
50 | * @param {Object} vueInstance - Vue instance
51 | * @param {String} message - Message which to display on Notification
52 | */
53 | static info(vueInstance, message) {
54 | vueInstance.$notify({
55 | type: 'info',
56 | title: 'Info',
57 | message,
58 | duration: 5000
59 | });
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/content/ClientApp/utils/helpers/table-column-composer.js:
--------------------------------------------------------------------------------
1 | // This is a helper to compose columns to the el-table dynamically
2 |
3 | const unCamelCase = str => str
4 | .replace(/([a-z])([A-Z])/g, '$1 $2')
5 | .replace(/\b([A-Z]+)([A-Z])([a-z])/, '$1 $2$3')
6 | .replace(/^./, str => str.toUpperCase());
7 |
8 | const createLabels = (property) => unCamelCase(property);
9 |
10 | /**
11 | * This is necessary because the table component of element-ui, when in a v-for, sets the
12 | * first column to the end. So, here, we put the real last option to start.
13 | * @param columns - The columns of the table
14 | */
15 | const resolveOrder = (columns) => {
16 | const lastOption = columns[columns.length - 1];
17 |
18 | const oldOptions = columns.filter(op => op !== lastOption);
19 | const newOptions = [];
20 |
21 | newOptions.push(lastOption);
22 | newOptions.push(...oldOptions);
23 |
24 | return newOptions;
25 | };
26 |
27 | class TableColumnComposer {
28 | /**
29 | * Compose the column array by receiving the column objects.
30 | * @param columns - The array of columns.
31 | * @returns {Array} - The reordered array of columns.
32 | */
33 | static composeColumns(columns) {
34 | return resolveOrder(columns);
35 | }
36 |
37 | /**
38 | * Compose the array of columns for some object.
39 | * @param model - The object showed in the table. CANNOT have inner objects.
40 | * @param options - Object with another options for the columns.
41 | * Each option is an array for each model attribute.
42 | * @returns {Array} - The reordered array of columns.
43 | */
44 | static compose(model, options) {
45 | const columns = [];
46 |
47 | const modelAsArray = Object.entries(model).map(o => o[0]);
48 |
49 | modelAsArray.forEach(property => {
50 | columns.push(this.newColumn(
51 | options && options.labels && options.labels.length === modelAsArray.length
52 | ? options.labels[modelAsArray.indexOf(property)]
53 | : createLabels(property),
54 | property,
55 | options
56 | ? options[modelAsArray.indexOf(property)]
57 | : null
58 | ));
59 | });
60 |
61 | return resolveOrder(columns);
62 | }
63 |
64 | /**
65 | * Creates an column.
66 | * @param label - The label of the column.
67 | * @param property - The property, i.e, the attribute name of the object showed.
68 | * @param options - Object with additional options for the
69 | * column, as 'width', 'type' and 'showOverflowTooltip'.
70 | * @returns {{property, label, type, showOverflowTooltip}} - A column.
71 | */
72 | static newColumn(label, property, options) {
73 | return {
74 | label,
75 | property,
76 | type: options && options.type || 'name',
77 | showOverflowTooltip: options && options.showOverflowTooltip || false
78 | };
79 | }
80 | }
81 |
82 | export default TableColumnComposer;
83 |
--------------------------------------------------------------------------------
/content/ClientApp/utils/helpers/vuex-logger.js:
--------------------------------------------------------------------------------
1 | import { deepCopy, pad } from './functions';
2 |
3 | /* eslint-disable */
4 | export default function logger({
5 | collapsed = true,
6 | filter = (mutation, stateBefore, stateAfter) => true,
7 | transformer = state => state,
8 | mutationTransformer = mut => mut,
9 | logger = console
10 | } = {}) {
11 | return store => {
12 | let prevState = deepCopy(store.state);
13 |
14 | store.subscribe((mutation, state) => {
15 | if (typeof logger === 'undefined') {
16 | return;
17 | }
18 | const nextState = deepCopy(state);
19 |
20 | if (filter(mutation, prevState, nextState)) {
21 | const time = new Date();
22 | const formattedTime = ` @ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(time.getSeconds(), 2)}.${pad(time.getMilliseconds(), 3)}`;
23 | const formattedMutation = mutationTransformer(mutation);
24 | const message = `mutation ${mutation.type}${formattedTime}`;
25 | const startMessage = collapsed
26 | ? logger.groupCollapsed
27 | : logger.group;
28 |
29 | try {
30 | startMessage.call(logger, message);
31 | } catch (e) {
32 | console.error(message);
33 | }
34 |
35 | logger.log('%c prev state', 'color: #9E9E9E; font-weight: bold', transformer(prevState));
36 | logger.log('%c mutation', 'color: #03A9F4; font-weight: bold', formattedMutation);
37 | logger.log('%c next state', 'color: #4CAF50; font-weight: bold', transformer(nextState));
38 |
39 | try {
40 | logger.groupEnd();
41 | } catch (e) {
42 | logger.log('—— log end ——');
43 | }
44 | }
45 |
46 | prevState = nextState;
47 | });
48 | };
49 | }
50 |
--------------------------------------------------------------------------------
/content/Controllers/WeatherController.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using System.Threading;
3 | using AspDotnetVueJs.Providers;
4 | using Microsoft.AspNetCore.Cors;
5 | using Microsoft.AspNetCore.Mvc;
6 |
7 | namespace AspDotnetVueJs.Controllers
8 | {
9 | [Route("api/[controller]")]
10 | public class WeatherController : ControllerBase
11 | {
12 | private readonly IWeatherProvider _weatherProvider;
13 |
14 | public WeatherController(IWeatherProvider weatherProvider)
15 | {
16 | _weatherProvider = weatherProvider;
17 | }
18 |
19 | [HttpGet("[action]")]
20 | public IActionResult Forecasts([FromQuery(Name = "from")] int from = 0, [FromQuery(Name = "to")] int to = 4)
21 | {
22 | var quantity = to - from;
23 |
24 | // We should also avoid going too far in the list.
25 | if (quantity <= 0) return BadRequest("You cannot have the 'to' parameter higher than 'from' parameter.");
26 |
27 | if (from < 0) return BadRequest("You cannot go in the negative with the 'from' parameter");
28 |
29 | var allForecasts = _weatherProvider.GetForecasts();
30 | var result = new
31 | {
32 | Total = allForecasts.Count,
33 | Forecasts = allForecasts.Skip(from).Take(quantity).ToArray()
34 | };
35 |
36 | Thread.Sleep(2000);
37 |
38 | return Ok(result);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/content/Dockerfile:
--------------------------------------------------------------------------------
1 | # Build the container with Source code compiled
2 | FROM mcr.microsoft.com/dotnet/core/sdk:2.2-alpine3.8 as buildenv
3 | WORKDIR /source
4 | RUN apk add --update nodejs nodejs-npm
5 | COPY *.csproj .
6 | RUN dotnet restore
7 | COPY . .
8 | # Publishing will also restore (install) the npm packages.
9 | RUN dotnet publish -c Release -o /app/ -r linux-musl-x64
10 |
11 | # Stage 2 - Creating Image for compiled app
12 | FROM mcr.microsoft.com/dotnet/core/runtime:2.2-alpine3.8 as baseimage
13 | RUN addgroup -S coreApp && adduser -S -G coreApp coreApp
14 |
15 | # Define other environment variable if needed.
16 | ENV ASPNETCORE_URLS=http://+:$port
17 |
18 | WORKDIR /app
19 | COPY --from=buildenv /app .
20 | RUN chown -R coreApp:coreApp /app
21 |
22 | # Replace the application name if required.
23 | ENTRYPOINT ["dotnet", "AspDotnetVueJs.dll"]
24 | EXPOSE $port
25 |
--------------------------------------------------------------------------------
/content/Extensions/ServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | using AspDotnetVueJs.Providers;
2 | using Microsoft.Extensions.DependencyInjection;
3 |
4 | namespace AspDotnetVueJs.Extensions
5 | {
6 | public static class ServiceCollectionExtensions
7 | {
8 | public static IServiceCollection AddWeather(this IServiceCollection services)
9 | {
10 | services.AddSingleton();
11 |
12 | return services;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/content/Models/WeatherForecast.cs:
--------------------------------------------------------------------------------
1 | namespace AspDotnetVueJs.Models
2 | {
3 | public class WeatherForecast
4 | {
5 | public string DateFormatted { get; set; }
6 |
7 | public string Summary { get; set; }
8 |
9 | public int TemperatureC { get; set; }
10 |
11 | public int TemperatureF => 32 + (int) (TemperatureC / 0.5556);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/content/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.Extensions.Hosting;
4 |
5 | namespace AspDotnetVueJs
6 | {
7 | public class Program
8 | {
9 | public static void Main(string[] args)
10 | {
11 | CreateHostBuilder(args).Build().Run();
12 | }
13 |
14 | public static IHostBuilder CreateHostBuilder(string[] args) =>
15 | Host.CreateDefaultBuilder(args)
16 | .ConfigureWebHostDefaults(webBuilder =>
17 | {
18 | webBuilder.UseStartup();
19 | });
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/content/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:36025",
8 | "sslPort": 44353
9 | }
10 | },
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "launchUrl": "",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "AspDotnetVueJS": {
21 | "commandName": "Project",
22 | "launchBrowser": true,
23 | "launchUrl": "",
24 | "applicationUrl": "http://localhost:5000",
25 | "environmentVariables": {
26 | "ASPNETCORE_ENVIRONMENT": "Development"
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/content/Providers/IWeatherProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using AspDotnetVueJs.Models;
3 |
4 | namespace AspDotnetVueJs.Providers
5 | {
6 | public interface IWeatherProvider
7 | {
8 | List GetForecasts();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/content/Providers/WeatherProviderFake.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using AspDotnetVueJs.Models;
5 |
6 | namespace AspDotnetVueJs.Providers
7 | {
8 | public class WeatherProviderFake : IWeatherProvider
9 | {
10 | private readonly string[] summaries =
11 | {
12 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
13 | };
14 |
15 | public WeatherProviderFake()
16 | {
17 | Initialize(100);
18 | }
19 |
20 | private List WeatherForecasts { get; set; }
21 |
22 | public List GetForecasts()
23 | {
24 | return WeatherForecasts;
25 | }
26 |
27 | private void Initialize(int quantity)
28 | {
29 | var rng = new Random();
30 | WeatherForecasts = Enumerable.Range(1, quantity).Select(index => new WeatherForecast
31 | {
32 | DateFormatted = DateTime.Now.AddDays(index).ToString("d"),
33 | TemperatureC = rng.Next(-20, 55),
34 | Summary = summaries[rng.Next(summaries.Length)]
35 | }).ToList();
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/content/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.IO.Compression;
4 | using System.Reflection;
5 | using AspDotnetVueJs.Extensions;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.AspNetCore.Mvc;
9 | using Microsoft.AspNetCore.ResponseCompression;
10 | using Microsoft.AspNetCore.SpaServices.Webpack;
11 | using Microsoft.Extensions.Configuration;
12 | using Microsoft.Extensions.DependencyInjection;
13 | using Microsoft.Extensions.Hosting;
14 | using Swashbuckle.AspNetCore.Swagger;
15 | using Westwind.AspNetCore.LiveReload;
16 |
17 | [assembly: ApiConventionType(typeof(DefaultApiConventions))]
18 |
19 | namespace AspDotnetVueJs
20 | {
21 | public class Startup
22 | {
23 | public Startup(IConfiguration configuration)
24 | {
25 | Configuration = configuration;
26 | }
27 |
28 | public static IConfiguration Configuration { get; private set; }
29 |
30 | public void ConfigureServices(IServiceCollection services)
31 | {
32 | services.AddLiveReload(config =>
33 | {
34 | });
35 |
36 | services
37 | .AddMvc().AddNewtonsoftJson()
38 | .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
39 |
40 | services.AddSwaggerGen(c =>
41 | {
42 | c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
43 | {
44 | Title = Configuration["App:Title"],
45 | Description = Configuration["App:Description"],
46 | TermsOfService = new Uri(Configuration["App:TermsOfService"]),
47 | Version = Configuration["App:Version"]
48 | });
49 |
50 | var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
51 | var xmlPath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location), xmlFile);
52 | c.IncludeXmlComments(xmlPath);
53 | });
54 |
55 | services.AddCors(options =>
56 | {
57 | /*
58 | Specifying AllowAnyOrigin and AllowCredentials is an insecure configuration and can result in cross-site request forgery.
59 | The CORS service returns an invalid CORS response when an app is configured with both methods.
60 | */
61 | options.AddPolicy("CorsPolicy",
62 | builder => builder.AllowAnyOrigin()
63 | .AllowAnyMethod()
64 | .AllowAnyHeader()
65 | //.AllowCredentials()
66 | );
67 | });
68 |
69 | services.Configure(options =>
70 | options.Level = CompressionLevel.Optimal);
71 |
72 | services.AddResponseCompression(options =>
73 | {
74 | #if (!NoHttps)
75 | options.EnableForHttps = true;
76 | #endif
77 | });
78 |
79 | services.AddSpaStaticFiles(config => { config.RootPath = "wwwroot/"; });
80 |
81 | // Example with dependency injection for a data provider.
82 | services.AddWeather();
83 | }
84 |
85 | [System.Obsolete]
86 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
87 | {
88 | if (env.IsDevelopment())
89 | {
90 | app.UseLiveReload();
91 | app.UseDeveloperExceptionPage();
92 | }
93 | else
94 | {
95 | app.UseExceptionHandler("/Error");
96 | #if (!NoHttps)
97 | app.UseHsts();
98 | }
99 |
100 | app.UseHttpsRedirection();
101 | #else
102 | }
103 | #endif
104 |
105 | //app.UseResponseCompression();
106 |
107 | app.UseSwagger();
108 | app.UseSwaggerUI(c =>
109 | {
110 | c.SwaggerEndpoint(
111 | $"{Configuration["BaseUriPath"]}/swagger/v1/swagger.json",
112 | $"{Configuration["App:Title"]} {Configuration["App:Version"]}"
113 | );
114 | });
115 |
116 | //app.UseDefaultFiles();
117 | app.UseStaticFiles();
118 | app.UseSpaStaticFiles();
119 | app.UseRouting();
120 | app.UseCors("CorsPolicy");
121 | app.UseEndpoints(endpoints =>
122 | {
123 | endpoints.MapControllerRoute(
124 | name: "default",
125 | pattern: "{controller}/{action=Index}/{id?}");
126 | });
127 |
128 | app.UseSpa(spa =>
129 | {
130 | spa.Options.SourcePath = "ClientApp";
131 |
132 | if (env.IsDevelopment())
133 | spa.ApplicationBuilder.UseWebpackDevMiddleware(
134 | new WebpackDevMiddlewareOptions
135 | {
136 | HotModuleReplacement = true,
137 | ConfigFile = "./ClientApp/build/webpack.config.js"
138 | });
139 | });
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/content/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "System": "Information",
6 | "Microsoft": "Information"
7 | }
8 | },
9 | "BaseUriPath": "",
10 | "Environment": "dev",
11 | "GenerateMapFiles": "false",
12 | "WebRoot": "null",
13 | "Port": 5000,
14 | "LiveReload": {
15 | "LiveReloadEnabled": true,
16 | "ClientFileExtensions": ".cshtml,.css,.js,.htm,.html,.ts,.wc",
17 | "ServerRefreshTimeout": 3000,
18 | "WebSocketUrl": "/__livereload"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/content/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*",
10 | "App": {
11 | "Title": "ASP.NET VueJs | Template",
12 | "Description": "Template com .NET Core e VueJs",
13 | "Version": "3.0.0",
14 | "TermsOfService": "https://github.com/hvpaiva/aspdotnet-vuejs"
15 | },
16 | "ApiUrl": "http://localhost:5000",
17 | "BaseUriPath": "",
18 | "Environment": "prod",
19 | "GenerateMapFiles": "true",
20 | "LiveReload": {
21 | "LiveReloadEnabled": false
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/content/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "aspdotnet-vuejs",
3 | "description": "ASP.NET Core & VueJS",
4 | "author": "Highlander Paiva",
5 | "repository": {
6 | "url": "https://github.com/hvpaiva/aspdotnet-vuejs"
7 | },
8 | "license": "MIT",
9 | "scripts": {
10 | "build": "webpack --config ./ClientApp/build/webpack.config.js --hide-modules --progress --colors",
11 | "build:dev": "cross-env ASPNETCORE_ENVIRONMENT=Development NODE_ENV=development npm run build",
12 | "build:prod": "cross-env ASPNETCORE_ENVIRONMENT=Production NODE_ENV=production npm run build",
13 | "update-packages": "npx npm-check -u",
14 | "lint": "eslint ./ClientApp/ --ext .js,.vue --fix"
15 | },
16 | "dependencies": {
17 | "axios": "^0.18.0",
18 | "vue": "^2.6.8",
19 | "vue-router": "^3.0.2",
20 | "vuex": "^3.1.0",
21 | "vuex-router-sync": "^5.0.0",
22 | "lodash": "^4.17.11"
23 | },
24 | "devDependencies": {
25 | "cross-env": "^5.2.0",
26 | "@babel/core": "^7.3.4",
27 | "@babel/plugin-proposal-class-properties": "^7.0.0",
28 | "@babel/plugin-proposal-decorators": "^7.0.0",
29 | "@babel/plugin-proposal-export-namespace-from": "^7.0.0",
30 | "@babel/plugin-proposal-function-sent": "^7.0.0",
31 | "@babel/plugin-proposal-json-strings": "^7.0.0",
32 | "@babel/plugin-proposal-numeric-separator": "^7.0.0",
33 | "@babel/plugin-proposal-throw-expressions": "^7.0.0",
34 | "@babel/plugin-syntax-dynamic-import": "^7.0.0",
35 | "@babel/plugin-syntax-import-meta": "^7.0.0",
36 | "@babel/plugin-transform-async-to-generator": "^7.3.4",
37 | "@babel/plugin-transform-runtime": "^7.3.4",
38 | "@babel/preset-env": "^7.3.4",
39 | "@babel/register": "^7.0.0",
40 | "@babel/runtime": "^7.3.4",
41 | "@fortawesome/fontawesome-svg-core": "^1.2.13",
42 | "@fortawesome/free-brands-svg-icons": "^5.7.0",
43 | "@fortawesome/free-solid-svg-icons": "^5.7.0",
44 | "@fortawesome/vue-fontawesome": "^0.1.5",
45 | "aspnet-webpack": "^3.0.0",
46 | "babel-eslint": "^10.0.1",
47 | "babel-loader": "^8.0.5",
48 | "babel-preset-env": "^1.7.0",
49 | "copy-webpack-plugin": "^5.0.0",
50 | "css-loader": "^2.1.0",
51 | "element-ui": "^2.7.0",
52 | "eslint": "^5.15.1",
53 | "eslint-config-airbnb": "^17.1.0",
54 | "eslint-plugin-import": "^2.16.0",
55 | "eslint-plugin-jsx-a11y": "^6.1.1",
56 | "eslint-plugin-node": "^8.0.1",
57 | "eslint-plugin-promise": "^4.0.1",
58 | "eslint-plugin-react": "^7.11.0",
59 | "eslint-plugin-vue": "^5.2.2",
60 | "file-loader": "^3.0.1",
61 | "font-awesome": "^4.7.0",
62 | "html-webpack-plugin": "^3.2.0",
63 | "mini-css-extract-plugin": "^0.5.0",
64 | "node-sass": "^4.11.0",
65 | "optimize-css-assets-webpack-plugin": "^5.0.1",
66 | "pug": "^2.0.3",
67 | "pug-plain-loader": "^1.0.0",
68 | "rimraf": "^2.6.3",
69 | "sass-loader": "^7.1.0",
70 | "uglifyjs-webpack-plugin": "^2.1.2",
71 | "url-loader": "^1.1.2",
72 | "vue-loader": "^15.7.0",
73 | "vue-style-loader": "^4.1.2",
74 | "vue-template-compiler": "^2.6.8",
75 | "webpack": "^4.29.6",
76 | "webpack-cli": "^3.2.3",
77 | "webpack-dev-middleware": "^3.6.0",
78 | "webpack-hot-middleware": "^2.24.3"
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/content/wwwroot/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hvpaiva/aspdotnet-vuejs/e7bf3c5ed78e95f0f5a9a392b8dc32fdfdbe9b16/content/wwwroot/.gitkeep
--------------------------------------------------------------------------------