├── .gitattributes ├── .gitignore ├── README.md ├── ShapingAPI.sln ├── global.json ├── licence └── src └── ShapingAPI ├── .bowerrc ├── Controllers ├── AlbumsController.cs ├── ArtistsController.cs ├── CustomersController.cs ├── HomeController.cs ├── InvoicesController.cs └── TracksController.cs ├── Entities ├── Album.cs ├── Artist.cs ├── ChinookContext.cs ├── Customer.cs ├── Employee.cs ├── Genre.cs ├── Invoice.cs ├── InvoiceLine.cs ├── MediaType.cs ├── Playlist.cs ├── PlaylistTrack.cs ├── Track.cs └── sysdiagrams.cs ├── Infrastructure ├── Core │ ├── Expressions.cs │ ├── TokenService.cs │ └── Utils.cs ├── Data │ ├── IRepository.cs │ ├── Repositories │ │ ├── IRepositories.cs │ │ └── Repositories.cs │ └── Repository.cs └── Mappings │ ├── AutoMapperConfiguration.cs │ └── DomainToViewModelMappingProfile.cs ├── Project_Readme.html ├── Properties └── launchSettings.json ├── SQL └── Chinook_SqlServer_AutoIncrementPKs.sql ├── ShapingAPI.xproj ├── Startup.cs ├── ViewModels ├── AddressViewModel.cs ├── AlbumViewModel.cs ├── ArtistViewModel.cs ├── ContactViewModel.cs ├── CustomerViewModel.cs ├── InvoiceLineViewModel.cs ├── InvoiceViewModel.cs └── TrackViewModel.cs ├── Views ├── Home │ ├── Albums.cshtml │ ├── Artists.cshtml │ ├── Customers.cshtml │ └── Index.cshtml ├── Shared │ └── _Layout.cshtml └── _ViewStart.cshtml ├── appsettings.json ├── bower.json ├── project.json └── wwwroot ├── app ├── app.js └── controllers │ ├── albumsCtrl.js │ ├── artistsCtrl.js │ ├── customersCtrl.js │ └── tracksCtrl.js ├── images ├── facebook.png ├── github.png ├── spinner.gif └── twitter.png ├── styles └── site.css └── web.config /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | # DNX 42 | project.lock.json 43 | artifacts/ 44 | 45 | *_i.c 46 | *_p.c 47 | *_i.h 48 | *.ilk 49 | *.meta 50 | *.obj 51 | *.pch 52 | *.pdb 53 | *.pgc 54 | *.pgd 55 | *.rsp 56 | *.sbr 57 | *.tlb 58 | *.tli 59 | *.tlh 60 | *.tmp 61 | *.tmp_proj 62 | *.log 63 | *.vspscc 64 | *.vssscc 65 | .builds 66 | *.pidb 67 | *.svclog 68 | *.scc 69 | 70 | # Chutzpah Test files 71 | _Chutzpah* 72 | 73 | # Visual C++ cache files 74 | ipch/ 75 | *.aps 76 | *.ncb 77 | *.opensdf 78 | *.sdf 79 | *.cachefile 80 | 81 | # Visual Studio profiler 82 | *.psess 83 | *.vsp 84 | *.vspx 85 | 86 | # TFS 2012 Local Workspace 87 | $tf/ 88 | 89 | # Guidance Automation Toolkit 90 | *.gpState 91 | 92 | # ReSharper is a .NET coding add-in 93 | _ReSharper*/ 94 | *.[Rr]e[Ss]harper 95 | *.DotSettings.user 96 | 97 | # JustCode is a .NET coding add-in 98 | .JustCode 99 | 100 | # TeamCity is a build add-in 101 | _TeamCity* 102 | 103 | # DotCover is a Code Coverage Tool 104 | *.dotCover 105 | 106 | # NCrunch 107 | _NCrunch_* 108 | .*crunch*.local.xml 109 | 110 | # MightyMoose 111 | *.mm.* 112 | AutoTest.Net/ 113 | 114 | # Web workbench (sass) 115 | .sass-cache/ 116 | 117 | # Installshield output folder 118 | [Ee]xpress/ 119 | 120 | # DocProject is a documentation generator add-in 121 | DocProject/buildhelp/ 122 | DocProject/Help/*.HxT 123 | DocProject/Help/*.HxC 124 | DocProject/Help/*.hhc 125 | DocProject/Help/*.hhk 126 | DocProject/Help/*.hhp 127 | DocProject/Help/Html2 128 | DocProject/Help/html 129 | 130 | # Click-Once directory 131 | publish/ 132 | 133 | # Publish Web Output 134 | *.[Pp]ublish.xml 135 | *.azurePubxml 136 | ## TODO: Comment the next line if you want to checkin your 137 | ## web deploy settings but do note that will include unencrypted 138 | ## passwords 139 | #*.pubxml 140 | 141 | *.publishproj 142 | 143 | # NuGet Packages 144 | *.nupkg 145 | # The packages folder can be ignored because of Package Restore 146 | **/packages/* 147 | # except build/, which is used as an MSBuild target. 148 | !**/packages/build/ 149 | # Uncomment if necessary however generally it will be regenerated when needed 150 | #!**/packages/repositories.config 151 | 152 | # Windows Azure Build Output 153 | csx/ 154 | *.build.csdef 155 | 156 | # Windows Store app package directory 157 | AppPackages/ 158 | 159 | # Visual Studio cache files 160 | # files ending in .cache can be ignored 161 | *.[Cc]ache 162 | # but keep track of directories ending in .cache 163 | !*.[Cc]ache/ 164 | 165 | # Others 166 | ClientBin/ 167 | [Ss]tyle[Cc]op.* 168 | ~$* 169 | *~ 170 | *.dbmdl 171 | *.dbproj.schemaview 172 | *.pfx 173 | *.publishsettings 174 | node_modules/ 175 | orleans.codegen.cs 176 | 177 | # RIA/Silverlight projects 178 | Generated_Code/ 179 | 180 | # Backup & report files from converting an old project file 181 | # to a newer Visual Studio version. Backup files are not needed, 182 | # because we have git ;-) 183 | _UpgradeReport_Files/ 184 | Backup*/ 185 | UpgradeLog*.XML 186 | UpgradeLog*.htm 187 | 188 | # SQL Server files 189 | *.mdf 190 | *.ldf 191 | 192 | # Business Intelligence projects 193 | *.rdl.data 194 | *.bim.layout 195 | *.bim_*.settings 196 | 197 | # Microsoft Fakes 198 | FakesAssemblies/ 199 | 200 | # Node.js Tools for Visual Studio 201 | .ntvs_analysis.dat 202 | 203 | # Visual Studio 6 build log 204 | *.plg 205 | 206 | # Visual Studio 6 workspace options file 207 | *.opt 208 | 209 | # LightSwitch generated files 210 | GeneratedArtifacts/ 211 | _Pvt_Extensions/ 212 | ModelManifest.xml 213 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Building multi-client APIs in ASP.NET

2 | multi-client-api-06 3 |
4 | The project introduces a method that processes JTokens in order to return only the properties requested by the client. 5 | 8 | Assuming the result of the resource uri /api/tracks/1 is the following: 9 | 10 | ```javascript 11 | { 12 | "TrackId": 1, 13 | "AlbumId": 1, 14 | "Bytes": 11170334, 15 | "Composer": "Angus Young, Malcolm Young, Brian Johnson", 16 | "GenreId": 1, 17 | "MediaTypeId": 1, 18 | "Milliseconds": 343719, 19 | "Name": "For Those About To Rock (We Salute You)", 20 | "UnitPrice": 0.99 21 | } 22 | ``` 23 | You can request only specific properties of that resource by making the request /api/tracks/1?props=bytes,milliseconds,name 24 | ```javascript 25 | { 26 | "Bytes": 11170334, 27 | "Milliseconds": 343719, 28 | "Name": "For Those About To Rock (We Salute You)" 29 | } 30 | ``` 31 | The algorithm supports nested navigation properties as well. If /api/albums/1 returns.. 32 | ```javascript 33 | { 34 | "AlbumId": 1, 35 | "ArtistName": "AC/DC", 36 | "Title": "For Those About To Rock We Salute You", 37 | "Track": [ 38 | { 39 | "TrackId": 1, 40 | "AlbumId": 1, 41 | "Bytes": 11170334, 42 | "Composer": "Angus Young, Malcolm Young, Brian Johnson", 43 | "GenreId": 1, 44 | "MediaTypeId": 1, 45 | "Milliseconds": 343719, 46 | "Name": "For Those About To Rock (We Salute You)", 47 | "UnitPrice": 0.99 48 | }, 49 | { 50 | "TrackId": 6, 51 | "AlbumId": 1, 52 | "Bytes": 6713451, 53 | "Composer": "Angus Young, Malcolm Young, Brian Johnson", 54 | "GenreId": 1, 55 | "MediaTypeId": 1, 56 | "Milliseconds": 205662, 57 | "Name": "Put The Finger On You", 58 | "UnitPrice": 0.99 59 | } 60 | ] 61 | } 62 | ``` 63 | Then /api/albums/1?props=artistname,title,track(composer;name) should return the following: 64 | ```javascript 65 | { 66 | "ArtistName": "AC/DC", 67 | "Title": "For Those About To Rock We Salute You", 68 | "Track": [ 69 | { 70 | "Composer": "Angus Young, Malcolm Young, Brian Johnson", 71 | "Name": "For Those About To Rock (We Salute You)" 72 | }, 73 | { 74 | "Composer": "Angus Young, Malcolm Young, Brian Johnson", 75 | "Name": "Put The Finger On You" 76 | } 77 | ] 78 | } 79 | ``` 80 | Properties in navigations should be semicolon (;) separated inside parethensis. 81 | 84 | 85 | ```javascript 86 | var _tracks = _trackRepository.GetAll(includeProperties).Skip(page).Take(pageSize); 87 | 88 | var _tracksVM = Mapper.Map, IEnumerable>(_tracks); 89 | 90 | string _serializedTracks = JsonConvert.SerializeObject(_tracksVM, Formatting.None, 91 | new JsonSerializerSettings() 92 | { 93 | ReferenceLoopHandling = ReferenceLoopHandling.Ignore 94 | }); 95 | 96 | JToken _jtoken = JToken.Parse(_serializedTracks); 97 | if (!string.IsNullOrEmpty(props)) 98 | Utils.FilterProperties(_jtoken, props.ToLower().Split(',').ToList()); 99 | 100 | return Ok(_jtoken); 101 | ``` 102 |

103 | The project is built in Visual Studio 2015 and ASP.NET Core but the technique and the method can be easily integrated in any version of ASP.NET API. In case you want to run the ShapingAPI application: 104 |

    105 |
  1. 106 | Download the source code and open the solution in Visual Studio 2015 107 |
  2. 108 |
  3. 109 | Restore Nuget and Bower packages 110 |
  4. 111 |
  5. 112 | Install the Chinook database in your SQL Server by running the script inside the SQL folder. 113 |
  6. 114 |
  7. 115 | Alter the appsettings.json file to reflect your database environment. 116 |
  8. 117 |
  9. 118 | Run the application 119 |
  10. 120 |
121 |

122 | 123 |

