├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── LICENSE ├── README.MD ├── global.json └── src ├── demo1 ├── Controllers │ └── MessageController.cs ├── Hubs │ └── ApplicationHub.cs ├── Models │ └── ChatMessage.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── demo1.csproj └── wwwroot │ └── index.html ├── demo10 ├── Controllers │ └── ValidationController.cs ├── Pages │ ├── Index.cshtml │ ├── Index.cshtml.cs │ ├── _Layout.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── Validation │ └── VeeValidateAttribute.cs ├── client │ ├── .postcssrc.js │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── main.ts │ │ ├── shims-vue.d.ts │ │ └── validations.ts │ ├── tsconfig.json │ └── vue.config.js └── demo10.csproj ├── demo11 ├── .vscode │ ├── launch.json │ └── tasks.json ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── client │ ├── .gitignore │ ├── .postcssrc.js │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ ├── src │ │ ├── App.vue │ │ ├── assets │ │ │ └── logo.png │ │ ├── components │ │ │ └── HelloWorld.vue │ │ ├── main.ts │ │ ├── router.ts │ │ ├── shims-tsx.d.ts │ │ ├── shims-vue.d.ts │ │ ├── store.ts │ │ └── views │ │ │ ├── About.vue │ │ │ └── Home.vue │ ├── tsconfig.json │ └── vue.config.js ├── custom.d.ts └── demo11.csproj ├── demo12 └── client │ └── vue.config.js ├── demo2 ├── Controllers │ └── MessageController.cs ├── Hubs │ └── ApplicationHub.cs ├── Models │ └── ChatMessage.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── client │ ├── custom.d.ts │ ├── main.html │ ├── main.js │ └── tsconfig.json ├── demo2.csproj ├── package-lock.json ├── package.json ├── webpack.config.js └── wwwroot │ └── index.html ├── demo3 ├── Controllers │ └── MessageController.cs ├── Hubs │ └── ApplicationHub.cs ├── Models │ └── ChatMessage.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── client │ ├── custom.d.ts │ ├── main.html │ ├── main.ts │ └── tsconfig.json ├── demo3.csproj ├── package-lock.json ├── package.json ├── webpack.config.js └── wwwroot │ └── index.html ├── demo4 ├── Controllers │ └── MessageController.cs ├── Hubs │ └── ApplicationHub.cs ├── Models │ └── ChatMessage.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── client │ ├── custom.d.ts │ ├── main-component.vue │ └── main.ts ├── demo4.csproj ├── package-lock.json ├── package.json ├── tsconfig.json ├── webpack.config.js └── wwwroot │ └── index.html ├── demo5 ├── Controllers │ └── MessageController.cs ├── Hubs │ └── ApplicationHub.cs ├── Models │ └── ChatMessage.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── client │ ├── custom.d.ts │ ├── main-component.vue │ ├── main.ts │ └── stream-adapter.ts ├── demo5.csproj ├── package-lock.json ├── package.json ├── tsconfig.json ├── webpack.config.js └── wwwroot │ ├── index.html │ └── main.build.min.js ├── demo6 ├── Controllers │ └── MessageController.cs ├── Hubs │ └── ApplicationHub.cs ├── Models │ └── ChatMessage.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── client │ ├── custom.d.ts │ ├── main-component │ │ ├── main-component.ts │ │ └── main-component.vue │ ├── main.ts │ ├── store.ts │ └── stream-adapter.ts ├── demo6.csproj ├── package-lock.json ├── package.json ├── tsconfig.json ├── webpack.config.js └── wwwroot │ └── index.html ├── demo7 ├── Controllers │ └── MessageController.cs ├── Hubs │ ├── ApplicationHub.cs │ └── SecondHub.cs ├── Models │ └── ChatMessage.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── client │ ├── custom.d.ts │ ├── main-component │ │ ├── main-component.ts │ │ └── main-component.vue │ ├── main.ts │ ├── signalr-plugin.ts │ ├── store.ts │ ├── stream-adapter.ts │ └── vue.d.ts ├── demo7.csproj ├── package-lock.json ├── package.json ├── tsconfig.json ├── webpack.config.js └── wwwroot │ └── index.html ├── demo8 ├── Pages │ ├── Index.cshtml │ ├── Index.cshtml.cs │ ├── _Layout.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── client │ ├── custom.d.ts │ ├── main.ts │ └── validations.ts ├── demo8.csproj ├── package-lock.json ├── package.json ├── tsconfig.json └── webpack.config.js ├── demo9 ├── Controllers │ └── ValidationController.cs ├── Pages │ ├── Index.cshtml │ ├── Index.cshtml.cs │ ├── _Layout.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── Validation │ └── VeeValidateAttribute.cs ├── client │ ├── custom.d.ts │ ├── main.ts │ └── validations.ts ├── demo9.csproj ├── package-lock.json ├── package.json ├── tsconfig.json └── webpack.config.js └── signalrcore-demos.sln /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # local env files 13 | .env.local 14 | .env.*.local 15 | 16 | # User-specific files (MonoDevelop/Xamarin Studio) 17 | *.userprefs 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | bld/ 27 | [Bb]in/ 28 | [Oo]bj/ 29 | [Ll]og/ 30 | 31 | # Visual Studio 2015 cache/options directory 32 | .vs/ 33 | # Uncomment if you have tasks that create the project's static files in wwwroot 34 | #wwwroot/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # .NET Core 50 | project.lock.json 51 | project.fragment.lock.json 52 | artifacts/ 53 | 54 | *_i.c 55 | *_p.c 56 | *_i.h 57 | *.ilk 58 | *.meta 59 | *.obj 60 | *.pch 61 | *.pdb 62 | *.pgc 63 | *.pgd 64 | *.rsp 65 | *.sbr 66 | *.tlb 67 | *.tli 68 | *.tlh 69 | *.tmp 70 | *.tmp_proj 71 | *.log 72 | *.vspscc 73 | *.vssscc 74 | .builds 75 | *.pidb 76 | *.svclog 77 | *.scc 78 | 79 | # Chutzpah Test files 80 | _Chutzpah* 81 | 82 | # Visual C++ cache files 83 | ipch/ 84 | *.aps 85 | *.ncb 86 | *.opendb 87 | *.opensdf 88 | *.sdf 89 | *.cachefile 90 | *.VC.db 91 | *.VC.VC.opendb 92 | 93 | # Visual Studio profiler 94 | *.psess 95 | *.vsp 96 | *.vspx 97 | *.sap 98 | 99 | # TFS 2012 Local Workspace 100 | $tf/ 101 | 102 | # Guidance Automation Toolkit 103 | *.gpState 104 | 105 | # ReSharper is a .NET coding add-in 106 | _ReSharper*/ 107 | *.[Rr]e[Ss]harper 108 | *.DotSettings.user 109 | 110 | # JustCode is a .NET coding add-in 111 | .JustCode 112 | 113 | # TeamCity is a build add-in 114 | _TeamCity* 115 | 116 | # DotCover is a Code Coverage Tool 117 | *.dotCover 118 | 119 | # Visual Studio code coverage results 120 | *.coverage 121 | *.coveragexml 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 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 160 | # checkin your Azure Web App publish settings, but sensitive information contained 161 | # in these scripts will be unencrypted 162 | PublishScripts/ 163 | 164 | # NuGet Packages 165 | *.nupkg 166 | # The packages folder can be ignored because of Package Restore 167 | **/packages/* 168 | # except build/, which is used as an MSBuild target. 169 | !**/packages/build/ 170 | # Uncomment if necessary however generally it will be regenerated when needed 171 | #!**/packages/repositories.config 172 | # NuGet v3's project.json files produces more ignorable files 173 | *.nuget.props 174 | *.nuget.targets 175 | 176 | # Microsoft Azure Build Output 177 | csx/ 178 | *.build.csdef 179 | 180 | # Microsoft Azure Emulator 181 | ecf/ 182 | rcf/ 183 | 184 | # Windows Store app package directories and files 185 | AppPackages/ 186 | BundleArtifacts/ 187 | Package.StoreAssociation.xml 188 | _pkginfo.txt 189 | 190 | # Visual Studio cache files 191 | # files ending in .cache can be ignored 192 | *.[Cc]ache 193 | # but keep track of directories ending in .cache 194 | !*.[Cc]ache/ 195 | 196 | # Others 197 | ClientBin/ 198 | ~$* 199 | *~ 200 | *.dbmdl 201 | *.dbproj.schemaview 202 | *.jfm 203 | *.pfx 204 | *.publishsettings 205 | orleans.codegen.cs 206 | 207 | # Since there are multiple workflows, uncomment next line to ignore bower_components 208 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 209 | #bower_components/ 210 | 211 | # RIA/Silverlight projects 212 | Generated_Code/ 213 | 214 | # Backup & report files from converting an old project file 215 | # to a newer Visual Studio version. Backup files are not needed, 216 | # because we have git ;-) 217 | _UpgradeReport_Files/ 218 | Backup*/ 219 | UpgradeLog*.XML 220 | UpgradeLog*.htm 221 | 222 | # SQL Server files 223 | *.mdf 224 | *.ldf 225 | *.ndf 226 | 227 | # Business Intelligence projects 228 | *.rdl.data 229 | *.bim.layout 230 | *.bim_*.settings 231 | 232 | # Microsoft Fakes 233 | FakesAssemblies/ 234 | 235 | # GhostDoc plugin setting file 236 | *.GhostDoc.xml 237 | 238 | # Node.js Tools for Visual Studio 239 | .ntvs_analysis.dat 240 | node_modules/ 241 | 242 | # Typescript v1 declaration files 243 | typings/ 244 | 245 | # Visual Studio 6 build log 246 | *.plg 247 | 248 | # Visual Studio 6 workspace options file 249 | *.opt 250 | 251 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 252 | *.vbw 253 | 254 | # Visual Studio LightSwitch build output 255 | **/*.HTMLClient/GeneratedArtifacts 256 | **/*.DesktopClient/GeneratedArtifacts 257 | **/*.DesktopClient/ModelManifest.xml 258 | **/*.Server/GeneratedArtifacts 259 | **/*.Server/ModelManifest.xml 260 | _Pvt_Extensions 261 | 262 | # Paket dependency manager 263 | .paket/paket.exe 264 | paket-files/ 265 | 266 | # FAKE - F# Make 267 | .fake/ 268 | 269 | # JetBrains Rider 270 | .idea/ 271 | *.sln.iml 272 | 273 | # CodeRush 274 | .cr/ 275 | 276 | # Python Tools for Visual Studio (PTVS) 277 | __pycache__/ 278 | *.pyc 279 | 280 | # Cake - Uncomment if you are using it 281 | # tools/** 282 | # !tools/packages.config 283 | 284 | # Telerik's JustMock configuration file 285 | *.jmconfig 286 | 287 | # BizTalk build output 288 | *.btp.cs 289 | *.btm.cs 290 | *.odx.cs 291 | *.xsd.cs 292 | 293 | .publish/ 294 | .DS_Store 295 | 296 | # ignore generated bundles 297 | **/wwwroot/**/*.map 298 | **/wwwroot/**/*.js -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to find out which attributes exist for C# debugging 3 | // Use hover for the description of the existing attributes 4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": ".NET Core Launch (web)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/src/demo11/bin/Debug/netcoreapp2.1/demo11.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}/src/demo11", 16 | "stopAtEntry": false, 17 | "internalConsoleOptions": "openOnSessionStart", 18 | "launchBrowser": { 19 | "enabled": true, 20 | "args": "${auto-detect-url}", 21 | "windows": { 22 | "command": "cmd.exe", 23 | "args": "/C start ${auto-detect-url}" 24 | }, 25 | "osx": { 26 | "command": "open" 27 | }, 28 | "linux": { 29 | "command": "xdg-open" 30 | } 31 | }, 32 | "env": { 33 | "ASPNETCORE_ENVIRONMENT": "Development" 34 | }, 35 | "sourceFileMap": { 36 | "/Views": "${workspaceFolder}/Views" 37 | } 38 | }, 39 | { 40 | "name": ".NET Core Attach", 41 | "type": "coreclr", 42 | "request": "attach", 43 | "processId": "${command:pickProcess}" 44 | } 45 | ,] 46 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/src/demo11/demo11.csproj" 11 | ], 12 | "problemMatcher": "$msCompile" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Cecil Phillip 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # ASP.NET Core, Webpack and Vue.js playground 2 | 3 | This repo contains demos showing various ways of configuring webpack and vue.js with ASP.NET Core projects. 4 | 5 | Running the samples 6 | 7 | ```bash 8 | > npm run build-dev or npm run build-prod 9 | > dotnet run 10 | ``` 11 | 12 | ## Demos 13 | 14 | The master branch is currently using .NET Core 2.2, ASP.NET Core 2.2, Vue.js 2.6.8, Vue CLI 3.5.1, webpack 4.29.6 and TypeScript 3.3.3 15 | 16 | - [Demo 1](src/demo1) - Loads Vue & SignalR from CDNs. No webpack. JavaScript in page. 17 | 18 | - [Demo 2](src/demo2) - Loads JavaScript dependencies from NPM. Webpack bundling with TypeScript transpiling JavaScript to ES2015. Defines vue.js global component with external template. 19 | 20 | - [Demo 3](src/demo3) - Loads JavaScript dependencies from NPM. Webpack bundling with TypeScript transpiling to ES2015. Defines vue.js global component with external template and class decorators. 21 | 22 | - [Demo 4](src/demo4) - Loads JavaScript dependencies from NPM. Webpack bundling with TypeScript transpiling to ES2015. Custom vue.js component using single file component with .vue extension. 23 | 24 | - [Demo 5](src/demo5) - NPM for JavaScript. Webpack bundling with TypeScript transpiling to ES2015. Async vue.js component (SFC). RxJS 6 w/ SignalR stream adapter. 25 | 26 | - [Demo 6](src/demo6) - NPM for JavaScript. Webpack bundling with TypeScript transpiling. Async vue.js component (SFC) + vuex state management. RxJS 6 w/ SignalR stream adapter. 27 | 28 | - [Demo 7](src/demo7) - NPM for JavaScript. Webpack bundling with TypeScript transpiling. Async vue.js component (SFC) + vuex state management + experimental SignalR VueJS plugin. RxJS 6 w/ SignalR stream adapter. 29 | 30 | - [Demo 8](src/demo8) - Simple client side validation using Razor Pages, VueJS and Vee-Validate. Converts data-val-* into Vee-Validate rules 31 | 32 | - [Demo 9](src/demo9) - Attempt at (somewhat) unobstrusive validation using Razor Pages, VueJS, Vee-Validate. Converts data-val-* into Vee-Validate rules. Uses a custom [ValidationAttribute](src/demo9/Validation/VeeValidateAttribute.cs) and a custom Vee-Validate [rule](src/demo9/client/validations.ts) to add client side validation to the input elements. Also does remote validation. 33 | 34 | - [Demo 10](src/demo10) - Same as demo 9, but built using the .NET CLI and the Vue.js CLI. 35 | 36 | - [Demo 11](src/demo11) - Vue CLI w/ [VueCliMiddleware](https://github.com/EEParker/aspnetcore-vueclimiddleware) for development interaction with the Vue cli. 37 | 38 | 39 | ## Useful tools 40 | 41 | - [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=code-github-cephilli) 42 | - [Vue.js devtools for Firefox](https://addons.mozilla.org/en-GB/firefox/addon/vue-js-devtools/) 43 | - [Vetur - Vue tooling for VS Code](https://marketplace.visualstudio.com/items?itemName=octref.vetur&WT.mc_id=code-github-cephilli) 44 | - [Vue VSCode Snippets](https://marketplace.visualstudio.com/items?itemName=sdras.vue-vscode-snippets&WT.mc_id=code-github-cephilli) 45 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "2.2.104" 4 | } 5 | } -------------------------------------------------------------------------------- /src/demo1/Controllers/MessageController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using demo1.Hubs; 3 | using demo1.Models; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.SignalR; 6 | 7 | namespace demo1.Controllers 8 | { 9 | 10 | [ApiController] 11 | [Route("/message")] 12 | public class MessageController : Controller 13 | { 14 | public IHubContext _hubContext { get; } 15 | 16 | public MessageController(IHubContext hubContext) 17 | { 18 | _hubContext = hubContext; 19 | } 20 | 21 | [HttpPost] 22 | public Task PostMessage(ChatMessage message) 23 | { 24 | return _hubContext.Clients.All.SendAsync("Send", message.Message); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo1/Hubs/ApplicationHub.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.SignalR; 2 | using System.Threading.Tasks; 3 | using demo1.Models; 4 | using System.Threading.Channels; 5 | using System; 6 | 7 | namespace demo1.Hubs 8 | { 9 | public class ApplicationHub : Hub 10 | { 11 | public Task Send(ChatMessage message) 12 | { 13 | return Clients.All.SendAsync("Send", message.Message); 14 | } 15 | 16 | public ChannelReader CountDown(int count) 17 | { 18 | var channel = Channel.CreateUnbounded(); 19 | 20 | _ = WriteToChannel(channel.Writer, count); 21 | 22 | return channel.Reader; 23 | 24 | async Task WriteToChannel(ChannelWriter writer, int thing) 25 | { 26 | for (int i = thing; i >= 0; i--) 27 | { 28 | await writer.WriteAsync(i); 29 | await Task.Delay(TimeSpan.FromSeconds(2)); 30 | } 31 | 32 | writer.Complete(); 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/demo1/Models/ChatMessage.cs: -------------------------------------------------------------------------------- 1 | namespace demo1.Models 2 | { 3 | public class ChatMessage 4 | { 5 | public string Message { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /src/demo1/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace demo1 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/demo1/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:41595", 7 | "sslPort": 44376 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "demo1": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo1/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using demo1.Hubs; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.Extensions.DependencyInjection; 10 | 11 | namespace demo1 12 | { 13 | public class Startup 14 | { 15 | // This method gets called by the runtime. Use this method to add services to the container. 16 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 17 | public void ConfigureServices(IServiceCollection services) 18 | { 19 | services.AddMvc(); 20 | services.AddSignalR() 21 | .AddMessagePackProtocol() ; 22 | } 23 | 24 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 25 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 26 | { 27 | if (env.IsDevelopment()) 28 | { 29 | app.UseDeveloperExceptionPage(); 30 | } 31 | 32 | app.UseFileServer(); 33 | app.UseMvc(); 34 | app.UseSignalR(routes => 35 | { 36 | routes.MapHub("/app"); 37 | }); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/demo1/demo1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | latest 4 | netcoreapp2.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo1/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | SignalR Demo 8 | 9 | 10 | 11 |
12 |

