├── ApiNCoreApplication1 ├── .vs │ └── ApiNCoreApplication1 │ │ └── v15 │ │ ├── .suo │ │ └── Server │ │ └── sqlite3 │ │ ├── storage.ide │ │ ├── storage.ide-shm │ │ └── storage.ide-wal ├── ApiNCoreApplication1.sln └── ApiNCoreApplication1 │ ├── ApiNCoreApplication1.Api │ ├── ApiNCoreApplication1.Api.csproj │ ├── Controllers │ │ ├── AccountAsyncControler.cs │ │ ├── AccountControler.cs │ │ ├── InfoController.cs │ │ ├── TokenController.cs │ │ ├── UserAsyncController.cs │ │ └── UserController.cs │ ├── ExceptionHandler.cs │ ├── Globals.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Seed │ │ ├── accounts.json │ │ └── users.json │ ├── Settings │ │ └── LogglySettings.cs │ ├── Startup.cs │ ├── _nugets.txt │ ├── appsettings.Development.json │ ├── appsettings.json │ └── obj │ │ ├── ApiNCoreApplication1.Api.csproj.nuget.cache │ │ ├── ApiNCoreApplication1.Api.csproj.nuget.g.props │ │ ├── ApiNCoreApplication1.Api.csproj.nuget.g.targets │ │ ├── Debug │ │ └── netcoreapp2.1 │ │ │ ├── ApiNCoreApplication1.Api.AssemblyInfo.cs │ │ │ ├── ApiNCoreApplication1.Api.AssemblyInfoInputs.cache │ │ │ ├── ApiNCoreApplication1.Api.RazorAssemblyInfo.cache │ │ │ ├── ApiNCoreApplication1.Api.RazorAssemblyInfo.cs │ │ │ ├── ApiNCoreApplication1.Api.assets.cache │ │ │ ├── ApiNCoreApplication1.Api.csproj.CoreCompileInputs.cache │ │ │ ├── ApiNCoreApplication1.Api.csprojAssemblyReference.cache │ │ │ ├── TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs │ │ │ ├── TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs │ │ │ └── TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs │ │ └── project.assets.json │ ├── ApiNCoreApplication1.Domain │ ├── ApiNCoreApplication1.Domain.csproj │ ├── BaseDomain.cs │ ├── Domain │ │ ├── AccountViewModel.cs │ │ └── UserViewModel.cs │ ├── Mapping │ │ └── MappingProfile.cs │ ├── Service │ │ ├── AccountService.cs │ │ ├── Generic │ │ │ ├── GenericService.cs │ │ │ ├── GenericServiceAsync.cs │ │ │ ├── IService.cs │ │ │ └── IServiceAsync.cs │ │ └── UserService.cs │ ├── _nugets.txt │ └── obj │ │ ├── ApiNCoreApplication1.Domain.csproj.nuget.cache │ │ ├── ApiNCoreApplication1.Domain.csproj.nuget.g.props │ │ ├── ApiNCoreApplication1.Domain.csproj.nuget.g.targets │ │ ├── Debug │ │ └── netcoreapp2.1 │ │ │ ├── ApiNCoreApplication1.Domain.AssemblyInfo.cs │ │ │ ├── ApiNCoreApplication1.Domain.AssemblyInfoInputs.cache │ │ │ ├── ApiNCoreApplication1.Domain.assets.cache │ │ │ ├── ApiNCoreApplication1.Domain.csproj.CoreCompileInputs.cache │ │ │ ├── ApiNCoreApplication1.Domain.csprojAssemblyReference.cache │ │ │ ├── TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs │ │ │ ├── TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs │ │ │ └── TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs │ │ └── project.assets.json │ └── ApiNCoreApplication1.Entity │ ├── ApiNCoreApplication1.Entity.csproj │ ├── BaseEntity.cs │ ├── Context │ ├── ApiNCoreApplication1Context.cs │ └── DBContextExtension.cs │ ├── Entity │ ├── Account.cs │ ├── EntityHelper.cs │ └── User.cs │ ├── Migrations │ ├── 20180708205028_InitialCreate.Designer.cs │ └── 20180708205028_InitialCreate.cs │ ├── Repository │ ├── IRepository.cs │ ├── IRepositoryAsync.cs │ ├── Repository.cs │ └── RepositoryAsync.cs │ ├── UnitofWork │ └── UnitofWork.cs │ └── _nugets.txt ├── ApiNCoreE.vsix ├── LICENSE.md └── LICENSE.md └── README.md /ApiNCoreApplication1/.vs/ApiNCoreApplication1/v15/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anasoftinc/apincore/a192c3f65ea9548cccfcb4e46b142a36497f942e/ApiNCoreApplication1/.vs/ApiNCoreApplication1/v15/.suo -------------------------------------------------------------------------------- /ApiNCoreApplication1/.vs/ApiNCoreApplication1/v15/Server/sqlite3/storage.ide: -------------------------------------------------------------------------------- 1 | SQLite format 3@ .A  -------------------------------------------------------------------------------- /ApiNCoreApplication1/.vs/ApiNCoreApplication1/v15/Server/sqlite3/storage.ide-shm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anasoftinc/apincore/a192c3f65ea9548cccfcb4e46b142a36497f942e/ApiNCoreApplication1/.vs/ApiNCoreApplication1/v15/Server/sqlite3/storage.ide-shm -------------------------------------------------------------------------------- /ApiNCoreApplication1/.vs/ApiNCoreApplication1/v15/Server/sqlite3/storage.ide-wal: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anasoftinc/apincore/a192c3f65ea9548cccfcb4e46b142a36497f942e/ApiNCoreApplication1/.vs/ApiNCoreApplication1/v15/Server/sqlite3/storage.ide-wal -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2016 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiNCoreApplication1.Api", "ApiNCoreApplication1\ApiNCoreApplication1.Api\ApiNCoreApplication1.Api.csproj", "{EA9E8F2A-DE89-482B-9667-6E94BAA28EA8}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiNCoreApplication1.Domain", "ApiNCoreApplication1\ApiNCoreApplication1.Domain\ApiNCoreApplication1.Domain.csproj", "{79665F30-85A1-43C6-976F-C73E5588CEC1}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiNCoreApplication1.Entity", "ApiNCoreApplication1\ApiNCoreApplication1.Entity\ApiNCoreApplication1.Entity.csproj", "{93B603E5-095F-487B-817F-0C8AFEF87B85}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {EA9E8F2A-DE89-482B-9667-6E94BAA28EA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {EA9E8F2A-DE89-482B-9667-6E94BAA28EA8}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {EA9E8F2A-DE89-482B-9667-6E94BAA28EA8}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {EA9E8F2A-DE89-482B-9667-6E94BAA28EA8}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {79665F30-85A1-43C6-976F-C73E5588CEC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {79665F30-85A1-43C6-976F-C73E5588CEC1}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {79665F30-85A1-43C6-976F-C73E5588CEC1}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {79665F30-85A1-43C6-976F-C73E5588CEC1}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {93B603E5-095F-487B-817F-0C8AFEF87B85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {93B603E5-095F-487B-817F-0C8AFEF87B85}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {93B603E5-095F-487B-817F-0C8AFEF87B85}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {93B603E5-095F-487B-817F-0C8AFEF87B85}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {3502F2B2-AD61-4C21-8213-AFFDDD4C921D} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/ApiNCoreApplication1.Api.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/Controllers/AccountAsyncControler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.AspNetCore.Authorization; 5 | using ApiNCoreApplication1.Domain; 6 | using ApiNCoreApplication1.Entity.Context; 7 | using ApiNCoreApplication1.Domain.Service; 8 | using Microsoft.Extensions.Logging; 9 | using Serilog; 10 | using System.Threading.Tasks; 11 | using ApiNCoreApplication1.Entity; 12 | 13 | namespace ApiNCoreApplication1.Api.Controllers 14 | { 15 | [Route("api/[controller]")] 16 | public class AccountAsyncController : ControllerBase 17 | { 18 | private readonly AccountServiceAsync _accountServiceAsync; 19 | public AccountAsyncController(AccountServiceAsync accountServiceAsync) 20 | { 21 | _accountServiceAsync = accountServiceAsync; 22 | } 23 | 24 | 25 | //get all 26 | [Authorize] 27 | [HttpGet] 28 | public async Task GetAll() 29 | { 30 | var items = await _accountServiceAsync.GetAll(); 31 | return Ok(items); 32 | } 33 | 34 | //get one 35 | [Authorize] 36 | [HttpGet("{id}")] 37 | public async Task GetById(int id) 38 | { 39 | var item = await _accountServiceAsync.GetOne(id); 40 | if (item == null) 41 | { 42 | Log.Error("GetById({ ID}) NOT FOUND", id); 43 | return NotFound(); 44 | } 45 | 46 | return Ok(item); 47 | } 48 | 49 | //add 50 | [Authorize(Roles = "Administrator")] 51 | [HttpPut] 52 | public async Task Create([FromBody] AccountViewModel account) 53 | { 54 | if (account == null) 55 | return BadRequest(); 56 | 57 | var id = await _accountServiceAsync.Add(account); 58 | return Created($"api/Account/{id}", id); //HTTP201 Resource created 59 | } 60 | 61 | //update 62 | [Authorize(Roles = "Administrator")] 63 | [HttpPost("{id}")] 64 | public async Task Update(int id, [FromBody] AccountViewModel account) 65 | { 66 | if (account == null || account.Id != id) 67 | return BadRequest(); 68 | if (await _accountServiceAsync.Update(account)) 69 | return Accepted(account); 70 | else 71 | return StatusCode(304); 72 | } 73 | 74 | 75 | //delete -- it will check ClaimTypes.Role 76 | [Authorize(Roles = "Administrator")] 77 | [HttpDelete("{id}")] 78 | public async Task Delete(int id) 79 | { 80 | if (await _accountServiceAsync.Remove(id)) 81 | return NoContent(); //204 82 | else 83 | return NotFound(); //404 84 | } 85 | } 86 | } 87 | 88 | 89 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/Controllers/AccountControler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.AspNetCore.Authorization; 5 | using ApiNCoreApplication1.Domain; 6 | using ApiNCoreApplication1.Entity.Context; 7 | using ApiNCoreApplication1.Domain.Service; 8 | using Microsoft.Extensions.Logging; 9 | using Serilog; 10 | using ApiNCoreApplication1.Entity; 11 | 12 | namespace ApiNCoreApplication1.Api.Controllers 13 | { 14 | [Route("api/[controller]")] 15 | public class AccountController : ControllerBase 16 | { 17 | private readonly AccountService _accountService; 18 | public AccountController(AccountService accountService) 19 | { 20 | _accountService = accountService; 21 | } 22 | 23 | //get all 24 | [Authorize] 25 | [HttpGet] 26 | public IEnumerable GetAll() 27 | { 28 | //Log.Information("Log: Log.Information"); 29 | //Log.Warning("Log: Log.Warning"); 30 | //Log.Error("Log: Log.Error"); 31 | //Log.Fatal("Log: Log.Fatal"); 32 | var test = _accountService.DoNothing(); 33 | var items = _accountService.GetAll(); 34 | return items; 35 | } 36 | 37 | //get one 38 | [Authorize] 39 | [HttpGet("{id}")] 40 | public IActionResult GetById(int id) 41 | { 42 | var item = _accountService.GetOne(id); 43 | if (item == null) 44 | { 45 | Log.Error("GetById({ ID}) NOT FOUND", id); 46 | return NotFound(); 47 | } 48 | 49 | return Ok(item); 50 | } 51 | 52 | //add 53 | [Authorize(Roles = "Administrator")] 54 | [HttpPut] 55 | public IActionResult Create([FromBody] AccountViewModel account) 56 | { 57 | if (account == null) 58 | return BadRequest(); 59 | 60 | var id = _accountService.Add(account); 61 | return Created($"api/Account/{id}", id); //HTTP201 Resource created 62 | } 63 | 64 | //update 65 | [Authorize(Roles = "Administrator")] 66 | //[HttpPost("{id}")] 67 | [HttpPost("{id}")] 68 | public IActionResult Update(int id, [FromBody] AccountViewModel account) 69 | { 70 | if (account == null || account.Id != id) 71 | return BadRequest(); 72 | 73 | if (_accountService.Update(account)) 74 | return Accepted(account); 75 | else 76 | return StatusCode(304); //Not Modified 77 | } 78 | 79 | //delete -- it will check ClaimTypes.Role 80 | [Authorize(Roles = "Administrator")] 81 | [HttpDelete("{id}")] 82 | public IActionResult Delete(int id) 83 | { 84 | if (_accountService.Remove(id)) 85 | return NoContent(); //204 86 | else 87 | return NotFound(); //404 88 | } 89 | } 90 | } 91 | 92 | 93 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/Controllers/InfoController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Authorization; 7 | using Microsoft.AspNetCore.Mvc; 8 | using Microsoft.Extensions.Logging; 9 | using Microsoft.Extensions.Configuration; 10 | 11 | 12 | namespace ApiNCoreApplication1.Api.Controllers 13 | { 14 | [Route("api/[controller]")] 15 | public class InfoController : ControllerBase 16 | { 17 | 18 | public IConfiguration Configuration { get; } 19 | public InfoController(IConfiguration configuration) 20 | { 21 | Configuration = configuration; 22 | } 23 | 24 | //get info 25 | [AllowAnonymous] 26 | [HttpGet] 27 | [Produces("application/json")] 28 | public IActionResult ApiInfo() 29 | { 30 | 31 | var migration = Configuration["ConnectionStrings:UseMigrationService"]; 32 | var seed = Configuration["ConnectionStrings:UseSeedService"]; 33 | var memorydb = Configuration["ConnectionStrings:UseInMemoryDatabase"]; 34 | var connstring = Configuration["ConnectionStrings:ApiNCoreApplication1DB"]; 35 | 36 | var controlers = MvcHelper.GetControllerMethodsNames(); 37 | return Content("" + 38 | 39 | "
" + 40 | "

ApiNCoreApplication1 Api

" + 41 | "

v.1.5

" + 42 | "NET.Core Api REST service started!
" + 43 | "appsettings.json configuration:
" + 44 | "
  • UseMigrationService:" + migration + "
  • " + 45 | "
  • UseSeedService:" + seed + "
  • " + 46 | "
  • UseInMemoryDatabase:" + memorydb + "
  • " + 47 | "
  • ConnectionStrings:" + connstring + "
" + 48 | "
" + 49 | 50 | "
" + 51 | 52 | "
" + 53 | "

API controlers and methods

" + 54 | "
    " + controlers + "
" + 55 | "

" + 56 | "
" + 57 | "
" + 58 | "

API services and patterns

" + 59 | "

  • Dependency Injection (Net Core feature)
  • Repository and Unit of Work Patterns
  • Generic services
  • Automapper
  • Sync and Async calls
  • Generic exception handler
  • Serilog logging with Console and File sinks
  • Seed from json objects
  • JWT authorization and authentication
" + 60 | "
" + 61 | "
" + 62 | "

API projects

" + 63 | "
  • Api
  • Domain
  • Entity
" + 64 | "
" + 65 | 66 | "
" + 67 | "" 68 | , "text/html"); 69 | 70 | } 71 | 72 | } 73 | 74 | public class MvcHelper 75 | { 76 | private static List GetSubClasses() 77 | { 78 | return Assembly.GetCallingAssembly().GetTypes().Where( 79 | type => type.IsSubclassOf(typeof(T))).ToList(); 80 | } 81 | 82 | public static string GetControllerMethodsNames() 83 | { 84 | List cmdtypes = GetSubClasses(); 85 | var controlersInfo = ""; 86 | foreach (Type ctrl in cmdtypes) 87 | { 88 | var methodsInfo = ""; 89 | const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; 90 | MemberInfo[] methodName = ctrl.GetMethods(flags); 91 | foreach (MemberInfo method in methodName) 92 | { 93 | if (method.DeclaringType.ToString() == ctrl.UnderlyingSystemType.ToString()) 94 | methodsInfo += "
  • " + method.Name.ToString() + "
  • "; 95 | } 96 | controlersInfo += "
  • " + ctrl.Name.Replace("Controller", "") + "
      " + methodsInfo + "
  • "; 97 | } 98 | return controlersInfo; 99 | } 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/Controllers/TokenController.cs: -------------------------------------------------------------------------------- 1 | 2 | using ApiNCoreApplication1.Domain; 3 | using ApiNCoreApplication1.Domain.Service; 4 | using ApiNCoreApplication1.Entity; 5 | using Microsoft.AspNetCore.Authorization; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.Extensions.Configuration; 8 | using Microsoft.IdentityModel.Tokens; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.IdentityModel.Tokens.Jwt; 12 | using System.Linq; 13 | using System.Security.Claims; 14 | using System.Text; 15 | 16 | namespace JWT.Controllers 17 | { 18 | [Route("api/[controller]")] 19 | public class TokenController : Controller 20 | { 21 | private IConfiguration _config; 22 | private readonly IService _userService; 23 | 24 | public TokenController(IConfiguration config, IService userService) 25 | { 26 | _config = config; 27 | _userService = userService; 28 | } 29 | 30 | [AllowAnonymous] 31 | [HttpPost] 32 | public IActionResult Create([FromBody]LoginModel login) 33 | { 34 | IActionResult response = Unauthorized(); 35 | var user = Authenticate(login); 36 | 37 | if (user != null) 38 | { 39 | var tokenString = BuildToken(user); 40 | response = Ok(new { token = tokenString }); 41 | } 42 | 43 | return response; 44 | } 45 | 46 | private string BuildToken(UserModel user) 47 | { 48 | 49 | List claims = new List(); 50 | claims.Add(new Claim(JwtRegisteredClaimNames.Sub, user.Name)); 51 | claims.Add(new Claim(JwtRegisteredClaimNames.Email, user.Email)); 52 | claims.Add(new Claim(JwtRegisteredClaimNames.Birthdate, user.Birthdate.ToString("yyyy-MM-dd"))); 53 | claims.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())); 54 | //attach roles 55 | foreach (string role in user.Roles) 56 | { 57 | claims.Add(new Claim(ClaimTypes.Role, role)); 58 | } 59 | 60 | var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"])); 61 | var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); 62 | 63 | var token = new JwtSecurityToken( 64 | _config["Jwt:Issuer"], 65 | _config["Jwt:Issuer"], 66 | claims, 67 | expires: DateTime.Now.AddMinutes(60), //60 min expiry and a client monitor token quality and should request new token with this one expiries 68 | signingCredentials: creds); 69 | 70 | return new JwtSecurityTokenHandler().WriteToken(token); 71 | } 72 | 73 | //Authenticates login information, retrieves authorization infomation (roles) 74 | private UserModel Authenticate(LoginModel login) 75 | { 76 | UserModel user = null; 77 | 78 | var userView = _userService.Get(x => x.UserName == login.Username).SingleOrDefault(); 79 | if (userView != null && userView.Password == login.Password) 80 | { 81 | user = new UserModel { Name = userView.FirstName + " " + userView.LastName, Email = userView.Email, Roles = new string[] { } }; 82 | foreach (string role in userView.Roles) user.Roles = new List(user.Roles) { role }.ToArray(); 83 | if (userView.IsAdminRole) user.Roles = new List(user.Roles) { "Administrator" }.ToArray(); 84 | } 85 | 86 | return user; 87 | } 88 | 89 | public class LoginModel 90 | { 91 | public string Username { get; set; } 92 | public string Password { get; set; } 93 | } 94 | 95 | private class UserModel 96 | { 97 | public string Name { get; set; } 98 | public string Email { get; set; } 99 | public DateTime Birthdate { get; set; } 100 | public string[] Roles { get; set; } 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/Controllers/UserAsyncController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.AspNetCore.Authorization; 5 | using ApiNCoreApplication1.Domain; 6 | using ApiNCoreApplication1.Entity.Context; 7 | using ApiNCoreApplication1.Domain.Service; 8 | using Microsoft.Extensions.Logging; 9 | using Serilog; 10 | using ApiNCoreApplication1.Entity; 11 | using System.Threading.Tasks; 12 | 13 | namespace ApiNCoreApplication1.Api.Controllers 14 | { 15 | [Route("api/[controller]")] 16 | public class UserAsyncController : ControllerBase 17 | { 18 | private readonly UserServiceAsync _userServiceAsync; 19 | public UserAsyncController(UserServiceAsync userServiceAsync) 20 | { 21 | _userServiceAsync = userServiceAsync; 22 | } 23 | 24 | 25 | //get all 26 | [Authorize] 27 | [HttpGet] 28 | public async Task> GetAll() 29 | { 30 | var items = await _userServiceAsync.GetAll(); 31 | return items; 32 | } 33 | 34 | //get one 35 | [Authorize] 36 | [HttpGet("{id}")] 37 | public async Task GetById(int id) 38 | { 39 | var item = await _userServiceAsync.GetOne(id); 40 | if (item == null) 41 | { 42 | Log.Error("GetById({ ID}) NOT FOUND", id); 43 | return NotFound(); 44 | } 45 | 46 | return Ok(item); 47 | } 48 | 49 | //add 50 | [Authorize(Roles = "Administrator")] 51 | [HttpPut] 52 | public async Task Create([FromBody] UserViewModel user) 53 | { 54 | if (user == null) 55 | return BadRequest(); 56 | 57 | var id = await _userServiceAsync.Add(user); 58 | return Created($"api/User/{id}", id); //HTTP201 Resource created 59 | } 60 | 61 | //update 62 | [Authorize(Roles = "Administrator")] 63 | [HttpPost("{id}")] 64 | public async Task Update(int id, [FromBody] UserViewModel user) 65 | { 66 | if (user == null || user.Id != id) 67 | return BadRequest(); 68 | 69 | if (await _userServiceAsync.Update(user)) 70 | return Accepted(user); 71 | else 72 | return StatusCode(304); //Not Modified 73 | } 74 | 75 | //delete -- it will check ClaimTypes.Role 76 | [Authorize(Roles = "Administrator")] 77 | [HttpDelete("{id}")] 78 | public async Task Delete(int id) 79 | { 80 | if (await _userServiceAsync.Remove(id)) 81 | return NoContent(); //204 82 | else 83 | return NotFound(); //404 84 | } 85 | 86 | } 87 | } 88 | 89 | 90 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/Controllers/UserController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.AspNetCore.Authorization; 5 | using ApiNCoreApplication1.Domain; 6 | using ApiNCoreApplication1.Entity.Context; 7 | using ApiNCoreApplication1.Domain.Service; 8 | using Microsoft.Extensions.Logging; 9 | using Serilog; 10 | using ApiNCoreApplication1.Entity; 11 | 12 | namespace ApiNCoreApplication1.Api.Controllers 13 | { 14 | [Route("api/[controller]")] 15 | public class UserController : ControllerBase 16 | { 17 | private readonly UserService _userService; 18 | public UserController(UserService userService) 19 | { 20 | _userService = userService; 21 | } 22 | 23 | //get all 24 | [Authorize] 25 | [HttpGet] 26 | public IEnumerable GetAll() 27 | { 28 | var test = _userService.DoNothing(); 29 | var items = _userService.GetAll(); 30 | return items; 31 | } 32 | 33 | //get one 34 | [Authorize] 35 | [HttpGet("{id}")] 36 | public IActionResult GetById(int id) 37 | { 38 | var item = _userService.GetOne(id); 39 | if (item == null) 40 | { 41 | Log.Error("GetById({ ID}) NOT FOUND", id); 42 | return NotFound(); 43 | } 44 | 45 | return Ok(item); 46 | } 47 | 48 | //add 49 | [Authorize(Roles = "Administrator")] 50 | [HttpPut] 51 | public IActionResult Create([FromBody] UserViewModel user) 52 | { 53 | if (user == null) 54 | return BadRequest(); 55 | 56 | var id = _userService.Add(user); 57 | return Created($"api/User/{id}", id); //HTTP201 Resource created 58 | } 59 | 60 | //update 61 | [Authorize(Roles = "Administrator")] 62 | [HttpPost("{id}")] 63 | public IActionResult Update(int id, [FromBody] UserViewModel user) 64 | { 65 | if (user == null || user.Id != id) 66 | return BadRequest(); 67 | 68 | if (_userService.Update(user)) 69 | return Accepted(user); 70 | else 71 | return StatusCode(304); //Not Modified 72 | } 73 | 74 | //delete -- it will check ClaimTypes.Role 75 | [Authorize(Roles = "Administrator")] 76 | [HttpDelete("{id}")] 77 | public IActionResult Delete(int id) 78 | { 79 | if (_userService.Remove(id)) 80 | return NoContent(); //204 81 | else 82 | return NotFound(); //404 83 | } 84 | 85 | } 86 | } 87 | 88 | 89 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/ExceptionHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Http; 7 | using Newtonsoft.Json; 8 | using Serilog; 9 | 10 | namespace ApiNCoreApplication1.Api 11 | { 12 | /// 13 | /// Middleware - error handling 14 | /// 15 | public class ExceptionHandler 16 | { 17 | private readonly RequestDelegate _next; 18 | 19 | public ExceptionHandler(RequestDelegate next) 20 | { 21 | _next = next; 22 | } 23 | 24 | public async Task Invoke(HttpContext context) 25 | { 26 | try 27 | { 28 | await _next.Invoke(context); 29 | } 30 | catch (Exception ex) 31 | { 32 | await HandleExceptionAsync(context, ex); 33 | 34 | } 35 | } 36 | 37 | private async Task HandleExceptionAsync(HttpContext context, Exception exception) 38 | { 39 | var response = context.Response; 40 | response.ContentType = "application/json"; 41 | response.StatusCode = (int)HttpStatusCode.InternalServerError; 42 | var result = JsonConvert.SerializeObject(new 43 | { 44 | // customize as you need 45 | error = new 46 | { 47 | message = exception.Message, 48 | exception = exception.GetType().Name 49 | } 50 | }); 51 | await response.WriteAsync(result); 52 | //serilog 53 | Log.Error("ERROR FOUND", result); 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/Globals.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace ApiNCoreApplication1.Api 7 | { 8 | public static class Globals 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using ApiNCoreApplication1.Api.Settings; 4 | using Loggly; 5 | using Loggly.Config; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | using Serilog; 11 | using Serilog.Events; 12 | 13 | /// 14 | /// Designed by AnaSoft Inc. 2018 15 | /// http://www.anasoft.net/apincore 16 | /// 17 | /// The template version VSIX with test projects included you can get here: http://www.anasoft.net/apincore with added features: 18 | /// -XUnit integration tests project added to the solution (just update the connection string and run tests) 19 | /// -API tests as json file for import to the Postman 20 | /// Another VSIX control can be downloaded to create API .NET Core solution with Dapper ORM implemented instead of Entity Framework and for migration 21 | /// FluentMigrator.Runner is added to created solution. 22 | /// 23 | /// NOTE: 24 | /// Must update database connection in appsettings.json - "ApiNCoreApplication1.ApiDB" 25 | /// 26 | 27 | namespace ApiNCoreApplication1.Api 28 | { 29 | public class Program 30 | { 31 | 32 | private static string _environmentName; 33 | 34 | public static void Main(string[] args) 35 | { 36 | var webHost = BuildWebHost(args); 37 | 38 | //read configuration 39 | var configuration = new ConfigurationBuilder() 40 | .SetBasePath(Directory.GetCurrentDirectory()) 41 | .AddJsonFile("appsettings.json") 42 | .AddJsonFile($"appsettings.{_environmentName}.json", optional: true, reloadOnChange: true) 43 | .Build(); 44 | 45 | //Must have Loggly account and setup correct info in appsettings 46 | if (configuration["Serilog:UseLoggly"] == "true") 47 | { 48 | var logglySettings = new LogglySettings(); 49 | configuration.GetSection("Serilog:Loggly").Bind(logglySettings); 50 | SetupLogglyConfiguration(logglySettings); 51 | } 52 | 53 | Log.Logger = new LoggerConfiguration() 54 | .ReadFrom.Configuration(configuration) 55 | .CreateLogger(); 56 | 57 | //Start webHost 58 | try 59 | { 60 | Log.Information("Starting web host"); 61 | webHost.Run(); 62 | } 63 | catch (Exception ex) 64 | { 65 | Log.Fatal(ex, "Host terminated unexpectedly"); 66 | } 67 | finally 68 | { 69 | Log.CloseAndFlush(); 70 | } 71 | 72 | } 73 | 74 | 75 | public static IWebHost BuildWebHost(string[] args) => 76 | WebHost.CreateDefaultBuilder(args) 77 | .ConfigureLogging((hostingContext, config) => 78 | { 79 | config.ClearProviders(); //Disabling default integrated logger 80 | _environmentName = hostingContext.HostingEnvironment.EnvironmentName; 81 | }) 82 | .UseStartup() 83 | .UseSerilog() // <-- Add this line 84 | .Build(); 85 | 86 | 87 | /// 88 | /// Configure Loggly provider 89 | /// 90 | /// 91 | private static void SetupLogglyConfiguration(LogglySettings logglySettings) 92 | { 93 | //Configure Loggly 94 | var config = LogglyConfig.Instance; 95 | config.CustomerToken = logglySettings.CustomerToken; 96 | config.ApplicationName = logglySettings.ApplicationName; 97 | config.Transport = new TransportConfiguration() 98 | { 99 | EndpointHostname = logglySettings.EndpointHostname, 100 | EndpointPort = logglySettings.EndpointPort, 101 | LogTransport = logglySettings.LogTransport 102 | }; 103 | config.ThrowExceptions = logglySettings.ThrowExceptions; 104 | 105 | //Define Tags sent to Loggly 106 | config.TagConfig.Tags.AddRange(new ITag[]{ 107 | new ApplicationNameTag {Formatter = "Application-{0}"}, 108 | new HostnameTag { Formatter = "Host-{0}" } 109 | }); 110 | } 111 | 112 | 113 | } 114 | } 115 | 116 | 117 | //Configuration in code for serilog in Main 118 | //no appsetting option - in code settings not in configuration file 119 | //Log.Logger = new LoggerConfiguration() 120 | // .MinimumLevel.Debug() 121 | // .MinimumLevel.Override("Microsoft", LogEventLevel.Information) 122 | // .Enrich.FromLogContext() 123 | // .WriteTo.Console() 124 | // .WriteTo.File( 125 | // @"iCodify-API.txt", 126 | // fileSizeLimitBytes: 1_000_000, 127 | // rollOnFileSizeLimit: true, 128 | // shared: true, 129 | // flushToDiskInterval: TimeSpan.FromSeconds(1)) 130 | // .CreateLogger(); -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:44341/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "launchUrl": "api/info", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "ApiNCoreApplication1Api": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "launchUrl": "api/info", 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | }, 26 | "applicationUrl": "http://localhost:44342/" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/Seed/accounts.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "Created": "1/1/2018", 3 | "Modified" :"1/1/2018", 4 | "Name": "Account 1", 5 | "Email": "apincore@anasoft.net", 6 | "Description": " ", 7 | "IsTrial": false, 8 | "IsActive": true, 9 | "SetActive": "1/1/2018" 10 | }] -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/Seed/users.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "Created": "1/1/2018", 3 | "Modified": "1/1/2018", 4 | "FirstName": "TestF", 5 | "LastName": "TestF", 6 | "UserName": "my@email.com", 7 | "Email": "my@email.com", 8 | "Description": " ", 9 | "IsAdminRole": true, 10 | "Roles": "Administrator", 11 | "IsActive": true, 12 | "Password": "peaRlg4IIkOWvH2ZF0NjIJHr/CrykSgt5u6wsolkFNCwYoJJEPJ1fZryeBaxcpLZ", 13 | "AccountId": 1 14 | }] -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/Settings/LogglySettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Loggly.Config; 6 | 7 | namespace ApiNCoreApplication1.Api.Settings 8 | { 9 | public class LogglySettings 10 | { 11 | public string ApplicationName { get; set; } 12 | public string Account { get; set; } 13 | public string Username { get; set; } 14 | public string Password { get; set; } 15 | public int EndpointPort { get; set; } 16 | public bool IsEnabled { get; set; } 17 | public bool ThrowExceptions { get; set; } 18 | public LogTransport LogTransport { get; set; } 19 | public string EndpointHostname { get; set; } 20 | public string CustomerToken { get; set; } 21 | } 22 | 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Builder; 6 | using Microsoft.AspNetCore.Hosting; 7 | using Microsoft.Extensions.Configuration; 8 | using Microsoft.Extensions.DependencyInjection; 9 | using Microsoft.Extensions.Logging; 10 | using Microsoft.Extensions.Options; 11 | using Microsoft.EntityFrameworkCore; 12 | using System.Text; 13 | using Microsoft.IdentityModel.Tokens; 14 | using Microsoft.AspNetCore.Authentication.JwtBearer; 15 | using ApiNCoreApplication1.Api; 16 | using ApiNCoreApplication1.Entity.UnitofWork; 17 | using ApiNCoreApplication1.Entity.Context; 18 | using ApiNCoreApplication1.Entity.Repository; 19 | using AutoMapper; 20 | using ApiNCoreApplication1.Domain.Mapping; 21 | using ApiNCoreApplication1.Domain.Service; 22 | using System.Net; 23 | using Microsoft.AspNetCore.Diagnostics; 24 | using Microsoft.AspNetCore.Http; 25 | using Serilog; 26 | 27 | 28 | /// 29 | /// Designed by AnaSoft Inc. 2018 30 | /// http://www.anasoft.net/apincore 31 | /// 32 | /// The template version VSIX with test projects included you can get here: http://www.anasoft.net/apincore with added features: 33 | /// -XUnit integration tests project added to the solution (just update the connection string and run tests) 34 | /// -API tests as json file for import to the Postman 35 | /// Another VSIX control can be downloaded to create API .NET Core solution with Dapper ORM implemented instead of Entity Framework and for migration 36 | /// FluentMigrator.Runner is added to created solution. 37 | /// 38 | /// NOTE: 39 | /// Must update database connection in appsettings.json - "ApiNCoreApplication1.ApiDB" 40 | /// 41 | 42 | namespace ApiNCoreApplication1.Api 43 | { 44 | public class Startup 45 | { 46 | 47 | public Startup(IConfiguration configuration) 48 | { 49 | Configuration = configuration; 50 | } 51 | 52 | public IConfiguration Configuration { get; } 53 | 54 | public void ConfigureServices(IServiceCollection services) 55 | { 56 | //db service 57 | if (Configuration["ConnectionStrings:UseInMemoryDatabase"] == "True") 58 | services.AddDbContext(opt => opt.UseInMemoryDatabase("TestDB-" + Guid.NewGuid().ToString())); 59 | else 60 | services.AddDbContext(options => options.UseSqlServer(Configuration["ConnectionStrings:ApiNCoreApplication1DB"])); 61 | 62 | //API authentication service 63 | services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) 64 | .AddJwtBearer(options => 65 | { 66 | options.TokenValidationParameters = new TokenValidationParameters 67 | { 68 | ValidateIssuer = true, 69 | ValidateAudience = true, 70 | ValidateLifetime = true, 71 | ValidateIssuerSigningKey = true, 72 | ValidIssuer = Configuration["Jwt:Issuer"], 73 | ValidAudience = Configuration["Jwt:Issuer"], 74 | IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"])) 75 | }; 76 | } 77 | ); 78 | 79 | // include support for CORS 80 | // More often than not, we will want to specify that our API accepts requests coming from other origins (other domains). When issuing AJAX requests, browsers make preflights to check if a server accepts requests from the domain hosting the web app. If the response for these preflights don't contain at least the Access-Control-Allow-Origin header specifying that accepts requests from the original domain, browsers won't proceed with the real requests (to improve security). 81 | services.AddCors(options => 82 | { 83 | options.AddPolicy("CorsPolicy-public", 84 | builder => builder.AllowAnyOrigin() //WithOrigins and define a specific origin to be allowed (e.g. https://mydomain.com) 85 | .AllowAnyMethod() 86 | .AllowAnyHeader() 87 | .AllowCredentials() 88 | .Build()); 89 | }); 90 | 91 | //mvc service 92 | services.AddMvc(); 93 | 94 | //general unitofwork injections 95 | services.AddTransient(); 96 | 97 | //services injections 98 | services.AddTransient(typeof(AccountService<,>), typeof(AccountService<,>)); 99 | services.AddTransient(typeof(UserService<,>), typeof(UserService<,>)); 100 | services.AddTransient(typeof(AccountServiceAsync<,>), typeof(AccountServiceAsync<,>)); 101 | services.AddTransient(typeof(UserServiceAsync<,>), typeof(UserServiceAsync<,>)); 102 | //...add other services 103 | // 104 | services.AddTransient(typeof(IService<,>), typeof(GenericService<,>)); 105 | services.AddTransient(typeof(IServiceAsync<,>), typeof(GenericServiceAsync<,>)); 106 | 107 | //data mapper profiler setting 108 | Mapper.Initialize((config) => 109 | { 110 | config.AddProfile(); 111 | }); 112 | 113 | } 114 | 115 | 116 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 117 | { 118 | if (env.IsDevelopment()) 119 | app.UseDeveloperExceptionPage(); 120 | else 121 | app.UseMiddleware(); 122 | 123 | app.UseAuthentication(); //needs to be up in the pipeline, before MVC 124 | app.UseCors("CorsPolicy-public"); //apply to every request 125 | app.UseMvc(); //must be last line 126 | 127 | //migrations and seeds from json files 128 | using (var serviceScope = app.ApplicationServices.GetRequiredService().CreateScope()) 129 | { 130 | if (Configuration["ConnectionStrings:UseInMemoryDatabase"] == "False" && !serviceScope.ServiceProvider.GetService().AllMigrationsApplied()) 131 | { 132 | if (Configuration["ConnectionStrings:UseMigrationService"] == "True") 133 | serviceScope.ServiceProvider.GetService().Database.Migrate(); 134 | } 135 | //it will seed tables on aservice run from json files if tables empty 136 | if (Configuration["ConnectionStrings:UseSeedService"] == "True") 137 | serviceScope.ServiceProvider.GetService().EnsureSeeded(); 138 | } 139 | } 140 | 141 | 142 | } 143 | } 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/_nugets.txt: -------------------------------------------------------------------------------- 1 |  2 | dotnet restore 3 | 4 | https://www.nuget.org/packages/Microsoft.AspNetCore 5 | install-Package Microsoft.AspNetCore -Version 2.1.0 6 | 7 | https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication/ 8 | PM> Install-Package Microsoft.AspNetCore.Authentication -Version 2.1.1 9 | 10 | https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc/ 11 | PM> Install-Package Microsoft.AspNetCore.Mvc -Version 2.1.1 12 | 13 | https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBearer/ 14 | PM> Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -Version 2.1.1 15 | 16 | https://www.nuget.org/packages/automapper/ 17 | PM> Install-Package AutoMapper -Version 7.0. 18 | 19 | https://www.newtonsoft.com/json 20 | PM> Install-Package Newtonsoft.Json 21 | 22 | //required when use this db provider 23 | Install-Package Microsoft.EntityFrameworkCore.InMemory 24 | 25 | PM> Install-Package Serilog.AspNetCore -DependencyVersion Highest 26 | PM> Install-Package Serilog.Sinks.Console 27 | PM> Install-Package Serilog.Sinks.File 28 | PM> Install-Package Serilog.Sinks.Loggly 29 | PM> Install-Package Serilog.Settings.Configuration 30 | 31 | 32 | ------------- 33 | Serilog Logger 34 | https://github.com/serilog/serilog-aspnetcore 35 | https://itnext.io/loggly-in-asp-net-core-using-serilog-dc0e2c7d52eb 36 | https://www.blinkingcaret.com/2018/02/14/net-core-console-logging/ 37 | https://nblumhardt.com/2017/08/use-serilog/ 38 | https://github.com/loggly/log4net-loggly/#net-core-support 39 | 40 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "UseMigrationService": true, 4 | "UseSeedService": true, 5 | "UseInMemoryDatabase": true, 6 | "ApiNCoreApplication1DB": "Data Source=.\\SQLEXPRESS;Initial Catalog=ApiNCoreApplication1;Trusted_Connection=True;MultipleActiveResultSets=True;" 7 | }, 8 | //"Logging": { 9 | // "IncludeScopes": false, 10 | // "LogLevel": { 11 | // "Default": "Debug", 12 | // "System": "Information", 13 | // "Microsoft": "Information" 14 | // } 15 | //}, 16 | "Jwt": { 17 | "Key": "12345678910111213141516", 18 | "Issuer": "http://localhost:44341/" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "UseMigrationService": true, 4 | "UseSeedService": true, 5 | "UseInMemoryDatabase": true, 6 | "ApiNCoreApplication1DB": "Data Source=.\\SQLEXPRESS;Initial Catalog=ApiNCoreApplication1;Trusted_Connection=True;MultipleActiveResultSets=True;" 7 | }, 8 | //"Logging": { 9 | // "IncludeScopes": false, 10 | // "Debug": { 11 | // "LogLevel": { 12 | // "Default": "Warning" 13 | // } 14 | // }, 15 | // "Console": { 16 | // "LogLevel": { 17 | // "Default": "Debug" 18 | // } 19 | // } 20 | //}, 21 | "Serilog": { 22 | "MinimumLevel": "Debug", 23 | "WriteTo": [ 24 | { 25 | "Name": "Console", 26 | "Args": { 27 | "outputTemplate": "===> {Timestamp:HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}" 28 | } 29 | }, 30 | { 31 | "Name": "RollingFile", 32 | "Args": { 33 | "pathFormat": "logs/ApiNCoreApplication1-API-{Date}.txt", 34 | "outputTemplate": "===> {Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}" 35 | } 36 | }, 37 | { 38 | "Name": "Loggly" 39 | } 40 | ], 41 | "UseLoggly": false, 42 | "Loggly": 43 | { 44 | "ApplicationName": "ApiNCoreApplication1", 45 | "Account": "yourLogglyAccount", 46 | "Username": "YourLogglyUserName", 47 | //"Password": "lalala", 48 | //"EndpointPort": "443", 49 | "IsEnabled": "true", 50 | "ThrowExceptions": "true", 51 | "LogTransport": "Https", 52 | "EndpointHostname": "logs-01.loggly.com", 53 | "CustomerToken": "1aa11a1a1-aa11-aa11-a11a-1a1aaa111a1a" //Loggly account customer token 54 | } 55 | }, 56 | "Jwt": { 57 | "Key": "12345678910111213141516", 58 | "Issuer": "http://localhost:44342/" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/ApiNCoreApplication1.Api.csproj.nuget.cache: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "dgSpecHash": "ADhea4m2eBvG17mMTAtBjfnR46QqzFj4L61uM7XVAoZwBBJxkNa/+0UswkY7E7y1v1vnc8VGmHdTTfQFlfvKeA==", 4 | "success": true 5 | } -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/ApiNCoreApplication1.Api.csproj.nuget.g.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | True 5 | NuGet 6 | C:\Users\zoran\source\repos\ApiNCoreApplication1\ApiNCoreApplication1\ApiNCoreApplication1.Api\obj\project.assets.json 7 | $(UserProfile)\.nuget\packages\ 8 | C:\Users\zoran\.nuget\packages\;C:\Program Files\dotnet\sdk\NuGetFallbackFolder 9 | PackageReference 10 | 4.8.0 11 | 12 | 13 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/ApiNCoreApplication1.Api.csproj.nuget.g.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Api.AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | using System; 12 | using System.Reflection; 13 | 14 | [assembly: System.Reflection.AssemblyCompanyAttribute("ApiNCoreApplication1.Api")] 15 | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] 16 | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] 17 | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] 18 | [assembly: System.Reflection.AssemblyProductAttribute("ApiNCoreApplication1.Api")] 19 | [assembly: System.Reflection.AssemblyTitleAttribute("ApiNCoreApplication1.Api")] 20 | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] 21 | 22 | // Generated by the MSBuild WriteCodeFragment class. 23 | 24 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Api.AssemblyInfoInputs.cache: -------------------------------------------------------------------------------- 1 | bd8f6947faef33414bd413f065681b58d154a0dc 2 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Api.RazorAssemblyInfo.cache: -------------------------------------------------------------------------------- 1 | b4bcf64fd54f555043f6c78fc04fd9d2f5905400 2 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Api.RazorAssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | using System; 12 | using System.Reflection; 13 | 14 | [assembly: Microsoft.AspNetCore.Mvc.ApplicationParts.RelatedAssemblyAttribute("ApiNCoreApplication1.Api.Views")] 15 | [assembly: Microsoft.AspNetCore.Razor.Hosting.RazorLanguageVersionAttribute("2.1")] 16 | [assembly: Microsoft.AspNetCore.Razor.Hosting.RazorConfigurationNameAttribute("MVC-2.1")] 17 | [assembly: Microsoft.AspNetCore.Razor.Hosting.RazorExtensionAssemblyNameAttribute("MVC-2.1", "Microsoft.AspNetCore.Mvc.Razor.Extensions")] 18 | 19 | // Generated by the MSBuild WriteCodeFragment class. 20 | 21 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Api.assets.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anasoftinc/apincore/a192c3f65ea9548cccfcb4e46b142a36497f942e/ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Api.assets.cache -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Api.csproj.CoreCompileInputs.cache: -------------------------------------------------------------------------------- 1 | 309408f0015ee574b727c96e7cef53a04b68c1af 2 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Api.csprojAssemblyReference.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anasoftinc/apincore/a192c3f65ea9548cccfcb4e46b142a36497f942e/ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Api.csprojAssemblyReference.cache -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anasoftinc/apincore/a192c3f65ea9548cccfcb4e46b142a36497f942e/ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anasoftinc/apincore/a192c3f65ea9548cccfcb4e46b142a36497f942e/ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anasoftinc/apincore/a192c3f65ea9548cccfcb4e46b142a36497f942e/ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Api/obj/Debug/netcoreapp2.1/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/ApiNCoreApplication1.Domain.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/BaseDomain.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace ApiNCoreApplication1.Domain 6 | { 7 | public class BaseDomain 8 | { 9 | public int Id { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/Domain/AccountViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using AutoMapper; 4 | 5 | namespace ApiNCoreApplication1.Domain 6 | { 7 | public class AccountViewModel : BaseDomain 8 | { 9 | public string Name { get; set; } 10 | public string Email { get; set; } 11 | public string Description { get; set; } 12 | public bool IsTrial { get; set; } 13 | public bool IsActive { get; set; } 14 | public DateTime SetActive { get; set; } 15 | 16 | public virtual ICollection Users { get; set; } 17 | } 18 | 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/Domain/UserViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Text; 5 | 6 | namespace ApiNCoreApplication1.Domain 7 | { 8 | /// 9 | /// A user attached to an account 10 | /// 11 | public class UserViewModel : BaseDomain 12 | { 13 | public string FirstName { get; set; } 14 | public string LastName { get; set; } 15 | public string UserName { get; set; } 16 | public string Email { get; set; } 17 | public string Description { get; set; } 18 | public bool IsAdminRole { get; set; } 19 | public ICollection Roles { get; set; } //map from semicolumn delimited from Entity 20 | public bool IsActive { get; set; } 21 | public string Password { get; set; } 22 | public int AccountId { get; set; } 23 | 24 | public virtual AccountViewModel Account { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/Mapping/MappingProfile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using AutoMapper; 5 | using ApiNCoreApplication1.Entity; 6 | 7 | namespace ApiNCoreApplication1.Domain.Mapping 8 | { 9 | public class MappingProfile : Profile 10 | { 11 | /// 12 | /// Create automap mapping profiles 13 | /// 14 | public MappingProfile() 15 | { 16 | CreateMap(); 17 | CreateMap(); 18 | CreateMap() 19 | .ForMember(dest => dest.DecryptedPassword, opts => opts.MapFrom(src => src.Password)) 20 | .ForMember(dest => dest.Roles, opts => opts.MapFrom(src => string.Join(";", src.Roles))); 21 | CreateMap() 22 | .ForMember(dest => dest.Password, opts => opts.MapFrom(src => src.DecryptedPassword)) 23 | .ForMember(dest => dest.Roles, opts => opts.MapFrom(src => src.Roles.Split(";", StringSplitOptions.RemoveEmptyEntries))); 24 | 25 | 26 | //CreateMap() 27 | // .ForMember(dest => dest.Date, opts => opts.MapFrom(src => src.DateAnswersSubmitted)) 28 | // .ForMember(dest => dest.Id, opts => opts.MapFrom(src => src.AnswerSetId)) 29 | // .ForMember(dest => dest.Answers, opts => opts.MapFrom(src => src.AnswerSetAnswers)) 30 | // .ForMember(dest => dest.IsActive, opts => opts.Ignore()); 31 | //CreateMap() 32 | // .ForMember(dest => dest.DateAnswersSubmitted, opts => opts.MapFrom(src => src.Date)) 33 | // .ForMember(dest => dest.AnswerSetId, opts => opts.MapFrom(src => src.Id)) 34 | // .ForMember(dest => dest.AnswerSetAnswers, opts => opts.MapFrom(src => src.Answers)); 35 | 36 | CreateMissingTypeMaps = true; 37 | } 38 | 39 | } 40 | 41 | 42 | 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/Service/AccountService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using System.Text; 5 | using AutoMapper; 6 | using ApiNCoreApplication1.Entity; 7 | using ApiNCoreApplication1.Entity.UnitofWork; 8 | 9 | namespace ApiNCoreApplication1.Domain.Service 10 | { 11 | 12 | public class AccountService : GenericService 13 | where Tv : AccountViewModel 14 | where Te : Account 15 | { 16 | //DI must be implemented in specific service as well beside GenericService constructor 17 | public AccountService(IUnitOfWork unitOfWork) 18 | { 19 | if (_unitOfWork == null) 20 | _unitOfWork = unitOfWork; 21 | } 22 | 23 | //add any custom service method or override generic service method 24 | //...test, it can be removed 25 | public bool DoNothing() 26 | { 27 | return true; 28 | } 29 | } 30 | 31 | public class AccountServiceAsync : GenericServiceAsync 32 | where Tv : AccountViewModel 33 | where Te : Account 34 | { 35 | //DI must be implemented specific service as well beside GenericAsyncService constructor 36 | public AccountServiceAsync(IUnitOfWork unitOfWork) 37 | { 38 | if (_unitOfWork == null) 39 | _unitOfWork = unitOfWork; 40 | } 41 | 42 | //add any custom service method or override genericasync service method 43 | //... 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/Service/Generic/GenericService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using System.Text; 5 | using AutoMapper; 6 | using ApiNCoreApplication1.Entity; 7 | using ApiNCoreApplication1.Entity.UnitofWork; 8 | 9 | namespace ApiNCoreApplication1.Domain.Service 10 | { 11 | public class GenericService : IService where Tv : BaseDomain 12 | where Te : BaseEntity 13 | { 14 | 15 | protected IUnitOfWork _unitOfWork; 16 | public GenericService(IUnitOfWork unitOfWork) 17 | { 18 | _unitOfWork = unitOfWork; 19 | } 20 | 21 | public GenericService() 22 | { 23 | } 24 | 25 | public virtual IEnumerable GetAll() 26 | { 27 | var entities = _unitOfWork.GetRepository() 28 | .GetAll(); 29 | return Mapper.Map>(source: entities); 30 | } 31 | public virtual Tv GetOne(int id) 32 | { 33 | var entity = _unitOfWork.GetRepository() 34 | .GetOne(predicate: x => x.Id == id); 35 | return Mapper.Map(source: entity); 36 | } 37 | 38 | public virtual int Add(Tv view) 39 | { 40 | var entity = Mapper.Map(source: view); 41 | _unitOfWork.GetRepository().Insert(entity); 42 | _unitOfWork.Save(); 43 | return entity.Id; 44 | } 45 | 46 | public virtual bool Update(Tv view) 47 | { 48 | _unitOfWork.GetRepository().Update(view.Id, Mapper.Map(source: view)); 49 | return _unitOfWork.Save(); 50 | } 51 | 52 | 53 | public virtual bool Remove(int id) 54 | { 55 | _unitOfWork.GetRepository().Delete(id); 56 | return _unitOfWork.Save(); 57 | } 58 | 59 | public virtual IEnumerable Get(Expression> predicate) 60 | { 61 | var entities = _unitOfWork.GetRepository() 62 | .Get(predicate: predicate); 63 | return Mapper.Map>(source: entities); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/Service/Generic/GenericServiceAsync.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using AutoMapper; 7 | using ApiNCoreApplication1.Entity; 8 | using ApiNCoreApplication1.Entity.UnitofWork; 9 | 10 | 11 | namespace ApiNCoreApplication1.Domain.Service 12 | { 13 | 14 | public class GenericServiceAsync : IServiceAsync where Tv : BaseDomain 15 | where Te : BaseEntity 16 | { 17 | protected IUnitOfWork _unitOfWork; 18 | public GenericServiceAsync(IUnitOfWork unitOfWork) 19 | { 20 | _unitOfWork = unitOfWork; 21 | } 22 | 23 | public GenericServiceAsync() 24 | { 25 | } 26 | 27 | public virtual async Task> GetAll() 28 | { 29 | var entities = await _unitOfWork.GetRepositoryAsync() 30 | .GetAll(); 31 | return Mapper.Map>(source: entities); 32 | } 33 | 34 | public virtual async Task GetOne(int id) 35 | { 36 | var entity = await _unitOfWork.GetRepositoryAsync() 37 | .GetOne(predicate: x => x.Id == id); 38 | return Mapper.Map(source: entity); 39 | } 40 | 41 | public virtual async Task Add(Tv view) 42 | { 43 | var entity = Mapper.Map(source: view); 44 | await _unitOfWork.GetRepositoryAsync().Insert(entity); 45 | await _unitOfWork.SaveAsync(); 46 | return entity.Id; 47 | } 48 | 49 | public async Task Update(Tv view) 50 | { 51 | await _unitOfWork.GetRepositoryAsync().Update(view.Id, Mapper.Map(source: view)); 52 | return await _unitOfWork.SaveAsync(); 53 | } 54 | 55 | public virtual async Task Remove(int id) 56 | { 57 | await _unitOfWork.GetRepositoryAsync().Delete(id); 58 | return await _unitOfWork.SaveAsync(); 59 | } 60 | 61 | public virtual async Task> Get(Expression> predicate) 62 | { 63 | var items = await _unitOfWork.GetRepositoryAsync() 64 | .Get(predicate: predicate); 65 | return Mapper.Map>(source: items); 66 | } 67 | } 68 | 69 | 70 | } 71 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/Service/Generic/IService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using System.Text; 5 | 6 | namespace ApiNCoreApplication1.Domain.Service 7 | { 8 | public interface IService 9 | { 10 | IEnumerable GetAll(); 11 | int Add(Tv obj); 12 | bool Update(Tv obj); 13 | bool Remove(int id); 14 | Tv GetOne(int id); 15 | IEnumerable Get(Expression> predicate); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/Service/Generic/IServiceAsync.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ApiNCoreApplication1.Domain.Service 8 | { 9 | public interface IServiceAsync 10 | { 11 | Task> GetAll(); 12 | Task Add(Tv obj); 13 | Task Update(Tv obj); 14 | Task Remove(int id); 15 | Task GetOne(int id); 16 | Task> Get(Expression> predicate); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/Service/UserService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using System.Text; 5 | using AutoMapper; 6 | using ApiNCoreApplication1.Entity; 7 | using ApiNCoreApplication1.Entity.UnitofWork; 8 | 9 | namespace ApiNCoreApplication1.Domain.Service 10 | { 11 | 12 | public class UserService : GenericService 13 | where Tv : UserViewModel 14 | where Te : User 15 | { 16 | //DI must be implemented in specific service as well beside GenericService constructor 17 | public UserService(IUnitOfWork unitOfWork) 18 | { 19 | if (_unitOfWork == null) 20 | _unitOfWork = unitOfWork; 21 | } 22 | 23 | //add any custom service method or override generic service method 24 | //...test, it can be removed 25 | public bool DoNothing() 26 | { 27 | return true; 28 | } 29 | } 30 | 31 | public class UserServiceAsync : GenericServiceAsync 32 | where Tv : UserViewModel 33 | where Te : User 34 | { 35 | //DI must be implemented specific service as well beside GenericAsyncService constructor 36 | public UserServiceAsync(IUnitOfWork unitOfWork) 37 | { 38 | if (_unitOfWork == null) 39 | _unitOfWork = unitOfWork; 40 | } 41 | 42 | //add any custom service method or override genericasync service method 43 | //... 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/_nugets.txt: -------------------------------------------------------------------------------- 1 |  2 | https://www.nuget.org/packages/automapper/ 3 | PM> Install-Package AutoMapper -Version 7.0.0 4 | 5 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/ApiNCoreApplication1.Domain.csproj.nuget.cache: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "dgSpecHash": "fDWZOvPBDQ7PI2f5OvfqWBD3qTd4D6e+tsSZegvCBgH1OtaOPHGYMVEWvG9IebrmTEtI6bLWnNDJrFmuImPA6A==", 4 | "success": true 5 | } -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/ApiNCoreApplication1.Domain.csproj.nuget.g.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | True 5 | NuGet 6 | C:\Users\zoran\source\repos\ApiNCoreApplication1\ApiNCoreApplication1\ApiNCoreApplication1.Domain\obj\project.assets.json 7 | $(UserProfile)\.nuget\packages\ 8 | C:\Users\zoran\.nuget\packages\;C:\Program Files\dotnet\sdk\NuGetFallbackFolder 9 | PackageReference 10 | 4.8.0 11 | 12 | 13 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/ApiNCoreApplication1.Domain.csproj.nuget.g.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Domain.AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | using System; 12 | using System.Reflection; 13 | 14 | [assembly: System.Reflection.AssemblyCompanyAttribute("ApiNCoreApplication1.Domain")] 15 | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] 16 | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] 17 | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] 18 | [assembly: System.Reflection.AssemblyProductAttribute("ApiNCoreApplication1.Domain")] 19 | [assembly: System.Reflection.AssemblyTitleAttribute("ApiNCoreApplication1.Domain")] 20 | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] 21 | 22 | // Generated by the MSBuild WriteCodeFragment class. 23 | 24 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Domain.AssemblyInfoInputs.cache: -------------------------------------------------------------------------------- 1 | 4fde7469eb449c1c51c24673f8aef8afb0c9d9fc 2 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Domain.assets.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anasoftinc/apincore/a192c3f65ea9548cccfcb4e46b142a36497f942e/ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Domain.assets.cache -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Domain.csproj.CoreCompileInputs.cache: -------------------------------------------------------------------------------- 1 | 92d60607b179d9789b9fc9353951ff71c747156c 2 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Domain.csprojAssemblyReference.cache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anasoftinc/apincore/a192c3f65ea9548cccfcb4e46b142a36497f942e/ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/Debug/netcoreapp2.1/ApiNCoreApplication1.Domain.csprojAssemblyReference.cache -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/Debug/netcoreapp2.1/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anasoftinc/apincore/a192c3f65ea9548cccfcb4e46b142a36497f942e/ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/Debug/netcoreapp2.1/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/Debug/netcoreapp2.1/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anasoftinc/apincore/a192c3f65ea9548cccfcb4e46b142a36497f942e/ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/Debug/netcoreapp2.1/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/Debug/netcoreapp2.1/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anasoftinc/apincore/a192c3f65ea9548cccfcb4e46b142a36497f942e/ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Domain/obj/Debug/netcoreapp2.1/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/ApiNCoreApplication1.Entity.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/BaseEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace ApiNCoreApplication1.Entity 6 | { 7 | public class BaseEntity 8 | { 9 | [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 10 | [Key] 11 | public int Id { get; set; } 12 | public DateTime Created { get; set; } 13 | public DateTime Modified { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/Context/ApiNCoreApplication1Context.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using System.Linq; 4 | using System.Configuration; 5 | using Microsoft.EntityFrameworkCore; 6 | using Microsoft.Extensions.Configuration; 7 | 8 | namespace ApiNCoreApplication1.Entity.Context 9 | { 10 | public class ApiNCoreApplication1Context : DbContext 11 | { 12 | 13 | public ApiNCoreApplication1Context(DbContextOptions options) 14 | : base(options) 15 | { 16 | } 17 | 18 | public DbSet Accounts { get; set; } 19 | public DbSet Users { get; set; } 20 | 21 | protected override void OnModelCreating(ModelBuilder modelBuilder) 22 | { 23 | //Fluent API 24 | modelBuilder.Entity() 25 | .HasOne(u => u.Account) 26 | .WithMany(e => e.Users); 27 | 28 | //modelBuilder.Entity() 29 | //.Property(p => p.DecryptedPassword) 30 | //.HasComputedColumnSql("Uncrypt(p.PasswordText)"); 31 | } 32 | 33 | public override int SaveChanges() 34 | { 35 | Audit(); 36 | return base.SaveChanges(); 37 | } 38 | 39 | public async Task SaveChangesAsync() 40 | { 41 | Audit(); 42 | return await base.SaveChangesAsync(); 43 | } 44 | 45 | private void Audit() 46 | { 47 | var entries = ChangeTracker.Entries().Where(x => x.Entity is BaseEntity && (x.State == EntityState.Added || x.State == EntityState.Modified)); 48 | foreach (var entry in entries) 49 | { 50 | if (entry.State == EntityState.Added) 51 | { 52 | ((BaseEntity)entry.Entity).Created = DateTime.UtcNow; 53 | } 54 | ((BaseEntity)entry.Entity).Modified = DateTime.UtcNow; 55 | } 56 | } 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/Context/DBContextExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using ApiNCoreApplication1.Entity.Context; 7 | using Microsoft.EntityFrameworkCore; 8 | using Microsoft.EntityFrameworkCore.Infrastructure; 9 | using Microsoft.EntityFrameworkCore.Migrations; 10 | using Newtonsoft.Json; 11 | 12 | namespace ApiNCoreApplication1.Entity.Context 13 | { 14 | public static class DbContextExtension 15 | { 16 | 17 | public static bool AllMigrationsApplied(this DbContext context) 18 | { 19 | var applied = context.GetService() 20 | .GetAppliedMigrations() 21 | .Select(m => m.MigrationId); 22 | 23 | var total = context.GetService() 24 | .Migrations 25 | .Select(m => m.Key); 26 | 27 | return !total.Except(applied).Any(); 28 | //return false; 29 | } 30 | 31 | public static void EnsureSeeded(this ApiNCoreApplication1Context context) 32 | { 33 | 34 | if (!context.Accounts.Any()) 35 | { 36 | var accounts = JsonConvert.DeserializeObject>(File.ReadAllText("seed" + Path.DirectorySeparatorChar + "accounts.json")); 37 | context.AddRange(accounts); 38 | context.SaveChanges(); 39 | } 40 | 41 | //Ensure we have some status 42 | if (!context.Users.Any()) 43 | { 44 | var stati = JsonConvert.DeserializeObject>(File.ReadAllText(@"seed" + Path.DirectorySeparatorChar + "users.json")); 45 | context.AddRange(stati); 46 | context.SaveChanges(); 47 | } 48 | } 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/Entity/Account.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.ComponentModel.DataAnnotations; 5 | 6 | namespace ApiNCoreApplication1.Entity 7 | { 8 | public class Account : BaseEntity 9 | { 10 | [Required] 11 | [StringLength(30)] 12 | public string Name { get; set; } 13 | [Required] 14 | [StringLength(30)] 15 | public string Email { get; set; } 16 | [StringLength(255)] 17 | public string Description { get; set; } 18 | public bool IsTrial { get; set; } 19 | public bool IsActive { get; set; } 20 | public DateTime SetActive { get; set; } 21 | 22 | public virtual ICollection Users { get; set; } 23 | 24 | } 25 | 26 | 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/Entity/EntityHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Text; 5 | using System.Security.Cryptography; 6 | 7 | namespace ApiNCoreApplication1.Entity 8 | { 9 | public static class EntityHelper 10 | { 11 | 12 | static readonly String _EncryptionKey = "eid729"; 13 | 14 | public static string Encrypt(string clearText) 15 | { 16 | byte[] clearBytes = Encoding.Unicode.GetBytes(clearText); 17 | using (Aes encryptor = Aes.Create()) 18 | { 19 | Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(_EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 }); 20 | encryptor.Key = pdb.GetBytes(32); 21 | encryptor.IV = pdb.GetBytes(16); 22 | using (MemoryStream ms = new MemoryStream()) 23 | { 24 | using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write)) 25 | { 26 | cs.Write(clearBytes, 0, clearBytes.Length); 27 | cs.Close(); 28 | } 29 | clearText = Convert.ToBase64String(ms.ToArray()); 30 | } 31 | } 32 | return clearText; 33 | } 34 | public static string Decrypt(string cipherText) 35 | { 36 | cipherText = cipherText.Replace(" ", "+"); 37 | byte[] cipherBytes = Convert.FromBase64String(cipherText); 38 | using (Aes encryptor = Aes.Create()) 39 | { 40 | Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(_EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 }); 41 | encryptor.Key = pdb.GetBytes(32); 42 | encryptor.IV = pdb.GetBytes(16); 43 | using (MemoryStream ms = new MemoryStream()) 44 | { 45 | using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write)) 46 | { 47 | cs.Write(cipherBytes, 0, cipherBytes.Length); 48 | cs.Close(); 49 | } 50 | cipherText = Encoding.Unicode.GetString(ms.ToArray()); 51 | } 52 | } 53 | return cipherText; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/Entity/User.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.ComponentModel.DataAnnotations.Schema; 5 | using System.Text; 6 | 7 | namespace ApiNCoreApplication1.Entity 8 | { 9 | /// 10 | /// A user attached to an account 11 | /// 12 | public class User : BaseEntity 13 | { 14 | [Required] 15 | [StringLength(20)] 16 | public string FirstName { get; set; } 17 | [Required] 18 | [StringLength(20)] 19 | public string LastName { get; set; } 20 | [StringLength(30)] 21 | public string UserName { get; set; } 22 | [Required] 23 | [StringLength(30)] 24 | public string Email { get; set; } 25 | [StringLength(255)] 26 | public string Description { get; set; } 27 | public bool IsAdminRole { get; set; } 28 | [StringLength(255)] 29 | public string Roles { get; set; } 30 | public bool IsActive { get; set; } 31 | [StringLength(50)] 32 | public string Password { get; set; } //stored encrypted 33 | [NotMapped] 34 | public string DecryptedPassword 35 | { 36 | get { return Decrypt(Password); } 37 | set { Password = Encrypt(value); } 38 | } 39 | public int AccountId { get; set; } 40 | 41 | 42 | public virtual Account Account { get; set; } 43 | 44 | private string Decrypt(string cipherText) 45 | { 46 | return EntityHelper.Decrypt(cipherText); 47 | } 48 | private string Encrypt(string clearText) 49 | { 50 | return EntityHelper.Encrypt(clearText); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/Migrations/20180708205028_InitialCreate.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using ApiNCoreApplication1.Entity.Context; 9 | 10 | namespace ApiNCoreApplication1.Entity.Migrations 11 | { 12 | [DbContext(typeof(ApiNCoreApplication1Context))] 13 | [Migration("20180708205028_InitialCreate")] 14 | partial class InitialCreate 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .HasAnnotation("ProductVersion", "2.1.0-rtm-30799") 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 22 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 23 | 24 | modelBuilder.Entity("ApiNCoreApplication1.Entity.Account", b => 25 | { 26 | b.Property("Id") 27 | .ValueGeneratedOnAdd() 28 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 29 | 30 | b.Property("Created"); 31 | 32 | b.Property("Description") 33 | .HasMaxLength(255); 34 | 35 | b.Property("Email") 36 | .IsRequired() 37 | .HasMaxLength(30); 38 | 39 | b.Property("IsActive"); 40 | 41 | b.Property("IsTrial"); 42 | 43 | b.Property("Modified"); 44 | 45 | b.Property("Name") 46 | .IsRequired() 47 | .HasMaxLength(30); 48 | 49 | b.Property("SetActive"); 50 | 51 | b.HasKey("Id"); 52 | 53 | b.ToTable("Accounts"); 54 | }); 55 | 56 | modelBuilder.Entity("ApiNCoreApplication1.Entity.User", b => 57 | { 58 | b.Property("Id") 59 | .ValueGeneratedOnAdd() 60 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 61 | 62 | b.Property("AccountId"); 63 | 64 | b.Property("Created"); 65 | 66 | b.Property("Description") 67 | .HasMaxLength(255); 68 | 69 | b.Property("Email") 70 | .IsRequired() 71 | .HasMaxLength(30); 72 | 73 | b.Property("FirstName") 74 | .IsRequired() 75 | .HasMaxLength(20); 76 | 77 | b.Property("IsActive"); 78 | 79 | b.Property("IsAdminRole"); 80 | 81 | b.Property("LastName") 82 | .IsRequired() 83 | .HasMaxLength(20); 84 | 85 | b.Property("Modified"); 86 | 87 | b.Property("Password") 88 | .HasMaxLength(50); 89 | 90 | b.Property("Roles") 91 | .HasMaxLength(255); 92 | 93 | b.Property("UserName") 94 | .HasMaxLength(30); 95 | 96 | b.HasKey("Id"); 97 | 98 | b.HasIndex("AccountId"); 99 | 100 | b.ToTable("Users"); 101 | }); 102 | 103 | modelBuilder.Entity("ApiNCoreApplication1.Entity.User", b => 104 | { 105 | b.HasOne("ApiNCoreApplication1.Entity.Account", "Account") 106 | .WithMany("Users") 107 | .HasForeignKey("AccountId") 108 | .OnDelete(DeleteBehavior.Cascade); 109 | }); 110 | #pragma warning restore 612, 618 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/Migrations/20180708205028_InitialCreate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Metadata; 3 | using Microsoft.EntityFrameworkCore.Migrations; 4 | 5 | namespace ApiNCoreApplication1.Entity.Migrations 6 | { 7 | public partial class InitialCreate : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.CreateTable( 12 | name: "Accounts", 13 | columns: table => new 14 | { 15 | Id = table.Column(nullable: false) 16 | .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), 17 | Created = table.Column(nullable: false), 18 | Modified = table.Column(nullable: false), 19 | Name = table.Column(maxLength: 30, nullable: false), 20 | Email = table.Column(maxLength: 30, nullable: false), 21 | Description = table.Column(maxLength: 255, nullable: true), 22 | IsTrial = table.Column(nullable: false), 23 | IsActive = table.Column(nullable: false), 24 | SetActive = table.Column(nullable: false) 25 | }, 26 | constraints: table => 27 | { 28 | table.PrimaryKey("PK_Accounts", x => x.Id); 29 | }); 30 | 31 | migrationBuilder.CreateTable( 32 | name: "Users", 33 | columns: table => new 34 | { 35 | Id = table.Column(nullable: false) 36 | .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), 37 | Created = table.Column(nullable: false), 38 | Modified = table.Column(nullable: false), 39 | FirstName = table.Column(maxLength: 20, nullable: false), 40 | LastName = table.Column(maxLength: 20, nullable: false), 41 | UserName = table.Column(maxLength: 30, nullable: true), 42 | Email = table.Column(maxLength: 30, nullable: false), 43 | Description = table.Column(maxLength: 255, nullable: true), 44 | IsAdminRole = table.Column(nullable: false), 45 | Roles = table.Column(maxLength: 255, nullable: true), 46 | IsActive = table.Column(nullable: false), 47 | Password = table.Column(maxLength: 255, nullable: true), 48 | AccountId = table.Column(nullable: false) 49 | }, 50 | constraints: table => 51 | { 52 | table.PrimaryKey("PK_Users", x => x.Id); 53 | table.ForeignKey( 54 | name: "FK_Users_Accounts_AccountId", 55 | column: x => x.AccountId, 56 | principalTable: "Accounts", 57 | principalColumn: "Id", 58 | onDelete: ReferentialAction.Cascade); 59 | }); 60 | 61 | migrationBuilder.CreateIndex( 62 | name: "IX_Users_AccountId", 63 | table: "Users", 64 | column: "AccountId"); 65 | } 66 | 67 | protected override void Down(MigrationBuilder migrationBuilder) 68 | { 69 | migrationBuilder.DropTable( 70 | name: "Users"); 71 | 72 | migrationBuilder.DropTable( 73 | name: "Accounts"); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/Repository/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 ApiNCoreApplication1.Entity.Repository 8 | { 9 | public interface IRepository where T : class 10 | { 11 | IEnumerable GetAll(); 12 | IEnumerable Get(Expression> predicate); 13 | T GetOne(Expression> predicate); 14 | void Insert(T entity); 15 | void Delete(T entity); 16 | void Delete(object id); 17 | void Update(object id, T entity); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/Repository/IRepositoryAsync.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 ApiNCoreApplication1.Entity.Repository 8 | { 9 | public interface IRepositoryAsync where T : class 10 | { 11 | Task> GetAll(); 12 | Task> Get(Expression> predicate); 13 | Task GetOne(Expression> predicate); 14 | Task Insert(T entity); 15 | void Delete(T entity); 16 | Task Delete(object id); 17 | Task Update(object id, T entity); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/Repository/Repository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using ApiNCoreApplication1.Entity.Context; 6 | using ApiNCoreApplication1.Entity.UnitofWork; 7 | using Microsoft.EntityFrameworkCore; 8 | 9 | 10 | namespace ApiNCoreApplication1.Entity.Repository 11 | { 12 | 13 | /// 14 | /// General repository class 15 | /// 16 | /// 17 | public class Repository : IRepository where T : class 18 | { 19 | private readonly IUnitOfWork _unitOfWork; 20 | public Repository(IUnitOfWork unitOfWork) 21 | { 22 | _unitOfWork = unitOfWork; 23 | } 24 | 25 | 26 | public IEnumerable GetAll() 27 | { 28 | return _unitOfWork.Context.Set(); 29 | } 30 | public IEnumerable Get(System.Linq.Expressions.Expression> predicate) 31 | { 32 | return _unitOfWork.Context.Set().Where(predicate).AsEnumerable(); 33 | } 34 | public T GetOne(System.Linq.Expressions.Expression> predicate) 35 | { 36 | return _unitOfWork.Context.Set().Where(predicate).FirstOrDefault(); 37 | } 38 | public void Insert(T entity) 39 | { 40 | if (entity != null) _unitOfWork.Context.Set().Add(entity); 41 | } 42 | public void Update(object id, T entity) 43 | { 44 | if (entity != null) 45 | { 46 | T entitytoUpdate = _unitOfWork.Context.Set().Find(id); 47 | if (entitytoUpdate != null) 48 | _unitOfWork.Context.Entry(entitytoUpdate).CurrentValues.SetValues(entity); 49 | } 50 | } 51 | public void Delete(object id) 52 | { 53 | T entity = _unitOfWork.Context.Set().Find(id); 54 | Delete(entity); 55 | } 56 | public void Delete(T entity) 57 | { 58 | if (entity != null) _unitOfWork.Context.Set().Remove(entity); 59 | } 60 | 61 | } 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/Repository/RepositoryAsync.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Threading.Tasks; 6 | using ApiNCoreApplication1.Entity.Context; 7 | using ApiNCoreApplication1.Entity.UnitofWork; 8 | using Microsoft.EntityFrameworkCore; 9 | 10 | 11 | namespace ApiNCoreApplication1.Entity.Repository 12 | { 13 | 14 | /// 15 | /// General repository class async 16 | /// 17 | /// 18 | public class RepositoryAsync : IRepositoryAsync where T : class 19 | { 20 | private readonly IUnitOfWork _unitOfWork; 21 | public RepositoryAsync(IUnitOfWork unitOfWork) 22 | { 23 | _unitOfWork = unitOfWork; 24 | } 25 | 26 | public async Task> GetAll() 27 | { 28 | return await _unitOfWork.Context.Set().ToListAsync(); 29 | } 30 | public async Task> Get(System.Linq.Expressions.Expression> predicate) 31 | { 32 | return await _unitOfWork.Context.Set().Where(predicate).ToListAsync(); 33 | } 34 | 35 | public async Task GetOne(System.Linq.Expressions.Expression> predicate) 36 | { 37 | return await _unitOfWork.Context.Set().Where(predicate).FirstOrDefaultAsync(); 38 | } 39 | public async Task Insert(T entity) 40 | { 41 | if (entity != null) 42 | await _unitOfWork.Context.Set().AddAsync(entity); 43 | } 44 | public async Task Update(object id, T entity) 45 | { 46 | if (entity != null) 47 | { 48 | T entitytoUpdate = await _unitOfWork.Context.Set().FindAsync(id); 49 | if (entitytoUpdate != null) 50 | _unitOfWork.Context.Entry(entitytoUpdate).CurrentValues.SetValues(entity); 51 | } 52 | } 53 | public async Task Delete(object id) 54 | { 55 | T entity = await _unitOfWork.Context.Set().FindAsync(id); 56 | Delete(entity); 57 | } 58 | public void Delete(T entity) 59 | { 60 | if (entity != null) _unitOfWork.Context.Set().Remove(entity); 61 | } 62 | 63 | 64 | 65 | } 66 | 67 | 68 | } 69 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/UnitofWork/UnitofWork.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using ApiNCoreApplication1.Entity.Context; 5 | using ApiNCoreApplication1.Entity.Repository; 6 | using Microsoft.EntityFrameworkCore; 7 | 8 | namespace ApiNCoreApplication1.Entity.UnitofWork 9 | { 10 | 11 | 12 | public interface IUnitOfWork : IDisposable 13 | { 14 | 15 | IRepository GetRepository() where TEntity : class; 16 | IRepositoryAsync GetRepositoryAsync() where TEntity : class; 17 | 18 | ApiNCoreApplication1Context Context { get; } 19 | bool Save(); 20 | Task SaveAsync(); 21 | } 22 | 23 | public interface IUnitOfWork : IUnitOfWork where TContext : DbContext 24 | { 25 | } 26 | 27 | public class UnitOfWork : IUnitOfWork 28 | { 29 | public ApiNCoreApplication1Context Context { get; } 30 | 31 | private Dictionary _repositoriesAsync; 32 | private Dictionary _repositories; 33 | private bool _disposed; 34 | 35 | public UnitOfWork(ApiNCoreApplication1Context context) 36 | { 37 | Context = context; 38 | _disposed = false; 39 | } 40 | 41 | public IRepository GetRepository() where TEntity : class 42 | { 43 | if (_repositories == null) _repositories = new Dictionary(); 44 | var type = typeof(TEntity); 45 | if (!_repositories.ContainsKey(type)) _repositories[type] = new Repository(this); 46 | return (IRepository)_repositories[type]; 47 | } 48 | 49 | public IRepositoryAsync GetRepositoryAsync() where TEntity : class 50 | { 51 | if (_repositories == null) _repositoriesAsync = new Dictionary(); 52 | var type = typeof(TEntity); 53 | if (!_repositoriesAsync.ContainsKey(type)) _repositoriesAsync[type] = new RepositoryAsync(this); 54 | return (IRepositoryAsync)_repositoriesAsync[type]; 55 | } 56 | 57 | public bool Save() 58 | { 59 | return Context.SaveChanges() > 0; 60 | } 61 | public async Task SaveAsync() 62 | { 63 | return await Context.SaveChangesAsync() > 0; 64 | } 65 | 66 | public void Dispose() 67 | { 68 | Dispose(true); 69 | GC.SuppressFinalize(this); 70 | } 71 | public void Dispose(bool isDisposing) 72 | { 73 | if (!_disposed) 74 | { 75 | if (isDisposing) 76 | { 77 | Context.Dispose(); 78 | } 79 | } 80 | _disposed = true; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /ApiNCoreApplication1/ApiNCoreApplication1/ApiNCoreApplication1.Entity/_nugets.txt: -------------------------------------------------------------------------------- 1 |  2 | https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/ 3 | PM> Install-Package Microsoft.EntityFrameworkCore -Version 2.1.0 4 | 5 | https://duszekmestre.github.io/dsp2017/2017/03/26/repository-pattern-unit-of-work/ 6 | PM> Install-Package Microsoft.EntityFrameworkCore.InMemory 7 | PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer 8 | PM> Install-Package Microsoft.EntityFrameworkCore.Tools 9 | 10 | https://www.nuget.org/packages/Microsoft.AspNet.Identity.EntityFramework/ 11 | PM>Install-Package Microsoft.AspNet.Identity.EntityFramework -Version 2.2.1 12 | 13 | https://www.newtonsoft.com/json 14 | PM> Install-Package Newtonsoft.Json 15 | 16 | -------------------------------------------------------------------------------- /ApiNCoreE.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anasoftinc/apincore/a192c3f65ea9548cccfcb4e46b142a36497f942e/ApiNCoreE.vsix -------------------------------------------------------------------------------- /LICENSE.md/LICENSE.md: -------------------------------------------------------------------------------- 1 | (C)Note that there is no restriction to use, copy, modify, and distribute software created with this Visual Studio extension template. Created solution using this template may contain code with unintentional flaws or limitations. Please adjust created solution to your needs and test it before any production use. IN NO EVENT SHALL OWNER OF THIS EXTENSION BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE OWNER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # apincore 2 | Api NetCore Template for VS2017 and VS2019 3 | 4 | This is example of VS project created with ApiNCore.vsix VS project template extension. 5 | 6 | Creates startup VS2017 solution for WebAPI .Net Core 2.1 with DI, Automapper, UnitOfWork, Repository, Sync/Async Service, JWT autentication/authorization and Logging (Serilog) 7 | 8 | Deployment: 9 | 10 | 1)Execute ApiNCore.vsix or visit https://marketplace.visualstudio.com/items?itemName=anasoft-code.ApiNcore1 11 | 12 | 2)Open template from VS2017 and create new solution 13 | 14 | 3)VS2017 should restore nuget depedencies automaticaly. Otherwise open each project in new solution right click a project -> Manage Nuget Packages -> Restore 15 | 16 | Full-featured VSIX (T4 code generation, XUnit integration project tests and Postman API tests) versions you can get from http://www.anasoft.net/apincore 17 | --------------------------------------------------------------------------------