Donations

124 | For being part of open source projects and documenting my work here and on chsakell's blog I really do not charge anything. I try to avoid any type of ads also. 125 | 126 | If you think that any information you obtained here is worth of some money and are willing to pay for it, feel free to send any amount through paypal. 127 | 128 | 129 | 130 | 131 | 132 | 135 | 136 | 137 |
Paypal
133 | Buy me a beer 134 |
138 | 139 |

Follow chsakell's Blog

140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 157 | 160 | 161 | 162 |
FacebookTwitter
Microsoft Web Application Development
155 | facebook 156 | 158 | twitter-small 159 |
163 |

License

164 | Code released under the MIT license. 165 | -------------------------------------------------------------------------------- /ShapingAPI.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B1752202-EC14-4A1F-A52C-0FE85D891D2B}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2B8F9A03-FA1B-494C-BD99-562248B190D3}" 9 | ProjectSection(SolutionItems) = preProject 10 | global.json = global.json 11 | EndProjectSection 12 | EndProject 13 | Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ShapingAPI", "src\ShapingAPI\ShapingAPI.xproj", "{6C8D22BC-4F3B-4F8F-947D-F9CDEB82F3DE}" 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {6C8D22BC-4F3B-4F8F-947D-F9CDEB82F3DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {6C8D22BC-4F3B-4F8F-947D-F9CDEB82F3DE}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {6C8D22BC-4F3B-4F8F-947D-F9CDEB82F3DE}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {6C8D22BC-4F3B-4F8F-947D-F9CDEB82F3DE}.Release|Any CPU.Build.0 = Release|Any CPU 25 | EndGlobalSection 26 | GlobalSection(SolutionProperties) = preSolution 27 | HideSolutionNode = FALSE 28 | EndGlobalSection 29 | GlobalSection(NestedProjects) = preSolution 30 | {6C8D22BC-4F3B-4F8F-947D-F9CDEB82F3DE} = {B1752202-EC14-4A1F-A52C-0FE85D891D2B} 31 | EndGlobalSection 32 | EndGlobal 33 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "projects": [ "src", "test" ], 3 | "sdk": { 4 | "version": "1.0.0-rc1-update1" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /licence: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 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 | -------------------------------------------------------------------------------- /src/ShapingAPI/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "wwwroot/lib" 3 | } 4 | -------------------------------------------------------------------------------- /src/ShapingAPI/Controllers/AlbumsController.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using Microsoft.AspNet.Mvc; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Linq; 5 | using ShapingAPI.Entities; 6 | using ShapingAPI.Infrastructure.Core; 7 | using ShapingAPI.Infrastructure.Data.Repositories; 8 | using ShapingAPI.ViewModels; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Linq.Expressions; 13 | using System.Threading.Tasks; 14 | 15 | namespace ShapingAPI.Controllers 16 | { 17 | [Route("api/[controller]")] 18 | public class AlbumsController : Controller 19 | { 20 | #region Properties 21 | private readonly IAlbumRepository _albumRepository; 22 | private Expression>[] includeProperties; 23 | private const int maxSize = 50; 24 | #endregion 25 | 26 | #region Constructor 27 | public AlbumsController(IAlbumRepository albumRepository) 28 | { 29 | _albumRepository = albumRepository; 30 | 31 | includeProperties = Expressions.LoadAlbumNavigations(); 32 | } 33 | #endregion 34 | 35 | #region Actions 36 | public ActionResult Get(string props = null, int page = 1, int pageSize = maxSize) 37 | { 38 | try 39 | { 40 | var _albums = _albumRepository.LoadAll().Skip((page - 1) * pageSize).Take(pageSize); 41 | 42 | var test = _albums.ToList(); 43 | 44 | var _albumsVM = Mapper.Map, IEnumerable>(_albums); 45 | 46 | JToken _jtoken = TokenService.CreateJToken(_albumsVM, props); 47 | 48 | return Ok(_jtoken); 49 | } 50 | catch (Exception ex) 51 | { 52 | return new HttpStatusCodeResult(500); 53 | } 54 | } 55 | 56 | [Route("{albumId}")] 57 | public ActionResult Get(int albumId, string props = null) 58 | { 59 | try 60 | { 61 | var _album = _albumRepository.Get(t => t.AlbumId == albumId, includeProperties); 62 | 63 | if (_album == null) 64 | { 65 | return HttpNotFound(); 66 | } 67 | 68 | var _albumVM = Mapper.Map(_album); 69 | 70 | JToken _jtoken = TokenService.CreateJToken(_albumVM, props); 71 | 72 | return Ok(_jtoken); 73 | } 74 | catch (Exception ex) 75 | { 76 | return new HttpStatusCodeResult(500); 77 | } 78 | } 79 | #endregion 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/ShapingAPI/Controllers/ArtistsController.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using Microsoft.AspNet.Mvc; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Linq; 5 | using ShapingAPI.Entities; 6 | using ShapingAPI.Infrastructure.Core; 7 | using ShapingAPI.Infrastructure.Data.Repositories; 8 | using ShapingAPI.ViewModels; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Threading.Tasks; 13 | 14 | namespace ShapingAPI.Controllers 15 | { 16 | [Route("api/[controller]")] 17 | public class ArtistsController : Controller 18 | { 19 | #region Properties 20 | private readonly IArtistRepository _artistRepository; 21 | private const int maxSize = 50; 22 | #endregion 23 | 24 | #region Constructor 25 | public ArtistsController(IArtistRepository artistRepository) 26 | { 27 | _artistRepository = artistRepository; 28 | } 29 | #endregion 30 | 31 | #region Actions 32 | public ActionResult Get(string props = null, int page = 1, int pageSize = maxSize) 33 | { 34 | try 35 | { 36 | var _artists = _artistRepository.LoadAll().Skip((page - 1) * pageSize).Take(pageSize); 37 | 38 | var _artistsVM = Mapper.Map, IEnumerable>(_artists); 39 | 40 | JToken _jtoken = TokenService.CreateJToken(_artistsVM, props); 41 | 42 | return Ok(_jtoken); 43 | } 44 | catch (Exception ex) 45 | { 46 | return new HttpStatusCodeResult(500); 47 | } 48 | } 49 | 50 | [Route("{artistId}")] 51 | public ActionResult Get(int artistId, string props = null) 52 | { 53 | try 54 | { 55 | var _artist = _artistRepository.Load(artistId); 56 | 57 | if (_artist == null) 58 | { 59 | return HttpNotFound(); 60 | } 61 | 62 | var _artistVM = Mapper.Map(_artist); 63 | 64 | JToken _jtoken = TokenService.CreateJToken(_artistVM, props); 65 | 66 | return Ok(_jtoken); 67 | } 68 | catch (Exception ex) 69 | { 70 | return new HttpStatusCodeResult(500); 71 | } 72 | } 73 | #endregion 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/ShapingAPI/Controllers/CustomersController.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using Microsoft.AspNet.Mvc; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Linq; 5 | using ShapingAPI.Entities; 6 | using ShapingAPI.Infrastructure.Core; 7 | using ShapingAPI.Infrastructure.Data.Repositories; 8 | using ShapingAPI.ViewModels; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Linq.Expressions; 13 | using System.Threading.Tasks; 14 | 15 | namespace ShapingAPI.Controllers 16 | { 17 | [Route("api/[controller]")] 18 | public class CustomersController : Controller 19 | { 20 | #region Properties 21 | private readonly ICustomerRepository _customerRepository; 22 | private const int maxSize = 50; 23 | #endregion 24 | 25 | #region Constructor 26 | public CustomersController(ICustomerRepository customerRepository) 27 | { 28 | _customerRepository = customerRepository; 29 | } 30 | #endregion 31 | 32 | #region Actions 33 | public ActionResult Get(string props = null, int page = 1, int pageSize = maxSize) 34 | { 35 | try 36 | { 37 | var _customers = _customerRepository.LoadAll().Skip((page - 1) * pageSize).Take(pageSize); 38 | 39 | var _customersVM = Mapper.Map, IEnumerable>(_customers); 40 | 41 | JToken _jtoken = TokenService.CreateJToken(_customersVM, props); 42 | 43 | return Ok(_jtoken); 44 | } 45 | catch (Exception ex) 46 | { 47 | return new HttpStatusCodeResult(500); 48 | } 49 | } 50 | 51 | [Route("{customerId}")] 52 | public ActionResult Get(int customerId, string props = null) 53 | { 54 | try 55 | { 56 | var _customer = _customerRepository.Load(customerId); 57 | 58 | if (_customer == null) 59 | { 60 | return HttpNotFound(); 61 | } 62 | 63 | var _customerVM = Mapper.Map(_customer); 64 | 65 | JToken _jtoken = TokenService.CreateJToken(_customerVM, props); 66 | 67 | return Ok(_jtoken); 68 | } 69 | catch (Exception ex) 70 | { 71 | return new HttpStatusCodeResult(500); 72 | } 73 | } 74 | #endregion 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/ShapingAPI/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNet.Mvc; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace ShapingAPI.Controllers 8 | { 9 | public class HomeController : Controller 10 | { 11 | // GET: // 12 | public IActionResult Index() 13 | { 14 | return View(); 15 | } 16 | 17 | public IActionResult Albums() 18 | { 19 | return View(); 20 | } 21 | 22 | public IActionResult Artists() 23 | { 24 | return View(); 25 | } 26 | 27 | public IActionResult Customers() 28 | { 29 | return View(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/ShapingAPI/Controllers/InvoicesController.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using Microsoft.AspNet.Mvc; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Linq; 5 | using ShapingAPI.Entities; 6 | using ShapingAPI.Infrastructure.Core; 7 | using ShapingAPI.Infrastructure.Data.Repositories; 8 | using ShapingAPI.ViewModels; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Linq.Expressions; 13 | using System.Threading.Tasks; 14 | 15 | namespace ShapingAPI.Controllers 16 | { 17 | [Route("api/[controller]")] 18 | public class InvoicesController : Controller 19 | { 20 | #region Properties 21 | private readonly IInvoiceRepository _invoiceRepository; 22 | private const int maxSize = 50; 23 | #endregion 24 | 25 | #region Constructor 26 | public InvoicesController(IInvoiceRepository invoiceRepository) 27 | { 28 | _invoiceRepository = invoiceRepository; 29 | } 30 | #endregion 31 | 32 | #region Actions 33 | public ActionResult Get(string props = null, int page = 1, int pageSize = maxSize) 34 | { 35 | try 36 | { 37 | var _invoices = _invoiceRepository.LoadAll().Skip((page - 1) * pageSize).Take(pageSize); 38 | 39 | var _invoicesVM = Mapper.Map, IEnumerable>(_invoices); 40 | 41 | JToken _jtoken = TokenService.CreateJToken(_invoicesVM, props); 42 | 43 | return Ok(_jtoken); 44 | } 45 | catch (Exception ex) 46 | { 47 | return new HttpStatusCodeResult(500); 48 | } 49 | } 50 | 51 | [Route("{invoiceId}")] 52 | public ActionResult Get(int invoiceId, string props = null) 53 | { 54 | try 55 | { 56 | var _invoice = _invoiceRepository.Load(invoiceId); 57 | 58 | if (_invoice == null) 59 | { 60 | return HttpNotFound(); 61 | } 62 | 63 | var _invoiceVM = Mapper.Map(_invoice); 64 | 65 | JToken _jtoken = TokenService.CreateJToken(_invoiceVM, props); 66 | 67 | return Ok(_jtoken); 68 | } 69 | catch (Exception ex) 70 | { 71 | return new HttpStatusCodeResult(500); 72 | } 73 | } 74 | #endregion 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/ShapingAPI/Controllers/TracksController.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using Microsoft.AspNet.Mvc; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Linq; 5 | using ShapingAPI.Entities; 6 | using ShapingAPI.Infrastructure.Core; 7 | using ShapingAPI.Infrastructure.Data.Repositories; 8 | using ShapingAPI.ViewModels; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Linq.Expressions; 13 | using System.Threading.Tasks; 14 | 15 | namespace ShapingAPI.Controllers 16 | { 17 | [Route("api/[controller]")] 18 | public class TracksController : Controller 19 | { 20 | #region Properties 21 | private readonly ITrackRepository _trackRepository; 22 | private Expression>[] includeProperties; 23 | private const int maxSize = 50; 24 | #endregion 25 | 26 | #region Constructor 27 | public TracksController(ITrackRepository trackRepository) 28 | { 29 | _trackRepository = trackRepository; 30 | 31 | includeProperties = Expressions.LoadTrackNavigations(); 32 | } 33 | #endregion 34 | 35 | #region Actions 36 | public ActionResult Get(string props = null, int page = 1, int pageSize = maxSize) 37 | { 38 | try 39 | { 40 | var _tracks = _trackRepository.GetAll(includeProperties).Skip((page - 1) * pageSize).Take(pageSize); 41 | 42 | var _tracksVM = Mapper.Map, IEnumerable>(_tracks); 43 | 44 | JToken _jtoken = TokenService.CreateJToken(_tracksVM, props); 45 | 46 | return Ok(_jtoken); 47 | } 48 | catch (Exception ex) 49 | { 50 | return new HttpStatusCodeResult(500); 51 | } 52 | } 53 | 54 | [Route("{trackId}")] 55 | public ActionResult Get(int trackId, string props = null) 56 | { 57 | try 58 | { 59 | 60 | 61 | var _track = _trackRepository.Get(t => t.TrackId == trackId, includeProperties); 62 | 63 | if (_track == null) 64 | { 65 | return HttpNotFound(); 66 | } 67 | 68 | var _trackVM = Mapper.Map(_track); 69 | 70 | JToken _jtoken = TokenService.CreateJToken(_trackVM, props); 71 | 72 | return Ok(_jtoken); 73 | } 74 | catch (Exception ex) 75 | { 76 | return new HttpStatusCodeResult(500); 77 | } 78 | } 79 | #endregion 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/ShapingAPI/Entities/Album.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.Entities 5 | { 6 | public partial class Album 7 | { 8 | public Album() 9 | { 10 | Track = new HashSet(); 11 | } 12 | 13 | public int AlbumId { get; set; } 14 | public int ArtistId { get; set; } 15 | public string Title { get; set; } 16 | 17 | public virtual ICollection Track { get; set; } 18 | public virtual Artist Artist { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ShapingAPI/Entities/Artist.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.Entities 5 | { 6 | public partial class Artist 7 | { 8 | public Artist() 9 | { 10 | Album = new HashSet(); 11 | } 12 | 13 | public int ArtistId { get; set; } 14 | public string Name { get; set; } 15 | 16 | public virtual ICollection Album { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/ShapingAPI/Entities/ChinookContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Data.Entity; 2 | using Microsoft.Data.Entity.Metadata; 3 | 4 | namespace ShapingAPI.Entities 5 | { 6 | public partial class ChinookContext : DbContext 7 | { 8 | protected override void OnConfiguring(DbContextOptionsBuilder options) 9 | { 10 | //options.UseSqlServer(@"Server=(localdb)\v11.0;Database=Chinook;Trusted_Connection=True;"); 11 | } 12 | 13 | protected override void OnModelCreating(ModelBuilder modelBuilder) 14 | { 15 | modelBuilder.Entity(entity => 16 | { 17 | entity.HasIndex(e => e.ArtistId).HasName("IFK_AlbumArtistId"); 18 | 19 | entity.Property(e => e.Title) 20 | .IsRequired() 21 | .HasMaxLength(160); 22 | 23 | entity.HasOne(d => d.Artist).WithMany(p => p.Album).HasForeignKey(d => d.ArtistId).OnDelete(DeleteBehavior.Restrict); 24 | }); 25 | 26 | modelBuilder.Entity(entity => 27 | { 28 | entity.Property(e => e.Name).HasMaxLength(120); 29 | }); 30 | 31 | modelBuilder.Entity(entity => 32 | { 33 | entity.HasIndex(e => e.SupportRepId).HasName("IFK_CustomerSupportRepId"); 34 | 35 | entity.Property(e => e.Address).HasMaxLength(70); 36 | 37 | entity.Property(e => e.City).HasMaxLength(40); 38 | 39 | entity.Property(e => e.Company).HasMaxLength(80); 40 | 41 | entity.Property(e => e.Country).HasMaxLength(40); 42 | 43 | entity.Property(e => e.Email) 44 | .IsRequired() 45 | .HasMaxLength(60); 46 | 47 | entity.Property(e => e.Fax).HasMaxLength(24); 48 | 49 | entity.Property(e => e.FirstName) 50 | .IsRequired() 51 | .HasMaxLength(40); 52 | 53 | entity.Property(e => e.LastName) 54 | .IsRequired() 55 | .HasMaxLength(20); 56 | 57 | entity.Property(e => e.Phone).HasMaxLength(24); 58 | 59 | entity.Property(e => e.PostalCode).HasMaxLength(10); 60 | 61 | entity.Property(e => e.State).HasMaxLength(40); 62 | 63 | entity.HasOne(d => d.SupportRep).WithMany(p => p.Customer).HasForeignKey(d => d.SupportRepId); 64 | }); 65 | 66 | modelBuilder.Entity(entity => 67 | { 68 | entity.HasIndex(e => e.ReportsTo).HasName("IFK_EmployeeReportsTo"); 69 | 70 | entity.Property(e => e.Address).HasMaxLength(70); 71 | 72 | entity.Property(e => e.BirthDate).HasColumnType("datetime"); 73 | 74 | entity.Property(e => e.City).HasMaxLength(40); 75 | 76 | entity.Property(e => e.Country).HasMaxLength(40); 77 | 78 | entity.Property(e => e.Email).HasMaxLength(60); 79 | 80 | entity.Property(e => e.Fax).HasMaxLength(24); 81 | 82 | entity.Property(e => e.FirstName) 83 | .IsRequired() 84 | .HasMaxLength(20); 85 | 86 | entity.Property(e => e.HireDate).HasColumnType("datetime"); 87 | 88 | entity.Property(e => e.LastName) 89 | .IsRequired() 90 | .HasMaxLength(20); 91 | 92 | entity.Property(e => e.Phone).HasMaxLength(24); 93 | 94 | entity.Property(e => e.PostalCode).HasMaxLength(10); 95 | 96 | entity.Property(e => e.State).HasMaxLength(40); 97 | 98 | entity.Property(e => e.Title).HasMaxLength(30); 99 | 100 | entity.HasOne(d => d.ReportsToNavigation).WithMany(p => p.InverseReportsToNavigation).HasForeignKey(d => d.ReportsTo); 101 | }); 102 | 103 | modelBuilder.Entity(entity => 104 | { 105 | entity.Property(e => e.Name).HasMaxLength(120); 106 | }); 107 | 108 | modelBuilder.Entity(entity => 109 | { 110 | entity.HasIndex(e => e.CustomerId).HasName("IFK_InvoiceCustomerId"); 111 | 112 | entity.Property(e => e.BillingAddress).HasMaxLength(70); 113 | 114 | entity.Property(e => e.BillingCity).HasMaxLength(40); 115 | 116 | entity.Property(e => e.BillingCountry).HasMaxLength(40); 117 | 118 | entity.Property(e => e.BillingPostalCode).HasMaxLength(10); 119 | 120 | entity.Property(e => e.BillingState).HasMaxLength(40); 121 | 122 | entity.Property(e => e.InvoiceDate).HasColumnType("datetime"); 123 | 124 | entity.Property(e => e.Total).HasColumnType("numeric"); 125 | 126 | entity.HasOne(d => d.Customer).WithMany(p => p.Invoice).HasForeignKey(d => d.CustomerId).OnDelete(DeleteBehavior.Restrict); 127 | }); 128 | 129 | modelBuilder.Entity(entity => 130 | { 131 | entity.HasIndex(e => e.InvoiceId).HasName("IFK_InvoiceLineInvoiceId"); 132 | 133 | entity.HasIndex(e => e.TrackId).HasName("IFK_InvoiceLineTrackId"); 134 | 135 | entity.Property(e => e.UnitPrice).HasColumnType("numeric"); 136 | 137 | entity.HasOne(d => d.Invoice).WithMany(p => p.InvoiceLine).HasForeignKey(d => d.InvoiceId).OnDelete(DeleteBehavior.Restrict); 138 | 139 | entity.HasOne(d => d.Track).WithMany(p => p.InvoiceLine).HasForeignKey(d => d.TrackId).OnDelete(DeleteBehavior.Restrict); 140 | }); 141 | 142 | modelBuilder.Entity(entity => 143 | { 144 | entity.Property(e => e.Name).HasMaxLength(120); 145 | }); 146 | 147 | modelBuilder.Entity(entity => 148 | { 149 | entity.Property(e => e.Name).HasMaxLength(120); 150 | }); 151 | 152 | modelBuilder.Entity(entity => 153 | { 154 | entity.HasKey(e => new { e.PlaylistId, e.TrackId }); 155 | 156 | entity.HasIndex(e => e.TrackId).HasName("IFK_PlaylistTrackTrackId"); 157 | 158 | entity.HasOne(d => d.Playlist).WithMany(p => p.PlaylistTrack).HasForeignKey(d => d.PlaylistId).OnDelete(DeleteBehavior.Restrict); 159 | 160 | entity.HasOne(d => d.Track).WithMany(p => p.PlaylistTrack).HasForeignKey(d => d.TrackId).OnDelete(DeleteBehavior.Restrict); 161 | }); 162 | 163 | modelBuilder.Entity(entity => 164 | { 165 | entity.HasIndex(e => e.AlbumId).HasName("IFK_TrackAlbumId"); 166 | 167 | entity.HasIndex(e => e.GenreId).HasName("IFK_TrackGenreId"); 168 | 169 | entity.HasIndex(e => e.MediaTypeId).HasName("IFK_TrackMediaTypeId"); 170 | 171 | entity.Property(e => e.Composer).HasMaxLength(220); 172 | 173 | entity.Property(e => e.Name) 174 | .IsRequired() 175 | .HasMaxLength(200); 176 | 177 | entity.Property(e => e.UnitPrice).HasColumnType("numeric"); 178 | 179 | entity.HasOne(d => d.Album).WithMany(p => p.Track).HasForeignKey(d => d.AlbumId); 180 | 181 | entity.HasOne(d => d.Genre).WithMany(p => p.Track).HasForeignKey(d => d.GenreId); 182 | 183 | entity.HasOne(d => d.MediaType).WithMany(p => p.Track).HasForeignKey(d => d.MediaTypeId).OnDelete(DeleteBehavior.Restrict); 184 | }); 185 | 186 | modelBuilder.Entity(entity => 187 | { 188 | entity.HasKey(e => e.diagram_id); 189 | 190 | entity.Property(e => e.definition).HasColumnType("varbinary"); 191 | }); 192 | } 193 | 194 | public virtual DbSet Album { get; set; } 195 | public virtual DbSet Artist { get; set; } 196 | public virtual DbSet Customer { get; set; } 197 | public virtual DbSet Employee { get; set; } 198 | public virtual DbSet Genre { get; set; } 199 | public virtual DbSet Invoice { get; set; } 200 | public virtual DbSet InvoiceLine { get; set; } 201 | public virtual DbSet MediaType { get; set; } 202 | public virtual DbSet Playlist { get; set; } 203 | public virtual DbSet PlaylistTrack { get; set; } 204 | public virtual DbSet Track { get; set; } 205 | public virtual DbSet sysdiagrams { get; set; } 206 | } 207 | } -------------------------------------------------------------------------------- /src/ShapingAPI/Entities/Customer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.Entities 5 | { 6 | public partial class Customer 7 | { 8 | public Customer() 9 | { 10 | Invoice = new HashSet(); 11 | } 12 | 13 | public int CustomerId { get; set; } 14 | public string Address { get; set; } 15 | public string City { get; set; } 16 | public string Company { get; set; } 17 | public string Country { get; set; } 18 | public string Email { get; set; } 19 | public string Fax { get; set; } 20 | public string FirstName { get; set; } 21 | public string LastName { get; set; } 22 | public string Phone { get; set; } 23 | public string PostalCode { get; set; } 24 | public string State { get; set; } 25 | public int? SupportRepId { get; set; } 26 | 27 | public virtual ICollection Invoice { get; set; } 28 | public virtual Employee SupportRep { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/ShapingAPI/Entities/Employee.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.Entities 5 | { 6 | public partial class Employee 7 | { 8 | public Employee() 9 | { 10 | Customer = new HashSet(); 11 | } 12 | 13 | public int EmployeeId { get; set; } 14 | public string Address { get; set; } 15 | public DateTime? BirthDate { get; set; } 16 | public string City { get; set; } 17 | public string Country { get; set; } 18 | public string Email { get; set; } 19 | public string Fax { get; set; } 20 | public string FirstName { get; set; } 21 | public DateTime? HireDate { get; set; } 22 | public string LastName { get; set; } 23 | public string Phone { get; set; } 24 | public string PostalCode { get; set; } 25 | public int? ReportsTo { get; set; } 26 | public string State { get; set; } 27 | public string Title { get; set; } 28 | 29 | public virtual ICollection Customer { get; set; } 30 | public virtual Employee ReportsToNavigation { get; set; } 31 | public virtual ICollection InverseReportsToNavigation { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/ShapingAPI/Entities/Genre.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.Entities 5 | { 6 | public partial class Genre 7 | { 8 | public Genre() 9 | { 10 | Track = new HashSet(); 11 | } 12 | 13 | public int GenreId { get; set; } 14 | public string Name { get; set; } 15 | 16 | public virtual ICollection Track { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/ShapingAPI/Entities/Invoice.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.Entities 5 | { 6 | public partial class Invoice 7 | { 8 | public Invoice() 9 | { 10 | InvoiceLine = new HashSet(); 11 | } 12 | 13 | public int InvoiceId { get; set; } 14 | public string BillingAddress { get; set; } 15 | public string BillingCity { get; set; } 16 | public string BillingCountry { get; set; } 17 | public string BillingPostalCode { get; set; } 18 | public string BillingState { get; set; } 19 | public int CustomerId { get; set; } 20 | public DateTime InvoiceDate { get; set; } 21 | public decimal Total { get; set; } 22 | 23 | public virtual ICollection InvoiceLine { get; set; } 24 | public virtual Customer Customer { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ShapingAPI/Entities/InvoiceLine.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.Entities 5 | { 6 | public partial class InvoiceLine 7 | { 8 | public int InvoiceLineId { get; set; } 9 | public int InvoiceId { get; set; } 10 | public int Quantity { get; set; } 11 | public int TrackId { get; set; } 12 | public decimal UnitPrice { get; set; } 13 | 14 | public virtual Invoice Invoice { get; set; } 15 | public virtual Track Track { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/ShapingAPI/Entities/MediaType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.Entities 5 | { 6 | public partial class MediaType 7 | { 8 | public MediaType() 9 | { 10 | Track = new HashSet(); 11 | } 12 | 13 | public int MediaTypeId { get; set; } 14 | public string Name { get; set; } 15 | 16 | public virtual ICollection Track { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/ShapingAPI/Entities/Playlist.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.Entities 5 | { 6 | public partial class Playlist 7 | { 8 | public Playlist() 9 | { 10 | PlaylistTrack = new HashSet(); 11 | } 12 | 13 | public int PlaylistId { get; set; } 14 | public string Name { get; set; } 15 | 16 | public virtual ICollection PlaylistTrack { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/ShapingAPI/Entities/PlaylistTrack.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.Entities 5 | { 6 | public partial class PlaylistTrack 7 | { 8 | public int PlaylistId { get; set; } 9 | public int TrackId { get; set; } 10 | 11 | public virtual Playlist Playlist { get; set; } 12 | public virtual Track Track { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ShapingAPI/Entities/Track.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.Entities 5 | { 6 | public partial class Track 7 | { 8 | public Track() 9 | { 10 | InvoiceLine = new HashSet(); 11 | PlaylistTrack = new HashSet(); 12 | } 13 | 14 | public int TrackId { get; set; } 15 | public int? AlbumId { get; set; } 16 | public int? Bytes { get; set; } 17 | public string Composer { get; set; } 18 | public int? GenreId { get; set; } 19 | public int MediaTypeId { get; set; } 20 | public int Milliseconds { get; set; } 21 | public string Name { get; set; } 22 | public decimal UnitPrice { get; set; } 23 | 24 | public virtual ICollection InvoiceLine { get; set; } 25 | public virtual ICollection PlaylistTrack { get; set; } 26 | public virtual Album Album { get; set; } 27 | public virtual Genre Genre { get; set; } 28 | public virtual MediaType MediaType { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/ShapingAPI/Entities/sysdiagrams.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.Entities 5 | { 6 | public partial class sysdiagrams 7 | { 8 | public int diagram_id { get; set; } 9 | public byte[] definition { get; set; } 10 | public int principal_id { get; set; } 11 | public int? version { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/ShapingAPI/Infrastructure/Core/Expressions.cs: -------------------------------------------------------------------------------- 1 | using ShapingAPI.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Linq.Expressions; 7 | using System.Threading.Tasks; 8 | 9 | namespace ShapingAPI.Infrastructure.Core 10 | { 11 | public class Expressions 12 | { 13 | public static Expression>[] LoadTrackNavigations() 14 | { 15 | Expression>[] _navigations = { 16 | t => t.Album, 17 | t => t.Genre, 18 | t => t.InvoiceLine, 19 | t => t.MediaType 20 | }; 21 | 22 | return _navigations; 23 | } 24 | 25 | public static Expression>[] LoadCustomerNavigations() 26 | { 27 | Expression>[] _navigations = { 28 | c => c.Invoice, 29 | c => c.SupportRep 30 | }; 31 | 32 | return _navigations; 33 | } 34 | 35 | public static Expression>[] LoadAlbumNavigations() 36 | { 37 | Expression>[] _navigations = { 38 | a => a.Track, 39 | a => a.Artist 40 | }; 41 | 42 | return _navigations; 43 | } 44 | 45 | public static Expression>[] LoadArtistNavigations() 46 | { 47 | Expression>[] _navigations = { 48 | a => a.Album 49 | }; 50 | 51 | return _navigations; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/ShapingAPI/Infrastructure/Core/TokenService.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Linq; 3 | using System.Linq; 4 | 5 | namespace ShapingAPI.Infrastructure.Core 6 | { 7 | public class TokenService 8 | { 9 | public static JToken CreateJToken(object obj, string props) 10 | { 11 | string _serializedTracks = JsonConvert.SerializeObject(obj, Formatting.None, 12 | new JsonSerializerSettings() 13 | { 14 | ReferenceLoopHandling = ReferenceLoopHandling.Ignore 15 | }); 16 | 17 | JToken jtoken = JToken.Parse(_serializedTracks); 18 | if (!string.IsNullOrEmpty(props)) 19 | Utils.FilterProperties(jtoken, props.ToLower().Split(',').ToList()); 20 | 21 | return jtoken; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ShapingAPI/Infrastructure/Core/Utils.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Linq; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Dynamic; 5 | using System.Linq; 6 | using System.Linq.Expressions; 7 | using System.Reflection; 8 | using System.Threading.Tasks; 9 | 10 | namespace ShapingAPI.Infrastructure.Core 11 | { 12 | public class Utils 13 | { 14 | public static void FilterProperties(JToken token, List fields) 15 | { 16 | try 17 | { 18 | JContainer container = token as JContainer; 19 | if (container == null) return; 20 | 21 | JProperty jprop = null; 22 | JObject jobj = null; 23 | 24 | JProperty pNested = null; 25 | JObject poNested = null; 26 | 27 | List removeList = new List(); 28 | foreach (JToken el in container.Children()) 29 | { 30 | if (el is JProperty) 31 | { 32 | jprop = el as JProperty; 33 | 34 | if (fields.Any(f => f.StartsWith(el.Path.ToLower() + "("))) 35 | { 36 | string nestedProperty = fields.First(f => f.StartsWith(el.Path.ToLower() + "(")); 37 | int startField = nestedProperty.IndexOf("("); 38 | int lastField = nestedProperty.LastIndexOf(")"); 39 | string nestedFields = nestedProperty.Substring(startField + 1, (lastField - 1) - startField); 40 | 41 | List _nestedFieldList = GetNestedFiels(nestedFields);// nestedFields.Split(';').ToList(); 42 | 43 | JToken nestedProperties = el.First(); 44 | List removeListNested = new List(); 45 | foreach (JToken elNested in (nestedProperties as JContainer).Children()) 46 | { 47 | if (elNested is JProperty) 48 | { 49 | pNested = elNested as JProperty; 50 | if (!_nestedFieldList.Contains(pNested.Path.ToLower().Substring(pNested.Path.IndexOf('.') + 1))) 51 | removeListNested.Add(pNested); 52 | } 53 | else if (elNested is JObject) 54 | { 55 | poNested = elNested as JObject; 56 | 57 | foreach (JToken _poNested in (poNested as JContainer).Children().OrderBy(order => order.Parent)) 58 | { 59 | if (!(_poNested.ToString().Contains('(') && _poNested.ToString().Contains(';') && _poNested.ToString().Contains(')')) 60 | && !_poNested.ToString().Replace(" ", "").Replace("\r\n", "").Contains("[{")) 61 | { 62 | if (!_nestedFieldList.Contains(_poNested.Path.ToLower().Substring(_poNested.Path.IndexOf('.') + 1))) 63 | removeListNested.Add(_poNested); 64 | } 65 | else 66 | { 67 | foreach (JToken el2 in (_poNested as JContainer).Children()) 68 | { 69 | if (el2 is JProperty) 70 | { 71 | jprop = el2 as JProperty; 72 | 73 | if (fields.Any(f => f.StartsWith(el2.Path.ToLower() + "("))) 74 | { 75 | string nestedProperty2 = fields.First(f => f.StartsWith(el2.Path.ToLower() + "(")); 76 | int startField2 = nestedProperty.IndexOf("("); 77 | int lastField2 = nestedProperty.LastIndexOf(")"); 78 | string nestedFields2 = nestedProperty.Substring(startField + 1, (lastField - 1) - startField); 79 | } 80 | } 81 | else if (el2 is JArray) 82 | { 83 | JArray jar = el2 as JArray; 84 | 85 | if (_nestedFieldList.Contains(el2.Path.ToLower().Substring(el2.Path.ToLower().LastIndexOf('.') + 1))) 86 | break; 87 | 88 | foreach (JToken el3 in (jar as JContainer).Children()) 89 | { 90 | if (el3 is JObject) 91 | { 92 | string _nestedField = _nestedFieldList.FirstOrDefault(f => f.ToLower().StartsWith(_poNested.Path.ToLower().Substring(_poNested.Path.IndexOf('.') + 1) + "(")); 93 | 94 | if (string.IsNullOrEmpty(_nestedField)) 95 | { 96 | removeListNested.Add(_poNested); 97 | break; 98 | } 99 | 100 | int startField2 = _nestedField.IndexOf("("); 101 | int lastField2 = _nestedField.LastIndexOf(")"); 102 | string nestedFields2 = _nestedField.Substring(startField2 + 1, (lastField2 - 1) - startField2); 103 | 104 | string[] _nestedFields = nestedFields2.Split(','); 105 | 106 | JObject job = el3 as JObject; 107 | foreach (JToken el4 in (job as JContainer).Children()) 108 | { 109 | if (!_nestedFields.Contains(el4.Path.ToLower().Substring(el4.Path.ToLower().LastIndexOf('.') + 1))) 110 | removeListNested.Add(el4); 111 | } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | } 118 | } 119 | } 120 | foreach (JToken elNest in removeListNested) 121 | { 122 | elNest.Remove(); 123 | } 124 | 125 | if (fields.Contains(nestedProperty)) 126 | fields.Remove(nestedProperty); 127 | 128 | if (fields.Contains(el.Path.ToLower())) 129 | fields.Remove(el.Path.ToLower()); 130 | } 131 | else if (jprop != null && !fields.Contains(jprop.Name.ToLower())) 132 | { 133 | removeList.Add(el); 134 | } 135 | } 136 | else 137 | { 138 | jobj = el as JObject; 139 | 140 | foreach (JToken _joNested in (jobj as JContainer).Children().OrderBy(order => order.Parent)) 141 | { 142 | if (fields.Any(field => field.ToLower().StartsWith(_joNested.Path.ToLower().Substring(_joNested.Path.IndexOf('.') + 1) + "("))) 143 | { 144 | string nestedProperty = fields.First(f => f.StartsWith(_joNested.Path.ToLower().Substring(_joNested.Path.IndexOf('.') + 1) + "(")); 145 | int startField = nestedProperty.IndexOf("("); 146 | int lastField = nestedProperty.LastIndexOf(")"); 147 | string nestedFields = nestedProperty.Substring(startField + 1, (lastField - 1) - startField); 148 | 149 | List _nestedFieldList = GetNestedFiels(nestedFields); // nestedFields.Split(';').ToList(); 150 | JToken nestedProperties = _joNested.First(); 151 | List removeListNested = new List(); 152 | foreach (JToken elNested in (nestedProperties as JContainer).Children()) 153 | { 154 | if (elNested is JProperty) 155 | { 156 | pNested = elNested as JProperty; 157 | if (!_nestedFieldList.Contains(pNested.Path.ToLower().Substring(pNested.Path.IndexOf('.') + 1))) 158 | removeListNested.Add(pNested); 159 | } 160 | else if (elNested is JObject) 161 | { 162 | poNested = elNested as JObject; 163 | 164 | foreach (JToken _poNested in (poNested as JContainer).Children().OrderBy(order => order.Parent)) 165 | { 166 | if (_nestedFieldList.Any(f => f.ToLower().StartsWith(_poNested.Path.ToLower().Substring(_poNested.Path.LastIndexOf('.') + 1) + "("))) 167 | { 168 | string field = _nestedFieldList.First(f => f.ToLower().StartsWith(_poNested.Path.ToLower().Substring(_poNested.Path.LastIndexOf('.') + 1) + "(")); 169 | int startNestedField = field.IndexOf("("); 170 | int lastNestedField = field.LastIndexOf(")"); 171 | string nestedFields2 = field.Substring(startNestedField + 1, (lastNestedField - 1) - startNestedField); 172 | 173 | List _nestedFieldList2 = nestedFields2.Split(',').ToList(); // GetNestedFiels(nestedFields2); // nestedFields.Split(';').ToList(); 174 | JToken nestedProperties2 = _poNested.First(); 175 | List removeListNested2 = new List(); 176 | foreach (JToken elNested2 in (nestedProperties2 as JContainer).Children()) 177 | { 178 | if (elNested2 is JProperty) 179 | { 180 | pNested = elNested2 as JProperty; 181 | if (!_nestedFieldList2.Contains(pNested.Path.ToLower().Substring(pNested.Path.IndexOf('.') + 1))) 182 | removeListNested.Add(pNested); 183 | } 184 | else if (elNested2 is JObject) 185 | { 186 | poNested = elNested2 as JObject; 187 | 188 | foreach (JToken _poNested2 in (poNested as JContainer).Children().OrderBy(order => order.Parent)) 189 | { 190 | if ((!_nestedFieldList2.Contains(_poNested2.Path.ToLower().Substring(_poNested2.Path.LastIndexOf('.') + 1)))) 191 | removeListNested.Add(_poNested2); 192 | } 193 | } 194 | } 195 | 196 | } 197 | 198 | else if ((!_nestedFieldList.Contains(_poNested.Path.ToLower().Substring(_poNested.Path.LastIndexOf('.') + 1)))) 199 | removeListNested.Add(_poNested); 200 | } 201 | } 202 | } 203 | foreach (JToken elNest in removeListNested) 204 | { 205 | elNest.Remove(); 206 | } 207 | 208 | if (fields.Contains(nestedProperty) && el.Next == null) 209 | fields.Remove(nestedProperty); 210 | 211 | if (fields.Contains(el.Path.ToLower())) 212 | fields.Remove(el.Path.ToLower()); 213 | } 214 | else if (!fields.Contains(_joNested.Path.ToLower().Substring(_joNested.Path.IndexOf('.') + 1))) 215 | removeList.Add(_joNested); 216 | } 217 | } 218 | } 219 | 220 | foreach (JToken el in removeList) 221 | { 222 | el.Remove(); 223 | } 224 | } 225 | catch (Exception ex) 226 | { 227 | throw ex; 228 | } 229 | } 230 | private static List GetNestedFiels(string fields) 231 | { 232 | if (!fields.Contains('(') && !fields.Contains(')')) 233 | return fields.Split(';').ToList(); 234 | 235 | List _fieldList = new List(); 236 | string _tempField = string.Empty; 237 | char[] _fieldArray = fields.ToCharArray(); 238 | bool _skip = false; 239 | 240 | try 241 | { 242 | for (int i = 0; i < _fieldArray.Length; i++) 243 | { 244 | if (_fieldArray[i] != ';' && _fieldArray[i] != ')') 245 | { 246 | _tempField += _fieldArray[i]; 247 | 248 | if (_fieldArray[i] == '(') 249 | { 250 | _skip = true; 251 | } 252 | } 253 | else if (_fieldArray[i] == ';') 254 | { 255 | if (!_skip) 256 | { 257 | _fieldList.Add(_tempField); 258 | _tempField = string.Empty; 259 | } 260 | else 261 | { 262 | _tempField += ','; 263 | } 264 | } 265 | else if (_fieldArray[i] == ')') 266 | { 267 | _tempField += ')'; 268 | _fieldList.Add(_tempField); 269 | _tempField = string.Empty; 270 | _skip = false; 271 | } 272 | 273 | } 274 | } 275 | catch (Exception ex) 276 | { 277 | throw ex; 278 | } 279 | 280 | return _fieldList; 281 | } 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /src/ShapingAPI/Infrastructure/Data/IRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Threading.Tasks; 6 | 7 | namespace ShapingAPI.Infrastructure.Data 8 | { 9 | public interface IRepository 10 | { 11 | #region READ 12 | TEntity Get(Expression> predicate); 13 | TEntity Get(Expression> predicate, params Expression>[] includeProperties); 14 | IQueryable GetAll(); 15 | IQueryable GetAll(params Expression>[] includeProperties); 16 | 17 | #endregion 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/ShapingAPI/Infrastructure/Data/Repositories/IRepositories.cs: -------------------------------------------------------------------------------- 1 | using ShapingAPI.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace ShapingAPI.Infrastructure.Data.Repositories 8 | { 9 | public interface IAlbumRepository : IRepository { 10 | IEnumerable LoadAll(); 11 | Album Load(int albumId); 12 | } 13 | 14 | public interface IArtistRepository : IRepository 15 | { 16 | IEnumerable LoadAll(); 17 | Artist Load(int artistId); 18 | } 19 | 20 | public interface ICustomerRepository : IRepository 21 | { 22 | IEnumerable LoadAll(); 23 | Customer Load(int customerId); 24 | } 25 | 26 | public interface IEmployeeRepository : IRepository { } 27 | 28 | public interface IGenreRepository : IRepository { } 29 | 30 | public interface IInvoiceLineRepository : IRepository { } 31 | 32 | public interface IInvoiceRepository : IRepository 33 | { 34 | IEnumerable LoadAll(); 35 | Invoice Load(int invoiceId); 36 | } 37 | 38 | public interface IMediaTypeRepository : IRepository { } 39 | 40 | public interface IPlaylistTrackRepository : IRepository { } 41 | 42 | public interface IPlaylistRepository : IRepository { } 43 | 44 | public interface ITrackRepository : IRepository { } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/ShapingAPI/Infrastructure/Data/Repositories/Repositories.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Data.Entity; 2 | using ShapingAPI.Entities; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace ShapingAPI.Infrastructure.Data.Repositories 9 | { 10 | public class AlbumRepository : Repository, IAlbumRepository 11 | { 12 | public AlbumRepository(ChinookContext context) 13 | : base(context) 14 | { } 15 | 16 | public IEnumerable LoadAll() 17 | { 18 | IQueryable query = this._dbSet; 19 | 20 | query = query.Include(a => a.Track); 21 | 22 | return query.ToList(); 23 | } 24 | 25 | public Album Load(int artistId) 26 | { 27 | IQueryable query = this._dbSet; 28 | 29 | query = query.Include(a => a.Track); 30 | 31 | return query.FirstOrDefault(a => a.AlbumId == artistId); 32 | } 33 | } 34 | 35 | public class ArtistRepository : Repository, IArtistRepository 36 | { 37 | public ArtistRepository(ChinookContext context) 38 | : base(context) 39 | { 40 | 41 | } 42 | 43 | public IEnumerable LoadAll() 44 | { 45 | IQueryable query = this._dbSet; 46 | 47 | query = query.Include(a => a.Album).ThenInclude(al => al.Track); 48 | 49 | return query.ToList(); 50 | } 51 | 52 | public Artist Load(int artistId) 53 | { 54 | IQueryable query = this._dbSet; 55 | 56 | query = query.Include(a => a.Album).ThenInclude(al => al.Track); 57 | 58 | return query.FirstOrDefault(a => a.ArtistId == artistId); 59 | } 60 | } 61 | 62 | public class CustomerRepository : Repository, ICustomerRepository 63 | { 64 | public CustomerRepository(ChinookContext context) 65 | : base(context) 66 | { } 67 | 68 | public IEnumerable LoadAll() 69 | { 70 | IQueryable query = this._dbSet; 71 | 72 | query = query.Include(c => c.Invoice).ThenInclude(i => i.InvoiceLine); 73 | 74 | return query.ToList(); 75 | } 76 | 77 | public Customer Load(int customerId) 78 | { 79 | IQueryable query = this._dbSet; 80 | 81 | query = query.Include(c => c.Invoice).ThenInclude(i => i.InvoiceLine); 82 | 83 | return query.FirstOrDefault(c => c.CustomerId == customerId); 84 | } 85 | } 86 | 87 | public class EmployeeRepository : Repository, IEmployeeRepository 88 | { 89 | public EmployeeRepository(ChinookContext context) 90 | : base(context) 91 | { } 92 | } 93 | 94 | public class GenreRepository : Repository, IGenreRepository 95 | { 96 | public GenreRepository(ChinookContext context) 97 | : base(context) 98 | { } 99 | } 100 | 101 | public class InvoiceLineRepository : Repository, IInvoiceLineRepository 102 | { 103 | public InvoiceLineRepository(ChinookContext context) 104 | : base(context) 105 | { } 106 | } 107 | 108 | public class InvoiceRepository : Repository, IInvoiceRepository 109 | { 110 | public InvoiceRepository(ChinookContext context) 111 | : base(context) 112 | { } 113 | 114 | public IEnumerable LoadAll() 115 | { 116 | IQueryable query = this._dbSet; 117 | 118 | query = query.Include(i => i.Customer).ThenInclude(c => c.Invoice); 119 | query = query.Include(i => i.InvoiceLine); 120 | 121 | return query.ToList(); 122 | } 123 | 124 | public Invoice Load(int invoiceId) 125 | { 126 | IQueryable query = this._dbSet; 127 | 128 | query = query.Include(i => i.Customer).ThenInclude(c => c.Invoice); 129 | query = query.Include(i => i.InvoiceLine); 130 | 131 | return query.FirstOrDefault(i => i.InvoiceId == invoiceId); 132 | } 133 | } 134 | 135 | public class MediaTypeRepository : Repository, IMediaTypeRepository 136 | { 137 | public MediaTypeRepository(ChinookContext context) 138 | : base(context) 139 | { } 140 | } 141 | 142 | public class PlaylistTrackRepository : Repository, IPlaylistTrackRepository 143 | { 144 | public PlaylistTrackRepository(ChinookContext context) 145 | : base(context) 146 | { } 147 | } 148 | 149 | public class PlaylistRepository : Repository, IPlaylistRepository 150 | { 151 | public PlaylistRepository(ChinookContext context) 152 | : base(context) 153 | { } 154 | } 155 | 156 | public class TrackRepository : Repository, ITrackRepository 157 | { 158 | public TrackRepository(ChinookContext context) 159 | : base(context) 160 | { } 161 | } 162 | } -------------------------------------------------------------------------------- /src/ShapingAPI/Infrastructure/Data/Repository.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Data.Entity; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using System.Threading.Tasks; 7 | 8 | namespace ShapingAPI.Infrastructure.Data 9 | { 10 | public abstract class Repository : IRepository where TEntity : class 11 | { 12 | protected DbContext _context; 13 | protected DbSet _dbSet; 14 | 15 | public Repository(DbContext context) 16 | { 17 | _context = context; 18 | _dbSet = _context.Set(); 19 | } 20 | 21 | #region READ 22 | public TEntity Get(Expression> predicate) 23 | { 24 | return _dbSet.FirstOrDefault(predicate); 25 | } 26 | 27 | public TEntity Get(Expression> predicate, params Expression>[] includeProperties) 28 | { 29 | IQueryable query = _dbSet; 30 | 31 | if (includeProperties != null) 32 | foreach (var property in includeProperties) 33 | { 34 | query = query.Include(property); 35 | } 36 | 37 | return query.FirstOrDefault(predicate); 38 | } 39 | 40 | public IQueryable GetAll() 41 | { 42 | return _dbSet.AsQueryable(); 43 | } 44 | 45 | public IQueryable GetAll(params Expression>[] includeProperties) 46 | { 47 | IQueryable query = _dbSet.AsQueryable(); 48 | 49 | if (includeProperties != null) 50 | foreach (var property in includeProperties) 51 | { 52 | query = query.Include(property); 53 | } 54 | 55 | return query; 56 | } 57 | 58 | #endregion 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/ShapingAPI/Infrastructure/Mappings/AutoMapperConfiguration.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace ShapingAPI.Infrastructure.Mappings 8 | { 9 | public class AutoMapperConfiguration 10 | { 11 | public static void Configure() 12 | { 13 | Mapper.Initialize(x => 14 | { 15 | x.AddProfile(); 16 | }); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/ShapingAPI/Infrastructure/Mappings/DomainToViewModelMappingProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using ShapingAPI.Entities; 3 | using ShapingAPI.ViewModels; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | 9 | namespace ShapingAPI.Infrastructure.Mappings 10 | { 11 | public class DomainToViewModelMappingProfile : Profile 12 | { 13 | protected override void Configure() 14 | { 15 | Mapper.CreateMap(); 16 | 17 | Mapper.CreateMap() 18 | .ForMember(vm => vm.ArtistName, map => map.MapFrom(a => a.Artist.Name)); 19 | 20 | Mapper.CreateMap(); 21 | 22 | Mapper.CreateMap() 23 | .ForMember(vm => vm.Address, map => map.MapFrom(c => new AddressViewModel() 24 | { 25 | Address = c.Address, 26 | City = c.City, 27 | Country = c.Country, 28 | PostalCode = c.PostalCode, 29 | State = c.State 30 | })) 31 | .ForMember(vm => vm.Contact, map => map.MapFrom(c => new ContactViewModel() 32 | { 33 | Email = c.Email, 34 | Fax = c.Fax, 35 | Phone = c.Phone 36 | })) 37 | .ForMember(vm => vm.TotalInvoices, map => map.MapFrom(c => c.Invoice.Count())); 38 | 39 | //Mapper.CreateMap(); 40 | 41 | //Mapper.CreateMap() 42 | // .ForMember(vm => vm.Tracks, map => map.MapFrom(g => g.Track.Select(t => t.TrackId).ToList())); 43 | 44 | Mapper.CreateMap(); 45 | 46 | Mapper.CreateMap(); 47 | 48 | //Mapper.CreateMap() 49 | // .ForMember(vm => vm.Tracks, map => map.MapFrom(m => m.Track.Select(t => t.TrackId).ToList())); 50 | 51 | //Mapper.CreateMap(); 52 | 53 | //Mapper.CreateMap(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/ShapingAPI/Project_Readme.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Welcome to ASP.NET 5 6 | 127 | 128 | 129 | 130 | 138 | 139 |
140 |
141 |

This application consists of:

142 |
    143 |
  • Sample pages using ASP.NET MVC 6
  • 144 |
  • Gulp and Bower for managing client-side libraries
  • 145 |
  • Theming using Bootstrap
  • 146 |
147 |
148 | 160 | 172 | 181 | 182 | 185 |
186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /src/ShapingAPI/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:22249/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "Hosting:Environment": "Development" 16 | } 17 | }, 18 | "web": { 19 | "commandName": "web", 20 | "environmentVariables": { 21 | "Hosting:Environment": "Development" 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/ShapingAPI/SQL/Chinook_SqlServer_AutoIncrementPKs.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/multi-client-api/db6e537563c7adb1f47d269b8e6533793d9d6806/src/ShapingAPI/SQL/Chinook_SqlServer_AutoIncrementPKs.sql -------------------------------------------------------------------------------- /src/ShapingAPI/ShapingAPI.xproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 14.0 5 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 6 | 7 | 8 | 9 | 10 | 6c8d22bc-4f3b-4f8f-947d-f9cdeb82f3de 11 | ShapingAPI 12 | ..\..\artifacts\obj\$(MSBuildProjectName) 13 | ..\..\artifacts\bin\$(MSBuildProjectName)\ 14 | 15 | 16 | 17 | 2.0 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/ShapingAPI/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNet.Builder; 6 | using Microsoft.AspNet.Hosting; 7 | using Microsoft.AspNet.Http; 8 | using Microsoft.Extensions.DependencyInjection; 9 | using Newtonsoft.Json.Serialization; 10 | using Microsoft.Extensions.Logging; 11 | using ShapingAPI.Entities; 12 | using Microsoft.Data.Entity; 13 | using Microsoft.Extensions.Configuration; 14 | using ShapingAPI.Infrastructure.Data.Repositories; 15 | using ShapingAPI.Infrastructure.Mappings; 16 | 17 | namespace ShapingAPI 18 | { 19 | public class Startup 20 | { 21 | public Startup(IHostingEnvironment env) 22 | { 23 | // Set up configuration sources. 24 | var builder = new ConfigurationBuilder() 25 | .AddJsonFile("appsettings.json"); 26 | 27 | if (env.IsEnvironment("Development")) 28 | { 29 | // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately. 30 | builder.AddApplicationInsightsSettings(developerMode: true); 31 | } 32 | 33 | builder.AddEnvironmentVariables(); 34 | Configuration = builder.Build().ReloadOnChanged("appsettings.json"); 35 | } 36 | 37 | public IConfigurationRoot Configuration { get; set; } 38 | 39 | // This method gets called by the runtime. Use this method to add services to the container 40 | public void ConfigureServices(IServiceCollection services) 41 | { 42 | // Add framework services. 43 | services.AddApplicationInsightsTelemetry(Configuration); 44 | 45 | services.AddEntityFramework() 46 | .AddSqlServer() 47 | .AddDbContext(options => options.UseSqlServer(Configuration["Data:ChinookConnection:ConnectionString"])); 48 | 49 | // Repositories 50 | services.AddScoped(); 51 | services.AddScoped(); 52 | services.AddScoped(); 53 | services.AddScoped(); 54 | services.AddScoped(); 55 | services.AddScoped(); 56 | services.AddScoped(); 57 | services.AddScoped(); 58 | services.AddScoped(); 59 | services.AddScoped(); 60 | services.AddScoped(); 61 | 62 | services.AddMvc() 63 | .AddJsonOptions(options => 64 | { 65 | options.SerializerSettings.ReferenceLoopHandling = 66 | Newtonsoft.Json.ReferenceLoopHandling.Ignore; 67 | options.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; 68 | options.SerializerSettings.ContractResolver = 69 | new CamelCasePropertyNamesContractResolver(); 70 | }); 71 | } 72 | 73 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline 74 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 75 | { 76 | loggerFactory.AddConsole(Configuration.GetSection("Logging")); 77 | loggerFactory.AddDebug(); 78 | 79 | app.UseIISPlatformHandler(); 80 | 81 | app.UseApplicationInsightsRequestTelemetry(); 82 | 83 | app.UseApplicationInsightsExceptionTelemetry(); 84 | 85 | app.UseStaticFiles(); 86 | 87 | AutoMapperConfiguration.Configure(); 88 | 89 | app.UseMvc(routes => 90 | { 91 | routes.MapRoute( 92 | name: "default", 93 | template: "{controller=Home}/{action=Index}/{id?}"); 94 | 95 | // Uncomment the following line to add a route for porting Web API 2 controllers. 96 | //routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}"); 97 | }); 98 | } 99 | 100 | // Entry point for the application. 101 | public static void Main(string[] args) => WebApplication.Run(args); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/ShapingAPI/ViewModels/AddressViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace ShapingAPI.ViewModels 7 | { 8 | public class AddressViewModel 9 | { 10 | public string Address { get; set; } 11 | public string City { get; set; } 12 | public string Country { get; set; } 13 | public string PostalCode { get; set; } 14 | public string State { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ShapingAPI/ViewModels/AlbumViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace ShapingAPI.ViewModels 7 | { 8 | public class AlbumViewModel 9 | { 10 | public AlbumViewModel() 11 | { 12 | Track = new HashSet(); 13 | } 14 | 15 | public int AlbumId { get; set; } 16 | public string ArtistName { get; set; } 17 | public string Title { get; set; } 18 | public virtual ICollection Track { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ShapingAPI/ViewModels/ArtistViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace ShapingAPI.ViewModels 7 | { 8 | public class ArtistViewModel 9 | { 10 | public ArtistViewModel() 11 | { 12 | Album = new HashSet(); 13 | } 14 | 15 | public int ArtistId { get; set; } 16 | public string Name { get; set; } 17 | 18 | public virtual ICollection Album { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ShapingAPI/ViewModels/ContactViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace ShapingAPI.ViewModels 7 | { 8 | public class ContactViewModel 9 | { 10 | public string Email { get; set; } 11 | public string Fax { get; set; } 12 | public string Phone { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ShapingAPI/ViewModels/CustomerViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.ViewModels 5 | { 6 | public class CustomerViewModel 7 | { 8 | public CustomerViewModel() { } 9 | 10 | public int CustomerId { get; set; } 11 | public string Company { get; set; } 12 | public string FirstName { get; set; } 13 | public string LastName { get; set; } 14 | public int? SupportRepId { get; set; } 15 | public int TotalInvoices { get; set; } 16 | public ICollection Invoice { get; set; } 17 | public AddressViewModel Address { get; set; } 18 | public ContactViewModel Contact { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ShapingAPI/ViewModels/InvoiceLineViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.ViewModels 5 | { 6 | public class InvoiceLineViewModel 7 | { 8 | public int InvoiceLineId { get; set; } 9 | public int InvoiceId { get; set; } 10 | public int Quantity { get; set; } 11 | public int TrackId { get; set; } 12 | public decimal UnitPrice { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ShapingAPI/ViewModels/InvoiceViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ShapingAPI.ViewModels 5 | { 6 | public class InvoiceViewModel 7 | { 8 | public InvoiceViewModel() 9 | { 10 | InvoiceLine = new HashSet(); 11 | } 12 | 13 | public int InvoiceId { get; set; } 14 | public string BillingAddress { get; set; } 15 | public string BillingCity { get; set; } 16 | public string BillingCountry { get; set; } 17 | public string BillingPostalCode { get; set; } 18 | public string BillingState { get; set; } 19 | public int CustomerId { get; set; } 20 | public DateTime InvoiceDate { get; set; } 21 | public decimal Total { get; set; } 22 | public ICollection InvoiceLine { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ShapingAPI/ViewModels/TrackViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace ShapingAPI.ViewModels 7 | { 8 | public class TrackViewModel 9 | { 10 | public TrackViewModel() { } 11 | 12 | public int TrackId { get; set; } 13 | public int? AlbumId { get; set; } 14 | public int? Bytes { get; set; } 15 | public string Composer { get; set; } 16 | public int? GenreId { get; set; } 17 | public int MediaTypeId { get; set; } 18 | public int Milliseconds { get; set; } 19 | public string Name { get; set; } 20 | public decimal UnitPrice { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ShapingAPI/Views/Home/Albums.cshtml: -------------------------------------------------------------------------------- 1 | 
2 |
3 |
4 |
5 |
6 |

api/albums

7 |
8 | 9 |
10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 | 18 |
19 |
20 | 23 | 24 |
25 | 26 | 27 | 28 | 29 |
30 |
31 |
32 | 33 |
34 |
35 | 38 | 39 |
40 | 41 | 42 | 43 | 44 |
45 |
46 |
47 | 48 |
49 |
50 | 53 | 54 |
55 | 56 | 57 | 58 | 59 |
60 |
61 |
62 | 63 |
64 |
65 |
66 |

api/albums/1

67 |
68 | 69 |
70 | 71 | 72 | 73 | 74 |
75 |
76 |
77 | 78 |
79 |
80 | 83 | 84 |
85 | 86 | 87 | 88 | 89 |
90 |
91 |
92 | 93 |
94 |
95 | 96 | @section scripts 97 | { 98 | 99 | } -------------------------------------------------------------------------------- /src/ShapingAPI/Views/Home/Artists.cshtml: -------------------------------------------------------------------------------- 1 | 
2 |
3 | 4 |
5 |
6 |
7 |

api/artists

8 |
9 | 10 |
11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | 19 |
20 |
21 | 24 | 25 |
26 | 27 | 28 | 29 | 30 |
31 |
32 |
33 | 34 |
35 |
36 | 39 | 40 |
41 | 42 | 43 | 44 | 45 |
46 |
47 |
48 | 49 |
50 |
51 | 54 | 55 |
56 | 57 | 58 | 59 | 60 |
61 |
62 |
63 | 64 |
65 |
66 | 69 | 70 |
71 | 72 | 73 | 74 | 75 |
76 |
77 |
78 | 79 |
80 |
81 | 82 | @section scripts 83 | { 84 | 85 | } -------------------------------------------------------------------------------- /src/ShapingAPI/Views/Home/Customers.cshtml: -------------------------------------------------------------------------------- 1 | 
2 |
3 | 4 |
5 |
6 |
7 |

api/customers

8 |
9 | 10 |
11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | 19 |
20 |
21 | 24 | 25 |
26 | 27 | 28 | 29 | 30 |
31 |
32 |
33 | 34 |
35 |
36 | 39 | 40 |
41 | 42 | 43 | 44 | 45 |
46 |
47 |
48 | 49 |
50 |
51 | 54 | 55 |
56 | 57 | 58 | 59 | 60 |
61 |
62 |
63 | 64 | 78 | 79 | 93 |
94 |
95 | 96 | @section scripts 97 | { 98 | 99 | } -------------------------------------------------------------------------------- /src/ShapingAPI/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | 
2 |
3 | 4 |
5 |
6 |
7 |

api/tracks

8 |
9 | 10 |
11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | 19 |
20 |
21 | 24 | 25 |
26 | 27 | 28 | 29 | 30 |
31 |
32 |
33 | 34 |
35 |
36 | 39 | 40 |
41 | 42 | 43 | 44 | 45 |
46 |
47 |
48 | 49 |
50 |
51 |
52 |

api/tracks/1

53 |
54 | 55 |
56 | 57 | 58 | 59 | 60 |
61 |
62 |
63 | 64 |
65 |
66 | 69 | 70 |
71 | 72 | 73 | 74 | 75 |
76 |
77 |
78 | 79 |
80 |
81 | 82 | @section scripts 83 | { 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/ShapingAPI/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | Shaping APIs 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 49 |
50 | 66 | @RenderBody() 67 |
68 | @RenderSection("scripts", required: false) 69 | 72 | 73 | -------------------------------------------------------------------------------- /src/ShapingAPI/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /src/ShapingAPI/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Verbose", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | }, 10 | "Data": { 11 | "ChinookConnection": { 12 | "ConnectionString": "Server=(localdb)\\v11.0;Database=Chinook;Trusted_Connection=True;MultipleActiveResultSets=true" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ShapingAPI/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ASP.NET", 3 | "private": true, 4 | "dependencies": { 5 | "angular": "1.5.0", 6 | "bootstrap": "3.3.6", 7 | "font-awesome": "4.5.0", 8 | "angular-perfect-scrollbar": "0.0.4", 9 | "ng-json-prettifier": "*" 10 | }, 11 | "resolutions": { 12 | "angular": "1.5.0" 13 | } 14 | } -------------------------------------------------------------------------------- /src/ShapingAPI/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0-*", 3 | "compilationOptions": { 4 | "emitEntryPoint": true 5 | }, 6 | 7 | "dependencies": { 8 | "Microsoft.ApplicationInsights.AspNet": "1.0.0-rc1", 9 | "Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final", 10 | "Microsoft.AspNet.Mvc": "6.0.0-rc1-final", 11 | "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final", 12 | "Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final", 13 | "Microsoft.Extensions.Configuration.FileProviderExtensions": "1.0.0-rc1-final", 14 | "Microsoft.Extensions.Configuration.Json": "1.0.0-rc1-final", 15 | "Microsoft.Extensions.Logging": "1.0.0-rc1-final", 16 | "Microsoft.Extensions.Logging.Console": "1.0.0-rc1-final", 17 | "Microsoft.Extensions.Logging.Debug": "1.0.0-rc1-final", 18 | "EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final", 19 | "EntityFramework.MicrosoftSqlServer.Design": "7.0.0-rc1-final", 20 | "EntityFramework.Commands": "7.0.0-rc1-final", 21 | "AutoMapper.Data": "1.0.0-beta1", 22 | "Newtonsoft.Json": "7.0.1" 23 | }, 24 | 25 | "commands": { 26 | "web": "Microsoft.AspNet.Server.Kestrel", 27 | "ef": "EntityFramework.Commands" 28 | }, 29 | 30 | "frameworks": { 31 | "dnx451": { }, 32 | "dnxcore50": { } 33 | }, 34 | 35 | "exclude": [ 36 | "wwwroot", 37 | "node_modules" 38 | ], 39 | "publishExclude": [ 40 | "**.user", 41 | "**.vspscc" 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /src/ShapingAPI/wwwroot/app/app.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | var app = angular.module("shapeApp", ['perfect_scrollbar','pretty.json']); 4 | 5 | })(); 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/ShapingAPI/wwwroot/app/controllers/albumsCtrl.js: -------------------------------------------------------------------------------- 1 | (function (app) { 2 | 'use strict'; 3 | 4 | app.controller('albumsCtrl', albumsCtrl); 5 | 6 | albumsCtrl.$inject = ['$scope', '$http']; 7 | 8 | function albumsCtrl($scope, $http) { 9 | // api/albums 10 | $http.get('/api/albums/'). 11 | success(function (data, status, headers, config) { 12 | $scope.apiAlbums = data; 13 | }). 14 | error(function (data, status, headers, config) { 15 | console.log(data); 16 | }); 17 | 18 | 19 | //api/albums?props=artistname,title,track 20 | $http.get('/api/albums?props=artistname,title,track'). 21 | success(function (data, status, headers, config) { 22 | $scope.apiAlbumsPropsAll = data; 23 | }). 24 | error(function (data, status, headers, config) { 25 | console.log(data); 26 | }); 27 | 28 | //api/albums?props=artistname,title,track&page=2&pagesize=10 29 | $http.get('/api/albums?props=artistname,title,track&page=2&pagesize=10'). 30 | success(function (data, status, headers, config) { 31 | $scope.apiAlbumsPropsAllPaged = data; 32 | }). 33 | error(function (data, status, headers, config) { 34 | console.log(data); 35 | }); 36 | 37 | //api/albums?props=artistname,title,track 38 | $http.get('/api/albums?props=artistname,title,track(bytes;name;unitprice)'). 39 | success(function (data, status, headers, config) { 40 | $scope.apiAlbumsPropsAllParseTrack = data; 41 | }). 42 | error(function (data, status, headers, config) { 43 | console.log(data); 44 | }); 45 | 46 | // api/albums/1 47 | $http.get('/api/albums/1'). 48 | success(function (data, status, headers, config) { 49 | $scope.apiAlbumsOne = data; 50 | }). 51 | error(function (data, status, headers, config) { 52 | console.log(data); 53 | }); 54 | 55 | // api/albums/1?props=bytes,milliseconds,name 56 | $http.get('/api/albums/1?props=artistname,title,track(composer;name)'). 57 | success(function (data, status, headers, config) { 58 | $scope.apiAlbumsOneProps = data; 59 | }). 60 | error(function (data, status, headers, config) { 61 | console.log(data); 62 | }); 63 | } 64 | })(angular.module('shapeApp')); -------------------------------------------------------------------------------- /src/ShapingAPI/wwwroot/app/controllers/artistsCtrl.js: -------------------------------------------------------------------------------- 1 | (function (app) { 2 | 'use strict'; 3 | 4 | app.controller('artistsCtrl', artistsCtrl); 5 | 6 | artistsCtrl.$inject = ['$scope', '$http']; 7 | 8 | function artistsCtrl($scope, $http) { 9 | // api/artists 10 | $http.get('/api/artists/'). 11 | success(function (data, status, headers, config) { 12 | $scope.apiArtists = data; 13 | }). 14 | error(function (data, status, headers, config) { 15 | console.log(data); 16 | }); 17 | 18 | 19 | //api/artists?props=artistname,title,track 20 | $http.get('/api/artists?props=name,album(albumid;title)'). 21 | success(function (data, status, headers, config) { 22 | $scope.apiArtistsPropsOne = data; 23 | }). 24 | error(function (data, status, headers, config) { 25 | console.log(data); 26 | }); 27 | 28 | //api/artists?props=artistname,title,track 29 | $http.get('/api/artists?props=name,album(albumid;title;track)'). 30 | success(function (data, status, headers, config) { 31 | $scope.apiAlbumsPropsTwo = data; 32 | }). 33 | error(function (data, status, headers, config) { 34 | console.log(data); 35 | }); 36 | 37 | // api/artists/1 38 | $http.get('/api/artists/1?props=name,album(albumid;title;track)'). 39 | success(function (data, status, headers, config) { 40 | $scope.apiArtistsPropsThree = data; 41 | }). 42 | error(function (data, status, headers, config) { 43 | console.log(data); 44 | }); 45 | 46 | // api/albums/1?props=bytes,milliseconds,name 47 | $http.get('/api/artists/1?props=name,album(albumid;title;track(bytes;composer;unitprice))'). 48 | success(function (data, status, headers, config) { 49 | $scope.apiArtistsPropsFour = data; 50 | }). 51 | error(function (data, status, headers, config) { 52 | console.log(data); 53 | }); 54 | } 55 | })(angular.module('shapeApp')); -------------------------------------------------------------------------------- /src/ShapingAPI/wwwroot/app/controllers/customersCtrl.js: -------------------------------------------------------------------------------- 1 | (function (app) { 2 | 'use strict'; 3 | 4 | app.controller('customersCtrl', customersCtrl); 5 | 6 | customersCtrl.$inject = ['$scope', '$http']; 7 | 8 | function customersCtrl($scope, $http) { 9 | // api/customers 10 | $http.get('/api/customers/'). 11 | success(function (data, status, headers, config) { 12 | $scope.apiCustomers = data; 13 | }). 14 | error(function (data, status, headers, config) { 15 | console.log(data); 16 | }); 17 | 18 | 19 | //api/customers?props=city,company,firstname,lastname,Invoice 20 | $http.get('/api/customers?props=city,company,firstname,lastname,Invoice'). 21 | success(function (data, status, headers, config) { 22 | $scope.apiCustomersPropsOne = data; 23 | }). 24 | error(function (data, status, headers, config) { 25 | console.log(data); 26 | }); 27 | 28 | //api/customers?props=address,contact 29 | $http.get('/api/customers?props=firstname,lastname,address,contact'). 30 | success(function (data, status, headers, config) { 31 | $scope.apiCustomersPropsAddressContact = data; 32 | }). 33 | error(function (data, status, headers, config) { 34 | console.log(data); 35 | }); 36 | 37 | //api/customers?props=firstname,lastname,Invoice[billingcity;total] 38 | $http.get('/api/customers?props=firstname,lastname,Invoice(billingcity;total)&page=4&pagesize=5'). 39 | success(function (data, status, headers, config) { 40 | $scope.apiCustomersPropsOnePaged = data; 41 | }). 42 | error(function (data, status, headers, config) { 43 | console.log(data); 44 | }); 45 | 46 | //api/customers?props=customerid,city,company,firstname,lastname,Invoice[billingaddress;billingcity;total;invoiceline] 47 | $http.get('/api/customers?props=customerid,city,company,firstname,lastname,Invoice(billingaddress;billingcity;total;invoiceline)'). 48 | success(function (data, status, headers, config) { 49 | $scope.apiCustomersPropsTwo = data; 50 | }). 51 | error(function (data, status, headers, config) { 52 | console.log(data); 53 | }); 54 | 55 | // /api/customers/1?props=customerid,city,company,firstname,lastname,Invoice[billingaddress;billingcity;total;invoiceline[invoicelineid;quantity;trackid]] 56 | $http.get('/api/customers/1?props=customerid,city,company,firstname,lastname,Invoice(billingaddress;billingcity;total;invoiceline(invoicelineid;quantity;trackid))'). 57 | success(function (data, status, headers, config) { 58 | $scope.apiCustomersPropsThree = data; 59 | }). 60 | error(function (data, status, headers, config) { 61 | console.log(data); 62 | }); 63 | } 64 | })(angular.module('shapeApp')); -------------------------------------------------------------------------------- /src/ShapingAPI/wwwroot/app/controllers/tracksCtrl.js: -------------------------------------------------------------------------------- 1 | (function (app) { 2 | 'use strict'; 3 | 4 | app.controller('tracksCtrl', tracksCtrl); 5 | 6 | tracksCtrl.$inject = ['$scope', '$http']; 7 | 8 | function tracksCtrl($scope, $http) { 9 | // api/tracks 10 | $http.get('api/tracks/'). 11 | success(function (data, status, headers, config) { 12 | $scope.apiTracks = data; 13 | }). 14 | error(function (data, status, headers, config) { 15 | console.log(data); 16 | }); 17 | 18 | // api/tracks?page=2&pagesize=100 19 | $http.get('api/tracks?page=2&pagesize=100'). 20 | success(function (data, status, headers, config) { 21 | $scope.apiTracksPaged = data; 22 | }). 23 | error(function (data, status, headers, config) { 24 | console.log(data); 25 | }); 26 | 27 | // api/tracks?props=bytes,composer,milliseconds 28 | $http.get('api/tracks?props=bytes,composer,milliseconds'). 29 | success(function (data, status, headers, config) { 30 | $scope.apiTracksAll = data; 31 | }). 32 | error(function (data, status, headers, config) { 33 | console.log(data); 34 | }); 35 | 36 | // api/tracks/1 37 | $http.get('api/tracks/1'). 38 | success(function (data, status, headers, config) { 39 | $scope.apiTracksOne = data; 40 | }). 41 | error(function (data, status, headers, config) { 42 | console.log(data); 43 | }); 44 | 45 | // api/tracks/1?props=bytes,milliseconds,name 46 | $http.get('api/tracks/1?props=bytes,milliseconds,name'). 47 | success(function (data, status, headers, config) { 48 | $scope.apiTracksOneProps = data; 49 | }). 50 | error(function (data, status, headers, config) { 51 | console.log(data); 52 | }); 53 | } 54 | })(angular.module('shapeApp')); -------------------------------------------------------------------------------- /src/ShapingAPI/wwwroot/images/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/multi-client-api/db6e537563c7adb1f47d269b8e6533793d9d6806/src/ShapingAPI/wwwroot/images/facebook.png -------------------------------------------------------------------------------- /src/ShapingAPI/wwwroot/images/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/multi-client-api/db6e537563c7adb1f47d269b8e6533793d9d6806/src/ShapingAPI/wwwroot/images/github.png -------------------------------------------------------------------------------- /src/ShapingAPI/wwwroot/images/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/multi-client-api/db6e537563c7adb1f47d269b8e6533793d9d6806/src/ShapingAPI/wwwroot/images/spinner.gif -------------------------------------------------------------------------------- /src/ShapingAPI/wwwroot/images/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chsakell/multi-client-api/db6e537563c7adb1f47d269b8e6533793d9d6806/src/ShapingAPI/wwwroot/images/twitter.png -------------------------------------------------------------------------------- /src/ShapingAPI/wwwroot/styles/site.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #31708f; 3 | } 4 | 5 | .api-box { 6 | white-space: pre-line; 7 | height: 200px; 8 | overflow-y: hidden; 9 | position: relative; 10 | background-color: white; 11 | margin: 6px; 12 | } 13 | 14 | pre { 15 | border: none !important; 16 | background-color: white !important; 17 | } 18 | 19 | .spinner { 20 | display: block; 21 | margin-left: auto; 22 | margin-right: auto; 23 | } 24 | 25 | .blog-image { 26 | height: 70px; 27 | } 28 | 29 | .icon::before { 30 | display: inline-block; 31 | margin-right: .5em; 32 | font: normal normal normal 14px/1 FontAwesome; 33 | font-size: inherit; 34 | text-rendering: auto; 35 | -webkit-font-smoothing: antialiased; 36 | -moz-osx-font-smoothing: grayscale; 37 | transform: translate(0, 0); 38 | } -------------------------------------------------------------------------------- /src/ShapingAPI/wwwroot/web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | --------------------------------------------------------------------------------