Hub API

13 |
14 | 15 | 16 |
17 | 18 |

REST API

19 |
20 | 21 | 22 |
23 | 24 |

Streaming Hub

25 |
26 | 27 | 28 |
29 | 30 |
    31 |
  • {{message}}
  • 32 |
33 |
34 | 35 | 36 | 37 | 38 | 40 | 41 | 42 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /src/demo10/Controllers/ValidationController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace demo10.Controllers 5 | { 6 | [Route("api/validate")] 7 | [ApiController] 8 | public class ValidationController : ControllerBase 9 | { 10 | [HttpPost] 11 | public ActionResult IsUserNameAvailable([FromBody]string userName) 12 | { 13 | return userName.Equals("cecilphillip", StringComparison.OrdinalIgnoreCase) ? 14 | Ok(new { valid = false, message = "User name is already in use" }): Ok(new { valid = true, message = "" }); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/demo10/Pages/Index.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model IndexModel 3 | 4 |
5 |
6 | 7 |
8 |
9 | 10 |
11 | 12 | 13 | 14 | 15 |
16 |

{{errors.first('Input.Name')}}

17 |
18 | 19 |
20 | 21 |
22 | 23 | 24 | 25 | 26 |
27 |

{{errors.first('Input.UserName')}}

28 |
29 | 30 |
31 | 32 |
33 | 34 | 35 | 36 | 37 |
38 |

{{errors.first('Input.Email')}}

39 |
40 | 41 |
42 | 43 |
44 | 45 |
46 |

{{errors.first('Input.Message')}}

47 |
48 | 49 |
50 |
51 | 52 |
53 |
54 | 55 |
56 |
57 |
58 |
59 | 60 | @section scripts { 61 | 62 | 63 | 64 | 65 | 66 | 67 | } 68 |
-------------------------------------------------------------------------------- /src/demo10/Pages/Index.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using demo10.Validation; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.AspNetCore.Mvc.RazorPages; 5 | 6 | namespace demo10.Pages 7 | { 8 | public class IndexModel : PageModel 9 | { 10 | public class InputModel 11 | { 12 | [Required] 13 | [MinLength(5)] 14 | [VeeValidate] 15 | public string Name { get; set; } 16 | 17 | [Required] 18 | [MaxLength(15)] 19 | [MinLength(5)] 20 | [Remote(action:"IsUserNameAvailable", controller:"Validation", HttpMethod="POST")] 21 | [VeeValidate] 22 | public string UserName { get; set; } 23 | 24 | [Required] 25 | [EmailAddress] 26 | [VeeValidate] 27 | public string Email { get; set; } 28 | 29 | [MaxLength(150)] 30 | [VeeValidate] 31 | public string Message { get; set; } 32 | } 33 | 34 | [BindProperty] 35 | public InputModel Input { get; set; } 36 | 37 | public void OnGet() 38 | { 39 | } 40 | 41 | public void OnPost() { 42 | 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/demo10/Pages/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Razor pages, Vue, SignalR 9 | 10 | 11 |
12 |
13 | @RenderBody() 14 |
15 |
16 | 17 | @RenderSection("scripts", required: false) 18 | 19 | -------------------------------------------------------------------------------- /src/demo10/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @namespace demo10.Pages 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | -------------------------------------------------------------------------------- /src/demo10/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } -------------------------------------------------------------------------------- /src/demo10/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace demo10 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/demo10/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:21461", 7 | "sslPort": 44379 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "demo10": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo10/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using demo10.Validation; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.AspNetCore.Mvc.DataAnnotations; 10 | using Microsoft.Extensions.DependencyInjection; 11 | 12 | namespace demo10 13 | { 14 | public class Startup 15 | { 16 | public void ConfigureServices(IServiceCollection services) 17 | { 18 | services.AddMvc(); 19 | services.AddSingleton(); 20 | } 21 | 22 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 23 | { 24 | if (env.IsDevelopment()) 25 | { 26 | app.UseDeveloperExceptionPage(); 27 | } 28 | 29 | app.UseStaticFiles(); 30 | app.UseMvc(); 31 | 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/demo10/Validation/VeeValidateAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.ComponentModel.DataAnnotations; 4 | using Microsoft.AspNetCore.Mvc.DataAnnotations; 5 | using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; 6 | using Microsoft.Extensions.Localization; 7 | 8 | namespace demo10.Validation 9 | { 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] 11 | public class VeeValidateAttribute : ValidationAttribute 12 | { 13 | protected override ValidationResult IsValid(object value, ValidationContext validationContext) 14 | => ValidationResult.Success; 15 | } 16 | 17 | public class VeeValidateAttributeAdapter : AttributeAdapterBase 18 | { 19 | public VeeValidateAttributeAdapter(VeeValidateAttribute attribute, IStringLocalizer stringLocalizer) : base(attribute, stringLocalizer) { } 20 | 21 | public override void AddValidation(ClientModelValidationContext context) 22 | { 23 | if (context == null) 24 | { 25 | throw new ArgumentNullException(nameof(context)); 26 | } 27 | 28 | var elementName = context.Attributes["name"]; 29 | var attributeValue = $"aspnet:{elementName}"; 30 | 31 | // Special handling for required rule. Needs to be a part of the base rule definition 32 | // of the v-validate attribute 33 | var isRequired = context.Attributes.ContainsKey("data-val-required"); 34 | attributeValue = isRequired ? $"required|{attributeValue}" : attributeValue; 35 | 36 | MergeAttribute(context.Attributes, "v-validate", $"'{attributeValue}'"); 37 | } 38 | 39 | public override string GetErrorMessage(ModelValidationContextBase validationContext) 40 | => GetErrorMessage(validationContext.ModelMetadata, validationContext.ModelMetadata.GetDisplayName()); 41 | } 42 | 43 | public class VeeValidateAttributeAdapterProvider : IValidationAttributeAdapterProvider 44 | { 45 | IValidationAttributeAdapterProvider baseProvider = new ValidationAttributeAdapterProvider(); 46 | public IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer stringLocalizer) 47 | { 48 | if (attribute is VeeValidateAttribute) 49 | return new VeeValidateAttributeAdapter(attribute as VeeValidateAttribute, stringLocalizer); 50 | return baseProvider.GetAttributeAdapter(attribute, stringLocalizer); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/demo10/client/.postcssrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } -------------------------------------------------------------------------------- /src/demo10/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build-prod": "vue-cli-service build", 8 | "build-dev": "vue-cli-service build --mode development" 9 | }, 10 | "dependencies": { 11 | "@types/webpack-chain": "^5.0.1", 12 | "vee-validate": "^2.1.7", 13 | "vue": "^2.6.8", 14 | "vue-class-component": "^7.0.1", 15 | "vue-property-decorator": "^8.0.0" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "^11.11.3", 19 | "@vue/cli-plugin-typescript": "^3.5.1", 20 | "@vue/cli-service": "^3.5.1", 21 | "typescript": "^3.3.3333", 22 | "vue-template-compiler": "^2.6.8" 23 | }, 24 | "browserslist": [ 25 | "> 1%", 26 | "last 2 versions", 27 | "not ie <= 8" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /src/demo10/client/src/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import "./validations"; 3 | 4 | new Vue({ 5 | el: "#serverForm", 6 | methods: { 7 | async validateBeforeSubmit(evt:Event) { 8 | var result = await this.$validator.validateAll(); 9 | if (result) return true; 10 | evt.preventDefault(); 11 | return false; 12 | } 13 | } 14 | }); -------------------------------------------------------------------------------- /src/demo10/client/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import Vue from 'vue' 3 | export default Vue 4 | } 5 | 6 | import Vue from 'vue'; 7 | import { Validator } from "vee-validate"; 8 | 9 | declare module "vue/types/vue" { 10 | interface Vue { 11 | $validator: Validator 12 | } 13 | } -------------------------------------------------------------------------------- /src/demo10/client/src/validations.ts: -------------------------------------------------------------------------------- 1 | import Veevalidate, { Validator } from 'vee-validate'; 2 | import Vue from 'vue'; 3 | 4 | const validationConfig: Veevalidate.Configuration = { 5 | classNames: { invalid: 'is-danger', valid: 'is-success', dirty: 'is-warning' }, 6 | classes: true 7 | }; 8 | 9 | Vue.use(Veevalidate, validationConfig); 10 | 11 | Veevalidate.Validator.extend('aspnet', { 12 | 13 | getMessage(field, params, data) { 14 | return (data && data.message) || `${field} is not valid.`; 15 | }, 16 | 17 | async validate(value, args) { 18 | let ref = document.querySelector(`[name="${args[0]}"]`); 19 | 20 | let validations = Object.keys(ref.dataset) 21 | .filter(x => x.startsWith('val')) 22 | .map(x => x.slice(3)) 23 | .map(x => ({ [x === '' ? 'val' : x.toLowerCase()]: ref.dataset['val' + x] })) 24 | .reduce((acc, curr) => Object.assign(acc, curr), {}); 25 | 26 | let valDef = mapValidations(validations); 27 | let validator = new Validator({ 28 | [ref.name]: valDef 29 | }, { fastExit: false }); 30 | 31 | let validated: boolean = await validator.validate(ref.name, ref.value); 32 | 33 | if (validated) { 34 | let remoteValidated = await remoteValidation(validations, ref.value); 35 | validated = remoteValidated.valid && validated; 36 | validator.errors.add({ field: ref.name, msg: remoteValidated.message }); 37 | } 38 | 39 | return { 40 | valid: validated, 41 | data: validated ? undefined : { message: validator.errors.first(ref.name) } 42 | }; 43 | 44 | function mapValidations(validations: { [key: string]: string }) { 45 | if (!validations || validations['val'] !== 'true') return true; 46 | 47 | const ruleNames = Object.keys(Validator.rules); 48 | let vMap = Object.keys(validations).filter(x => x !== 'val') 49 | .map(x => { 50 | let found = ruleNames.some(r => r === x); 51 | if (found) return x; 52 | switch (x) { 53 | case "maxlength": 54 | return `max:${validations["maxlengthmax"]}`; 55 | case "minlength": 56 | return `min:${validations["minlengthmin"]}`; 57 | default: 58 | return ''; 59 | } 60 | }) 61 | .reduce((acc, curr) => { 62 | if (curr === '') return acc; 63 | return `${acc}|${curr}`; 64 | }); 65 | return vMap; 66 | } 67 | 68 | async function remoteValidation(validations: { [key: string]: string }, inputValue: any): Promise<{ valid: boolean, message: string }> { 69 | if (validations.remote) { 70 | let data: { valid: boolean, message: string } = await fetch(`${validations.remoteurl}`, { 71 | method: validations.remotetype || "POST", 72 | body: JSON.stringify(inputValue), 73 | headers: { 74 | "content-type": "application/json", 75 | "accept": "application/json" 76 | } 77 | }).then(resp => resp.json()); 78 | return data; 79 | } 80 | return { valid: true, message: '' }; 81 | } 82 | } 83 | }); 84 | 85 | 86 | -------------------------------------------------------------------------------- /src/demo10/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": false, 4 | "target": "es5", 5 | "allowJs": true, 6 | "module": "esnext", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "experimentalDecorators": true, 10 | "emitDecoratorMetadata": true, 11 | "allowSyntheticDefaultImports": true, 12 | "sourceMap": true, 13 | "baseUrl": ".", 14 | "types": [ 15 | "node", 16 | "webpack-chain" 17 | ], 18 | "paths": { 19 | "@/*": [ 20 | "src/*" 21 | ] 22 | }, 23 | "lib": [ 24 | "es2015", 25 | "dom", 26 | "dom.iterable", 27 | "scripthost" 28 | ] 29 | }, 30 | "include": [ 31 | "src/**/*.ts", 32 | "src/**/*.tsx", 33 | "src/**/*.vue", 34 | "tests/**/*.ts", 35 | "tests/**/*.tsx" 36 | ], 37 | "exclude": [ 38 | "node_modules" 39 | ] 40 | } -------------------------------------------------------------------------------- /src/demo10/client/vue.config.js: -------------------------------------------------------------------------------- 1 | /// 2 | const ChainableWebpackConfig = require("webpack-chain"); 3 | 4 | module.exports = { 5 | outputDir: '../wwwroot', 6 | // Include Vue runtime + compiler since we're using Vue directly within Razor 7 | runtimeCompiler: true, 8 | 9 | /** @type {(config:ChainableWebpackConfig) => void} */ 10 | chainWebpack: config => { 11 | config.entryPoints.delete('app'); 12 | config.entry('main').add('./src/main.ts'); 13 | config.output.when(process.env.NODE_ENV === 'production', 14 | config => config.filename('[name].build.min.js'), 15 | config => config.filename('[name].build.js') 16 | ); 17 | 18 | // disable generation of index.html to outputDir 19 | config.plugins.delete('html'); 20 | config.plugins.delete('preload'); 21 | config.plugins.delete('prefetch'); 22 | } 23 | }; -------------------------------------------------------------------------------- /src/demo10/demo10.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo11/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": ".NET Core Launch (web)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | "program": "${workspaceFolder}/bin/Debug/netcoreapp2.2/demo11.dll", 13 | "args": [], 14 | "cwd": "${workspaceFolder}", 15 | "stopAtEntry": false, 16 | "internalConsoleOptions": "openOnSessionStart", 17 | "launchBrowser": { 18 | "enabled": true, 19 | "args": "${auto-detect-url}", 20 | "windows": { 21 | "command": "cmd.exe", 22 | "args": "/C start ${auto-detect-url}" 23 | }, 24 | "osx": { 25 | "command": "open" 26 | }, 27 | "linux": { 28 | "command": "xdg-open" 29 | } 30 | }, 31 | "env": { 32 | "ASPNETCORE_ENVIRONMENT": "Development" 33 | }, 34 | "sourceFileMap": { 35 | "/Views": "${workspaceFolder}/Views" 36 | } 37 | }, 38 | { 39 | "name": ".NET Core Attach", 40 | "type": "coreclr", 41 | "request": "attach", 42 | "processId": "${command:pickProcess}" 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /src/demo11/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/demo11.csproj" 11 | ], 12 | "problemMatcher": "$msCompile" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /src/demo11/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace demo11 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/demo11/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:54056", 7 | "sslPort": 44327 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "demo11": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo11/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Hosting; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.AspNetCore.SpaServices.Webpack; 9 | using Microsoft.Extensions.DependencyInjection; 10 | using VueCliMiddleware; 11 | 12 | namespace demo11 13 | { 14 | public class Startup 15 | { 16 | public void ConfigureServices(IServiceCollection services) 17 | { 18 | } 19 | 20 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 21 | { 22 | app.UseStaticFiles(); 23 | 24 | app.UseSpa(spa => 25 | { 26 | spa.Options.SourcePath = "client"; 27 | if (env.IsDevelopment()) 28 | { 29 | spa.UseVueCli(npmScript: "serve", port: 8080); // optional port 30 | } 31 | }); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/demo11/client/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /src/demo11/client/.postcssrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } -------------------------------------------------------------------------------- /src/demo11/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve -o", 7 | "build": "vue-cli-service build", 8 | "build-dev": "vue-cli-service build --mode development" 9 | }, 10 | "dependencies": { 11 | "vue": "^2.6.8", 12 | "vue-class-component": "^7.0.1", 13 | "vue-property-decorator": "^8.0.0", 14 | "vue-router": "^3.0.2", 15 | "vuex": "^3.1.0" 16 | }, 17 | "devDependencies": { 18 | "@vue/cli-plugin-typescript": "^3.5.1", 19 | "@vue/cli-service": "^3.5.1", 20 | "typescript": "^3.3.3333", 21 | "vue-template-compiler": "^2.6.8" 22 | }, 23 | "browserslist": [ 24 | "> 1%", 25 | "last 2 versions", 26 | "not ie <= 8" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /src/demo11/client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cecilphillip/aspnetcore-webpack-vue-sandbox/644cdc036d04f351b6f67f87f05cdb0ce2a0cbc8/src/demo11/client/public/favicon.ico -------------------------------------------------------------------------------- /src/demo11/client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | client 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/demo11/client/src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 32 | -------------------------------------------------------------------------------- /src/demo11/client/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cecilphillip/aspnetcore-webpack-vue-sandbox/644cdc036d04f351b6f67f87f05cdb0ce2a0cbc8/src/demo11/client/src/assets/logo.png -------------------------------------------------------------------------------- /src/demo11/client/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 39 | 40 | 41 | 57 | -------------------------------------------------------------------------------- /src/demo11/client/src/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store' 5 | 6 | Vue.config.productionTip = false 7 | 8 | new Vue({ 9 | router, 10 | store, 11 | render: h => h(App) 12 | }).$mount('#app') 13 | -------------------------------------------------------------------------------- /src/demo11/client/src/router.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Home from './views/Home.vue' 4 | import About from './views/About.vue' 5 | 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '/', 12 | name: 'home', 13 | component: Home 14 | }, 15 | { 16 | path: '/about', 17 | name: 'about', 18 | component: About 19 | } 20 | ] 21 | }) 22 | -------------------------------------------------------------------------------- /src/demo11/client/src/shims-tsx.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { VNode } from 'vue' 2 | 3 | declare global { 4 | namespace JSX { 5 | // tslint:disable no-empty-interface 6 | interface Element extends VNode {} 7 | // tslint:disable no-empty-interface 8 | interface ElementClass extends Vue {} 9 | interface IntrinsicElements { 10 | [elem: string]: any 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/demo11/client/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import Vue from 'vue' 3 | export default Vue 4 | } 5 | -------------------------------------------------------------------------------- /src/demo11/client/src/store.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | 9 | }, 10 | mutations: { 11 | 12 | }, 13 | actions: { 14 | 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /src/demo11/client/src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/demo11/client/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /src/demo11/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "experimentalDecorators": true, 10 | "emitDecoratorMetadata": true, 11 | "allowSyntheticDefaultImports": true, 12 | "sourceMap": true, 13 | "baseUrl": ".", 14 | "types": [ 15 | "node" 16 | ], 17 | "paths": { 18 | "@/*": [ 19 | "src/*" 20 | ] 21 | }, 22 | "lib": [ 23 | "es2015", 24 | "dom", 25 | "dom.iterable", 26 | "scripthost" 27 | ] 28 | }, 29 | "include": [ 30 | "src/**/*.ts", 31 | "src/**/*.tsx", 32 | "src/**/*.vue", 33 | "tests/**/*.ts", 34 | "tests/**/*.tsx" 35 | ], 36 | "exclude": [ 37 | "node_modules" 38 | ] 39 | } -------------------------------------------------------------------------------- /src/demo11/client/vue.config.js: -------------------------------------------------------------------------------- 1 | /// 2 | const ChainableWebpackConfig = require("webpack-chain"); 3 | 4 | module.exports = { 5 | outputDir: '../wwwroot', 6 | // Include Vue runtime + compiler since we're using Vue directly within Razor 7 | runtimeCompiler: true, 8 | 9 | /** @type {(config:ChainableWebpackConfig) => void} */ 10 | chainWebpack: config => { 11 | config.entryPoints.delete('app'); 12 | config.entry('main').add('./src/main.ts'); 13 | config.output.when(process.env.NODE_ENV === 'production', 14 | config => config.filename('[name].build.min.js'), 15 | config => config.filename('[name].build.js') 16 | ); 17 | } 18 | }; -------------------------------------------------------------------------------- /src/demo11/custom.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.html' { 2 | var _: string; 3 | export default _; 4 | } 5 | 6 | declare module "*.vue" { 7 | import Vue from 'vue' 8 | export default Vue 9 | } -------------------------------------------------------------------------------- /src/demo11/demo11.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | true 6 | Latest 7 | client\ 8 | $(DefaultItemExcludes);$(SpaRoot)node_modules\** 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 | %(DistFiles.Identity) 48 | PreserveNewest 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/demo12/client/vue.config.js: -------------------------------------------------------------------------------- 1 | /// 2 | const ChainableWebpackConfig = require("webpack-chain"); 3 | 4 | module.exports = { 5 | outputDir: '../wwwroot', 6 | // Include Vue runtime + compiler since we're using Vue directly within Razor 7 | runtimeCompiler: true, 8 | 9 | /** @type {(config:ChainableWebpackConfig) => void} */ 10 | chainWebpack: config => { 11 | config.entryPoints.delete('app'); 12 | config.entry('main').add('./src/main.ts'); 13 | config.output.when(process.env.NODE_ENV === 'production', 14 | config => config.filename('[name].build.min.js'), 15 | config => config.filename('[name].build.js') 16 | ); 17 | } 18 | }; -------------------------------------------------------------------------------- /src/demo2/Controllers/MessageController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using demo2.Hubs; 3 | using demo2.Models; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.SignalR; 6 | 7 | namespace demo2.Controllers 8 | { 9 | 10 | [ApiController] 11 | [Route("/message")] 12 | public class MessageController : Controller 13 | { 14 | public IHubContext _hubContext { get; } 15 | 16 | public MessageController(IHubContext hubContext) 17 | { 18 | _hubContext = hubContext; 19 | } 20 | 21 | [HttpPost] 22 | public Task PostMessage(ChatMessage message) 23 | { 24 | return _hubContext.Clients.All.SendAsync("Send", message.Message); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo2/Hubs/ApplicationHub.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.SignalR; 2 | using System.Threading.Tasks; 3 | using demo2.Models; 4 | using System.Threading.Channels; 5 | using System; 6 | 7 | namespace demo2.Hubs 8 | { 9 | public class ApplicationHub : Hub 10 | { 11 | 12 | public Task Send(ChatMessage message){ 13 | return Clients.All.SendAsync("Send", message.Message); 14 | } 15 | 16 | public ChannelReader CountDown(int count) { 17 | var channel = Channel.CreateUnbounded(); 18 | 19 | _ = WriteToChannel(channel.Writer, count); 20 | 21 | return channel.Reader; 22 | 23 | async Task WriteToChannel(ChannelWriter writer, int thing) { 24 | for (int i = thing; i >= 0 ; i--) 25 | { 26 | await writer.WriteAsync(i); 27 | await Task.Delay(TimeSpan.FromSeconds(2)); 28 | } 29 | 30 | writer.Complete(); 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/demo2/Models/ChatMessage.cs: -------------------------------------------------------------------------------- 1 | namespace demo2.Models 2 | { 3 | public class ChatMessage 4 | { 5 | public string Message { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /src/demo2/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace demo2 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/demo2/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:36415", 7 | "sslPort": 44348 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "demo2": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo2/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using demo2.Hubs; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.Extensions.DependencyInjection; 10 | 11 | namespace demo2 12 | { 13 | public class Startup 14 | { 15 | // This method gets called by the runtime. Use this method to add services to the container. 16 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 17 | public void ConfigureServices(IServiceCollection services) 18 | { 19 | services.AddMvc(); 20 | services.AddSignalR() 21 | .AddMessagePackProtocol() ; 22 | } 23 | 24 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 25 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 26 | { 27 | if (env.IsDevelopment()) 28 | { 29 | app.UseDeveloperExceptionPage(); 30 | } 31 | 32 | app.UseFileServer(); 33 | app.UseMvc(); 34 | app.UseSignalR(routes => 35 | { 36 | routes.MapHub("/app"); 37 | }); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/demo2/client/custom.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.html' { 2 | var _: string; 3 | export default _; 4 | } -------------------------------------------------------------------------------- /src/demo2/client/main.html: -------------------------------------------------------------------------------- 1 |
2 |

Hub API

3 |
4 | 5 | 6 |
7 | 8 |

REST API

9 |
10 | 11 | 12 |
13 | 14 |

Streaming Hub

15 |
16 | 17 | 18 |
19 | 20 |
    21 |
  • {{message}}
  • 22 |
23 |
-------------------------------------------------------------------------------- /src/demo2/client/main.js: -------------------------------------------------------------------------------- 1 | import { HubConnectionBuilder, HubConnection, LogLevel } from '@aspnet/signalr'; 2 | import { MessagePackHubProtocol } from '@aspnet/signalr-protocol-msgpack'; 3 | import Vue from 'vue'; 4 | 5 | Vue.component("main-component", { 6 | data: () => { 7 | return { 8 | messages: [], 9 | newMessage: null, 10 | newRestMessage: null, 11 | number: null, 12 | /** @type {HubConnection} */ 13 | connection: null 14 | } 15 | }, 16 | methods: { 17 | addMessage: async function() { 18 | await this.connection.invoke("Send", { Message: this.newMessage }); 19 | this.newMessage = null; 20 | }, 21 | addRestMessage: async function() { 22 | await fetch("/message", { 23 | method: "post", 24 | body: JSON.stringify({ Message: this.newRestMessage }), 25 | headers: { 26 | "content-type": "application/json" 27 | } 28 | }); 29 | 30 | this.newRestMessage = null; 31 | }, 32 | countDown: async function() { 33 | var stream = this.connection.stream("CountDown", parseInt(this.number)); 34 | var messages = this.messages; 35 | stream.subscribe({ 36 | next: function(item) { 37 | console.log('item ' + item); 38 | messages.push(item); 39 | } 40 | }); 41 | 42 | this.number = null; 43 | } 44 | }, 45 | 46 | template: require('./main.html') + "", 47 | 48 | created: function() { 49 | this.connection = new HubConnectionBuilder() 50 | .configureLogging(LogLevel.Information) 51 | .withUrl("/app") 52 | .withHubProtocol(new MessagePackHubProtocol()) 53 | .build(); 54 | 55 | console.log(this.connection); 56 | 57 | this.connection.on("Send", message => { 58 | this.messages.push(message); 59 | }); 60 | 61 | this.connection.start() 62 | .catch(error => console.error(error)); 63 | } 64 | }); 65 | 66 | new Vue({ el: "#app" }); -------------------------------------------------------------------------------- /src/demo2/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "../wwwroot", 4 | "noImplicitAny": false, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "noEmitOnError": false, 8 | "sourceMap": true, 9 | "allowJs": true, 10 | "checkJs": true, 11 | "target": "es2016", 12 | "module": "commonjs", 13 | "moduleResolution": "node" 14 | }, 15 | "include": [ 16 | "**/*.js", 17 | "**/*.ts" 18 | ], 19 | "exclude": [ 20 | "node_modules" 21 | ], 22 | "types": [ 23 | "node" 24 | ] 25 | } -------------------------------------------------------------------------------- /src/demo2/demo2.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | latest 4 | netcoreapp2.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo2", 3 | "version": "1.0.0", 4 | "description": "demos", 5 | "main": "index.js", 6 | "scripts": { 7 | "build-dev": "webpack --mode=development", 8 | "build-prod": "webpack --mode=production" 9 | }, 10 | "keywords": [], 11 | "author": "Cecil Phillip", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "@types/node": "^10.14.1", 15 | "html-loader": "^0.5.5", 16 | "ts-loader": "^5.3.3", 17 | "typescript": "^3.3.3333", 18 | "webpack": "^4.29.6", 19 | "webpack-cli": "^3.2.3" 20 | }, 21 | "dependencies": { 22 | "@aspnet/signalr": "^1.1.2", 23 | "@aspnet/signalr-protocol-msgpack": "^1.1.0", 24 | "msgpack5": "^4.2.1", 25 | "vue": "^2.6.8" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/demo2/webpack.config.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | const path = require("path"); 3 | 4 | module.exports = function (env, argv) { 5 | return { 6 | context: path.join(__dirname, "./client"), 7 | resolve: { 8 | extensions: [".ts", ".js", '.vue'], 9 | alias: { 10 | 'vue$': 'vue/dist/vue.esm.js' 11 | } 12 | }, 13 | entry: { 14 | main: "./main" 15 | }, 16 | output: { 17 | publicPath: "/", 18 | path: path.join(__dirname, "./wwwroot"), 19 | filename: argv.mode === 'production' ? "[name].build.min.js" : "[name].build.js" 20 | }, 21 | module: { 22 | rules: [ 23 | { test: /\.(ts|js)$/, use: { loader: "ts-loader", options: { appendTsSuffixTo: [/\.vue$/] } }, exclude: /node_modules/ }, 24 | { test: /\.html$/, use: [{ loader: 'html-loader', options: { minimize: false } }] } 25 | ] 26 | } 27 | }; 28 | }; -------------------------------------------------------------------------------- /src/demo2/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SignalR Demo 7 | 8 | 9 | 10 |
11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo3/Controllers/MessageController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using demo3.Hubs; 3 | using demo3.Models; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.SignalR; 6 | 7 | namespace demo3.Controllers 8 | { 9 | 10 | [ApiController] 11 | [Route("/message")] 12 | public class MessageController : Controller 13 | { 14 | public IHubContext _hubContext { get; } 15 | 16 | public MessageController(IHubContext hubContext) 17 | { 18 | _hubContext = hubContext; 19 | } 20 | 21 | [HttpPost] 22 | public Task PostMessage(ChatMessage message) 23 | { 24 | return _hubContext.Clients.All.SendAsync("Send", message.Message); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo3/Hubs/ApplicationHub.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.SignalR; 2 | using System.Threading.Tasks; 3 | using demo3.Models; 4 | using System.Threading.Channels; 5 | using System; 6 | 7 | namespace demo3.Hubs 8 | { 9 | public class ApplicationHub : Hub 10 | { 11 | public Task Send(ChatMessage message){ 12 | return Clients.All.SendAsync("Send", message.Message); 13 | } 14 | 15 | public ChannelReader CountDown(int count) { 16 | var channel = Channel.CreateUnbounded(); 17 | 18 | _ = WriteToChannel(channel.Writer, count); 19 | 20 | return channel.Reader; 21 | 22 | async Task WriteToChannel(ChannelWriter writer, int thing) { 23 | for (int i = thing; i >= 0 ; i--) 24 | { 25 | await writer.WriteAsync(i); 26 | await Task.Delay(TimeSpan.FromSeconds(2)); 27 | } 28 | 29 | writer.Complete(); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/demo3/Models/ChatMessage.cs: -------------------------------------------------------------------------------- 1 | namespace demo3.Models 2 | { 3 | public class ChatMessage 4 | { 5 | public string Message { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /src/demo3/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace demo3 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/demo3/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:24752", 7 | "sslPort": 44390 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "demo3": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo3/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using demo3.Hubs; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.Extensions.DependencyInjection; 10 | 11 | namespace demo3 12 | { 13 | public class Startup 14 | { 15 | // This method gets called by the runtime. Use this method to add services to the container. 16 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 17 | public void ConfigureServices(IServiceCollection services) 18 | { 19 | services.AddMvc(); 20 | services.AddSignalR() 21 | .AddMessagePackProtocol() ; 22 | } 23 | 24 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 25 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 26 | { 27 | if (env.IsDevelopment()) 28 | { 29 | app.UseDeveloperExceptionPage(); 30 | } 31 | 32 | app.UseFileServer(); 33 | app.UseMvc(); 34 | app.UseSignalR(routes => 35 | { 36 | routes.MapHub("/app"); 37 | }); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/demo3/client/custom.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.html' { 2 | var _: string; 3 | export default _; 4 | } -------------------------------------------------------------------------------- /src/demo3/client/main.html: -------------------------------------------------------------------------------- 1 |
2 |

Hub API

3 |
4 | 5 | 6 |
7 | 8 |

REST API

9 |
10 | 11 | 12 |
13 | 14 |

Streaming Hub

15 |
16 | 17 | 18 |
19 | 20 |
    21 |
  • {{message}}
  • 22 |
23 |
-------------------------------------------------------------------------------- /src/demo3/client/main.ts: -------------------------------------------------------------------------------- 1 | import { HubConnectionBuilder, HubConnection, LogLevel } from '@aspnet/signalr'; 2 | import { MessagePackHubProtocol } from '@aspnet/signalr-protocol-msgpack'; 3 | 4 | import Vue from 'vue'; 5 | import { Component } from 'vue-property-decorator' 6 | 7 | @Component({ 8 | template: require('./main.html') 9 | }) 10 | class MainComponent extends Vue { 11 | messages: string[] = []; 12 | newMessage: string = ''; 13 | newRestMessage: string = ''; 14 | number: string = ''; 15 | connection: HubConnection = null; 16 | 17 | created() { 18 | this.connection = new HubConnectionBuilder() 19 | .configureLogging(LogLevel.Information) 20 | .withUrl("/app") 21 | .withHubProtocol(new MessagePackHubProtocol()) 22 | .build(); 23 | 24 | console.log(this.connection); 25 | 26 | this.connection.on("Send", message => { 27 | this.messages.push(message); 28 | }); 29 | 30 | this.connection.start() 31 | .catch(error => console.error(error)); 32 | } 33 | 34 | async addMessage() { 35 | await this.connection.invoke("Send", { Message: this.newMessage }); 36 | this.newMessage = null; 37 | } 38 | async addRestMessage() { 39 | await fetch("/message", { 40 | method: "post", 41 | body: JSON.stringify({ Message: this.newRestMessage }), 42 | headers: { 43 | "content-type": "application/json" 44 | } 45 | }); 46 | this.newRestMessage = null; 47 | } 48 | 49 | async countDown() { 50 | var stream = this.connection.stream("CountDown", parseInt(this.number)); 51 | var messages = this.messages; 52 | 53 | stream.subscribe({ 54 | next: function (item) { 55 | console.log('item ' + item); 56 | messages.push(item); 57 | }, 58 | complete: function () { }, 59 | error: function () { } 60 | }); 61 | 62 | this.number = null; 63 | } 64 | } 65 | 66 | new Vue({ el: "#app", components: { MainComponent } }); -------------------------------------------------------------------------------- /src/demo3/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": false, 4 | "emitDecoratorMetadata": true, 5 | "experimentalDecorators": true, 6 | "noEmitOnError": false, 7 | "sourceMap": true, 8 | "target": "es2015", 9 | "module": "commonjs", 10 | "moduleResolution": "node" 11 | }, 12 | "types": [ 13 | "node" 14 | ] 15 | } -------------------------------------------------------------------------------- /src/demo3/demo3.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | latest 4 | netcoreapp2.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo3", 3 | "version": "1.0.0", 4 | "description": "demos", 5 | "main": "index.js", 6 | "scripts": { 7 | "build-dev": "webpack --mode=development", 8 | "build-prod": "webpack --mode=production" 9 | }, 10 | "keywords": [], 11 | "author": "Cecil Phillip", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "@types/node": "^10.14.1", 15 | "css-loader": "^1.0.1", 16 | "html-loader": "^0.5.5", 17 | "ts-loader": "^5.3.3", 18 | "typescript": "^3.3.3333", 19 | "vue-class-component": "^6.3.2", 20 | "vue-property-decorator": "^7.3.0", 21 | "webpack": "^4.29.6", 22 | "webpack-cli": "^3.2.3" 23 | }, 24 | "dependencies": { 25 | "@aspnet/signalr": "^1.1.2", 26 | "@aspnet/signalr-protocol-msgpack": "^1.1.0", 27 | "msgpack5": "^4.2.1", 28 | "vue": "^2.6.8", 29 | "vue-loader": "^15.7.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/demo3/webpack.config.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | const path = require("path"); 3 | 4 | module.exports = function (env, argv) { 5 | return { 6 | context: path.join(__dirname, "./client"), 7 | resolve: { 8 | extensions: [".ts", ".js", '.vue'], 9 | alias: { 10 | 'vue$': 'vue/dist/vue.esm.js' 11 | } 12 | }, 13 | entry: { 14 | main: "./main" 15 | }, 16 | output: { 17 | publicPath: "/", 18 | path: path.join(__dirname, "./wwwroot"), 19 | filename: argv.mode === 'production' ? "[name].build.min.js" : "[name].build.js" 20 | }, 21 | module: { 22 | rules: [ 23 | { test: /\.(ts|js)$/, use: { loader: "ts-loader", options: { appendTsSuffixTo: [/\.vue$/] } }, exclude: /node_modules/ }, 24 | { test: /\.html$/, use: [{ loader: 'html-loader', options: { minimize: false } }] } 25 | ] 26 | } 27 | }; 28 | }; -------------------------------------------------------------------------------- /src/demo3/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SignalR Demo 7 | 8 | 9 | 10 |
11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo4/Controllers/MessageController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using demo4.Hubs; 3 | using demo4.Models; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.SignalR; 6 | 7 | namespace demo4.Controllers 8 | { 9 | 10 | [ApiController] 11 | [Route("/message")] 12 | public class MessageController : Controller 13 | { 14 | public IHubContext _hubContext { get; } 15 | 16 | public MessageController(IHubContext hubContext) 17 | { 18 | _hubContext = hubContext; 19 | } 20 | 21 | [HttpPost] 22 | public Task PostMessage(ChatMessage message) 23 | { 24 | return _hubContext.Clients.All.SendAsync("Send", message.Message); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo4/Hubs/ApplicationHub.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.SignalR; 2 | using System.Threading.Tasks; 3 | using demo4.Models; 4 | using System.Threading.Channels; 5 | using System; 6 | 7 | namespace demo4.Hubs 8 | { 9 | public class ApplicationHub : Hub 10 | { 11 | public Task Send(ChatMessage message){ 12 | return Clients.All.SendAsync("Send", message.Message); 13 | } 14 | 15 | public ChannelReader CountDown(int count) { 16 | var channel = Channel.CreateUnbounded(); 17 | 18 | _ = WriteToChannel(channel.Writer, count); 19 | 20 | return channel.Reader; 21 | 22 | async Task WriteToChannel(ChannelWriter writer, int thing) { 23 | for (int i = thing; i >= 0 ; i--) 24 | { 25 | await writer.WriteAsync(i); 26 | await Task.Delay(TimeSpan.FromSeconds(2)); 27 | } 28 | 29 | writer.Complete(); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/demo4/Models/ChatMessage.cs: -------------------------------------------------------------------------------- 1 | namespace demo4.Models 2 | { 3 | public class ChatMessage 4 | { 5 | public string Message { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /src/demo4/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace demo4 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/demo4/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:28655", 7 | "sslPort": 44310 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "demo4": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo4/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using demo4.Hubs; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.Extensions.DependencyInjection; 10 | 11 | namespace demo4 12 | { 13 | public class Startup 14 | { 15 | // This method gets called by the runtime. Use this method to add services to the container. 16 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 17 | public void ConfigureServices(IServiceCollection services) 18 | { 19 | services.AddMvc(); 20 | services.AddSignalR() 21 | .AddMessagePackProtocol() ; 22 | } 23 | 24 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 25 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 26 | { 27 | if (env.IsDevelopment()) 28 | { 29 | app.UseDeveloperExceptionPage(); 30 | } 31 | 32 | app.UseFileServer(); 33 | app.UseMvc(); 34 | app.UseSignalR(routes => 35 | { 36 | routes.MapHub("/app"); 37 | }); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/demo4/client/custom.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.html' { 2 | var _: string; 3 | export default _; 4 | } 5 | 6 | declare module "*.vue" { 7 | import Vue from 'vue' 8 | export default Vue 9 | } -------------------------------------------------------------------------------- /src/demo4/client/main-component.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 90 | -------------------------------------------------------------------------------- /src/demo4/client/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import MainComponent from './main-component.vue'; 3 | 4 | new Vue({ el: "#app", components: { MainComponent } }); -------------------------------------------------------------------------------- /src/demo4/demo4.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | latest 4 | netcoreapp2.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo4", 3 | "version": "1.0.0", 4 | "description": "demos", 5 | "main": "index.js", 6 | "scripts": { 7 | "build-dev": "webpack --mode=development", 8 | "build-prod": "webpack --mode=production" 9 | }, 10 | "keywords": [], 11 | "author": "Cecil Phillip", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "@types/node": "^10.14.1", 15 | "css-loader": "^1.0.1", 16 | "html-loader": "^0.5.5", 17 | "ts-loader": "^5.3.3", 18 | "typescript": "^3.3.3333", 19 | "vue-class-component": "^6.3.2", 20 | "vue-loader": "^15.7.0", 21 | "vue-property-decorator": "^7.3.0", 22 | "vue-template-compiler": "^2.6.8", 23 | "webpack": "^4.29.6", 24 | "webpack-cli": "^3.2.3" 25 | }, 26 | "dependencies": { 27 | "@aspnet/signalr": "^1.1.2", 28 | "@aspnet/signalr-protocol-msgpack": "^1.1.0", 29 | "msgpack5": "^4.2.1", 30 | "vue": "^2.6.8" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/demo4/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "module": "esnext", 5 | //"strict": true, 6 | "importHelpers": true, 7 | "noEmitOnError": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "sourceMap": true, 14 | "lib": [ 15 | "esnext", 16 | "dom", 17 | "dom.iterable", 18 | "scripthost" 19 | ] 20 | }, 21 | "include": [ 22 | "client/**/*.ts", 23 | "client/**/*.vue", 24 | ], 25 | "exclude": [ 26 | "node_modules" 27 | ] 28 | } -------------------------------------------------------------------------------- /src/demo4/webpack.config.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | const path = require("path"); 3 | const { VueLoaderPlugin } = require('vue-loader'); 4 | 5 | module.exports = function (env, argv) { 6 | return { 7 | context: path.join(__dirname, "./client"), 8 | resolve: { 9 | extensions: [".ts", ".js", '.vue'], 10 | alias: { 11 | 'vue$': 'vue/dist/vue.esm.js' 12 | } 13 | }, 14 | entry: { 15 | main: "./main" 16 | }, 17 | output: { 18 | publicPath: "/", 19 | path: path.join(__dirname, "./wwwroot"), 20 | filename: argv.mode === 'production' ? "[name].build.min.js" : "[name].build.js" 21 | }, 22 | plugins: [ 23 | new VueLoaderPlugin() 24 | ], 25 | module: { 26 | rules: [ 27 | { test: /\.(ts|js)$/, use: { loader: "ts-loader", options: { appendTsSuffixTo: [/\.vue$/] } }, exclude: /node_modules/ }, 28 | { test: /\.vue$/, loader: 'vue-loader', options: { esModule: true, loaders: {} } }, 29 | { test: /\.html$/, use: [{ loader: 'html-loader', options: { minimize: false } }] } 30 | ] 31 | } 32 | }; 33 | }; -------------------------------------------------------------------------------- /src/demo4/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SignalR Demo 7 | 8 | 9 | 10 |
11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo5/Controllers/MessageController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using demo5.Hubs; 3 | using demo5.Models; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.SignalR; 6 | 7 | namespace demo4.Controllers 8 | { 9 | 10 | [ApiController] 11 | [Route("/message")] 12 | public class MessageController : Controller 13 | { 14 | public IHubContext _hubContext { get; } 15 | 16 | public MessageController(IHubContext hubContext) 17 | { 18 | _hubContext = hubContext; 19 | } 20 | 21 | [HttpPost] 22 | public Task PostMessage(ChatMessage message) 23 | { 24 | return _hubContext.Clients.All.SendAsync("Send", message.Message); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo5/Hubs/ApplicationHub.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.SignalR; 2 | using System.Threading.Tasks; 3 | using demo5.Models; 4 | using System.Threading.Channels; 5 | using System; 6 | 7 | namespace demo5.Hubs 8 | { 9 | public class ApplicationHub : Hub 10 | { 11 | public Task Send(ChatMessage message){ 12 | return Clients.All.SendAsync("Send", message.Message); 13 | } 14 | 15 | public ChannelReader CountDown(int count) { 16 | var channel = Channel.CreateUnbounded(); 17 | 18 | _ = WriteToChannel(channel.Writer, count); 19 | 20 | return channel.Reader; 21 | 22 | async Task WriteToChannel(ChannelWriter writer, int thing) { 23 | for (int i = thing; i >= 0 ; i--) 24 | { 25 | await writer.WriteAsync(i); 26 | await Task.Delay(TimeSpan.FromSeconds(0.75)); 27 | } 28 | 29 | writer.Complete(); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/demo5/Models/ChatMessage.cs: -------------------------------------------------------------------------------- 1 | namespace demo5.Models 2 | { 3 | public class ChatMessage 4 | { 5 | public string Message { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /src/demo5/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace demo5 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/demo5/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:9016", 7 | "sslPort": 44344 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "demo5": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo5/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using demo5.Hubs; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.Extensions.DependencyInjection; 10 | 11 | namespace demo5 12 | { 13 | public class Startup 14 | { 15 | // This method gets called by the runtime. Use this method to add services to the container. 16 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 17 | public void ConfigureServices(IServiceCollection services) 18 | { 19 | services.AddMvc(); 20 | services.AddSignalR() 21 | .AddMessagePackProtocol() ; 22 | } 23 | 24 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 25 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 26 | { 27 | if (env.IsDevelopment()) 28 | { 29 | app.UseDeveloperExceptionPage(); 30 | } 31 | 32 | app.UseFileServer(); 33 | app.UseMvc(); 34 | app.UseSignalR(routes => 35 | { 36 | routes.MapHub("/app"); 37 | }); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/demo5/client/custom.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.html' { 2 | var _: string; 3 | export default _; 4 | } 5 | 6 | declare module "*.vue" { 7 | import Vue from 'vue' 8 | export default Vue 9 | } -------------------------------------------------------------------------------- /src/demo5/client/main-component.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 88 | -------------------------------------------------------------------------------- /src/demo5/client/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | 3 | new Vue({ 4 | el: "#app", 5 | components: { 6 | MainComponent: () => import('./main-component.vue') 7 | } 8 | }); -------------------------------------------------------------------------------- /src/demo5/client/stream-adapter.ts: -------------------------------------------------------------------------------- 1 | import { IStreamResult } from "@aspnet/signalr"; 2 | import { Subject, Observable } from "rxjs"; 3 | 4 | export function adapt(stream: IStreamResult): Observable { 5 | const subject = new Subject(); 6 | stream.subscribe(subject); 7 | return subject.asObservable(); 8 | } 9 | -------------------------------------------------------------------------------- /src/demo5/demo5.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | latest 4 | netcoreapp2.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo5/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo5", 3 | "version": "1.0.0", 4 | "description": "demos", 5 | "main": "index.js", 6 | "scripts": { 7 | "build-dev": "webpack --mode=development", 8 | "build-prod": "webpack --mode=production" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "@types/node": "^11.11.3", 15 | "css-loader": "^2.1.1", 16 | "html-loader": "^0.5.5", 17 | "ts-loader": "^5.3.3", 18 | "typescript": "^3.3.3333", 19 | "vue-class-component": "^7.0.1", 20 | "vue-loader": "^15.7.0", 21 | "vue-property-decorator": "^8.0.0", 22 | "vue-template-compiler": "^2.6.8", 23 | "webpack": "^4.29.6", 24 | "webpack-cli": "^3.2.3" 25 | }, 26 | "dependencies": { 27 | "@aspnet/signalr": "^1.1.2", 28 | "@aspnet/signalr-protocol-msgpack": "^1.1.0", 29 | "msgpack5": "^4.2.1", 30 | "rxjs": "^6.4.0", 31 | "vue": "^2.6.8" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/demo5/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": false, 4 | "allowSyntheticDefaultImports": true, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "noEmitOnError": false, 8 | "sourceMap": true, 9 | "target": "es2015", 10 | "module": "commonjs", 11 | "moduleResolution": "node" 12 | }, 13 | "types": [ 14 | "node" 15 | ], 16 | "exclude": [ 17 | "node_modules" 18 | ], 19 | "include": [ 20 | "client/**/*.ts", 21 | "client/**/*.vue" 22 | ] 23 | } -------------------------------------------------------------------------------- /src/demo5/webpack.config.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | const path = require("path"); 3 | const { VueLoaderPlugin } = require('vue-loader'); 4 | 5 | module.exports = function (env, argv) { 6 | return { 7 | context: path.join(__dirname, "./client"), 8 | resolve: { 9 | extensions: [".ts", ".js", '.vue'], 10 | alias: { 11 | 'vue$': 'vue/dist/vue.esm.js' 12 | } 13 | }, 14 | entry: { 15 | main: "./main" 16 | }, 17 | output: { 18 | publicPath: "/", 19 | path: path.join(__dirname, "./wwwroot"), 20 | filename: argv.mode === 'production' ? "[name].build.min.js" : "[name].build.js" 21 | }, 22 | plugins: [ 23 | new VueLoaderPlugin() 24 | ], 25 | module: { 26 | rules: [ 27 | { test: /\.(ts|js)$/, use: { loader: "ts-loader", options: { appendTsSuffixTo: [/\.vue$/] } }, exclude: /node_modules/ }, 28 | { test: /\.vue$/, loader: 'vue-loader', options: { esModule: true, loaders: {} } }, 29 | { test: /\.html$/, use: [{ loader: 'html-loader', options: { minimize: false } }] } 30 | ] 31 | } 32 | }; 33 | }; -------------------------------------------------------------------------------- /src/demo5/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SignalR Demo 7 | 8 | 9 | 10 |
11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo6/Controllers/MessageController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using demo6.Hubs; 3 | using demo6.Models; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.SignalR; 6 | 7 | namespace demo6.Controllers 8 | { 9 | 10 | [ApiController] 11 | [Route("/message")] 12 | public class MessageController : Controller 13 | { 14 | public IHubContext _hubContext { get; } 15 | 16 | public MessageController(IHubContext hubContext) 17 | { 18 | _hubContext = hubContext; 19 | } 20 | 21 | [HttpPost] 22 | public Task PostMessage(ChatMessage message) 23 | { 24 | return _hubContext.Clients.All.SendAsync("Send", message.Message); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo6/Hubs/ApplicationHub.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.SignalR; 2 | using System.Threading.Tasks; 3 | using demo6.Models; 4 | using System.Threading.Channels; 5 | using System; 6 | 7 | namespace demo6.Hubs 8 | { 9 | public class ApplicationHub : Hub 10 | { 11 | public Task Send(ChatMessage message){ 12 | return Clients.All.SendAsync("Send", message.Message); 13 | } 14 | 15 | public ChannelReader CountDown(int count) { 16 | var channel = Channel.CreateUnbounded(); 17 | 18 | _ = WriteToChannel(channel.Writer, count); 19 | 20 | return channel.Reader; 21 | 22 | async Task WriteToChannel(ChannelWriter writer, int thing) { 23 | for (int i = thing; i >= 0 ; i--) 24 | { 25 | await writer.WriteAsync(i); 26 | await Task.Delay(TimeSpan.FromSeconds(0.75)); 27 | } 28 | 29 | writer.Complete(); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/demo6/Models/ChatMessage.cs: -------------------------------------------------------------------------------- 1 | namespace demo6.Models 2 | { 3 | public class ChatMessage 4 | { 5 | public string Message { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /src/demo6/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace demo6 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/demo6/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:29196", 7 | "sslPort": 44355 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "demo6": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo6/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using demo6.Hubs; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.Extensions.DependencyInjection; 10 | 11 | namespace demo6 12 | { 13 | public class Startup 14 | { 15 | // This method gets called by the runtime. Use this method to add services to the container. 16 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 17 | public void ConfigureServices(IServiceCollection services) 18 | { 19 | services.AddMvc(); 20 | services.AddSignalR() 21 | .AddMessagePackProtocol() ; 22 | } 23 | 24 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 25 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 26 | { 27 | if (env.IsDevelopment()) 28 | { 29 | app.UseDeveloperExceptionPage(); 30 | } 31 | 32 | app.UseFileServer(); 33 | app.UseMvc(); 34 | app.UseSignalR(routes => 35 | { 36 | routes.MapHub("/app"); 37 | }); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/demo6/client/custom.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.html' { 2 | var _: string; 3 | export default _; 4 | } 5 | 6 | declare module "*.vue" { 7 | import Vue from 'vue' 8 | export default Vue 9 | } -------------------------------------------------------------------------------- /src/demo6/client/main-component/main-component.ts: -------------------------------------------------------------------------------- 1 | import { HubConnectionBuilder, HubConnection, LogLevel } from "@aspnet/signalr"; 2 | import { MessagePackHubProtocol } from "@aspnet/signalr-protocol-msgpack"; 3 | 4 | import Vue from "vue"; 5 | import { Component } from "vue-property-decorator"; 6 | 7 | import { map, filter, switchMap } from 'rxjs/operators'; 8 | import { adapt } from '../stream-adapter'; 9 | 10 | @Component({}) 11 | export default class MainComponent extends Vue { 12 | connection: HubConnection = null; 13 | 14 | get messages(): string[] { 15 | return this.$store.state.messages; 16 | } 17 | 18 | get newMessage(): string { 19 | return this.$store.state.newMessage; 20 | } 21 | 22 | set newMessage(value: string) { 23 | this.$store.commit('updateNewMessage', value); 24 | } 25 | 26 | get newRestMessage(): string { 27 | return this.$store.state.newRestMessage; 28 | } 29 | 30 | set newRestMessage(value: string) { 31 | this.$store.commit('updateNewRestMessage', value); 32 | } 33 | 34 | get number(): string { 35 | return this.$store.state.number; 36 | } 37 | 38 | set number(value: string) { 39 | this.$store.commit('updateNumber', value); 40 | } 41 | 42 | created() { 43 | this.connection = new HubConnectionBuilder() 44 | .configureLogging(LogLevel.Information) 45 | .withUrl("/app") 46 | .withHubProtocol(new MessagePackHubProtocol()) 47 | .build(); 48 | 49 | console.log(this.connection); 50 | 51 | this.connection.on("Send", message => { 52 | this.$store.commit("addNewMessage", message); 53 | }); 54 | 55 | this.connection.start().catch(error => console.error(error)); 56 | } 57 | 58 | async addMessage() { 59 | await this.connection.invoke("Send", { Message: this.newMessage }); 60 | this.$store.commit("updateNewMessage", null); 61 | } 62 | 63 | async addRestMessage() { 64 | await fetch("/message", { 65 | method: "post", 66 | body: JSON.stringify({ Message: this.newRestMessage }), 67 | headers: { 68 | "content-type": "application/json" 69 | } 70 | }); 71 | this.$store.commit("updateNewMessage", null); 72 | } 73 | 74 | async countDown() { 75 | var stream = this.connection.stream("CountDown", parseInt(this.number)); 76 | var store = this.$store; 77 | 78 | adapt(stream).pipe( 79 | filter(x => parseInt(x) % 2 === 0) 80 | ).subscribe(x => store.commit("addNewMessage", x)); 81 | 82 | this.number = null; 83 | } 84 | } -------------------------------------------------------------------------------- /src/demo6/client/main-component/main-component.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/demo6/client/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import { store } from "./store"; 3 | 4 | new Vue({ 5 | el: "#app", 6 | store: store, 7 | components: { 8 | MainComponent: () => import('./main-component/main-component.vue') 9 | } 10 | }); -------------------------------------------------------------------------------- /src/demo6/client/store.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex, { Store } from "vuex"; 3 | 4 | export interface StoreState { 5 | messages: string[]; 6 | newMessage: string; 7 | newRestMessage: string; 8 | number: string; 9 | } 10 | 11 | Vue.use(Vuex); 12 | 13 | export const store = new Store({ 14 | state: { 15 | messages: [], 16 | newMessage: "", 17 | newRestMessage: "", 18 | number: "" 19 | }, 20 | mutations: { 21 | addNewMessage(state: StoreState, message: string) { 22 | state.messages.push(message); 23 | }, 24 | 25 | updateNewMessage(state: StoreState, newMessage: string) { 26 | state.newMessage = newMessage; 27 | }, 28 | 29 | updateNewRestMessage(state: StoreState, newRestMessage: string) { 30 | state.newRestMessage = newRestMessage; 31 | }, 32 | 33 | updateNumber(state: StoreState, number: string) { 34 | state.number = number; 35 | } 36 | } 37 | }); -------------------------------------------------------------------------------- /src/demo6/client/stream-adapter.ts: -------------------------------------------------------------------------------- 1 | import { IStreamResult } from "@aspnet/signalr"; 2 | import { Subject, Observable } from "rxjs"; 3 | 4 | export function adapt(stream: IStreamResult): Observable { 5 | const subject = new Subject(); 6 | stream.subscribe(subject); 7 | return subject.asObservable(); 8 | } 9 | -------------------------------------------------------------------------------- /src/demo6/demo6.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/demo6/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo6", 3 | "version": "1.0.0", 4 | "description": "demos", 5 | "main": "index.js", 6 | "scripts": { 7 | "build-dev": "webpack --mode=development", 8 | "build-prod": "webpack --mode=production" 9 | }, 10 | "keywords": [], 11 | "author": "Cecil Phillip", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "@types/node": "^10.11.5", 15 | "css-loader": "^1.0.0", 16 | "html-loader": "^0.5.5", 17 | "ts-loader": "^5.2.1", 18 | "typescript": "^3.1.1", 19 | "vue-class-component": "^6.2.0", 20 | "vue-loader": "^15.0.12", 21 | "vue-property-decorator": "^7.2.0", 22 | "vue-template-compiler": "^2.5.17", 23 | "webpack": "^4.20.2", 24 | "webpack-cli": "^3.1.2" 25 | }, 26 | "dependencies": { 27 | "@aspnet/signalr": "^1.0.4", 28 | "@aspnet/signalr-protocol-msgpack": "^1.0.4", 29 | "msgpack5": "^4.2.1", 30 | "rxjs": "^6.3.3", 31 | "vue": "^2.5.17", 32 | "vuex": "^3.0.1" 33 | } 34 | } -------------------------------------------------------------------------------- /src/demo6/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": false, 4 | "allowSyntheticDefaultImports": true, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "noEmitOnError": false, 8 | "sourceMap": true, 9 | "target": "es2015", 10 | "module": "commonjs", 11 | "moduleResolution": "node" 12 | }, 13 | "exclude": [ 14 | "node_modules" 15 | ], 16 | "include": [ 17 | "client/**/*.ts", 18 | "client/**/*.vue" 19 | ] 20 | } -------------------------------------------------------------------------------- /src/demo6/webpack.config.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | const path = require("path"); 3 | const webpack = require("webpack"); 4 | const { VueLoaderPlugin } = require('vue-loader'); 5 | 6 | module.exports = function (env) { 7 | const isProduction = env === "prod"; 8 | return { 9 | mode: isProduction ? 'production' : 'development', 10 | context: path.join(__dirname, "./client"), 11 | resolve: { 12 | extensions: [".ts", ".js", '.vue'], 13 | alias: { 14 | 'vue$': 'vue/dist/vue.esm.js' 15 | } 16 | }, 17 | entry: { 18 | main: "./main" 19 | }, 20 | output: { 21 | publicPath: "/", 22 | path: path.join(__dirname, "./wwwroot"), 23 | filename: isProduction ? "[name].build.min.js" : "[name].build.js" 24 | }, 25 | plugins: [ 26 | new VueLoaderPlugin() 27 | ], 28 | module: { 29 | rules: [ 30 | { test: /\.(ts|js)$/, use: { loader: "ts-loader", options: { appendTsSuffixTo: [/\.vue$/] } }, exclude: /node_modules/ }, 31 | { test: /\.vue$/, loader: 'vue-loader', options: { esModule: true, loaders: {}} }, 32 | { test: /\.html$/, use: [{ loader: 'html-loader', options: { minimize: false } }]} 33 | ] 34 | } 35 | }; 36 | }; -------------------------------------------------------------------------------- /src/demo6/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SignalR Demo 7 | 8 | 9 | 10 |
11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo7/Controllers/MessageController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using demo7.Hubs; 3 | using demo7.Models; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.SignalR; 6 | 7 | namespace demo7.Controllers 8 | { 9 | 10 | [ApiController] 11 | [Route("/message")] 12 | public class MessageController : Controller 13 | { 14 | public IHubContext _hubContext { get; } 15 | 16 | public MessageController(IHubContext hubContext) 17 | { 18 | _hubContext = hubContext; 19 | } 20 | 21 | [HttpPost] 22 | public Task PostMessage(ChatMessage message) 23 | { 24 | return _hubContext.Clients.All.SendAsync("Send", message.Message); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo7/Hubs/ApplicationHub.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.SignalR; 2 | using System.Threading.Tasks; 3 | using demo7.Models; 4 | using System.Threading.Channels; 5 | using System; 6 | 7 | namespace demo7.Hubs 8 | { 9 | public class ApplicationHub : Hub 10 | { 11 | public Task Send(ChatMessage message){ 12 | return Clients.All.SendAsync("Send", message.Message); 13 | } 14 | 15 | public ChannelReader CountDown(int count) { 16 | var channel = Channel.CreateUnbounded(); 17 | 18 | _ = WriteToChannel(channel.Writer, count); 19 | 20 | return channel.Reader; 21 | 22 | async Task WriteToChannel(ChannelWriter writer, int thing) { 23 | for (int i = thing; i >= 0 ; i--) 24 | { 25 | await writer.WriteAsync(i); 26 | await Task.Delay(TimeSpan.FromSeconds(0.75)); 27 | } 28 | 29 | writer.Complete(); 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/demo7/Hubs/SecondHub.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.AspNetCore.SignalR; 3 | 4 | namespace demo7.Hubs 5 | { 6 | public class SecondHub: Hub 7 | { 8 | public Task Fire(string message) { 9 | return Clients.All.SendAsync("Fire", $"Firing from second Hub {message}"); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/demo7/Models/ChatMessage.cs: -------------------------------------------------------------------------------- 1 | namespace demo7.Models 2 | { 3 | public class ChatMessage 4 | { 5 | public string Message { get; set; } 6 | } 7 | } -------------------------------------------------------------------------------- /src/demo7/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace demo7 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/demo7/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:47333", 7 | "sslPort": 44398 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "demo7": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo7/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using demo7.Hubs; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.Extensions.DependencyInjection; 10 | 11 | namespace demo7 12 | { 13 | public class Startup 14 | { 15 | // This method gets called by the runtime. Use this method to add services to the container. 16 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 17 | public void ConfigureServices(IServiceCollection services) 18 | { 19 | services.AddMvc(); 20 | services.AddSignalR() 21 | .AddMessagePackProtocol() ; 22 | } 23 | 24 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 25 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 26 | { 27 | if (env.IsDevelopment()) 28 | { 29 | app.UseDeveloperExceptionPage(); 30 | } 31 | 32 | app.UseFileServer(); 33 | app.UseMvc(); 34 | app.UseSignalR(routes => 35 | { 36 | routes.MapHub("/app"); 37 | routes.MapHub("/second"); 38 | }); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/demo7/client/custom.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.html' { 2 | var _: string; 3 | export default _; 4 | } 5 | 6 | declare module "*.vue" { 7 | import Vue from 'vue' 8 | export default Vue 9 | } -------------------------------------------------------------------------------- /src/demo7/client/main-component/main-component.ts: -------------------------------------------------------------------------------- 1 | 2 | import Vue from "vue"; 3 | import { Component } from "vue-property-decorator"; 4 | import { State, Mutation } from "vuex-class"; 5 | 6 | import { filter } from 'rxjs/operators'; 7 | import { adapt } from '../stream-adapter'; 8 | import { StoreState } from "../store"; 9 | 10 | @Component 11 | export default class MainComponent extends Vue implements StoreState { 12 | @State messages 13 | @State newMessage 14 | @State newRestMessage 15 | @State number 16 | 17 | @Mutation updateNewMessage 18 | @Mutation updateNewRestMessage 19 | @Mutation updateNumber 20 | @Mutation addNewMessage 21 | 22 | created() { 23 | let conn = this.$signalR["app"]; 24 | 25 | conn.on("Send", message => { 26 | this.addNewMessage(message); 27 | }); 28 | 29 | let secondConn = this.$signalR["second"]; 30 | secondConn.on("Fire", message => { 31 | this.addNewMessage(message); 32 | }); 33 | 34 | Promise.all([conn.start(), secondConn.start()]) 35 | .catch(error => console.error(error)); 36 | } 37 | 38 | async addMessage() { 39 | let conn = this.$signalR["app"]; 40 | await conn.invoke("Send", { Message: this.newMessage }); 41 | 42 | let secondConn = this.$signalR["second"]; 43 | await secondConn.invoke("Fire", this.newMessage); 44 | 45 | this.updateNewMessage(""); 46 | } 47 | 48 | async addRestMessage() { 49 | await fetch("/message", { 50 | method: "post", 51 | body: JSON.stringify({ Message: this.newRestMessage }), 52 | headers: { 53 | "content-type": "application/json" 54 | } 55 | }); 56 | this.updateNewMessage(""); 57 | } 58 | 59 | async countDown() { 60 | let conn = this.$signalR["app"]; 61 | var stream = conn.stream("CountDown", parseInt(this.number)); 62 | 63 | adapt(stream).pipe( 64 | filter(x => parseInt(x) % 2 === 0) 65 | ).subscribe(x => this.addNewMessage(x)); 66 | 67 | this.updateNumber(""); 68 | } 69 | } -------------------------------------------------------------------------------- /src/demo7/client/main-component/main-component.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/demo7/client/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import { store } from "./store"; 3 | import SignalRConnectionPlugin, { SignalRConnectionOptions } from "./signalr-plugin"; 4 | import { HubConnectionBuilder, LogLevel } from "@aspnet/signalr"; 5 | import { MessagePackHubProtocol } from "@aspnet/signalr-protocol-msgpack"; 6 | import MainComponent from "./main-component/main-component.vue"; 7 | 8 | Vue.use(SignalRConnectionPlugin, { 9 | urls: ["/app", "/second"], 10 | builderFactory(): HubConnectionBuilder { 11 | return new HubConnectionBuilder() 12 | .configureLogging(LogLevel.Information) 13 | .withHubProtocol(new MessagePackHubProtocol()); 14 | } 15 | }); 16 | 17 | new Vue({ 18 | el: "#app", 19 | store, 20 | components: { MainComponent }, 21 | render: createElement => createElement(MainComponent) 22 | }); 23 | -------------------------------------------------------------------------------- /src/demo7/client/signalr-plugin.ts: -------------------------------------------------------------------------------- 1 | import { PluginObject } from "vue"; 2 | import { HubConnectionBuilder, HubConnection, LogLevel } from "@aspnet/signalr"; 3 | import { MessagePackHubProtocol } from "@aspnet/signalr-protocol-msgpack"; 4 | 5 | export interface SignalRConnectionOptions { 6 | builderFactory: () => HubConnectionBuilder 7 | urls: string[] 8 | } 9 | 10 | function stripSlash(value: string): string { 11 | if (value.startsWith("/")) 12 | value = value.slice(1); 13 | return value; 14 | } 15 | 16 | const SignalRConnectionPlugin: PluginObject = { 17 | install(Vue, options?: SignalRConnectionOptions): void { 18 | if (this.install.installed) return; 19 | 20 | let connections: { [index: string]: HubConnection } = {}; 21 | 22 | options.urls.forEach((url: string): void => { 23 | connections[stripSlash(url)] = options.builderFactory() 24 | .withUrl(url) 25 | .build(); 26 | }); 27 | 28 | Vue.mixin({ 29 | destroyed() { 30 | console.log('Kill all connections'); 31 | } 32 | }); 33 | 34 | Vue.prototype.$signalR = connections; 35 | 36 | this.install.installed = true; 37 | console.log("SignalR plugin installed..."); 38 | } 39 | } 40 | 41 | export default SignalRConnectionPlugin; -------------------------------------------------------------------------------- /src/demo7/client/store.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex, { Store } from "vuex"; 3 | 4 | export interface StoreState { 5 | messages: string[]; 6 | newMessage: string; 7 | newRestMessage: string; 8 | number: string; 9 | } 10 | 11 | Vue.use(Vuex); 12 | 13 | export const store = new Store({ 14 | strict: process.env.NODE_ENV !== 'production', 15 | state: { 16 | messages: [], 17 | newMessage: "", 18 | newRestMessage: "", 19 | number: "" 20 | }, 21 | mutations: { 22 | addNewMessage(state: StoreState, message: string) { 23 | state.messages.push(message); 24 | }, 25 | 26 | updateNewMessage(state: StoreState, newMessage: string) { 27 | state.newMessage = newMessage; 28 | }, 29 | 30 | updateNewRestMessage(state: StoreState, newRestMessage: string) { 31 | state.newRestMessage = newRestMessage; 32 | }, 33 | 34 | updateNumber(state: StoreState, number: string) { 35 | state.number = number; 36 | } 37 | } 38 | }); -------------------------------------------------------------------------------- /src/demo7/client/stream-adapter.ts: -------------------------------------------------------------------------------- 1 | import { IStreamResult } from "@aspnet/signalr"; 2 | import { Subject, Observable } from "rxjs"; 3 | 4 | export function adapt(stream: IStreamResult): Observable { 5 | const subject = new Subject(); 6 | stream.subscribe(subject); 7 | return subject.asObservable(); 8 | } 9 | -------------------------------------------------------------------------------- /src/demo7/client/vue.d.ts: -------------------------------------------------------------------------------- 1 | import { HubConnection } from "@aspnet/signalr"; 2 | 3 | declare module "vue/types/vue" { 4 | 5 | interface Vue { 6 | $signalR: { [index: string]: HubConnection } 7 | } 8 | } -------------------------------------------------------------------------------- /src/demo7/demo7.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | latest 4 | netcoreapp2.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo7/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo7", 3 | "version": "1.0.0", 4 | "description": "demps", 5 | "main": "index.js", 6 | "scripts": { 7 | "build-dev": "webpack --mode=development", 8 | "build-prod": "webpack --mode=production" 9 | }, 10 | "keywords": [], 11 | "author": "Cecil Phillip", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "@types/node": "^10.11.5", 15 | "css-loader": "^1.0.0", 16 | "html-loader": "^0.5.5", 17 | "ts-loader": "^5.2.1", 18 | "typescript": "^3.1.1", 19 | "vue-class-component": "^6.2.0", 20 | "vue-loader": "^15.0.12", 21 | "vue-property-decorator": "^7.2.0", 22 | "vue-template-compiler": "^2.5.16", 23 | "webpack": "^4.8.3", 24 | "webpack-cli": "^3.1.2" 25 | }, 26 | "dependencies": { 27 | "@aspnet/signalr": "^1.0.4", 28 | "@aspnet/signalr-protocol-msgpack": "^1.0.4", 29 | "msgpack5": "^4.1.0", 30 | "rxjs": "^6.1.0", 31 | "vue": "^2.5.17", 32 | "vuex": "^3.0.1", 33 | "vuex-class": "^0.3.1" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/demo7/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": false, 4 | "allowSyntheticDefaultImports": true, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "noEmitOnError": false, 8 | "sourceMap": true, 9 | "target": "es2015", 10 | "module": "commonjs", 11 | "moduleResolution": "node" 12 | }, 13 | "exclude": [ 14 | "node_modules" 15 | ], 16 | "include": [ 17 | "client/**/*.ts", 18 | "client/**/*.vue" 19 | ] 20 | } -------------------------------------------------------------------------------- /src/demo7/webpack.config.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | const path = require("path"); 3 | const { VueLoaderPlugin } = require('vue-loader'); 4 | 5 | module.exports = function (env, argv) { 6 | return { 7 | context: path.join(__dirname, "./client"), 8 | resolve: { 9 | extensions: [".ts", ".js", '.vue'], 10 | alias: { 11 | 'vue$': 'vue/dist/vue.esm.js' 12 | } 13 | }, 14 | entry: { 15 | main: "./main" 16 | }, 17 | output: { 18 | publicPath: "/", 19 | path: path.join(__dirname, "./wwwroot"), 20 | filename: argv.mode === 'production' ? "[name].build.min.js" : "[name].build.js" 21 | }, 22 | plugins: [ 23 | new VueLoaderPlugin() 24 | ], 25 | module: { 26 | rules: [ 27 | { test: /\.(ts|js)$/, use: { loader: "ts-loader", options: { appendTsSuffixTo: [/\.vue$/] } }, exclude: /node_modules/ }, 28 | { test: /\.vue$/, loader: 'vue-loader', options: { esModule: true, loaders: {} } }, 29 | { test: /\.html$/, use: [{ loader: 'html-loader', options: { minimize: false } }] } 30 | ] 31 | } 32 | }; 33 | }; -------------------------------------------------------------------------------- /src/demo7/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SignalR Demo 7 | 8 | 9 | 10 |
11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo8/Pages/Index.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model IndexModel 3 | 4 |
5 |
6 | 7 |
8 |
9 | 10 |
11 | 13 | 14 | 15 | 16 |
17 |

{{errors.first('Input.Name')}}

18 |
19 | 20 |
21 | 22 |
23 | 25 | 26 | 27 | 28 |
29 |

{{errors.first('Input.UserName')}}

30 |
31 | 32 |
33 | 34 |
35 | 37 | 38 | 39 | 40 |
41 |

{{errors.first('Input.Email')}}

42 |
43 | 44 | 45 |
46 | 47 |
48 | 49 |
50 |
51 | 52 | 53 |
54 |
55 | 56 |
57 |
58 | 59 |
60 |
61 |
62 |
63 | 64 |
65 |
66 |
67 | 68 | @section scripts { 69 | } 70 |
-------------------------------------------------------------------------------- /src/demo8/Pages/Index.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | 9 | namespace demo8.Pages 10 | { 11 | public class IndexModel : PageModel 12 | { 13 | public class InputModel 14 | { 15 | [Required] 16 | [MinLength(5)] 17 | public string Name { get; set; } 18 | 19 | [Required] 20 | [MaxLength(10)] 21 | [MinLength(5)] 22 | public string UserName { get; set; } 23 | 24 | [Required] 25 | [EmailAddress] 26 | public string Email { get; set; } 27 | public string Message { get; set; } 28 | } 29 | 30 | [BindProperty] 31 | public InputModel Input { get; set; } 32 | 33 | public void OnGet() 34 | { 35 | } 36 | 37 | public void OnPost() { 38 | 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/demo8/Pages/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Razor pages, Vue, SignalR 9 | 10 | 11 |
12 |
13 | @RenderBody() 14 |
15 |
16 | 17 | @RenderSection("scripts", required: false) 18 | 19 | -------------------------------------------------------------------------------- /src/demo8/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @namespace demo8.Pages 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | -------------------------------------------------------------------------------- /src/demo8/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } -------------------------------------------------------------------------------- /src/demo8/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace demo8 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/demo8/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:47333", 7 | "sslPort": 44398 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "demo7": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo8/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Hosting; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.Extensions.DependencyInjection; 9 | 10 | namespace demo8 11 | { 12 | public class Startup 13 | { 14 | public void ConfigureServices(IServiceCollection services) 15 | { 16 | services.AddMvc(); 17 | } 18 | 19 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 20 | { 21 | if (env.IsDevelopment()) 22 | { 23 | app.UseDeveloperExceptionPage(); 24 | } 25 | 26 | app.UseStaticFiles(); 27 | app.UseMvc(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/demo8/client/custom.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.html' { 2 | var _: string; 3 | export default _; 4 | } 5 | 6 | declare module "*.vue" { 7 | import Vue from 'vue' 8 | export default Vue 9 | } -------------------------------------------------------------------------------- /src/demo8/client/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import "./validations"; 3 | 4 | var vueApp = new Vue({ 5 | el: "#serverForm", 6 | methods: { 7 | async validateBeforeSubmit(evt: Event) { 8 | var result = await this.$validator.validateAll(); 9 | if (result) return true; 10 | evt.preventDefault(); 11 | return false; 12 | } 13 | } 14 | }); -------------------------------------------------------------------------------- /src/demo8/client/validations.ts: -------------------------------------------------------------------------------- 1 | import Veevalidate, { Validator } from 'vee-validate'; 2 | import Vue from 'vue'; 3 | 4 | const validationConfig: Veevalidate.Configuration = { 5 | classNames: { invalid: 'is-danger', valid: 'is-success', dirty: 'is-warning' }, 6 | classes: true 7 | }; 8 | 9 | Vue.use(Veevalidate, validationConfig); 10 | 11 | Veevalidate.Validator.extend('aspnet', { 12 | 13 | getMessage(field, params, data) { 14 | return (data && data.message) || `${field} is not valid.`; 15 | }, 16 | 17 | async validate(value, args) { 18 | let ref = document.querySelector(`[name="${args[0]}"]`); 19 | 20 | let validations = Object.keys(ref.dataset) 21 | .filter(x => x.startsWith('val')) 22 | .map(x => x.slice(3)) 23 | .map(x => ({ [x === '' ? 'val' : x.toLowerCase()]: ref.dataset['val' + x] })) 24 | .reduce((acc, curr) => Object.assign(acc, curr), {}); 25 | 26 | let valDef = mapValidations(validations); 27 | let validator = new Validator({ 28 | [ref.name]: valDef 29 | }, { fastExit: false }); 30 | 31 | let validated = await validator.validate(ref.name, ref.value); 32 | 33 | return { 34 | valid: validated, 35 | data: validated ? undefined : { message: validator.errors.first(ref.name) } 36 | }; 37 | 38 | function mapValidations(validations: { [key: string]: string }) { 39 | if (!validations || validations['val'] !== 'true') return true; 40 | 41 | const ruleNames = Object.keys(Validator.rules); 42 | let vMap = Object.keys(validations).filter(x => x !== 'val') 43 | .map(x => { 44 | let found = ruleNames.some(r => r === x); 45 | if (found) return x; 46 | switch (x) { 47 | case "maxlength": 48 | return `max:${validations["maxlengthmax"]}`; 49 | case "minlength": 50 | return `min:${validations["minlengthmin"]}`; 51 | default: 52 | return ''; 53 | } 54 | }) 55 | .reduce((acc, curr) => { 56 | if (curr === '') return acc; 57 | return `${acc}|${curr}`; 58 | }); 59 | return vMap; 60 | } 61 | } 62 | }); 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/demo8/demo8.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | latest 4 | netcoreapp2.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo8/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo8", 3 | "version": "1.0.0", 4 | "description": "demos", 5 | "main": "index.js", 6 | "scripts": { 7 | "build-dev": "webpack --mode=development", 8 | "build-prod": "webpack --mode=production" 9 | }, 10 | "keywords": [], 11 | "author": "Cecil Phillip", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "@types/node": "^11.11.3", 15 | "css-loader": "^2.1.1", 16 | "html-loader": "^0.5.5", 17 | "ts-loader": "^5.3.3", 18 | "typescript": "^3.3.3333", 19 | "vue-class-component": "^7.0.1", 20 | "vue-loader": "^15.7.0", 21 | "vue-property-decorator": "^8.0.0", 22 | "vue-template-compiler": "^2.6.8", 23 | "webpack": "^4.29.6", 24 | "webpack-cli": "^3.2.3" 25 | }, 26 | "dependencies": { 27 | "vee-validate": "^2.1.7", 28 | "vue": "^2.6.8", 29 | "vuex": "^3.1.0", 30 | "vuex-class": "^0.3.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/demo8/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": false, 4 | "allowSyntheticDefaultImports": true, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "noEmitOnError": false, 8 | "sourceMap": true, 9 | "target": "es2015", 10 | "module": "commonjs", 11 | "moduleResolution": "node" 12 | }, 13 | "include": [ 14 | "client/**/*.ts", 15 | "client/**/*.vue" 16 | ], 17 | "exclude": [ 18 | "node_modules" 19 | ] 20 | } -------------------------------------------------------------------------------- /src/demo8/webpack.config.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | const path = require("path"); 3 | const { VueLoaderPlugin } = require('vue-loader'); 4 | 5 | module.exports = function (env) { 6 | const isProduction = env === "prod"; 7 | return { 8 | mode: isProduction ? 'production' : 'development', 9 | context: path.join(__dirname, "./client"), 10 | resolve: { 11 | extensions: [".ts", ".js", '.vue'], 12 | alias: { 13 | 'vue$': 'vue/dist/vue.esm.js' 14 | } 15 | }, 16 | entry: { 17 | main: "./main" 18 | }, 19 | output: { 20 | publicPath: "/", 21 | path: path.join(__dirname, "./wwwroot"), 22 | filename: isProduction ? "[name].build.min.js" : "[name].build.js" 23 | }, 24 | plugins: [ 25 | new VueLoaderPlugin() 26 | ], 27 | module: { 28 | rules: [ 29 | { test: /\.(ts|js)$/, use: { loader: "ts-loader", options: { appendTsSuffixTo: [/\.vue$/] } }, exclude: /node_modules/ }, 30 | { test: /\.vue$/, loader: 'vue-loader', options: { esModule: true, loaders: {} } }, 31 | { test: /\.html$/, use: [{ loader: 'html-loader', options: { minimize: false } }] } 32 | ] 33 | } 34 | }; 35 | }; -------------------------------------------------------------------------------- /src/demo9/Controllers/ValidationController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace demo9.Controllers 5 | { 6 | [Route("api/validate")] 7 | [ApiController] 8 | public class ValidationController : ControllerBase 9 | { 10 | [HttpPost] 11 | public ActionResult IsUserNameAvailable([FromBody]string userName) 12 | { 13 | return userName.Equals("cecilphillip", StringComparison.OrdinalIgnoreCase) ? 14 | Ok(new { valid = false, message = "User name is already in use" }): Ok(new { valid = true, message = "" }); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/demo9/Pages/Index.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model IndexModel 3 | 4 |
5 |
6 | 7 |
8 |
9 | 10 |
11 | 12 | 13 | 14 | 15 |
16 |

{{errors.first('Input.Name')}}

17 |
18 | 19 |
20 | 21 |
22 | 23 | 24 | 25 | 26 |
27 |

{{errors.first('Input.UserName')}}

28 |
29 | 30 |
31 | 32 |
33 | 34 | 35 | 36 | 37 |
38 |

{{errors.first('Input.Email')}}

39 |
40 | 41 |
42 | 43 |
44 | 45 |
46 |

{{errors.first('Input.Message')}}

47 |
48 | 49 |
50 |
51 | 52 |
53 |
54 | 55 |
56 |
57 |
58 |
59 | 60 | @section scripts { 61 | 62 | } 63 |
-------------------------------------------------------------------------------- /src/demo9/Pages/Index.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using demo9.Validation; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.AspNetCore.Mvc.RazorPages; 5 | 6 | namespace demo9.Pages 7 | { 8 | public class IndexModel : PageModel 9 | { 10 | public class InputModel 11 | { 12 | [Required] 13 | [MinLength(5)] 14 | [VeeValidate] 15 | public string Name { get; set; } 16 | 17 | [Required] 18 | [MaxLength(15)] 19 | [MinLength(5)] 20 | [Remote(action:"IsUserNameAvailable", controller:"Validation", HttpMethod="POST")] 21 | [VeeValidate] 22 | public string UserName { get; set; } 23 | 24 | [Required] 25 | [EmailAddress] 26 | [VeeValidate] 27 | public string Email { get; set; } 28 | 29 | [MaxLength(150)] 30 | [VeeValidate] 31 | public string Message { get; set; } 32 | } 33 | 34 | [BindProperty] 35 | public InputModel Input { get; set; } 36 | 37 | public void OnGet() 38 | { 39 | } 40 | 41 | public void OnPost() { 42 | 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/demo9/Pages/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Razor pages, Vue, SignalR 9 | 10 | 11 |
12 |
13 | @RenderBody() 14 |
15 |
16 | 17 | @RenderSection("scripts", required: false) 18 | 19 | -------------------------------------------------------------------------------- /src/demo9/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @namespace demo9.Pages 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | -------------------------------------------------------------------------------- /src/demo9/Pages/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } -------------------------------------------------------------------------------- /src/demo9/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace demo9 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/demo9/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:51369", 7 | "sslPort": 44304 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "demo9": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/demo9/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using demo9.Validation; 6 | using Microsoft.AspNetCore.Builder; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.AspNetCore.Mvc.DataAnnotations; 10 | using Microsoft.Extensions.DependencyInjection; 11 | 12 | namespace demo9 13 | { 14 | public class Startup 15 | { 16 | public void ConfigureServices(IServiceCollection services) 17 | { 18 | services.AddMvc(); 19 | services.AddSingleton(); 20 | } 21 | 22 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 23 | { 24 | if (env.IsDevelopment()) 25 | { 26 | app.UseDeveloperExceptionPage(); 27 | } 28 | 29 | app.UseStaticFiles(); 30 | app.UseMvc(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/demo9/Validation/VeeValidateAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.ComponentModel.DataAnnotations; 4 | using Microsoft.AspNetCore.Mvc.DataAnnotations; 5 | using Microsoft.AspNetCore.Mvc.ModelBinding.Validation; 6 | using Microsoft.Extensions.Localization; 7 | 8 | namespace demo9.Validation 9 | { 10 | [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] 11 | public class VeeValidateAttribute : ValidationAttribute 12 | { 13 | protected override ValidationResult IsValid(object value, ValidationContext validationContext) 14 | => ValidationResult.Success; 15 | } 16 | 17 | public class VeeValidateAttributeAdapter : AttributeAdapterBase 18 | { 19 | public VeeValidateAttributeAdapter(VeeValidateAttribute attribute, IStringLocalizer stringLocalizer) : base(attribute, stringLocalizer) { } 20 | 21 | public override void AddValidation(ClientModelValidationContext context) 22 | { 23 | if (context == null) 24 | { 25 | throw new ArgumentNullException(nameof(context)); 26 | } 27 | 28 | var elementName = context.Attributes["name"]; 29 | var attributeValue = $"aspnet:{elementName}"; 30 | 31 | // Special handling for required rule. Needs to be a part of the base rule definition 32 | // of the v-validate attribute 33 | var isRequired = context.Attributes.ContainsKey("data-val-required"); 34 | attributeValue = isRequired ? $"required|{attributeValue}" : attributeValue; 35 | 36 | MergeAttribute(context.Attributes, "v-validate", $"'{attributeValue}'"); 37 | } 38 | 39 | public override string GetErrorMessage(ModelValidationContextBase validationContext) 40 | => GetErrorMessage(validationContext.ModelMetadata, validationContext.ModelMetadata.GetDisplayName()); 41 | } 42 | 43 | public class VeeValidateAttributeAdapterProvider : IValidationAttributeAdapterProvider 44 | { 45 | IValidationAttributeAdapterProvider baseProvider = new ValidationAttributeAdapterProvider(); 46 | public IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer stringLocalizer) 47 | { 48 | if (attribute is VeeValidateAttribute) 49 | return new VeeValidateAttributeAdapter(attribute as VeeValidateAttribute, stringLocalizer); 50 | return baseProvider.GetAttributeAdapter(attribute, stringLocalizer); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/demo9/client/custom.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.html' { 2 | var _: string; 3 | export default _; 4 | } 5 | 6 | declare module "*.vue" { 7 | import Vue from 'vue' 8 | export default Vue 9 | } 10 | 11 | import Vue from 'vue'; 12 | import { Validator } from "vee-validate"; 13 | 14 | declare module "vue/types/vue" { 15 | interface Vue { 16 | $validator: Validator 17 | } 18 | } -------------------------------------------------------------------------------- /src/demo9/client/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import "./validations"; 3 | 4 | let vm = new Vue({ 5 | el: "#serverForm", 6 | methods: { 7 | async validateBeforeSubmit(evt: Event) { 8 | var result = await this.$validator.validateAll(); 9 | if (result) return true; 10 | evt.preventDefault(); 11 | return false; 12 | } 13 | } 14 | }); -------------------------------------------------------------------------------- /src/demo9/client/validations.ts: -------------------------------------------------------------------------------- 1 | import Veevalidate, { Validator } from 'vee-validate'; 2 | import Vue from 'vue'; 3 | 4 | const validationConfig: Veevalidate.Configuration = { 5 | classNames: { invalid: 'is-danger', valid: 'is-success', dirty: 'is-warning' }, 6 | classes: true 7 | }; 8 | 9 | Vue.use(Veevalidate, validationConfig); 10 | 11 | Veevalidate.Validator.extend('aspnet', { 12 | 13 | getMessage(field, params, data) { 14 | return (data && data.message) || `${field} is not valid.`; 15 | }, 16 | 17 | async validate(value, args) { 18 | let ref = document.querySelector(`[name="${args[0]}"]`); 19 | 20 | let validations = Object.keys(ref.dataset) 21 | .filter(x => x.startsWith('val')) 22 | .map(x => x.slice(3)) 23 | .map(x => ({ [x === '' ? 'val' : x.toLowerCase()]: ref.dataset['val' + x] })) 24 | .reduce((acc, curr) => Object.assign(acc, curr), {}); 25 | 26 | let valDef = mapValidations(validations); 27 | let validator = new Validator({ 28 | [ref.name]: valDef 29 | }, { fastExit: false }); 30 | 31 | let validated: boolean = await validator.validate(ref.name, ref.value); 32 | 33 | if (validated) { 34 | let remoteValidated = await remoteValidation(validations, ref.value); 35 | validated = remoteValidated.valid && validated; 36 | validator.errors.add({ field: ref.name, msg: remoteValidated.message }); 37 | } 38 | 39 | return { 40 | valid: validated, 41 | data: validated ? undefined : { message: validator.errors.first(ref.name) } 42 | }; 43 | 44 | function mapValidations(validations: { [key: string]: string }) { 45 | if (!validations || validations['val'] !== 'true') return true; 46 | 47 | const ruleNames = Object.keys(Validator.rules); 48 | let vMap = Object.keys(validations).filter(x => x !== 'val') 49 | .map(x => { 50 | let found = ruleNames.some(r => r === x); 51 | if (found) return x; 52 | switch (x) { 53 | case "maxlength": 54 | return `max:${validations["maxlengthmax"]}`; 55 | case "minlength": 56 | return `min:${validations["minlengthmin"]}`; 57 | default: 58 | return ''; 59 | } 60 | }) 61 | .reduce((acc, curr) => { 62 | if (curr === '') return acc; 63 | return `${acc}|${curr}`; 64 | }); 65 | return vMap; 66 | } 67 | 68 | async function remoteValidation(validations: { [key: string]: string }, inputValue: any): Promise<{ valid: boolean, message: string }> { 69 | if (validations.remote) { 70 | let data: { valid: boolean, message: string } = await fetch(`${validations.remoteurl}`, { 71 | method: validations.remotetype || "POST", 72 | body: JSON.stringify(inputValue), 73 | headers: { 74 | "content-type": "application/json", 75 | "accept": "application/json" 76 | } 77 | }).then(resp => resp.json()); 78 | return data; 79 | } 80 | return { valid: true, message: '' }; 81 | } 82 | } 83 | }); 84 | 85 | 86 | -------------------------------------------------------------------------------- /src/demo9/demo9.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/demo9/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo9", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build-dev": "webpack", 8 | "build-prod": "webpack --env=prod" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "@types/node": "^11.11.3", 15 | "css-loader": "^2.1.1", 16 | "html-loader": "^0.5.5", 17 | "ts-loader": "^5.3.3", 18 | "typescript": "^3.3.3333", 19 | "vue-class-component": "^7.0.1", 20 | "vue-loader": "^15.7.0", 21 | "vue-property-decorator": "^8.0.0", 22 | "vue-template-compiler": "^2.6.8", 23 | "webpack": "^4.29.6", 24 | "webpack-cli": "^3.2.3" 25 | }, 26 | "dependencies": { 27 | "vee-validate": "^2.1.7", 28 | "vue": "^2.6.8", 29 | "vuex": "^3.1.0", 30 | "vuex-class": "^0.3.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/demo9/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": false, 4 | "allowSyntheticDefaultImports": true, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "noEmitOnError": false, 8 | "sourceMap": true, 9 | "target": "es2015", 10 | "module": "commonjs", 11 | "moduleResolution": "node" 12 | }, 13 | "include": [ 14 | "client/**/*.ts", 15 | "client/**/*.vue" 16 | ], 17 | "exclude": [ 18 | "node_modules" 19 | ] 20 | } -------------------------------------------------------------------------------- /src/demo9/webpack.config.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | const path = require("path"); 3 | const webpack = require("webpack"); 4 | const { VueLoaderPlugin } = require('vue-loader'); 5 | 6 | module.exports = function (env) { 7 | const isProduction = env === "prod"; 8 | return { 9 | mode: isProduction ? 'production' : 'development', 10 | context: path.join(__dirname, "./client"), 11 | resolve: { 12 | extensions: [".ts", ".js", '.vue'], 13 | alias: { 14 | 'vue$': 'vue/dist/vue.esm.js' 15 | } 16 | }, 17 | entry: { 18 | main: "./main" 19 | }, 20 | output: { 21 | publicPath: "/", 22 | path: path.join(__dirname, "./wwwroot"), 23 | filename: isProduction ? "[name].build.min.js" : "[name].build.js" 24 | }, 25 | plugins: [ 26 | new VueLoaderPlugin() 27 | ], 28 | module: { 29 | rules: [ 30 | { test: /\.(ts|js)$/, use: { loader: "ts-loader", options: { appendTsSuffixTo: [/\.vue$/] } }, exclude: /node_modules/ }, 31 | { test: /\.vue$/, loader: 'vue-loader', options: { esModule: true, loaders: {}} }, 32 | { test: /\.html$/, use: [{ loader: 'html-loader', options: { minimize: false } }]} 33 | ] 34 | } 35 | }; 36 | }; -------------------------------------------------------------------------------- /src/signalrcore-demos.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "demo1", "demo1\demo1.csproj", "{8A77EB67-A017-48C9-A8BC-747AAA3185BD}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "demo2", "demo2\demo2.csproj", "{7F187A4C-3742-4F1B-9EDD-CB70FCC57A0D}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "demo3", "demo3\demo3.csproj", "{9354A0CB-32A8-4A4D-B47F-A7DCD2A50EC4}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "demo4", "demo4\demo4.csproj", "{C740CED5-2465-4ECC-B4D9-BEBC6967A78B}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "demo5", "demo5\demo5.csproj", "{057E41B5-B8E2-490B-96E7-BB7E355556C2}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "demo6", "demo6\demo6.csproj", "{91E6B66C-BD80-458C-A756-22F4DC0F9C5D}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "demo7", "demo7\demo7.csproj", "{6DDFAB44-082F-4CC8-BA43-46291D851522}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "demo8", "demo8\demo8.csproj", "{0CF88B13-283F-464B-ABF9-C986E101E463}" 21 | EndProject 22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "demo9", "demo9\demo9.csproj", "{67C6A1AB-B87B-43E4-A077-386739E64B56}" 23 | EndProject 24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "demo10", "demo10\demo10.csproj", "{CB0F959B-8688-455F-A856-0036695EACCA}" 25 | EndProject 26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "demo11", "demo11\demo11.csproj", "{1DC636DE-81D7-46D1-B7FC-AD233E8FBBD0}" 27 | EndProject 28 | Global 29 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 30 | Debug|Any CPU = Debug|Any CPU 31 | Debug|x64 = Debug|x64 32 | Debug|x86 = Debug|x86 33 | Release|Any CPU = Release|Any CPU 34 | Release|x64 = Release|x64 35 | Release|x86 = Release|x86 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 41 | {8A77EB67-A017-48C9-A8BC-747AAA3185BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {8A77EB67-A017-48C9-A8BC-747AAA3185BD}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {8A77EB67-A017-48C9-A8BC-747AAA3185BD}.Debug|x64.ActiveCfg = Debug|Any CPU 44 | {8A77EB67-A017-48C9-A8BC-747AAA3185BD}.Debug|x64.Build.0 = Debug|Any CPU 45 | {8A77EB67-A017-48C9-A8BC-747AAA3185BD}.Debug|x86.ActiveCfg = Debug|Any CPU 46 | {8A77EB67-A017-48C9-A8BC-747AAA3185BD}.Debug|x86.Build.0 = Debug|Any CPU 47 | {8A77EB67-A017-48C9-A8BC-747AAA3185BD}.Release|Any CPU.ActiveCfg = Release|Any CPU 48 | {8A77EB67-A017-48C9-A8BC-747AAA3185BD}.Release|Any CPU.Build.0 = Release|Any CPU 49 | {8A77EB67-A017-48C9-A8BC-747AAA3185BD}.Release|x64.ActiveCfg = Release|Any CPU 50 | {8A77EB67-A017-48C9-A8BC-747AAA3185BD}.Release|x64.Build.0 = Release|Any CPU 51 | {8A77EB67-A017-48C9-A8BC-747AAA3185BD}.Release|x86.ActiveCfg = Release|Any CPU 52 | {8A77EB67-A017-48C9-A8BC-747AAA3185BD}.Release|x86.Build.0 = Release|Any CPU 53 | {7F187A4C-3742-4F1B-9EDD-CB70FCC57A0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 54 | {7F187A4C-3742-4F1B-9EDD-CB70FCC57A0D}.Debug|Any CPU.Build.0 = Debug|Any CPU 55 | {7F187A4C-3742-4F1B-9EDD-CB70FCC57A0D}.Debug|x64.ActiveCfg = Debug|Any CPU 56 | {7F187A4C-3742-4F1B-9EDD-CB70FCC57A0D}.Debug|x64.Build.0 = Debug|Any CPU 57 | {7F187A4C-3742-4F1B-9EDD-CB70FCC57A0D}.Debug|x86.ActiveCfg = Debug|Any CPU 58 | {7F187A4C-3742-4F1B-9EDD-CB70FCC57A0D}.Debug|x86.Build.0 = Debug|Any CPU 59 | {7F187A4C-3742-4F1B-9EDD-CB70FCC57A0D}.Release|Any CPU.ActiveCfg = Release|Any CPU 60 | {7F187A4C-3742-4F1B-9EDD-CB70FCC57A0D}.Release|Any CPU.Build.0 = Release|Any CPU 61 | {7F187A4C-3742-4F1B-9EDD-CB70FCC57A0D}.Release|x64.ActiveCfg = Release|Any CPU 62 | {7F187A4C-3742-4F1B-9EDD-CB70FCC57A0D}.Release|x64.Build.0 = Release|Any CPU 63 | {7F187A4C-3742-4F1B-9EDD-CB70FCC57A0D}.Release|x86.ActiveCfg = Release|Any CPU 64 | {7F187A4C-3742-4F1B-9EDD-CB70FCC57A0D}.Release|x86.Build.0 = Release|Any CPU 65 | {9354A0CB-32A8-4A4D-B47F-A7DCD2A50EC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 66 | {9354A0CB-32A8-4A4D-B47F-A7DCD2A50EC4}.Debug|Any CPU.Build.0 = Debug|Any CPU 67 | {9354A0CB-32A8-4A4D-B47F-A7DCD2A50EC4}.Debug|x64.ActiveCfg = Debug|Any CPU 68 | {9354A0CB-32A8-4A4D-B47F-A7DCD2A50EC4}.Debug|x64.Build.0 = Debug|Any CPU 69 | {9354A0CB-32A8-4A4D-B47F-A7DCD2A50EC4}.Debug|x86.ActiveCfg = Debug|Any CPU 70 | {9354A0CB-32A8-4A4D-B47F-A7DCD2A50EC4}.Debug|x86.Build.0 = Debug|Any CPU 71 | {9354A0CB-32A8-4A4D-B47F-A7DCD2A50EC4}.Release|Any CPU.ActiveCfg = Release|Any CPU 72 | {9354A0CB-32A8-4A4D-B47F-A7DCD2A50EC4}.Release|Any CPU.Build.0 = Release|Any CPU 73 | {9354A0CB-32A8-4A4D-B47F-A7DCD2A50EC4}.Release|x64.ActiveCfg = Release|Any CPU 74 | {9354A0CB-32A8-4A4D-B47F-A7DCD2A50EC4}.Release|x64.Build.0 = Release|Any CPU 75 | {9354A0CB-32A8-4A4D-B47F-A7DCD2A50EC4}.Release|x86.ActiveCfg = Release|Any CPU 76 | {9354A0CB-32A8-4A4D-B47F-A7DCD2A50EC4}.Release|x86.Build.0 = Release|Any CPU 77 | {C740CED5-2465-4ECC-B4D9-BEBC6967A78B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 78 | {C740CED5-2465-4ECC-B4D9-BEBC6967A78B}.Debug|Any CPU.Build.0 = Debug|Any CPU 79 | {C740CED5-2465-4ECC-B4D9-BEBC6967A78B}.Debug|x64.ActiveCfg = Debug|Any CPU 80 | {C740CED5-2465-4ECC-B4D9-BEBC6967A78B}.Debug|x64.Build.0 = Debug|Any CPU 81 | {C740CED5-2465-4ECC-B4D9-BEBC6967A78B}.Debug|x86.ActiveCfg = Debug|Any CPU 82 | {C740CED5-2465-4ECC-B4D9-BEBC6967A78B}.Debug|x86.Build.0 = Debug|Any CPU 83 | {C740CED5-2465-4ECC-B4D9-BEBC6967A78B}.Release|Any CPU.ActiveCfg = Release|Any CPU 84 | {C740CED5-2465-4ECC-B4D9-BEBC6967A78B}.Release|Any CPU.Build.0 = Release|Any CPU 85 | {C740CED5-2465-4ECC-B4D9-BEBC6967A78B}.Release|x64.ActiveCfg = Release|Any CPU 86 | {C740CED5-2465-4ECC-B4D9-BEBC6967A78B}.Release|x64.Build.0 = Release|Any CPU 87 | {C740CED5-2465-4ECC-B4D9-BEBC6967A78B}.Release|x86.ActiveCfg = Release|Any CPU 88 | {C740CED5-2465-4ECC-B4D9-BEBC6967A78B}.Release|x86.Build.0 = Release|Any CPU 89 | {057E41B5-B8E2-490B-96E7-BB7E355556C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 90 | {057E41B5-B8E2-490B-96E7-BB7E355556C2}.Debug|Any CPU.Build.0 = Debug|Any CPU 91 | {057E41B5-B8E2-490B-96E7-BB7E355556C2}.Debug|x64.ActiveCfg = Debug|Any CPU 92 | {057E41B5-B8E2-490B-96E7-BB7E355556C2}.Debug|x64.Build.0 = Debug|Any CPU 93 | {057E41B5-B8E2-490B-96E7-BB7E355556C2}.Debug|x86.ActiveCfg = Debug|Any CPU 94 | {057E41B5-B8E2-490B-96E7-BB7E355556C2}.Debug|x86.Build.0 = Debug|Any CPU 95 | {057E41B5-B8E2-490B-96E7-BB7E355556C2}.Release|Any CPU.ActiveCfg = Release|Any CPU 96 | {057E41B5-B8E2-490B-96E7-BB7E355556C2}.Release|Any CPU.Build.0 = Release|Any CPU 97 | {057E41B5-B8E2-490B-96E7-BB7E355556C2}.Release|x64.ActiveCfg = Release|Any CPU 98 | {057E41B5-B8E2-490B-96E7-BB7E355556C2}.Release|x64.Build.0 = Release|Any CPU 99 | {057E41B5-B8E2-490B-96E7-BB7E355556C2}.Release|x86.ActiveCfg = Release|Any CPU 100 | {057E41B5-B8E2-490B-96E7-BB7E355556C2}.Release|x86.Build.0 = Release|Any CPU 101 | {91E6B66C-BD80-458C-A756-22F4DC0F9C5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 102 | {91E6B66C-BD80-458C-A756-22F4DC0F9C5D}.Debug|Any CPU.Build.0 = Debug|Any CPU 103 | {91E6B66C-BD80-458C-A756-22F4DC0F9C5D}.Debug|x64.ActiveCfg = Debug|Any CPU 104 | {91E6B66C-BD80-458C-A756-22F4DC0F9C5D}.Debug|x64.Build.0 = Debug|Any CPU 105 | {91E6B66C-BD80-458C-A756-22F4DC0F9C5D}.Debug|x86.ActiveCfg = Debug|Any CPU 106 | {91E6B66C-BD80-458C-A756-22F4DC0F9C5D}.Debug|x86.Build.0 = Debug|Any CPU 107 | {91E6B66C-BD80-458C-A756-22F4DC0F9C5D}.Release|Any CPU.ActiveCfg = Release|Any CPU 108 | {91E6B66C-BD80-458C-A756-22F4DC0F9C5D}.Release|Any CPU.Build.0 = Release|Any CPU 109 | {91E6B66C-BD80-458C-A756-22F4DC0F9C5D}.Release|x64.ActiveCfg = Release|Any CPU 110 | {91E6B66C-BD80-458C-A756-22F4DC0F9C5D}.Release|x64.Build.0 = Release|Any CPU 111 | {91E6B66C-BD80-458C-A756-22F4DC0F9C5D}.Release|x86.ActiveCfg = Release|Any CPU 112 | {91E6B66C-BD80-458C-A756-22F4DC0F9C5D}.Release|x86.Build.0 = Release|Any CPU 113 | {6DDFAB44-082F-4CC8-BA43-46291D851522}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 114 | {6DDFAB44-082F-4CC8-BA43-46291D851522}.Debug|Any CPU.Build.0 = Debug|Any CPU 115 | {6DDFAB44-082F-4CC8-BA43-46291D851522}.Debug|x64.ActiveCfg = Debug|Any CPU 116 | {6DDFAB44-082F-4CC8-BA43-46291D851522}.Debug|x64.Build.0 = Debug|Any CPU 117 | {6DDFAB44-082F-4CC8-BA43-46291D851522}.Debug|x86.ActiveCfg = Debug|Any CPU 118 | {6DDFAB44-082F-4CC8-BA43-46291D851522}.Debug|x86.Build.0 = Debug|Any CPU 119 | {6DDFAB44-082F-4CC8-BA43-46291D851522}.Release|Any CPU.ActiveCfg = Release|Any CPU 120 | {6DDFAB44-082F-4CC8-BA43-46291D851522}.Release|Any CPU.Build.0 = Release|Any CPU 121 | {6DDFAB44-082F-4CC8-BA43-46291D851522}.Release|x64.ActiveCfg = Release|Any CPU 122 | {6DDFAB44-082F-4CC8-BA43-46291D851522}.Release|x64.Build.0 = Release|Any CPU 123 | {6DDFAB44-082F-4CC8-BA43-46291D851522}.Release|x86.ActiveCfg = Release|Any CPU 124 | {6DDFAB44-082F-4CC8-BA43-46291D851522}.Release|x86.Build.0 = Release|Any CPU 125 | {0CF88B13-283F-464B-ABF9-C986E101E463}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 126 | {0CF88B13-283F-464B-ABF9-C986E101E463}.Debug|Any CPU.Build.0 = Debug|Any CPU 127 | {0CF88B13-283F-464B-ABF9-C986E101E463}.Debug|x64.ActiveCfg = Debug|Any CPU 128 | {0CF88B13-283F-464B-ABF9-C986E101E463}.Debug|x64.Build.0 = Debug|Any CPU 129 | {0CF88B13-283F-464B-ABF9-C986E101E463}.Debug|x86.ActiveCfg = Debug|Any CPU 130 | {0CF88B13-283F-464B-ABF9-C986E101E463}.Debug|x86.Build.0 = Debug|Any CPU 131 | {0CF88B13-283F-464B-ABF9-C986E101E463}.Release|Any CPU.ActiveCfg = Release|Any CPU 132 | {0CF88B13-283F-464B-ABF9-C986E101E463}.Release|Any CPU.Build.0 = Release|Any CPU 133 | {0CF88B13-283F-464B-ABF9-C986E101E463}.Release|x64.ActiveCfg = Release|Any CPU 134 | {0CF88B13-283F-464B-ABF9-C986E101E463}.Release|x64.Build.0 = Release|Any CPU 135 | {0CF88B13-283F-464B-ABF9-C986E101E463}.Release|x86.ActiveCfg = Release|Any CPU 136 | {0CF88B13-283F-464B-ABF9-C986E101E463}.Release|x86.Build.0 = Release|Any CPU 137 | {67C6A1AB-B87B-43E4-A077-386739E64B56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 138 | {67C6A1AB-B87B-43E4-A077-386739E64B56}.Debug|Any CPU.Build.0 = Debug|Any CPU 139 | {67C6A1AB-B87B-43E4-A077-386739E64B56}.Debug|x64.ActiveCfg = Debug|Any CPU 140 | {67C6A1AB-B87B-43E4-A077-386739E64B56}.Debug|x64.Build.0 = Debug|Any CPU 141 | {67C6A1AB-B87B-43E4-A077-386739E64B56}.Debug|x86.ActiveCfg = Debug|Any CPU 142 | {67C6A1AB-B87B-43E4-A077-386739E64B56}.Debug|x86.Build.0 = Debug|Any CPU 143 | {67C6A1AB-B87B-43E4-A077-386739E64B56}.Release|Any CPU.ActiveCfg = Release|Any CPU 144 | {67C6A1AB-B87B-43E4-A077-386739E64B56}.Release|Any CPU.Build.0 = Release|Any CPU 145 | {67C6A1AB-B87B-43E4-A077-386739E64B56}.Release|x64.ActiveCfg = Release|Any CPU 146 | {67C6A1AB-B87B-43E4-A077-386739E64B56}.Release|x64.Build.0 = Release|Any CPU 147 | {67C6A1AB-B87B-43E4-A077-386739E64B56}.Release|x86.ActiveCfg = Release|Any CPU 148 | {67C6A1AB-B87B-43E4-A077-386739E64B56}.Release|x86.Build.0 = Release|Any CPU 149 | {CB0F959B-8688-455F-A856-0036695EACCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 150 | {CB0F959B-8688-455F-A856-0036695EACCA}.Debug|Any CPU.Build.0 = Debug|Any CPU 151 | {CB0F959B-8688-455F-A856-0036695EACCA}.Debug|x64.ActiveCfg = Debug|Any CPU 152 | {CB0F959B-8688-455F-A856-0036695EACCA}.Debug|x64.Build.0 = Debug|Any CPU 153 | {CB0F959B-8688-455F-A856-0036695EACCA}.Debug|x86.ActiveCfg = Debug|Any CPU 154 | {CB0F959B-8688-455F-A856-0036695EACCA}.Debug|x86.Build.0 = Debug|Any CPU 155 | {CB0F959B-8688-455F-A856-0036695EACCA}.Release|Any CPU.ActiveCfg = Release|Any CPU 156 | {CB0F959B-8688-455F-A856-0036695EACCA}.Release|Any CPU.Build.0 = Release|Any CPU 157 | {CB0F959B-8688-455F-A856-0036695EACCA}.Release|x64.ActiveCfg = Release|Any CPU 158 | {CB0F959B-8688-455F-A856-0036695EACCA}.Release|x64.Build.0 = Release|Any CPU 159 | {CB0F959B-8688-455F-A856-0036695EACCA}.Release|x86.ActiveCfg = Release|Any CPU 160 | {CB0F959B-8688-455F-A856-0036695EACCA}.Release|x86.Build.0 = Release|Any CPU 161 | {1DC636DE-81D7-46D1-B7FC-AD233E8FBBD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 162 | {1DC636DE-81D7-46D1-B7FC-AD233E8FBBD0}.Debug|Any CPU.Build.0 = Debug|Any CPU 163 | {1DC636DE-81D7-46D1-B7FC-AD233E8FBBD0}.Debug|x64.ActiveCfg = Debug|Any CPU 164 | {1DC636DE-81D7-46D1-B7FC-AD233E8FBBD0}.Debug|x64.Build.0 = Debug|Any CPU 165 | {1DC636DE-81D7-46D1-B7FC-AD233E8FBBD0}.Debug|x86.ActiveCfg = Debug|Any CPU 166 | {1DC636DE-81D7-46D1-B7FC-AD233E8FBBD0}.Debug|x86.Build.0 = Debug|Any CPU 167 | {1DC636DE-81D7-46D1-B7FC-AD233E8FBBD0}.Release|Any CPU.ActiveCfg = Release|Any CPU 168 | {1DC636DE-81D7-46D1-B7FC-AD233E8FBBD0}.Release|Any CPU.Build.0 = Release|Any CPU 169 | {1DC636DE-81D7-46D1-B7FC-AD233E8FBBD0}.Release|x64.ActiveCfg = Release|Any CPU 170 | {1DC636DE-81D7-46D1-B7FC-AD233E8FBBD0}.Release|x64.Build.0 = Release|Any CPU 171 | {1DC636DE-81D7-46D1-B7FC-AD233E8FBBD0}.Release|x86.ActiveCfg = Release|Any CPU 172 | {1DC636DE-81D7-46D1-B7FC-AD233E8FBBD0}.Release|x86.Build.0 = Release|Any CPU 173 | EndGlobalSection 174 | EndGlobal 175 | --------------------------------------------------------------------------------