├── F3 - JQuery.md ├── assets ├── 01.png ├── 02.png ├── 03.png ├── 04.png ├── 05.png ├── 06.png ├── 07.png ├── 08.png ├── 09.png ├── 10.png ├── 11.png ├── 12.png ├── 13.png ├── 14.png ├── 15.png ├── 16.png ├── 17.png ├── 18.png ├── 19.png └── 20.png ├── Readme.md ├── 01 - Web Protokolleri ve Web Yaşam Döngüsü.md ├── F2 - Responsive Tasarım ve Bootstrap.md ├── F1 - HTML ve CSS Yapısı ve Özellikleri.md ├── OnionArchitectureProjectExample ├── Project.Core │ ├── Entities │ │ ├── ILog.cs │ │ └── IEntity.cs │ ├── Project.Core.csproj │ ├── Logger │ │ ├── ILogRepository.cs │ │ └── FileLogger │ │ │ └── FileLogRepository.cs │ └── Data │ │ ├── IEntityRepository.cs │ │ └── EntityFramework │ │ └── EfEntityRepository.cs ├── Project.WebUI │ ├── Views │ │ └── Home │ │ │ └── Index.cshtml │ ├── Project.WebUI.csproj │ ├── Controllers │ │ └── HomeController.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ └── Startup.cs ├── Project.Entities │ ├── Project.Entities.csproj │ ├── Data │ │ ├── Address.cs │ │ └── Person.cs │ └── Logger │ │ ├── GeneralLog.cs │ │ └── ExceptionLog.cs ├── Project.Data │ ├── Abstract │ │ ├── IAddressRepository.cs │ │ └── IPersonRepository.cs │ ├── Project.Data.csproj │ └── Concrete │ │ └── EntityFramerwork │ │ ├── EfAddressRepository.cs │ │ ├── EfPersonRepository.cs │ │ └── DAL │ │ └── EfProjectContext.cs ├── Project.Services │ ├── Abstract │ │ ├── ILogService.cs │ │ └── IDatabaseService.cs │ ├── Project.Services.csproj │ └── Concrete │ │ ├── Logger │ │ └── FileLogService.cs │ │ └── Data │ │ └── EfDatabaseService.cs ├── Project.Logger │ ├── Abstarct │ │ ├── IGeneralLogRepository.cs │ │ └── IExceptionLogRepository.cs │ ├── Project.Logger.csproj │ └── Concrete │ │ └── FileLogger │ │ ├── FileGereralLogRepository.cs │ │ └── FileExceptionLogRepository.cs ├── .gitignore └── OnionArchitectureProjectExample.sln ├── 05 - Views.md ├── 10 - Action Result Türleri.md ├── F4 - JQuery ile Ajax İşlemleri.md ├── RoadMap.txt ├── 15 - Area Kavramı.md ├── 03 - Razor View Engine.md ├── 09 - Database CRUD İşlemleri.md ├── 06 - Controller ve View Arasındaki İletişim.md ├── 11 - View Components.md ├── 19 - ASP.NET Core In-Depth - Dependecy Injection.md ├── 22 - ASP.NET Core In-Depth - ORM Mimarileri.md ├── BONUS - FTP Server Kurulumu.md ├── 07 - Models ve Model Binding.md ├── 02 - ASP.NET Core MVC Giriş.md ├── 21 - ASP.NET Core In-Depth - Proje Geliştime Mimarileri.md ├── 12 - Durum Yönetimi.md ├── 20 - ASP.NET Core In-Depth - Middleware.md ├── 13 - Validation İşlemleri.md ├── 17 - Deployment.md └── 14 - Routing.md /F3 - JQuery.md: -------------------------------------------------------------------------------- 1 | ## JQUERY 2 | 3 | - Kaynaklar : 4 | - https://www.w3schools.com/jquery/default.asp -------------------------------------------------------------------------------- /assets/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/01.png -------------------------------------------------------------------------------- /assets/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/02.png -------------------------------------------------------------------------------- /assets/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/03.png -------------------------------------------------------------------------------- /assets/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/04.png -------------------------------------------------------------------------------- /assets/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/05.png -------------------------------------------------------------------------------- /assets/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/06.png -------------------------------------------------------------------------------- /assets/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/07.png -------------------------------------------------------------------------------- /assets/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/08.png -------------------------------------------------------------------------------- /assets/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/09.png -------------------------------------------------------------------------------- /assets/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/10.png -------------------------------------------------------------------------------- /assets/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/11.png -------------------------------------------------------------------------------- /assets/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/12.png -------------------------------------------------------------------------------- /assets/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/13.png -------------------------------------------------------------------------------- /assets/14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/14.png -------------------------------------------------------------------------------- /assets/15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/15.png -------------------------------------------------------------------------------- /assets/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/16.png -------------------------------------------------------------------------------- /assets/17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/17.png -------------------------------------------------------------------------------- /assets/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/18.png -------------------------------------------------------------------------------- /assets/19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/19.png -------------------------------------------------------------------------------- /assets/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/serhattsnmz/dotnet-core-ile-web-programlama/HEAD/assets/20.png -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | ## ASP .NET Core ile Web Programlama 2 | 3 | .NET Core ile Web Programlama dersinin ders notlarıdır. -------------------------------------------------------------------------------- /01 - Web Protokolleri ve Web Yaşam Döngüsü.md: -------------------------------------------------------------------------------- 1 | ## Web Protokolleri ve Web Yaşam Döngüsü 2 | - Bu kısım daha sonra eklenecektir. -------------------------------------------------------------------------------- /F2 - Responsive Tasarım ve Bootstrap.md: -------------------------------------------------------------------------------- 1 | ## RESPONSIVE TASARIM VE BOOTSTRAP 2 | 3 | - Kaynaklar: 4 | - http://getbootstrap.com -------------------------------------------------------------------------------- /F1 - HTML ve CSS Yapısı ve Özellikleri.md: -------------------------------------------------------------------------------- 1 | ## HTML ve CSS Yapısı ve Özellikleri 2 | 3 | ### HTML 4 | - https://www.w3schools.com/html/default.asp 5 | 6 | ### CSS 7 | - https://www.w3schools.com/css/default.asp -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Core/Entities/ILog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Project.Core.Entities 6 | { 7 | public interface ILog 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Core/Entities/IEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Project.Core.Entities 6 | { 7 | public interface IEntity 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.WebUI/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | 2 | @{ 3 | Layout = null; 4 | } 5 | 6 | 7 | 8 | 9 | 10 | 11 | Index 12 | 13 | 14 | Example Page 15 | 16 | 17 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Entities/Project.Entities.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Data/Abstract/IAddressRepository.cs: -------------------------------------------------------------------------------- 1 | using Project.Core.Data; 2 | using Project.Entities.Data; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace Project.Data.Abstract 8 | { 9 | public interface IAddressRepository : IEntityRepository
10 | { 11 | // Custom operations 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Data/Abstract/IPersonRepository.cs: -------------------------------------------------------------------------------- 1 | using Project.Core.Data; 2 | using Project.Entities.Data; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace Project.Data.Abstract 8 | { 9 | public interface IPersonRepository : IEntityRepository 10 | { 11 | // Custom operations 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Services/Abstract/ILogService.cs: -------------------------------------------------------------------------------- 1 | using Project.Logger.Abstarct; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Project.Services.Abstract 7 | { 8 | public interface ILogService 9 | { 10 | IGeneralLogRepository GeneralLog { get; } 11 | IExceptionLogRepository ExceptionLog { get; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Logger/Abstarct/IGeneralLogRepository.cs: -------------------------------------------------------------------------------- 1 | using Project.Core.Logger; 2 | using Project.Entities.Logger; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace Project.Logger.Abstarct 8 | { 9 | public interface IGeneralLogRepository : ILogRepository 10 | { 11 | // Custom operations 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Logger/Abstarct/IExceptionLogRepository.cs: -------------------------------------------------------------------------------- 1 | using Project.Core.Logger; 2 | using Project.Entities.Logger; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace Project.Logger.Abstarct 8 | { 9 | public interface IExceptionLogRepository : ILogRepository 10 | { 11 | // Custom operations 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Logger/Project.Logger.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Services/Project.Services.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Services/Abstract/IDatabaseService.cs: -------------------------------------------------------------------------------- 1 | using Project.Data.Abstract; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Project.Services.Abstract 7 | { 8 | public interface IDatabaseService : IDisposable 9 | { 10 | IPersonRepository People { get; } 11 | IAddressRepository Addresses { get; } 12 | 13 | int SaveChanges(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Core/Project.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Entities/Data/Address.cs: -------------------------------------------------------------------------------- 1 | using Project.Core.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Project.Entities.Data 7 | { 8 | public class Address : IEntity 9 | { 10 | public int ID { get; set; } 11 | public string FullAddress { get; set; } 12 | public string City { get; set; } 13 | 14 | public IEnumerable Persons { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Entities/Logger/GeneralLog.cs: -------------------------------------------------------------------------------- 1 | using Project.Core.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Project.Entities.Logger 7 | { 8 | public class GeneralLog : ILog 9 | { 10 | public GeneralLog() => this.Date = DateTime.Now; 11 | 12 | public DateTime Date { get; set; } 13 | public string LogName { get; set; } 14 | public string LogInfo { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Core/Logger/ILogRepository.cs: -------------------------------------------------------------------------------- 1 | using Project.Core.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using System.Text; 7 | 8 | namespace Project.Core.Logger 9 | { 10 | public interface ILogRepository 11 | where T : class, ILog, new() 12 | { 13 | List GetList(Func filter = null); 14 | 15 | void Add(T log); 16 | void Delete(T log); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Entities/Data/Person.cs: -------------------------------------------------------------------------------- 1 | using Project.Core.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Project.Entities.Data 7 | { 8 | public class Person : IEntity 9 | { 10 | public int ID { get; set; } 11 | public string Name { get; set; } 12 | public string Surname { get; set; } 13 | public int Age { get; set; } 14 | 15 | public int? AddressID { get; set; } 16 | public Address Address { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Entities/Logger/ExceptionLog.cs: -------------------------------------------------------------------------------- 1 | using Project.Core.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Project.Entities.Logger 7 | { 8 | public class ExceptionLog : ILog 9 | { 10 | public ExceptionLog() => this.Date = DateTime.Now; 11 | 12 | public DateTime Date { get; set; } 13 | public string ExceptionInfo { get; set; } 14 | public string Controller { get; set; } 15 | public string Action { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Logger/Concrete/FileLogger/FileGereralLogRepository.cs: -------------------------------------------------------------------------------- 1 | using Project.Core.Logger.FileLogger; 2 | using Project.Entities.Logger; 3 | using Project.Logger.Abstarct; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Text; 8 | 9 | namespace Project.Logger.Concrete.FileLogger 10 | { 11 | public class FileGereralLogRepository 12 | : FileLogRepository, IGeneralLogRepository 13 | { 14 | public FileGereralLogRepository() : base("generalLogs.json") { } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Logger/Concrete/FileLogger/FileExceptionLogRepository.cs: -------------------------------------------------------------------------------- 1 | using Project.Core.Logger.FileLogger; 2 | using Project.Entities.Logger; 3 | using Project.Logger.Abstarct; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Text; 8 | 9 | namespace Project.Logger.Concrete.FileLogger 10 | { 11 | public class FileExceptionLogRepository 12 | : FileLogRepository, IExceptionLogRepository 13 | { 14 | public FileExceptionLogRepository() : base("exceptionLogs.json"){} 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.*~ 3 | project.lock.json 4 | .DS_Store 5 | *.pyc 6 | nupkg/ 7 | 8 | # Visual Studio Code 9 | .vscode 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.userosscache 15 | *.sln.docstates 16 | 17 | # Build results 18 | [Dd]ebug/ 19 | [Dd]ebugPublic/ 20 | [Rr]elease/ 21 | [Rr]eleases/ 22 | x64/ 23 | x86/ 24 | build/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Oo]ut/ 29 | msbuild.log 30 | msbuild.err 31 | msbuild.wrn 32 | 33 | # Visual Studio 2015 34 | .vs/ 35 | 36 | generalLogs.json 37 | exceptionLogs.json 38 | Migrations/ -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.WebUI/Project.WebUI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Core/Data/IEntityRepository.cs: -------------------------------------------------------------------------------- 1 | using Project.Core.Entities; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Linq.Expressions; 6 | using System.Text; 7 | 8 | namespace Project.Core.Data 9 | { 10 | public interface IEntityRepository 11 | where T : class, IEntity, new() 12 | { 13 | T Get(Expression> filter); 14 | T GetByID(int ID); 15 | 16 | IQueryable GetAll(); 17 | IQueryable GetList(Expression> filter); 18 | 19 | void Add(T entity); 20 | void Update(T entity); 21 | void Delete(T entity); 22 | 23 | void SaveChanges(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Data/Project.Data.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.WebUI/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Project.Data.Abstract; 3 | using Project.Entities.Data; 4 | using Project.Services.Abstract; 5 | 6 | namespace Project.WebUI.Controllers 7 | { 8 | public class HomeController : Controller 9 | { 10 | private IDatabaseService database; 11 | private ILogService log; 12 | 13 | public HomeController(IDatabaseService _database, ILogService _log) 14 | { 15 | database = _database; 16 | log = _log; 17 | } 18 | 19 | public IActionResult Index() 20 | { 21 | database.People.Add(new Person 22 | { 23 | Name = "serhat" 24 | }); 25 | database.SaveChanges(); 26 | return View(); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Services/Concrete/Logger/FileLogService.cs: -------------------------------------------------------------------------------- 1 | using Project.Logger.Abstarct; 2 | using Project.Logger.Concrete.FileLogger; 3 | using Project.Services.Abstract; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | 8 | namespace Project.Services.Concrete.Logger 9 | { 10 | public class FileLogService : ILogService 11 | { 12 | // Fields 13 | IGeneralLogRepository _generalLog; 14 | IExceptionLogRepository _exceptionLog; 15 | 16 | public IGeneralLogRepository GeneralLog 17 | => _generalLog ?? (_generalLog = new FileGereralLogRepository()); 18 | 19 | public IExceptionLogRepository ExceptionLog 20 | => _exceptionLog ?? (_exceptionLog = new FileExceptionLogRepository()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.WebUI/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace Project.WebUI 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | BuildWebHost(args).Run(); 18 | } 19 | 20 | public static IWebHost BuildWebHost(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup() 23 | .Build(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.WebUI/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:52433/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "Project.WebUI": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | }, 24 | "applicationUrl": "http://localhost:52434/" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Data/Concrete/EntityFramerwork/EfAddressRepository.cs: -------------------------------------------------------------------------------- 1 | using Project.Core.Data.EntityFramework; 2 | using Project.Data.Abstract; 3 | using Project.Data.Concrete.EntityFramerwork.DAL; 4 | using Project.Entities.Data; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Project.Data.Concrete.EntityFramerwork 10 | { 11 | public class EfAddressRepository : EfEntityRepository
, IAddressRepository 12 | { 13 | // Database Injection 14 | // We inject db instead of create, because we will create only one db object for all entity repositories with Unit Of Work Architecture. 15 | // After Injection, we send the db object to the base. 16 | public EfAddressRepository(EfProjectContext context) : base(context) { } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Data/Concrete/EntityFramerwork/EfPersonRepository.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Project.Core.Data.EntityFramework; 3 | using Project.Data.Abstract; 4 | using Project.Data.Concrete.EntityFramerwork.DAL; 5 | using Project.Entities.Data; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Text; 9 | 10 | namespace Project.Data.Concrete.EntityFramerwork 11 | { 12 | public class EfPersonRepository : EfEntityRepository, IPersonRepository 13 | { 14 | // Database Injection 15 | // We inject db instead of create, because we will create only one db object for all entity repositories with Unit Of Work Architecture. 16 | // After Injection, we send the db object to the base. 17 | public EfPersonRepository(EfProjectContext context) : base(context) { } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Data/Concrete/EntityFramerwork/DAL/EfProjectContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Project.Entities.Data; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace Project.Data.Concrete.EntityFramerwork.DAL 8 | { 9 | public class EfProjectContext : DbContext 10 | { 11 | // For using "UseSqlServer", you must add the following line to the "Project.Data.csproj" 12 | // 13 | // 14 | // 15 | // 16 | 17 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 18 | { 19 | optionsBuilder.UseSqlServer( 20 | "Server=(localdb)\\mssqllocaldb;Database=ExampleProject;Trusted_Connection=True" 21 | ); 22 | } 23 | 24 | public DbSet People { get; set; } 25 | public DbSet
Addresses { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Services/Concrete/Data/EfDatabaseService.cs: -------------------------------------------------------------------------------- 1 | using Project.Data.Abstract; 2 | using Project.Data.Concrete.EntityFramerwork; 3 | using Project.Data.Concrete.EntityFramerwork.DAL; 4 | using Project.Services.Abstract; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | 9 | namespace Project.Services.Concrete.Data 10 | { 11 | public class EfDatabaseService : IDatabaseService 12 | { 13 | // Database 14 | private readonly EfProjectContext context; 15 | 16 | public EfDatabaseService() 17 | => context = new EfProjectContext(); 18 | 19 | // Fields 20 | private IPersonRepository _people; 21 | private IAddressRepository _address; 22 | 23 | // Properties 24 | public IPersonRepository People 25 | => _people ?? (_people = new EfPersonRepository(context)); 26 | 27 | public IAddressRepository Addresses 28 | => _address ?? (_address = new EfAddressRepository(context)); 29 | 30 | public int SaveChanges() 31 | => context.SaveChanges(); 32 | 33 | public void Dispose() 34 | => context.Dispose(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.WebUI/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Project.Data.Concrete.EntityFramerwork.DAL; 6 | using Project.Services.Abstract; 7 | using Project.Services.Concrete.Data; 8 | using Project.Services.Concrete.Logger; 9 | 10 | namespace Project.WebUI 11 | { 12 | public class Startup 13 | { 14 | public IConfiguration Configuration { get; } 15 | 16 | public Startup(IConfiguration configuration) 17 | { 18 | Configuration = configuration; 19 | } 20 | 21 | public void ConfigureServices(IServiceCollection services) 22 | { 23 | services.AddScoped(); 24 | services.AddScoped(); 25 | 26 | services.AddMvc(); 27 | } 28 | 29 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 30 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 31 | { 32 | if (env.IsDevelopment()) 33 | { 34 | app.UseDeveloperExceptionPage(); 35 | } 36 | 37 | app.UseStaticFiles(); 38 | app.UseStatusCodePages(); 39 | app.UseMvcWithDefaultRoute(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Core/Data/EntityFramework/EfEntityRepository.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Project.Core.Entities; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Linq.Expressions; 7 | using System.Text; 8 | 9 | namespace Project.Core.Data.EntityFramework 10 | { 11 | public class EfEntityRepository : IEntityRepository 12 | where T : class, IEntity, new() 13 | { 14 | // Database Injection 15 | // We inject db instead of create, because we will create only one db object for all entity repositories with Unit Of Work Architecture. 16 | protected readonly DbContext context; 17 | 18 | public EfEntityRepository(DbContext _context) 19 | => context = _context; 20 | 21 | // Get Single Entity 22 | public T Get(Expression> filter) 23 | => context.Set().FirstOrDefault(filter); 24 | 25 | public T GetByID(int ID) 26 | => context.Set().Find(ID); 27 | 28 | // Get Entity List 29 | public IQueryable GetAll() 30 | => context.Set(); 31 | 32 | public IQueryable GetList(Expression> filter) 33 | => context.Set().Where(filter); 34 | 35 | // Create 36 | public void Add(T entity) 37 | => context.Set().Add(entity); 38 | 39 | // Update 40 | public void Update(T entity) 41 | => context.Set().Update(entity); 42 | 43 | // Delete 44 | public void Delete(T entity) 45 | => context.Set().Remove(entity); 46 | 47 | // Save Changes 48 | public void SaveChanges() 49 | => context.SaveChanges(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /05 - Views.md: -------------------------------------------------------------------------------- 1 | ## VİEWS 2 | 3 | ### 1) Views ve Layout Kullanımı 4 | - Layout page oluşturma 5 | - `RenderBody()` kısmı 6 | 7 | ### 2) ViewStart Ne İşe Yarar 8 | - Views klasörü altına `_ViewStart.cshtml` tanımlama 9 | - ViewStart için layout tanımlama 10 | - Html sayfalarında layout tanımını kaldırma 11 | 12 | ### 3) Otomatik Layout Sayfası Oluşturma 13 | - Yeni bir view oluştururken “Use Layout Page” tanımını; 14 | - Belirtme 15 | - Boş bırakma 16 | - Tick kaldırma 17 | - .NET Core yapısında, ilk çalıştırıldığında tick işaretlenirse .NET Frameworkte olduğu gibi otomatik olarak JS ve CSS dosyalarını indirme yoktur. 18 | 19 | ### 4) Nested (İç İçe) Layout Oluşturma 20 | - View Page with Layout oluşturma 21 | 22 | ### 5) Section ( Bölüm ) Oluşturma 23 | - RenderSection – True/False 24 | - Default Section tanımlama: 25 | 26 | ```cs 27 | @if (IsSectionDefined("Footer")) 28 | { 29 | RenderSection("Footer"); 30 | } 31 | else 32 | { 33 | This is the default yo! 34 | } 35 | ``` 36 | 37 | ### 6) Partial View Kullanımı 38 | - Yeni bir Partial View oluşturma 39 | - @Html.Partial(“yol”) 40 | - @{ Html.RenderPartial(“yol”) } 41 | - Yol Belirtme 42 | - Shared içinde veya kendi klasörünün altında direk isim yazarak çağırılabilir. 43 | - Diğer klasörlerin altında ise tam yol belirtilmesi zorunludur. 44 | - Partial çekilirken, partial’a bir model gönderilerek de çekilebilir. 45 | 46 | ### 7) _ViewImports.cshtml Dosyası 47 | - Views içerisinde kullanacağımız using ifadeleri global olarak tanımlamak için kullanılır. 48 | - Views dizini altında oluşturulur ve ismi sabittir. 49 | - İçerisindeki ifadeler başında @ işaretiyle yazılır. 50 | 51 | ```cs 52 | @using Project.Models 53 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 54 | ... 55 | ``` -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/Project.Core/Logger/FileLogger/FileLogRepository.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Project.Core.Entities; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Linq.Expressions; 8 | using System.Reflection; 9 | using System.Text; 10 | 11 | namespace Project.Core.Logger.FileLogger 12 | { 13 | public class FileLogRepository : ILogRepository 14 | where T : class, ILog, new() 15 | { 16 | 17 | private readonly string filePath; 18 | 19 | public FileLogRepository(string _filePath) 20 | { 21 | filePath = _filePath; 22 | if (!File.Exists(filePath)) 23 | File.WriteAllText(filePath, ""); 24 | } 25 | public List GetList(Func filter = null) 26 | { 27 | List json = 28 | JsonConvert.DeserializeObject>(File.ReadAllText(filePath)) 29 | ?? new List(); 30 | 31 | if (filter != null) 32 | json = json.Where(filter).ToList(); 33 | return json; 34 | } 35 | 36 | public void Add(T log) 37 | { 38 | List json = 39 | JsonConvert.DeserializeObject>(File.ReadAllText(filePath)) 40 | ?? new List(); 41 | json.Add(log); 42 | File.WriteAllText(filePath, JsonConvert.SerializeObject(json)); 43 | } 44 | 45 | public void Delete(T log) 46 | { 47 | List json = 48 | JsonConvert.DeserializeObject>(File.ReadAllText(filePath)) 49 | ?? new List(); 50 | json.Remove(log); 51 | File.WriteAllText(filePath, JsonConvert.SerializeObject(json)); 52 | } 53 | 54 | public string PrintTModelPropertyAndValue(T tmodelObj) 55 | { 56 | string result = ""; 57 | 58 | //Getting Type of Generic Class Model 59 | Type tModelType = tmodelObj.GetType(); 60 | 61 | //We will be defining a PropertyInfo Object which contains details about the class property 62 | PropertyInfo[] arrayPropertyInfos = tModelType.GetProperties(); 63 | 64 | //Now we will loop in all properties one by one to get value 65 | foreach (PropertyInfo property in arrayPropertyInfos) 66 | { 67 | result += property.Name + " : "; 68 | result += property.GetValue(tmodelObj).ToString(); 69 | result += Environment.NewLine; 70 | } 71 | 72 | result += "---" + Environment.NewLine; 73 | 74 | return result; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /10 - Action Result Türleri.md: -------------------------------------------------------------------------------- 1 | ## ACTION RESULT TÜRLERİ 2 | 3 | - Tüm Result türleri `IActionResult`’tan türemiştir. 4 | - Bu nedenle `IActionResult` altında tüm result türlerini return edebiliriz. 5 | - Bir action içinde birden fazla farklı dönüş tipleri olabileceği için, genel olarak `IActionResult` kullanmak daha mantıklıdır. 6 | 7 | ### ViewResult - View() 8 | - Tanımlı bir View içeriğini render edip döndürmeyi sağlar. 9 | - Metot boş kullanılırsa, Controller ile aynı ismi taşıyan klasör içindeki Action ile aynı ismi taşıyan cshtml belgesini döndürür. 10 | - Farklı bir view döndürülmek isteniyorsa, metot içine ismi yazılabilir. 11 | 12 | ### PartialViewResult - PartialView() 13 | - Tanımlanmış bir partial görünümünün render edilip döndürülmesini sağlar. 14 | - Partial, Controller ile aynı isimli klasör içinde veya `Shared` klasörü içindeyse, sadece ismi girilerek partial döndürülebilir. Aksi durumda tam yol girilmesi gereklidir. 15 | - Partial tek başına döndürülebileceği gibi, bir model ile birlikte render edilerek döndürülebilir. 16 | 17 | ### ContentResult - Content() 18 | - Kullanıcı tarafına view kullanmadan içerik döndürür. 19 | - String parametre alır. 20 | 21 | ### RedirectResult - Redirect() 22 | - Url yönlendirmesi yapar 23 | - Dış siteye bağlantı verilecekse `http://` kullanılması unutulmamalıdır. 24 | - `Redirect` => 302 döndürür. 25 | - `RedirectPermanent` => 301 döndürür. 26 | 27 | ### RedirectToActionResult - RedirectToAction() 28 | - Farklı bir action metoduna yönlendirme yapar. 29 | - Sadece action ismi verilirse, aynı controller üzerinde bu action'ı arar. 30 | - Farklı bir controller üzerindeki action'a yönlendirme yapılabilir. 31 | - Yönlendirme yapılırken bilgi taşınacaksa, `routeValues` parametresi kullanılabilir. 32 | 33 | ### JsonResult - Json() 34 | - Verilen bir objeyi serialize edip Json formatına dönüştürür ve döndürür. 35 | - Özellikle Ajax işlemlerinde kullanılır. 36 | - İkinci parametre olarak serialize özellikleri girilebilir. 37 | 38 | ### FileResult - File() 39 | - Dosya döndürmek için kullanılır. 40 | - Dosya şu türlerde verilebilir: 41 | - Virtual Path (`VirtualFileResult`) 42 | - Byte dizisi (`FileContentResult`) 43 | - Stream nesnesi (`FileStreamResult`) 44 | - Burada dosya türü olarak `MimeType` verilmelidir. 45 | - Bu bilgi raw response'un headers kısmında iletilir. 46 | - Bu bilgi sayesinde tarayıcı gelen dosyanın türünü anlar ve ona göre işlem yapar. 47 | 48 | ### StatusCodeResult 49 | - `StatusCode()` 50 | -`int` türünde verilen durum kodunu döndürür. 51 | - `NotFound()` - (`NotFoundResult`) 52 | - Aranılan içeriğin bulunmadığını belirten sayfayı döndürür. 53 | - Durum kodu : 404 54 | - `Unauthorized()` - (`UnauthorizedResult`) 55 | - Yetkisizi işlem yaptığınıa dair bir durum kodu ve mesajı döndürür. 56 | - Durum kodu : 401 57 | 58 | ### ObjectResult - StatusCode() 59 | - Durum koduyla birlikte ikinci bir parametre olarak bir object döndürür. 60 | - Bu object raw request'in body kısmında taşınır. 61 | 62 | ### Diğer Result Türleri 63 | - `EmptyResult` 64 | - `ChallengeResult` 65 | - `ForbitResult` 66 | - `SignInResult` 67 | - `SignOutResult` 68 | - `PageResult` 69 | - `ViewComponentResult` -------------------------------------------------------------------------------- /F4 - JQuery ile Ajax İşlemleri.md: -------------------------------------------------------------------------------- 1 | ## JQUERY İLE AJAX İŞLEMLERİ 2 | 3 | - DOM ( Documet Object Model ) Nedir? 4 | - DOM, HTML ile programlama dilleri arasında bir standart oluşturarak bu dillerin HTML den bilgi alıp, bilgi vermesine yardımcı olur. DOM, Nesneler ve özelliklerden oluşur. 5 | - DOM’da HTML ile hazırladığınız sayfa, belge; bu belgenin içine yerleştirdiğiniz her türlü öğe ise nesne olarak adlandırılır. 6 | - DOM da nesnelerin birer öğe (element) olarak kullanılabilmesi için hiyerarşik bir düzen izlenerek çağrılmaları gerekir. 7 | 8 |

9 | 10 |

11 | 12 | #### Klasik Ajax işlemleri 13 | 14 | ```html 15 |
16 |

17 |

Veri alınmadı!

18 | 19 | 38 | ``` 39 | 40 | - Ajax ile gelen veri birden çok yapıda olabilir ve kullanımı da gelen bu yapıya göre değişir. 41 | - String döndüren ajax 42 | - Html döndüren ajax 43 | - Model döndüren ajax 44 | - Model Listesi döndüren ajax 45 | - PartialView döndüren ajax 46 | - $.each metodu 47 | 48 | ```js 49 | $.each(data, function (index, value) { 50 | liste.append("
  • " + value.Isim"
  • "); 51 | }); 52 | ``` 53 | 54 | - Kaynak : 55 | - http://api.jquery.com/jQuery.ajax/ 56 | 57 | 58 | #### $.load() fonksiyonu 59 | 60 | - load() metodu ile veri gönderirsek “post” olarak otomatik gönderir. Veri göndermediğimiz ve sadece veri çektiğimiz durumlarda, “get” gönderimi yapar. 61 | 62 | ```js 63 | yazi.load("/Home/ajax1", { data: input.val() }, 64 | function (responseTxt, statusTxt, xhr) { 65 | if (statusTxt == "success") 66 | alert("External content loaded successfully!"); 67 | if (statusTxt == "error") 68 | alert("Error: " + xhr.status + ": " + xhr.statusText); 69 | }); 70 | ``` 71 | 72 | - Kaynaklar : 73 | - https://www.w3schools.com/jquery/ajax_load.asp 74 | - http://api.jquery.com/load/ 75 | 76 | #### $.get ve $.post işlemleri 77 | 78 | ```js 79 | // Kullanımı 80 | $.get(URL,callback); 81 | $.post(URL,data,callback); 82 | 83 | // Örnek 84 | $.post("/Home/ajax2", function (data, status) { 85 | $.each(data, function (index, value) { 86 | liste.append("
  • " + value.Isim + "
  • "); 87 | }); 88 | }).done(function () { 89 | alert("Ajax method başarıyla çalıştı!"); 90 | }).fail(function () { 91 | alert("Bir hata oluştu!"); 92 | }).always(function () { 93 | alert("Her zaman gösterilecek!") 94 | }); 95 | ``` 96 | 97 | - Deferred Object Yapıları 98 | - .done(), .fail() ve .always() 99 | - Kaynaklar : 100 | - https://www.w3schools.com/jquery/jquery_ajax_get_post.asp 101 | - https://api.jquery.com/category/deferred-object/ 102 | -------------------------------------------------------------------------------- /OnionArchitectureProjectExample/OnionArchitectureProjectExample.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27428.2005 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Project.Data", "Project.Data\Project.Data.csproj", "{3E20360B-BBB9-4A75-9BE6-AC8AB8F73C23}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Project.Core", "Project.Core\Project.Core.csproj", "{10891C0E-CAA3-41E1-885D-3AB92E10C34A}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Project.Services", "Project.Services\Project.Services.csproj", "{C511B695-2BE4-4FCD-8209-621DC77C3AE6}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Project.Entities", "Project.Entities\Project.Entities.csproj", "{E965BA69-7F2C-468A-976E-46640F87F44A}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Project.WebUI", "Project.WebUI\Project.WebUI.csproj", "{C5EB061D-426B-4B1E-8E65-A6336C46B8A9}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Project.Logger", "Project.Logger\Project.Logger.csproj", "{24F8BDDA-8FCE-46A9-AD04-AE2CF22A1CBC}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Release|Any CPU = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {3E20360B-BBB9-4A75-9BE6-AC8AB8F73C23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {3E20360B-BBB9-4A75-9BE6-AC8AB8F73C23}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {3E20360B-BBB9-4A75-9BE6-AC8AB8F73C23}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {3E20360B-BBB9-4A75-9BE6-AC8AB8F73C23}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {10891C0E-CAA3-41E1-885D-3AB92E10C34A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {10891C0E-CAA3-41E1-885D-3AB92E10C34A}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {10891C0E-CAA3-41E1-885D-3AB92E10C34A}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {10891C0E-CAA3-41E1-885D-3AB92E10C34A}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {C511B695-2BE4-4FCD-8209-621DC77C3AE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {C511B695-2BE4-4FCD-8209-621DC77C3AE6}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {C511B695-2BE4-4FCD-8209-621DC77C3AE6}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {C511B695-2BE4-4FCD-8209-621DC77C3AE6}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {E965BA69-7F2C-468A-976E-46640F87F44A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {E965BA69-7F2C-468A-976E-46640F87F44A}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {E965BA69-7F2C-468A-976E-46640F87F44A}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {E965BA69-7F2C-468A-976E-46640F87F44A}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {C5EB061D-426B-4B1E-8E65-A6336C46B8A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {C5EB061D-426B-4B1E-8E65-A6336C46B8A9}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {C5EB061D-426B-4B1E-8E65-A6336C46B8A9}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {C5EB061D-426B-4B1E-8E65-A6336C46B8A9}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {24F8BDDA-8FCE-46A9-AD04-AE2CF22A1CBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {24F8BDDA-8FCE-46A9-AD04-AE2CF22A1CBC}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {24F8BDDA-8FCE-46A9-AD04-AE2CF22A1CBC}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {24F8BDDA-8FCE-46A9-AD04-AE2CF22A1CBC}.Release|Any CPU.Build.0 = Release|Any CPU 48 | EndGlobalSection 49 | GlobalSection(SolutionProperties) = preSolution 50 | HideSolutionNode = FALSE 51 | EndGlobalSection 52 | GlobalSection(ExtensibilityGlobals) = postSolution 53 | SolutionGuid = {381BE8F1-D376-4664-9019-F51B6ED03893} 54 | EndGlobalSection 55 | EndGlobal 56 | -------------------------------------------------------------------------------- /RoadMap.txt: -------------------------------------------------------------------------------- 1 | - ASP.NET Core Application Lifecycle 2 | - https://docs.microsoft.com/en-us/aspnet/core/fundamentals/?view=aspnetcore-2.1&tabs=aspnetcore2x 3 | - .NET Core çalışma alt yapısı 4 | - MIL - JIT Compiler vs. 5 | 6 | - External class içinde database bağlantısı nasıl yapılır? 7 | - Burada yapılacak şeylerden biri, context kısmını direk olarak dışarıdan almak. 8 | - Kullanılacağı yerde db bağlantısı yapılıp buraya verilebilir. 9 | 10 | - Startup.cs içindeki metotların ayrıntılı anlamları 11 | - Giriş kısmındaki kullanılabilir paket yöneticileri notu tamamlanacak. 12 | - asp.net kısmına ado.net ile ilgili notlar eklenecek. 13 | 14 | - Settings dosyalarının yapılandırılması 15 | - https://www.c-sharpcorner.com/article/all-about-appsettings-json-in-asp-net-core-2-0/ 16 | - DB bağlantı stringinin appsettings içinden çekilmesi ve notlara eklenmesi 17 | 18 | - BundleConfig ayarlamalarının yapılması (db önceki notlar) 19 | 20 | - Program başlangıcında çalışacak metotlar oluşturma. 21 | 22 | - IApplicationBuilder, IHostingEnvironment, IServiceCollection metotlarının ayrıtıları. 23 | - WebHostBuilder ayarlamaları. 24 | - https://wildermuth.com/2017/07/06/Program-cs-in-ASP-NET-Core-2-0 25 | 26 | - Root dizini alma yöntemleri. wwwroot dizininin nasıl alınacağı? Bu dizinin publish edildiğinde root files olarak bulunup bulunmadığı 27 | 28 | - Formlar ile ilgili bir not oluşturulacak. 29 | - Form elemanları 30 | - Form elemanlarının ayrı ayrı olarak kullnaılması ile ilgili CEO çıkarımları 31 | - Bunla ilgili bir medium yazısı vardı. 32 | - Formlar üzerinden dosya gönderim örnekleri 33 | - Tag helperlar dahil edilebilir. 34 | - Formların post ve get ile gönderimleri 35 | - Form bilgilerinin arka planda çekilmesi 36 | - Bunlardan model binding ve normal yöntem arasıdaki fark. 37 | 38 | - DI Liftime 39 | - https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection#service-lifetimes-and-registration-options 40 | 41 | - RoadMap dosyası içinde konu listesi yazılacak. 42 | - Aralara projeler ve front end konuları yereştirilecek 43 | - Örnek proje planlaması yapılacak, projeler yapılıp yüklenebilir. 44 | 45 | - Projelere, ASP dışında ek konular eklenecek. 46 | - Github 47 | - PDF belgesi 48 | - TFS 49 | - Temiz kod yazma 50 | - https://hackernoon.com/tips-from-the-book-every-programmer-should-read-425fb77873f8 51 | - Youtube videosu 52 | 53 | - Scaffolding nedir? 54 | 55 | - IDesignTimeDbContext sınıfı araştırılacak. 56 | 57 | - Idendity Core ile ilgili not hazırlanacak 58 | - 155. Setting up Idendity Core notuna bir daha bakılacak. 59 | - Cookie Authentication In ASP.net Core 2.0 60 | 61 | - Metadata olarak UIHint araştırılacak. 62 | 63 | - dotnet CLI commands 64 | - https://docs.microsoft.com/en-us/dotnet/core/tools/?tabs=netcore2x 65 | 66 | - App Secure kısmına bakılacak 67 | - https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-2.0&tabs=aspnetcore2x#securing-the-app 68 | 69 | - Core ile Docker kullanımı 70 | - Vagrant üzerinde deployment 71 | - Azure ve Amazon üzerinde deployment 72 | - https://www.vagrantup.com/ 73 | - https://github.com/sprosin/vagrant-dotnet-core 74 | 75 | - microsoftun kendi kütüphanesine bakılacak referans olarak : 76 | - https://docs.microsoft.com/en-us/aspnet/core/index 77 | - https://docs.microsoft.com/en-us/ef/#pivot=efcore&panel=efcore-all 78 | - https://www.tektutorialshub.com/asp-net-core-tutorial/ 79 | 80 | // GENEL 81 | - Design patterns ( % Strategy Pattern ) 82 | - Class yapısındaki base yapısı 83 | - Derinlemesine C# ile ilgil araştırma yapılacak. 84 | - İsimlendirme kuralları 85 | - http://wiki.c2.com/?CapitalizationRules 86 | - Generic Ifadeler (T ve T ile kullanılan where kavramları) -------------------------------------------------------------------------------- /15 - Area Kavramı.md: -------------------------------------------------------------------------------- 1 | ## AREA KAVRAMI 2 | 3 | - Area'lar, farklı namespace'ler ile ayrılmış, kendine ait routing ayarlarına ve MVC yapısına sahip alanlardır. 4 | - Farklı amaçlar için farklı app gruplarına ihtiyacımız olduğu durumlarda kullanırız. 5 | - Örneğin, bir sitenin ayrı bir müşteri paneli, admin paneli vb varsa, bu yapılar ayrı ayrı arealar oluşturularak kullanılabilir. 6 | - Bir Core projesi içinde istenilen sayıda area açılabilir. 7 | - Büyük projelerin bağımsız parçalarını birbirinden ayırarak yönetilebilirliği kolaylaştırır. 8 | - Aynı isimle controller açılması, bu controller farklı arealar altında olduğu müddetçe sorun oluşturmaz. 9 | - Core, area içindeki bir view'ı render ederken, default olarak aşağıdaki yollara bakar : 10 | 11 | ```cs 12 | /Areas//Views//.cshtml 13 | /Areas//Views/Shared/.cshtml 14 | /Views/Shared/.cshtml 15 | ``` 16 | 17 | - Bu default yolları değiştirmek mümkündür. 18 | - Bunun için `Microsoft.AspNetCore.Mvc.Razor.RazorViewEngineOptions` üzerinden `AreaViewLocationFormats` kısmı override edilebilir. (Servise yapısı içinde) 19 | - Buradaki numaralandırma : 20 | - `{0}` > Action Name 21 | - `{1}` > Controller Name 22 | - `{2}` > Area Name 23 | 24 | ```cs 25 | services.Configure(options => 26 | { 27 | options.AreaViewLocationFormats.Clear(); 28 | options.AreaViewLocationFormats.Add("/Categories/{2}/Views/{1}/{0}.cshtml"); 29 | options.AreaViewLocationFormats.Add("/Categories/{2}/Views/Shared/{0}.cshtml"); 30 | options.AreaViewLocationFormats.Add("/Views/Shared/{0}.cshtml"); 31 | }); 32 | ``` 33 | 34 | ### 01 - Area Ayarlamalarının Yapılması 35 | 36 | - Area kullanımı için basit olarak iki adımlı bir ayarlama yapmak gerekmektedir. 37 | - Route ayarlaması 38 | - Controllers ayarlaması 39 | 40 | #### Route ayarlaması 41 | 42 | - Route ayarlaması için, yeni bir routeMap eklenmesi gerekmektedir. 43 | - Bu yeni ayarlamanın diğer alanlarla çakışmaması için onların üstünde olması daha sağlıklıdır. 44 | 45 | ```cs 46 | app.UseMvc(routes => 47 | { 48 | routes.MapRoute( 49 | name: "areaRoute", 50 | template: "{area:exists}/{controller=Home}/{action=Index}/{id?}"); 51 | 52 | routes.MapRoute( 53 | name: "default", 54 | template: "{controller}/{action}/{id?}", 55 | defaults: new { controller = "Home", action = "Index" }); 56 | }); 57 | ``` 58 | 59 | #### Controllers ayarlaması 60 | 61 | - Controller kullanımında, her controller sınıfının üstüne `Area` attribute'ü ile, hangi areaya ait olduğu belirtilmelidir. 62 | - Eğer bu ayarlama yapılmazsa, root dizinden türetilmiş gibi algılanır ve çakışma yaratır. 63 | 64 | ```cs 65 | namespace MyStore.Areas.Products.Controllers 66 | { 67 | [Area("Products")] 68 | public class HomeController : Controller 69 | { 70 | // GET: /Products/Home/Index 71 | public IActionResult Index() 72 | { 73 | return View(); 74 | } 75 | 76 | // GET: /Products/Home/Create 77 | public IActionResult Create() 78 | { 79 | return View(); 80 | } 81 | } 82 | } 83 | ``` 84 | 85 | ### 02 - Area Link Yaratma 86 | 87 | - Program içinde başka bir action'a link yaratırken kullanacağımız yöntemler şunlardır: 88 | - Örnek olarak gideceğimiz link : `/Products/Home/Index` 89 | 90 | - Aynı area ve controller, farklı action : 91 | - HtmlHelper: 92 | - `@Html.ActionLink("Go to Product's Home Page", "Index")` 93 | - TagHelper: 94 | - `Go to Product's Home Page` 95 | 96 | - Aynı area, farklı controller ve action : 97 | - HtmlHelper: 98 | - `@Html.ActionLink("Go to Product's Home Page", "Index", "Home")` 99 | - TagHelper: 100 | - `Go to Product's Home Page` 101 | 102 | - Farklı area, controller ve action : 103 | - HtmlHelper: 104 | - `@Html.ActionLink("Go to Product's Home Page", "Index", "Home", new {area = "Products"})` 105 | - TagHelper: 106 | - `Go to Product's Home Page` -------------------------------------------------------------------------------- /03 - Razor View Engine.md: -------------------------------------------------------------------------------- 1 | ## RAZOR VIEW ENGINE 2 | 3 | ### 01 - Razor Syntax 4 | - View Engine nedir? 5 | - View’lerinizi HTML çıktısı olarak render etmek için kullanılan bir mekanizma/teknoloji’dir. 6 | - Razor View Engine nedir? 7 | - Razor blogu açma ve Razor içinde C# kodlarının kullanımı 8 | - Razor blogu içindeki değişkenlere Razor dışından ulaşım 9 | - Razor açıklama satırı 10 | - Parantez içinde iki değişkenin birleştirilmesi 11 | - View içinde Razor ile döngülerin ve karar yapılarının kullanımı 12 | 13 | #### Razor içinde html yapısı kullanırken oluşan hatalar 14 | - Razor yapılarından biri kullanıldığında, hemen içine normal yazı yazıldığında bunu C# dili olarak algılar. Eğer yazdığımız bu kısım C# değilse bize hata verecektir. 15 | 16 | ```cs 17 | @if (true) 18 | { 19 | Lorem Ipsum // Bu kısım hata verecektir! 20 | } 21 | ``` 22 | 23 | - Bu hatayı vermemesini sağlamak için bir kaç yöntem vardır: 24 | - Bir html tagı kullanmak 25 | - `@:` Razor hata bastırma kodu kullanmak 26 | - ` ` taglarını kullanmak. 27 | 28 | ```html 29 | @if (true) 30 | { 31 | Lorem Ipsum 32 | 33 | @: Lorem Ipsum 34 | 35 | 36 | Lorem Ipsum 37 | Lorem Ipsum 38 | 39 | } 40 | ``` 41 | 42 | ### 02 - HTML Helpers 43 | - Html Helper'lar adından da anlaşılacağı gibi, html kodlarını kısa yoldan, metotlarla oluşturmamız için bize yardımcı olur. 44 | - Yazdığımız bu metotlar daha sonrasında render edilirken, normal html kodlarına çevilir. 45 | - **NOT! :** Yazdığımız tüm html helper'ların son çıktısı html'dir. 46 | - **Bu nedenle helpers'lar ile yapılan her şey, normal html ile de yapılabilir!** 47 | - **NOT2! :** ASP .NET Core ile Html Helper yapıları kısmen bulunsa da artık bu yapılar kullanılmamaktadır. Bunların yerine şu yeni yapılar kullılmaktadır: 48 | - TagHelpers 49 | - ViewComponents 50 | 51 | #### General Helpers 52 | - Html.ActionLink() 53 | - Html.Partial() 54 | 55 | #### URL Helpers 56 | - Html.ActionLink() 57 | - Url.Action() 58 | - Url helperların otomatik link oluşturması ve bunun önemi 59 | - .NET Core içinde bunlar yerine tag helperlar kullanılıyor. 60 | 61 | #### System.Net.WebUtility Helpers 62 | - .HtmlEncode() 63 | - .HtmlDecode() 64 | - .UrlEncode() 65 | - .UrlDecode() 66 | - Html.Raw() 67 | 68 | #### Form Helpers 69 | - Form elemanlarını oluşturmak için kullandığımız helper metotları. 70 | - Her elemanın aynı zamanda bir de model ile kullanıma olanak tanıyan `-for` son ekli başka bir metodu da var. 71 | - Form helpers'ların yerini Core 2.0'da `tag helpers`'lar almıştır. 72 | - Form helperslar: 73 | - Html.BeginForm() 74 | - Html.TextBox() - Html.TextBoxFor() 75 | - Html.Label() - Html.LabelFor() 76 | - ... 77 | - Html.BeginForm metodu kullanıldığında .NET Core'da otomatik olarak bir AntiForgeryToken oluşturulur. 78 | 79 | ### 03 - Custom Html Helpers 80 | - `IHtmlHelper` sınıfı içerisine extension metotlar yazarak istediğimiz custom helper'ları ekleyebiliriz. 81 | - Bunun için yapılması gereken adımlar şunlardır: 82 | - Bir klasör içinde ( Library ) class dosyası ( extensions ) oluşturulur. 83 | - Bu kısım zorunlu değil, fakat dosyaların düzgün bir düzende olması için böyle yapılması daha uygun olur. 84 | - Model static yapılmak zorunda 85 | - Class içine statik bir fonksiyon oluşturulur. 86 | - Fonksiyonun return’ü -> `IHtmlContent` 87 | - Fonksiyonun kalıtımı -> `this IHtmlHelper helper` 88 | - String olarak html hazırlanır. 89 | - `return new HtmlString( )` 90 | - Kullanılacak sayfada using ile Library klasörüne link verilir. 91 | 92 | ```cs 93 | namespace Project.Library.Helpers 94 | { 95 | public static class CustomHelper 96 | { 97 | public static IHtmlContent Submit(this IHtmlHelper helper, string value) 98 | { 99 | string html = $""; 100 | return new HtmlString(html); 101 | } 102 | } 103 | } 104 | ``` 105 | 106 | - - Html içinde kullanımı: 107 | 108 | ```html 109 | 110 | @using WebApplication1.Library.Helpers 111 | ... 112 | 113 |
    114 | @Html.Submit("Kaydet") 115 |
    116 | ``` -------------------------------------------------------------------------------- /09 - Database CRUD İşlemleri.md: -------------------------------------------------------------------------------- 1 | ## DATABASE CRUD İŞLEMLERİ 2 | 3 | ### Controller 4 | 5 | ```cs 6 | using Microsoft.AspNetCore.Mvc; 7 | using Project.Models.Entities; 8 | using Project.Models.Interfaces; 9 | 10 | namespace Project.Controllers 11 | { 12 | public class HomeController : Controller 13 | { 14 | private IPersonRepository context; 15 | 16 | public HomeController(IPersonRepository repo) 17 | => context = repo; 18 | 19 | public IActionResult Index() 20 | => View(context.Persons); 21 | 22 | public IActionResult Create() 23 | => View(); 24 | 25 | [HttpPost] 26 | public IActionResult Create(Person person) 27 | { 28 | context.CreatePerson(person); 29 | return RedirectToAction("Index"); 30 | } 31 | 32 | public IActionResult Edit(int id) 33 | => View(context.GetById(id)); 34 | 35 | [HttpPost] 36 | public ActionResult Edit(Person person) 37 | { 38 | context.UpdatePerson(person); 39 | return RedirectToAction("Index"); 40 | } 41 | 42 | public ActionResult Delete(int id) 43 | { 44 | context.DeletePerson(id); 45 | return RedirectToAction("Index"); 46 | } 47 | } 48 | } 49 | ``` 50 | 51 | ### Views 52 | 53 | #### Index.cshtml 54 | 55 | ```html 56 | @model IEnumerable 57 | 58 | 59 | 60 | 61 | 62 | 63 | Index 64 | 65 | 66 | 67 |
    68 | Create 69 |
    70 | 71 | @foreach (var item in Model) 72 | { 73 |
    74 | @item.Name - 75 | @item.Surname - 76 | @item.Age - 77 | Edit - 78 | Delete 79 |
    80 | } 81 | 82 | 83 | ``` 84 | 85 | #### Create.cshtml 86 | 87 | ```html 88 | @model Person 89 | 90 | 91 | 92 | 93 | 94 | 95 | Create 96 | 97 | 98 | 99 |
    100 | 101 | 102 |
    103 | 104 | 105 |
    106 | 107 | 108 |
    109 | 110 | 111 |
    112 | 113 | 114 | 115 | ``` 116 | 117 | #### Edit.cshtml 118 | 119 | - Update işlemleri yapılırken, Crate html dosyasından farklı olarak, ID property'sinin hidden olarak alınacağı unutulmamalıdır. 120 | - Update yapılırken, update yapılacak db elemanı bu gelen ID'ye göre bulunur. 121 | - Eğer ID kısmını hidden olarak formdan göndermezsek, ID = 0 olarak gidecektir ve güncelleme yapılmayacaktır. 122 | - Update işleminde post edilen nesne içinde, sadece form içinde çağırılan elemanların gönderileceği unutulmamalıdır. 123 | - Örneğin `CreatedDate`, `IsActive` gibi property'ler varsa ve biz bunları form içinden göndermezsek, bu kısımların default değeri alınarak gönderilen nesne oluşturulur ve update yapıldığında eski değerler yerine bu default değerler gelir. 124 | - Bu durumda bizim db üzerinde istenmeyen değişiklikler yapılmasına neden olur. 125 | - Bu sorunu çözmek için iki yöntem vardır: 126 | 1. Form içinine bu parametreler hidden olarak gönderilir, böylece yeni nesne oluşurken, bu bilgiler eskisiyle aynı olarak gönderilecektir. 127 | 2. Update yapılırken `_context.Update(person);` fonksiyonunu kullanmak yerine, gelen ID'ye göre db elemanı çekilip sadece ilgili alanlar replace edilerek tekrar db'ye gönderilir. 128 | 129 | ```html 130 | @model Person 131 | 132 | 133 | 134 | 135 | 136 | 137 | Create 138 | 139 | 140 | 141 |
    142 | 143 | 144 | 145 | 146 |
    147 | 148 | 149 |
    150 | 151 | 152 |
    153 | 154 | 155 |
    156 | 157 | 158 | 159 | ``` 160 | 161 | #### SQL Sorgusu Çalıştırma 162 | 163 | - .NET üzerinde, LinQ ile yapılan işlemler sınırlı kaldığında, direk SQL komutları çalıştırılabilir. 164 | - Bunun için `.Database.ExecuteSqlCommand()` metodunu kullanıyoruz. 165 | - Metot, geri dönüş olarak `int` tipinde, üzerinde değişiklik yapılan `row` sayısını döndürür. 166 | - Hata olması durumunda `SqlException` fırlatır. 167 | - **NOT:** Bu yöntem kullanılırken `SQLInjection` açığı yaratmamasına dikkat edilmelidir! 168 | 169 | ```cs 170 | public int DeletePersonWithSQLCommand(int personID) 171 | { 172 | string cmd = $"DELETE FROM Persons WHERE ID={personID}"; 173 | return efProjectContext.Database.ExecuteSqlCommand(cmd); 174 | } 175 | ``` -------------------------------------------------------------------------------- /06 - Controller ve View Arasındaki İletişim.md: -------------------------------------------------------------------------------- 1 | ## CONTROLER VE VİEW ARASI İLETİŞİM 2 | 3 | ### 1) Controller'dan View'e Veri Gönderme 4 | - 3 Yöntem vardır: 5 | - `ViewData` 6 | - Daha sonra daha kolay kullanım için `ViewBag` yapısına geçmiştir. 7 | - `ViewDataDictionary` yapısındadır. 8 | - `ViewBag` 9 | - Controller'dan bilgilerin View üzerine gönderilmesi için kullanılır. 10 | - Arka planda `ViewData` kullanır. 11 | - `Dynamic` yapıdadır. 12 | - Okunduğu zaman veri tipini kazanır. 13 | - Bu yapısı nedeniyle kullanıldığı zaman tür dönüşümü yapılması *zorunlu değildir.* 14 | - Süresi yoktur, sadece view'a kadar ilerleyebilir. 15 | - `TempData` 16 | - `ITempDataDictioanry` yapısındadır. 17 | - Bilgileri, okunana kadar saklar. 18 | - Okuma yapıldıktan sonra `silinecek` olarak işaretlenip, **request sonunda** silinir. 19 | - `Silinecek` olarak işaretlenmesini engellemek için `Peek()`, işaretlendikten sonra işaretini kaldırmak için `Keep()` metotları kullanılabilir. 20 | - Saklanması: 21 | - `CookieTempDataProvider` nesnesi yaratılır. 22 | - Bu nesne `Base64UrlTextEncoder` ile encode edilir. 23 | - Encode edilen nesne default olarak `Cookie`'de saklanır. 24 | - `Cookie-Based TempData Provider` default gelir, istenilirse bu yapı, `Session-Based TempData Provider` olarak değiştirilebilir. 25 | 26 | ```cs 27 | public void ConfigureServices(IServiceCollection services) 28 | { 29 | // Session-Based 30 | services.AddMvc().AddSessionStateTempDataProvider(); 31 | 32 | // Cookie-Based (Default) 33 | // services.AddMvc().AddCookieTempDataProvider(); 34 | 35 | services.AddSession(); 36 | } 37 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 38 | { 39 | app.UseSession(); 40 | app.UseMvcWithDefaultRoute(); 41 | } 42 | 43 | ```cs 44 | //second request, PEEK value so it is not deleted at the end of the request 45 | object value = TempData.Peek("value"); 46 | 47 | //third request, read value and mark it for deletion 48 | object value = TempData["value"]; 49 | ``` 50 | 51 | ```cs 52 | //second request, get value marking it from deletion 53 | object value = TempData["value"]; 54 | //later on decide to keep it 55 | TempData.Keep("value"); 56 | 57 | //third request, read value and mark it for deletion 58 | object value = TempData["value"]; 59 | ``` 60 | 61 | ### 2) View’dan Controller’a Veri Gönderme 62 | - View'dan Controller'a veri gönderim 3 şekilde olur (Request): 63 | - 1. Route Values : `/Course/Details/2` 64 | - 2. Query String : `/Course/Details?ID=2` 65 | - 3. Form Data : `ID=2` 66 | - GET ve POST Yöntemleri 67 | - GET Metodu: 68 | - Raw request içinde url içinde taşınır. 69 | - Query String yapısındadır. 70 | - POST Metodu: 71 | - Raw request içinde body kısmında taşınır. 72 | - Form Data yapısındadır. 73 | - GET ve POST ile gönderilen veriler, action üzerinden nasıl alınır. 74 | - Her iki metotla gönderilen veri de, parametre olarak alınabilir. 75 | - Parametre olarak almanın dışında her iki metotla gelen bilgi de `Request` üzerinde taşındığı için, bu sınıf içinden alınabilir. 76 | - GET -> `Request.Query["key"]` 77 | - POST -> `Request.Form["key"]` 78 | - Route -> `RouteData.Values["key"]` 79 | 80 | ```html 81 | 82 |
    83 |
    84 |
    85 |
    86 | 87 |
    88 | ``` 89 | 90 | ```cs 91 | // Metot 01 92 | [HttpPost] 93 | public ActionResult GetInfo() 94 | { 95 | string name = Request.Form["name"]; 96 | string surname = Request.Form["surname"]; 97 | int age = int.Parse(Request.Form["age"]); 98 | return RedirectToAction("Index"); 99 | } 100 | ``` 101 | 102 | ```cs 103 | // Metot 02 104 | [HttpPost] 105 | public ActionResult GetInfo(string name, string surname, int age) 106 | { 107 | return RedirectToAction("Index"); 108 | } 109 | ``` 110 | 111 | - If( IsPost ) Kullanımı 112 | - Using ( Html.BeginForm ) Kullanımı 113 | - Başka bir controller'a veri gönderme yöntemi 114 | 115 | #### AntiForgeryToken Kontrolü 116 | - [XSRF/CSRF](https://docs.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.0) zaafiyetlerini engellemek için kullanılan yöntemdir. 117 | - Bu yöntem kullanıldığında, form client tarafına gönderilirken bir token oluşturulur ve bu token session üzerinde kaydedilir. 118 | - Kullanıcı formu post ettiğinde, bu token app tarafına gönderilir. 119 | - Controller çalışmadan önce bu token'ın, session üzerinde kaydedilen token ile eşleştirilmesi yapılır. Eğer token uyumsuz ise geçişe izin verilmez. 120 | - Böylece başka bir sayfadan veya harici olarak form gönderimi engellenmiş, sadece uygulamının render edip gönderdiği html üzerindeki form gönderimi kabul edilmiş olunur. 121 | - Bu yöntemi kullanmak için yapılması gereken şudur: 122 | - Öncelikle html tarafındaki form içine bir `__RequestVerificationToken` adında bir token üretilmelidir. 123 | - Eğer projeye `TagHelpers`'lar dahilse, form tagları açılıp **form metodu post olarak işaretlenirse** bu token otomatik olarak üretilir. 124 | - Eğer TagHelper'lar kullanılmıyorsa, htmlde form taglarının arasına `@Html.AntiForgeryToken()` yazılarak, Html Helper'lar yardımıyla bu token üretilebilir. 125 | - Daha sonra bu formun post edildiği controller üzerinde attribute olarak şu satır eklenir. Bu attribute'ün amacı, token kontrolü yapıp, uyumsuzluk durumda controller'a erişimi engellemektir. 126 | - `[ValidateAntiForgeryToken]` -------------------------------------------------------------------------------- /11 - View Components.md: -------------------------------------------------------------------------------- 1 | ## VIEW COMPONENTS 2 | 3 | - Daha önceki .NET Framework sürümünde kullanılan `Partial View` yapısına benzer fakat biraz daha esnek ve geniş kullanım özellikleri sunan yapıdır. 4 | - `Partial View` kavramı .NET Core sürümünde halen olsa da, daha kullanışlı olması nedeniyle `View Components` yapısını kullanmayı tercih ederiz. 5 | - Buradaki temel mantık, bir kere yazılan html parçasının, modelli veya modelsiz (dinamik veya statik) bir yapıda tekrar tekrar kullanılmasını sağlamaktır. Bu sayede, bu html parçasında yapılan tek bir değişiklik, bu parçanın kullanıldığı tüm yerlerde değişecektir. 6 | - View Componentleri, View yapısının fonksiyonları gibi düşünebiliriz. Parametre alabilen ve geriye html döndüren bir yapısı vardır. 7 | - View Components kullanmak `DRY` prensibi gereği kod tekrarının önleyecektir. 8 | - View Componentler, parametre alımına izin verir, bu Partial View'da olmayan bir özelliktir. 9 | - Componentler, direk olarak `Layout` içinde kullanılabilir. Bu kullanım için, View dosyalarının shared dizini altında bulunması gereklidir. 10 | 11 | ### 01 - View Component Oluşturma 12 | 13 | - Projemiz içinde bir class oluşturuyoruz. 14 | - Class'ı bir klasör içinde oluşturmamız projenin toplu durması açısından daha iyi olur. 15 | - Açtığımız class yapısının component olduğunu belirtmek için üç yol vardır : 16 | 1. Herhangi bir isimle oluşturulup `ViewComponent` sınıfından kalıtım verebiliriz. 17 | 2. Herhangi bir isimle oluşturulup `[ViewComponent]` attribute'ü eklenebilir. 18 | 3. İsimlendirme yaparken isminin sonuna `-ViewComponent` ekleyebiliriz. 19 | - Her üç durumda da, oluşturduğumuz class artık bir View Component olacaktır. 20 | - **NOT:** Bu üç durumdan sadece 1. durumda View Component `View()` döndürecektir. Bu sınıfın özelliklerine ulaşabilmek için en doğru olan metot kalıtım vermektir. 21 | - View Component sınıfı, Controller sınıflarında olduğu gibi; public, non-nested ve non-abstract olmalıdır. 22 | - Oluşturduğumuz component sınıfı içinde bir tane `Invoke()` adlı metot oluşturuyoruz. 23 | - Component'i çağırdığımız zaman çalışan ve bize geri dönüş veren metot bu metottur. 24 | 25 | ```cs 26 | public class Hello : ViewComponent 27 | { 28 | public string Invoke() 29 | { 30 | return "Hello World!"; 31 | } 32 | } 33 | ``` 34 | 35 | ### 02 - Oluşturulan View Component'i View İçinde Kullanma 36 | 37 | - View Component'i çağırmak için `Component.InvokeAsync()` metodunu `await` olarak çağırmak yeterlidir. 38 | 39 | ```cs 40 | @await Component.InvokeAsync("Hello") 41 | ``` 42 | 43 | **NOT:** Componentler, Controller içinden de direk olarak return edilebilirler: 44 | 45 | ```cs 46 | public IActionResult IndexVC() 47 | { 48 | return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false }); 49 | } 50 | ``` 51 | 52 | ### 03 - ViewComponent Result Türleri 53 | 54 | - ViewComponent sınıfı içindeki Invoke() metodunun genel geri dönüş tipi `IViewComponentResult`'tur. Bunun dışında aşağıdaki gibi bilinen C# veri türleri döndürlürse, bu tipler de geri dönüş tipi olarak verilebilir. 55 | 56 | #### Bilinen türleri döndürme 57 | 58 | - Yazılan `Invoke()` metodu sonucunda, C# yapısındaki bilinen türleri döndürebilir. Örn: string, int, double vs. 59 | 60 | ```cs 61 | public class Hello : ViewComponent 62 | { 63 | public string Invoke() 64 | { 65 | return "Hello World!"; 66 | } 67 | } 68 | ``` 69 | 70 | #### Html Döndürme 71 | 72 | - String olarak veri döndürdüğümüzde ve bunu view içinde kullandığımda, html taglarının string olarak algılanıp biçimlendirme yapılmadığını görürüz. Bunların html olarak algılanması için `HtmlString` türünde bir geri dönüş kullanmamız gerekmektedir. 73 | 74 | ```cs 75 | [ViewComponent] 76 | public class Hello 77 | { 78 | public HtmlString Invoke() 79 | { 80 | return new HtmlString("Hello World!"); 81 | } 82 | } 83 | ``` 84 | 85 | #### ViewComponent ile View Döndürme 86 | 87 | - ViewCompoenentler, Invoke metotları içinde statik veya model ile dinamik bir view döndürebilirler. 88 | - Oluşturulacak view dosyalarının aranacağı dizinler : 89 | - `Views//Components//` 90 | - `Views/Shared/Components//` 91 | - **NOT:** Eğer return edilen View() metodu içinde, html dosyasının adı belirtilmemişse, default olarak arayacağı view ismi `default.cshtml`'dir. 92 | 93 | ```cs 94 | public IViewComponentResult Invoke(){ 95 | return View(); // Default.cshtml dosyasını arar 96 | } 97 | 98 | public IViewComponentResult Invoke(){ 99 | return View("foo"); // foo.cshtml dosyasını arar 100 | } 101 | ``` 102 | 103 | - View Component'lerde View ile model kullanımı, Views'larda olduğu gibidir. 104 | - Örnek vermek gerekirse: 105 | 106 | ```cs 107 | // View Component Sınıfı 108 | using Microsoft.AspNetCore.Mvc; 109 | using System.Collections.Generic; 110 | 111 | namespace Project.Library.Components 112 | { 113 | public class SideBar : ViewComponent 114 | { 115 | public IViewComponentResult Invoke() 116 | { 117 | var model = new Dictionary(); 118 | for (int i = 0; i < 5; i++) 119 | model.Add($"www.example{i}.com", $"Web Site {i}"); 120 | 121 | return View(model); 122 | } 123 | } 124 | } 125 | ``` 126 | 127 | ```html 128 | 129 | @model Dictionary 130 | 131 |

    Side Bar

    132 |
      133 | @foreach (var key in Model.Keys) 134 | { 135 |
    • @Model[key]
    • 136 | } 137 |
    138 | ``` 139 | 140 | ```html 141 | 142 | @await Component.InvokeAsync("SideBar") 143 | 144 | 156 | ``` 157 | 158 | ### 04 - ViewComponent Üzerine Parametre Gönderme 159 | 160 | ```cs 161 | // Component Model 162 | public HtmlString Invoke(string message) 163 | { 164 | return new HtmlString($"{message}"); 165 | } 166 | 167 | // Html 168 | @await Component.InvokeAsync("Hello", new { message = "Test Message" }) 169 | ``` 170 | -------------------------------------------------------------------------------- /19 - ASP.NET Core In-Depth - Dependecy Injection.md: -------------------------------------------------------------------------------- 1 | ## DEPENDENCY INJECTION NEDİR? 2 | 3 | #### DI Nedir ? 4 | 5 | - Bir sınıfın bağımlı olduğu sınıfların, bu sınıfın içine dışarıdan enjekte edilmesi işlemidir. 6 | - Temel amaç, sınıfın bağımlılığını ortadan kaldırmaktır. 7 | - Nesne tabanlı programanın en önemli prensiplerinden biri olan SOLID ilkesinin içinde bulunur. 8 | 9 | #### Var olan bir kodu neden değiştirmek istemeyiz? 10 | 11 | - Program içindeki bir kodu zorunlu kalmadıkça değiştirmek istemeyiz. 12 | - Bunun en büyük nedeni, mevcut kodun uzun zamandır test edilmiş ve sorunları devamlı düzeltilmiş olup, yapacağınız ufak değişiklikler bile, hem kodu hem de bağlı olan yapıları tekrar test etmeyi gerektirecektir. 13 | - Eğer yazdığımız unit testler yeterince kapsamlı değilse, kodun güvenirliliğine emin olmak için, uzun bir süre daha kullanıp hatalarını gidermek gerekecektir. 14 | - Bunun içindir ki SOLID prensiplerinden bir tanesi de Open/Closed Principle (OCP) olarak geçmektedir. OCP kısaca bir kod değişime kapalı ama genişletmeye açık olmalıdır demektir. Yani bir koda yeni şeyler ekleyebilirsiniz, mesela yeni sınıflar gibi. Ama var olan sınıfları ve sınıflar içinde ki methodların içeriğini değiştirmeniz yukarıda açıkladığım sebeplerden dolayı çoğu zaman tavsiye edilmez. 15 | - DI ile bağımlılıklar genel olarak ortadan kaldırıldığı için, genişletilebilirlik ve her genişletmenin bağımsız olarak test edilebilirliği sağlanmış olur. 16 | 17 | #### DI Kullanmadan programlama 18 | 19 | - Örnek olarak elimizde aşağıdaki gibi bir sınıf olsun. 20 | 21 | ```cs 22 | public class Creator { 23 | 24 | private Checker _checker = new Checker(); 25 | // işlemler 26 | } 27 | 28 | // veya aynı class'ı constructor ile yazarsak; 29 | 30 | public class Creator { 31 | 32 | private Checker _checker; 33 | 34 | public Creator() { 35 | _checker = new Checker(); 36 | } 37 | // işlemler 38 | } 39 | ``` 40 | 41 | - Yukarıdaki sınıf incelenirse, dışarıdan `Checker` adında başka bir sınıftan türeyen nesneye sahip. Yani bu sınıfa bağlı. 42 | - Eğer ileride farklı bir checker kullanılmak isteniyorsa veya birden fazla müşteri için birden fazla checker yazmak gerekiyorsa, yapılabilecek iki çözüm yolu vardır : 43 | 1. olarak, Checker adlı sınıf değiştirilebilir. 44 | - Böyle bir değişim yapılırsa, eski sınıfın bilgilerinin üzerine override edilmesi gerektiği gibi, yeniden kodun test edilmesi ve bağlı yapılarla uyumunun kontrol edilmesi gerekmektedir. 45 | - Üstelik böyle bir düzenlemenin geri dönüşü olmayacaktır, çünkü eski yapı silinip yeni bir yapıya geçilmiştir. 46 | 2. olarak, Checker benzeri başka sınıflar oluşturulabilir ( Öneğin; NetChecker, AISChecker vb. ). 47 | - Böyle bir durumda, Creator sınıfı ve buna benzer Checker sınıfından kalıtım alan diğer tüm sınıflar içinde değişiklik yapılmalıdır. 48 | - Bu durum önceki duruma göre geri dönüşüme izin verir, fakat birden çok class yapısı etkilendiği için sağlıklı değildir. Üstelik gözden kaçırılan bağımlılıkların olmaması için, tüm bağımlı sınıfların loglarının tutulması da gereklidir. 49 | - Bunlar dışında oluşturulacak yeni sınıfların belli bir düzenini tutturmak zor olacaktır ve eksik metot veya property ekleme olasılığı artacaktır. Bu da sınıfı kullanan diğer yerlerdeki hata olasılığını arttıracaktır. 50 | 51 | #### Interface kullanarak programlama 52 | 53 | - Türetilen sınıfların belli bir düzende olmasını ve hepsinde ortak property ve metotların olmasını sağlamak için interface'ler kullanılır. 54 | - Interface'lerin implament edildiği tüm sınıflar aynı düzende olacaktır. 55 | 56 | ```cs 57 | public interface IChecker 58 | { 59 | bool Exists(AccountNumber accountNumber); 60 | } 61 | 62 | public class DatabaseAccountChecker: IChecker {} 63 | 64 | public class AzureAccountChecker: IChecker {} 65 | 66 | public class XmlAccountChecker: IChecker {} 67 | ``` 68 | 69 | - Creator sınıfını artık aşağıdaki gibi yazabiliriz: 70 | 71 | ```cs 72 | public class Creator { 73 | 74 | private IChecker _checker; 75 | 76 | public Creator() { 77 | _checker = new DatabaseAccountChecker(); 78 | } 79 | // işlemler 80 | } 81 | ``` 82 | 83 | - Bu durumda sadece ctor içindeki nesneyi değiştirmemiz yeterli olacaktır. 84 | - Bu şekilde yeni sınıflar için düzen sağlanmış ve bağımlılık kısmen azaltılmış olacaktır. 85 | - Fakat bu durumda bile halen Creator sınıfı IChecker interface'inden türetilen sınıflara bağımlı durumdadır. 86 | 87 | #### Dependency Injection kullanarak programlama 88 | 89 | - Oluşturacağımız sınıflarda, interface'ler dışında başka hiçbir sınıfa bağımlılık bulunmamalıdır. 90 | - Yukarıdaki kodları aşağıdaki gibi değiştirebilir: 91 | 92 | ```cs 93 | public class Creator { 94 | 95 | private IChecker _checker; 96 | 97 | public Creator(IChecker checker) { 98 | _checker = checker; 99 | } 100 | // işlemler 101 | } 102 | ``` 103 | 104 | - Son durumda, sınıf içinde interface dışında herhangi bir bağımlılık bulunmamaktadır. 105 | - Interface'ten türetilen sınıflar, Creator sınıfı kullanıldığında (ctor metot parametresi olarak tanımlandığından) dışarıdan zorunlu olarak girilmesi istendiğinden, her kullanıldığı yerde parametre olarak almak zorundadır. 106 | - Fakat DI kütüphaneleri kullanarak (örn: Ninject DI framework), global olarak bu ilişkilendirme işlemi yapılabilir. Örneğin, her `IChecker` interface'i kullanıldığı zaman `DatabaseAccountChecker` sınıfından bir nesne gönder gibi. 107 | - Bu kütüpnanelere örnek olarak [Ninject](http://www.ninject.org/) verilebilir. Ayarlaması basit olarak aşağıdaki gibidir: 108 | 109 | ```cs 110 | public class CheckerModule : NinjectModule 111 | { 112 | public override void Load() 113 | { 114 | this.Bind().To(); 115 | } 116 | } 117 | ``` 118 | 119 | - .NET Core içinde DI otomatik olarak gelir ve `Startup.cs` içinde birleştirme yapılabilir. 120 | - Örnek olarak `IPersonRepository` interface'i ile `SQLPersonRepository` sınıfı birleştirilmek isteniyorsa, aşağıdaki gibi bir kod, `Startup.cs` içine eklenir. 121 | 122 | ```cs 123 | services.AddTransient(); 124 | ``` 125 | 126 | ### Sonuç : DI Faydaları 127 | 128 | - Projede somut sınıflar üzerine olan bağımlılığı azaltacaktır ve dolayısıyla genel olarak bakımın daha kolay olmasını sağlayacak. 129 | - Daha düzgün tasarlanmış modüller arası dependency tree’ye sahip olacaksınız. 130 | - Programda istenilen sınıfların rahatlıkla değiştirilmesine yardımcı olacak. Çünkü bağımlılık olmadığı için bir sınıf yerine başka bir sınıf kullanmak istediğinizde değiştirmek zorunda olacağınız kod miktarı ya sıfır yada çok daha az olacak. 131 | - Uygulama çalışma anında sizlere daha rahat configuration yapma şansı tanıyacak. Mesela, XML kullanarak hangi interface ile hangi sınıfın birbirlerine bağlı olacağını kolayca tanımlayabilirsiniz. Bu farklı müşterilen farklı isteklerini kodunuzu değiştirmek zorunda kalmadan rahatlıkla sunabilmeniz demektir. 132 | - Hangi sınıfları kullanacağınızı bir yerden kontrol etmiş olacaksınız. 133 | - Belkide en önemlisi çok daha rahat Unit Test ler yazmanızı sağlamış olacağı. İstediğiniz sınıfı rahatlıkla mock ederek farklı kod kısımlarını test edebileceksiniz. -------------------------------------------------------------------------------- /22 - ASP.NET Core In-Depth - ORM Mimarileri.md: -------------------------------------------------------------------------------- 1 | ## BAĞLI TABLOLARIN ÇEKİLMESİ İÇİN KULLANILAN ORM DESENLERİ 2 | 3 | - Entity Framework Core ile database üzerinde sorgu işlemleri yapılırken, bağlı tablolar otomatik olarak gelmez 4 | - Kullanılan desenler 3 tanedir: 5 | - **Eager Loading** 6 | - Sorgu içinde bağlı tabloların gelmesini sağlar. 7 | - **Explicit Loading** 8 | - Bağlı tabloların daha sonra sorgu içine yüklenmesini sağlar 9 | - **Lazy Loading** 10 | - Bağlı tabloların sanal olarak yüklenmesini ve istendiğinde dahil edilmesini sağlar. 11 | 12 | ### 01 - Eager Loading 13 | 14 | #### Bağlı tabloyu eklemek 15 | 16 | - Sorgu içine bağlı tabloları da dahil etmek için `Include` fonksiyonu kullanılır. 17 | - Bu fonksiyon .NET Core üzerinde yazılırken otomatik olarak çıkmayacağından aşağıdaki using ifadesine ihtiyaç duyar. 18 | - `using Microsoft.EntityFrameworkCore;` 19 | 20 | ```cs 21 | using (var context = new BloggingContext()) 22 | { 23 | var blogs = context.Blogs 24 | .Include(blog => blog.Posts) 25 | .ToList(); 26 | } 27 | ``` 28 | 29 | - Birden fazla `Include()` ifadesi aynı sorgu içinde kullanılabilir. 30 | 31 | ```cs 32 | using (var context = new BloggingContext()) 33 | { 34 | var blogs = context.Blogs 35 | .Include(blog => blog.Posts) 36 | .Include(blog => blog.Owner) 37 | .ToList(); 38 | } 39 | ``` 40 | 41 | #### Bağlı tabloların bağlı tablolarını eklemek 42 | 43 | - Sorgumuzu çektiğimiz tablonun bağlı tablolarının da bağlı olduğu tabloları çekmek istiyorsak, kullanmamız gereken yapı `ThenInclude()` metodudur. 44 | 45 | ```cs 46 | using (var context = new BloggingContext()) 47 | { 48 | var blogs = context.Blogs 49 | .Include(blog => blog.Posts) 50 | .ThenInclude(post => post.Author) 51 | .ToList(); 52 | } 53 | ``` 54 | 55 | - İstenilen tablo yapısına ulaşana kadar, istenilen kadar `ThenInclude()` metodu kullanılabilir. 56 | 57 | ```cs 58 | using (var context = new BloggingContext()) 59 | { 60 | var blogs = context.Blogs 61 | .Include(blog => blog.Posts) 62 | .ThenInclude(post => post.Author) 63 | .ThenInclude(author => author.Photo) 64 | .ToList(); 65 | } 66 | ``` 67 | 68 | - `Include()` ve `ThenInclude()` metotları birlikte combine edilebilir. 69 | 70 | ```cs 71 | using (var context = new BloggingContext()) 72 | { 73 | var blogs = context.Blogs 74 | .Include(blog => blog.Posts) 75 | .ThenInclude(post => post.Author) 76 | .ThenInclude(author => author.Photo) 77 | .Include(blog => blog.Owner) 78 | .ThenInclude(owner => owner.Photo) 79 | .ToList(); 80 | } 81 | ``` 82 | 83 | #### Sonradan tablo bağlama 84 | 85 | - Bir sorgu yaptıktan sonra, bağlı tablolar istenildiği zamanda çekilebilir. Bu duruma `ayrık sorgulama` denir. 86 | - Ayrık sorgulama yapılırken, ihtiyaç olduğu yerde, lazım olan tabloların sorgulaması yapılıp, context nesnesi üzerine `Load()` metoduyla eklenir. 87 | - EF bu eklemeyi otomatik olarak algılayıp tabloları bağlar. 88 | 89 | ```cs 90 | // Single Query 91 | var addresses = _context.Addresses.Include(k => k.Persons); 92 | foreach (var address in addresses) 93 | { 94 | foreach (var person in address.Persons) 95 | { 96 | liste.Add(person.Name); 97 | } 98 | } 99 | ``` 100 | 101 | ```cs 102 | // Separated Query 103 | var addresses = _context.Addresses; 104 | foreach (var address in addresses) 105 | { 106 | _context.Persons.Where(k => k.AddressID == address.ID).Load(); 107 | foreach (var person in address.Persons) 108 | { 109 | liste.Add(person.Name); 110 | } 111 | } 112 | ``` 113 | 114 | ### 02 - Explicit Loading 115 | - Sorgulama esnasında bağlı tabloların çekilmeyip, gerektiği yerde sorgunun tekrar yapılıp bağlı tabloların çekilmesine dayalı sorgulama biçimidir. 116 | - Eager Loading'teki ayrık sorgulamaya benzer bir yapıda, db üzerine birden fazla sorgu gönderir. Tek farkı kod yapısındadır. 117 | - EF Core 1.1 sürümü ve sonrasında desteklenmektedir. 118 | 119 | ```cs 120 | // Example 1 121 | var addresses = _context.Addresses; 122 | foreach (var address in addresses) 123 | { 124 | _context.Entry(address).Collection(k => k.Persons).Load(); 125 | foreach (var person in address.Persons) 126 | { 127 | liste.Add(person.Name); 128 | } 129 | } 130 | ``` 131 | 132 | ```cs 133 | // Example 2 134 | using (var context = new BloggingContext()) 135 | { 136 | var blog = context.Blogs 137 | .Single(b => b.BlogId == 1); 138 | 139 | context.Entry(blog) 140 | .Collection(b => b.Posts) 141 | .Load(); 142 | 143 | context.Entry(blog) 144 | .Reference(b => b.Owner) 145 | .Load(); 146 | } 147 | ``` 148 | 149 | - Explicit Loading ile bağlı tablolar sorgulandığında, sadece sorgu sonrasında geri dönen değerler ram üzerinde depolanır ve tüm bağlı tablo verileri depolanmaz. 150 | 151 | ```cs 152 | using (var context = new BloggingContext()) 153 | { 154 | var blog = context.Blogs 155 | .Single(b => b.BlogId == 1); 156 | 157 | var postCount = context.Entry(blog) 158 | .Collection(b => b.Posts) 159 | .Query() 160 | .Count(); // => Bu işlem sonucunda sadece sayısal değer ataması yapılır. 161 | } 162 | ``` 163 | 164 | ```cs 165 | using (var context = new BloggingContext()) 166 | { 167 | var blog = context.Blogs 168 | .Single(b => b.BlogId == 1); 169 | 170 | var goodPosts = context.Entry(blog) 171 | .Collection(b => b.Posts) 172 | .Query() 173 | .Where(p => p.Rating > 3) 174 | .ToList(); 175 | // => Bu işlem sonucunda sadece değeri 3ten büyük 176 | // olan değerler çekilip ram üzerine yazılır. 177 | } 178 | ``` 179 | 180 | ### 03 - Lazy Loading 181 | - Sorgu ilk yapıldığında, bağlı tablolar çekilmez. 182 | - Bağlı tablolara ait property'lere ilk ulaşılmaya çalışıldığı zaman, database sorgusu otomatik olarak gerçekleştirilir ve bağlı tablo bilgileri çekilir. 183 | - Bağlı tablolara her ulaşılmaya çalışıldığı ilk sefer, ayrı bir sorgu ile database sorgusu yapılır. 184 | - Lazy loading kullanmak için [Microsoft.EntityFrameworkCore.Proxies](https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Proxies/) paketi projeye dahil edilmeli ve `UseLazyLoadingProxies` aktif edilmelidir. 185 | 186 | ```cs 187 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 188 | => optionsBuilder 189 | .UseLazyLoadingProxies() 190 | .UseSqlServer(myConnectionString); 191 | ``` 192 | 193 | - Veya AddDbContext kullanılıyorsa; 194 | 195 | ```cs 196 | .AddDbContext( 197 | b => b.UseLazyLoadingProxies() 198 | .UseSqlServer(myConnectionString)); 199 | ``` 200 | 201 | - Lazy loading kullanıldığında tüm bağlı tablolar `virtual` olarak tanımlanmalıdır. 202 | 203 | ```cs 204 | public class Blog 205 | { 206 | public int Id { get; set; } 207 | public string Name { get; set; } 208 | 209 | public virtual ICollection Posts { get; set; } 210 | } 211 | 212 | public class Post 213 | { 214 | public int Id { get; set; } 215 | public string Title { get; set; } 216 | public string Content { get; set; } 217 | 218 | public virtual Blog Blog { get; set; } 219 | } 220 | ``` 221 | 222 | 223 | ### Performans Kıyaslaması 224 | - Genel olarak Eager Loading kullanılması daha uygundur. Çünkü tüm işlemlerin bir database sorgusu üzerinde yapılması, ayrı ayrı database'e bağlanılıp sorgu yapılmasından daha performanslıdır. Bu yüzden bağlı tablolarla fazla işlem yapılmasının gerekli olmadığı durumda bu yöntem tercih edilir. 225 | - Fakat bazı zamanlarda ayrık sorgulama, tek sorgulamadan daha performanslıdır. Özellikle bağlı tabloların hepsini çekmek yerine bir kısmının çekilmesi durumunda veya bağlı tablolar arasındaki ilişkilerin çok karmaşık olduğu durumda bu yöntemin tercih edilmesi daha uygundur. 226 | - Performansın çok kritik olduğu durumlarda bu iki durumda, o anki duruma uygun olarak mix edilir. 227 | 228 | ### Kaynaklar 229 | - https://docs.microsoft.com/en-us/ef/core/querying/related-data 230 | - https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/read-related-data -------------------------------------------------------------------------------- /BONUS - FTP Server Kurulumu.md: -------------------------------------------------------------------------------- 1 | ## FTP SERVER KURULUMU (Google Cloud) 2 | 3 | #### ADIM 1 - Google Cloud Hesabından Yeni Bir Sanal Makine Oluşturma ve Bağlanma 4 | 5 | - Google Cloud hesabına giriş yapılıp yeni bir proje eklenir. 6 | - `Compute Engine` > `Sanal makine örnekleri` yolundan yeni bir sanal makine eklenir. 7 | - `Ubuntu 16.04 LTS` versiyonunu seçiyoruz. 8 | - Giriş için SSH key aktifleştirmesi yapılabilir. 9 | - Kurulum yapıldıktan sonra çıkan ekrandaki `Harici IP` bizim ssh bağlantısını yapacağımız IP adresidir. 10 | - SSH ile giriş yapıyoruz. 11 | 12 | ``` 13 | $ ssh -i .ssh/id_rsa ssonmez@ 14 | ``` 15 | 16 | #### ADIM 2 - Kurulum Yapma 17 | 18 | - Sistem üzerinde güncelleştirmeleri kontrol ediyoruz. 19 | 20 | ``` 21 | $ sudo apt-get update 22 | $ sudo apt-get upgrade 23 | ``` 24 | 25 | - FTP server kurulumunu gerçekleştiriyoruz 26 | 27 | ``` 28 | $ sudo apt-get install vsftpd -y 29 | ``` 30 | 31 | #### ADIM 3 - Local Firewall Kuralları 32 | 33 | - FTP bağlantısında hata olmaması için, server üzerinde bulunan firewall kısmının kapalı veya gerekli izinleri barındırmış olması gerekmektedir. 34 | - Firewall durumunu kontrol etmek için : 35 | 36 | ``` 37 | $ sudo ufw status 38 | ``` 39 | 40 | ```bash 41 | # OUTPUT : Firewall kapalı 42 | 43 | Status: inactive 44 | 45 | # OUTPUT : Firewall açık 46 | 47 | Status: active 48 | 49 | To Action From 50 | -- ------ ---- 51 | OpenSSH ALLOW Anywhere 52 | OpenSSH (v6) ALLOW Anywhere (v6) 53 | ``` 54 | 55 | - Firewall üzerine kural eklemek için şu komutları yazıyoruz: 56 | 57 | ```bash 58 | $ sudo ufw allow 20/tcp # for FTP 59 | $ sudo ufw allow 21/tcp # for FTP 60 | $ sudo ufw allow 990/tcp # for TSL 61 | $ sudo ufw allow 40000:50000/tcp # for Passive Ports 62 | $ sudo ufw status 63 | 64 | Status: active 65 | 66 | To Action From 67 | -- ------ ---- 68 | OpenSSH ALLOW Anywhere 69 | 990/tcp ALLOW Anywhere 70 | 20/tcp ALLOW Anywhere 71 | 21/tcp ALLOW Anywhere 72 | 40000:50000/tcp ALLOW Anywhere 73 | OpenSSH (v6) ALLOW Anywhere (v6) 74 | 20/tcp (v6) ALLOW Anywhere (v6) 75 | 21/tcp (v6) ALLOW Anywhere (v6) 76 | 990/tcp (v6) ALLOW Anywhere (v6) 77 | 40000:50000/tcp (v6) ALLOW Anywhere (v6) 78 | ``` 79 | 80 | #### ADIM 4 - Yeni FTP Kullanıcısı Ekleme 81 | 82 | - Yeni bir kullanıcı ekleyip bu kullanıcı için bir ftp dizini ayarlıyoruz. 83 | 84 | ```bash 85 | # Yeni kullanıcı ekleme 86 | $ sudo adduser 87 | ``` 88 | 89 | ```bash 90 | # Kullanıcı için ftp dizini oluşturma 91 | $ sudo mkdir /home//ftp 92 | $ sudo chown nobody:nogroup /home//ftp 93 | $ sudo chmod a-w /home//ftp 94 | ``` 95 | 96 | - Son durumda ftp dizininin izinleri aşağıdaki gibi olmalıdır. 97 | 98 | ```bash 99 | $ sudo ls -la /home//ftp 100 | 101 | total 8 102 | 4 dr-xr-xr-x 2 nobody nogroup 4096 Aug 24 21:29 . 103 | 4 drwxr-xr-x 3 4096 Aug 24 21:29 .. 104 | ``` 105 | 106 | - Daha sonrasında ftp içinde dosyaların yükleneceği ve kullanıcının erişiminin olduğu bir dizin oluşturmamız gerekecektir. 107 | 108 | ```bash 109 | $ sudo mkdir /home//ftp/files 110 | $ sudo chown : /home//ftp/files 111 | ``` 112 | 113 | - Son durumda son eklediğimiz `files` adlı dizinin izinleri şu şekilde olmalıdır. 114 | 115 | ```bash 116 | $ sudo ls -la /home//ftp 117 | 118 | total 12 119 | dr-xr-xr-x 3 nobody nogroup 4096 Aug 26 14:01 . 120 | drwxr-xr-x 3 4096 Aug 26 13:59 .. 121 | drwxr-xr-x 2 4096 Aug 26 14:01 files 122 | ``` 123 | 124 | #### ADIM 5 - FTP Ayarlarının Yapılması 125 | 126 | - FTP programının ayar dosyaları `/etc/vsftpd.conf` altında bulunmaktadır. 127 | - Öncelikle bu dosyayı yeniden oluşturmak için eskisinin ismini değiştiriyoruz. 128 | 129 | ```bash 130 | $ sudo mv /etc/vsftpd.conf /etc/vsftpd.conf.orig 131 | ``` 132 | 133 | - Sonrasında bu dosyayı düzenlenebilir halde yeniden açıyoruz. 134 | 135 | ```bash 136 | $ sudo nano /etc/vsftpd.conf 137 | ``` 138 | 139 | - Açılan pencerede aşağıdaki satıları ekleyip kaydediyoruz. 140 | 141 | ```bash 142 | # FTP aktifleştirme 143 | listen=YES 144 | 145 | # Bilinmeyen kaynaklara erişimi kapatma 146 | anonymous_enable=NO 147 | 148 | # Lokal kaynaklara erişimi açma 149 | local_enable=YES 150 | write_enable=YES 151 | chroot_local_user=YES 152 | 153 | # FTP dosya yolu 154 | user_sub_token=$USER 155 | local_root=/home/$USER/ftp 156 | 157 | # İzin verilern kullanıcıların çekileceği dosya yolu 158 | userlist_enable=YES 159 | userlist_file=/etc/vsftpd.userlist 160 | userlist_deny=NO 161 | 162 | # Passive Port Ayarlamaları 163 | # Buraya hostun public ip adresinin girilmesi gerekmektedir. 164 | pasv_enable=YES 165 | pasv_min_port=40000 166 | pasv_max_port=50000 167 | pasv_address= 168 | ``` 169 | 170 | - Bu ayarları yaptıktan sonra daha önce FTP için oluşturduğumuz kullanıcı adını, FTP erişimine izin vermek için oluşturacağımız yeni bir dosyanın içine ekliyoruz. 171 | 172 | ``` 173 | $ echo "" | sudo tee -a /etc/vsftpd.userlist 174 | ``` 175 | 176 | - Eklediğimiz kullanıcı adının istediğimiz şekilde eklendiğinden emin olmamız gerekmektedir. 177 | 178 | ```bash 179 | $ cat /etc/vsftpd.userlist 180 | # Çıktı 181 | serhat 182 | ``` 183 | 184 | - Tüm işlemler düzgün ilerlediyse, ftp server'ı baştan başlatmamız gerekmektedir. 185 | 186 | ``` 187 | $ sudo systemctl restart vsftpd 188 | ``` 189 | 190 | #### ADIM 6 - Google Cloud Firewall Ayarlarının Yapılması 191 | 192 | - Lokal firewall ayarlarının yanında, Google Cloud Firewall ayarlarından da kullanacağımız portlara izin vermemiz gerekmektedir. 193 | - `VPS Ağı > Güvenlik duvarı kuralları` sekmesinden aşağıdaki ayarlamaları yapıyoruz. 194 | 195 | ``` 196 | AD : FTP-Rule-1 197 | Ag : Default 198 | Öncelik : 1000 199 | Yön : Giriş 200 | Eylem : İzin Ver 201 | Hedefler : Ağdaki tüm örnekler 202 | Kaynak filt : IP Aralıkları 203 | IP Aralık : 0.0.0.0/0 204 | Protokoller : tcp:21 205 | --- 206 | AD : FTP-Rule-2 207 | Ag : Default 208 | Öncelik : 1000 209 | Yön : Giriş 210 | Eylem : İzin Ver 211 | Hedefler : Ağdaki tüm örnekler 212 | Kaynak filt : IP Aralıkları 213 | IP Aralık : 0.0.0.0/0 214 | Protokoller : tcp:20 215 | --- 216 | AD : FTP-Rule-TSL 217 | Ag : Default 218 | Öncelik : 1000 219 | Yön : Giriş 220 | Eylem : İzin Ver 221 | Hedefler : Ağdaki tüm örnekler 222 | Kaynak filt : IP Aralıkları 223 | IP Aralık : 0.0.0.0/0 224 | Protokoller : tcp:990 225 | --- 226 | AD : FTP-Rule-PassivePorts 227 | Ag : Default 228 | Öncelik : 1000 229 | Yön : Giriş 230 | Eylem : İzin Ver 231 | Hedefler : Ağdaki tüm örnekler 232 | Kaynak filt : IP Aralıkları 233 | IP Aralık : 0.0.0.0/0 234 | Protokoller : tcp:40000-50000 235 | --- 236 | ``` 237 | 238 | #### ADIM 7 - FTP Giriş Kontrolü 239 | 240 | - Hızlıca ftp kontrolü yapmak için komut satırından `ftp` komutunu kullanabiliriz. 241 | - Buradaki girişte herhangi bir sorun yoksa, Filezilla vb ftp programlarından da giriş yapabilirsiniz. 242 | 243 | ```bash 244 | # Google Cloud üzerinden aldığımız public IP adres girilecek 245 | $ ftp -p 246 | Connected to . 247 | 220 (vsFTPd 3.0.3) 248 | 249 | # FTP kullanıcı adı girilecek 250 | Name (:serhat): serhat 251 | 331 Please specify the password. 252 | 253 | # Parola giriyoruz 254 | Password: 255 | 230 Login successful. 256 | Remote system type is UNIX. 257 | Using binary mode to transfer files. 258 | 259 | # ls ile dosyaları listeliyoruz. 260 | # Burada bir sorun varsa Passive Mode ayalarları kontrol edilmelidir. 261 | ftp> ls 262 | 227 Entering Passive Mode (35,227,17,158,175,27). 263 | 150 Here comes the directory listing. 264 | drwxr-xr-x 2 1002 1003 4096 May 08 14:14 files 265 | 226 Directory send OK. 266 | 267 | # Çıkış yapıyoruz. 268 | ftp> bye 269 | 221 Goodbye. 270 | 271 | ``` -------------------------------------------------------------------------------- /07 - Models ve Model Binding.md: -------------------------------------------------------------------------------- 1 | ## MODELS VE MODEL BINDING 2 | 3 | ### 01 - Controller'dan View'e Model ile Veri Taşıma 4 | - Controller üzerinden View'a veri taşınırken, `ViewBag` veya `TempData` gibi aracılarla veri gönderebileceğimiz gibi, bunları bir model üzerinde toplayıp, modeli de gönderebilir. 5 | - Modeli oluşturduktan sonra, döndüreceğimiz View metodu içinde parametre olarak veririz. 6 | - Önemli olan ve unutulmaması gereken, **model gönderildikten sonra, ilgili cshtml sayfasında da bu model tanıtılmalıdır.** Aksi halde gönderdiğimiz modele view üzerinden ulaşamayız. 7 | - Controller üzerinden gönderilen model yapısı ile view üzerinde tanıtılan model yapısı arasında fark varsa, uygulama hata verecektir. 8 | - Örnekler : 9 | - String, int gibi bilinen türleri gönderme 10 | - Tek model gönderme 11 | - Model listesi gönderme 12 | 13 | ```cs 14 | // Model yapısı 15 | public class Person 16 | { 17 | public int ID { get; set; } 18 | public string Name { get; set; } 19 | public string Surname { get; set; } 20 | 21 | public int AddressID { get; set; } 22 | public Address Address { get; set; } 23 | } 24 | ``` 25 | 26 | ```cs 27 | // Controller 28 | public IActionResult Index() 29 | { 30 | List persons = new List() 31 | { 32 | new Person() { Name = "Serhat", Surname = "Sönmez" }, 33 | new Person() { Name = "Ahmet", Surname = "Mete" }, 34 | new Person() { Name = "Ayşe", Surname = "Demir" } 35 | }; 36 | return View(persons); 37 | } 38 | ``` 39 | 40 | ```html 41 | 42 | @model List 43 | 44 | 45 | 46 | 47 | 48 | 49 | @foreach (var person in Model) 50 | { 51 | 52 | 53 | 54 | 55 | } 56 |
    NameSurname
    @person.Name@person.Surname
    57 | 58 | 62 | ``` 63 | 64 | ### 02 - Model Binding 65 | - View'den Controller'a bilgi taşırken, taşınan bilgileri Query String, Form veya Route Data içinden almak yerine, direk parametre olarak almamıza olanak veren yapıdır. 66 | - Girilen parametre değerleri `key` kabul edilerek, sırasıyla `FormData > RouteData > QueryString` içinde aranır ve bir değere ulaşılırsa bu değer value olarak alınır. 67 | - Parametreler alınırken gelen tüm değerler `string` türündedir. Fakat alınacak key değerinin türü değiştirilerek, alındığı zaman direk tür dönüşümü yapılması sağlanabilir. 68 | - **NOT:** Burada tür dönüşümü yapılmazsa veya non-nullable bir parametreye (örn: int, datetime...) null değeri gönderilirse, ASP.NET Framework sürümünde hata alınıyordu. Fakat .NET Core sürümünde, hata alınmaz, bu değerler kendi default değerleri olarak atanır (örn: int için 0 alınır). 69 | - Parametre değeri olarak model de alınabilir. 70 | - Bu durumda, modelin içindeki property'ler yukarıda belirtilen sırayla aranır ve uygun olanlar alınır. 71 | 72 | ```html 73 | 74 |
    75 | 76 | 77 | 78 |
    79 | 80 | 81 | 82 | Get Product 83 | 84 | 85 | New Products 86 | ``` 87 | 88 | - Model Binding olmadan alma 89 | 90 | ```cs 91 | // Form Data 92 | public IActionResult Save() 93 | { 94 | string productName = Request.Form["productName"]; 95 | int count = int.Parse(Request.Form["count"].ToString()); 96 | return View(); 97 | } 98 | 99 | // Route Data 100 | public IActionResult Get() 101 | { 102 | int id = int.Parse(RouteData.Values["id"]?.ToString()); 103 | return View(); 104 | } 105 | 106 | // Query String 107 | public IActionResult Search() 108 | { 109 | string q = Request.Query["q"]; 110 | return View(); 111 | } 112 | ``` 113 | 114 | - Model Binding ile alma 115 | 116 | ```cs 117 | // Form Data 118 | public IActionResult Save(string productName, double count) 119 | => View(); 120 | 121 | // Route Data 122 | public IActionResult Get(int id) 123 | => View(); 124 | 125 | // Query String 126 | public IActionResult Search(string q) 127 | => View(); 128 | ``` 129 | 130 | ### 03 - View'den Controller'a Model ile Veri Taşıma 131 | 132 | - Html üzerinden form üzerinden gönderilen bilgiler, model binding ile controller üzerinden alınırken, model yapısına çevrilebilir. 133 | - Bu yöntemle, istenen model yapısı içindeki property isimleri, FormData içinde araştırılır ve uygun olanlar modele bağlanır. 134 | - Modele bağlama işleminin doğru şekilde olması için, form içindeki input yapılarının name yapıları, model içindeki property isimlerinin birebir aynısı olmalıdır. Aksi durumda bağlantı sağlanmaz. 135 | - Bu html isimlendirme kısmında bize kolaylık sağlayan iki yapı bulunur : 136 | - Html helpers 137 | - Tag helpers 138 | - Bu iki yapı kullanıldığında, view kısmının üstünde tanımlanan model yapısından property isimleri çekilip input alanlarına name olarak verilir. 139 | 140 | Model yapısı : 141 | ```cs 142 | namespace Project.Models 143 | { 144 | public class Person 145 | { 146 | public string Name { get; set; } 147 | public string Surname { get; set; } 148 | } 149 | } 150 | ``` 151 | 152 | Html ile veri gönderilirken kullanılabilir yöntemler: 153 | 154 | ```html 155 | 156 |
    157 | 158 | 159 | 160 |
    161 | 162 | 163 | @model Project.Models.Person 164 | @using (Html.BeginForm()) 165 | { 166 | @Html.TextBoxFor(k => k.Name) 167 | @Html.TextBoxFor(k => k.Surname) 168 | 169 | } 170 | 171 | 172 | @model Project.Models.Person 173 |
    174 | 175 | 176 | 177 |
    178 | 179 | ``` 180 | 181 | Gönderilen verileri controller üzerinden alma yöntemleri: 182 | 183 | ```cs 184 | // Metot 1 - Model binding ile ayrı ayrı alma 185 | [HttpPost] 186 | public IActionResult Index(string Name, string Surname) 187 | => return View(); 188 | 189 | // Metot 2 - Model binding ile model yapısına çevirip alma 190 | [HttpPost] 191 | public IActionResult Index(Person person) 192 | => return View(); 193 | ``` 194 | 195 | > **NOT:** Birleşik modeller veya modelin foreign key ile bağlandığı başka bir model kullanıldığında, durum aynıdır. 196 | > - Eğer manuel olarak isimlendirme yapılacaksa, her seviye nokta ile ayrılır. 197 | > - Controller üzerinden model çekilirken, tüm modelin çekilmesi gereklidir. Sadece form içinde kullanılan model çekilmeye çalışılırsa, uyumsuzluktan dolayı null değer alınır. 198 | 199 | ### 04 - List Binding 200 | 201 | - Controller'a aynı key ismine sahip birden fazla eleman gönderilirse, bunlar dizi veya liste olarak bind edilip alınabilir. 202 | 203 | ```html 204 | @model List 205 |
    206 | 207 | 208 | 209 | 210 |
    211 | ``` 212 | 213 | ```cs 214 | public IActionResult Form(string[] names) 215 | => View(); 216 | 217 | // veya 218 | 219 | public IActionResult Form(List names) 220 | => View(); 221 | ``` 222 | 223 | - Aynı yapı birden çok model gönderimi için de kullanılabilir. 224 | 225 | ```html 226 | @model List 227 |
    228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 |
    239 | ``` 240 | 241 | ```cs 242 | public IActionResult Form(List customers) 243 | => View(); 244 | ``` 245 | 246 | ### 05 - ViewModel Oluşturma 247 | - Birleşik Model oluşturma 248 | - Birleşik Modelleri Controller’dan View’a gönderme 249 | - Birleşik Modelleri View’dan Controller’a gönderme 250 | 251 | ### 06 - Partial View'ı Model Yapısı Kullanarak Gönderme 252 | - Partial View yapısı ikinci parametre olarak bir model alarak dinamik bir hale bürünür. 253 | - Bu yapıyı html içinde `Html.Partial(, )` olarak kullanabileceğimiz gibi, ActionResult üzerinden `PartialView(, )` return ederek de kullanabiliriz. 254 | - Core MVC yapısında bu yapılar yerine `View Components` yapıları gelmiştir.(bkz. ilgili ders notu) 255 | 256 |

    257 | 258 |

    259 | 260 |

    261 | 262 |

    -------------------------------------------------------------------------------- /02 - ASP.NET Core MVC Giriş.md: -------------------------------------------------------------------------------- 1 | ## ASP .NET Core MVC PROGRAMLAMAYA GİRİŞ 2 | 3 | ### 01 - .NET Core ve .NET Standart Nedir? 4 | 5 | - .NET Core öncesinde kullanılan .NET Framework yapısı, aşağıdaki resimden de görüleceği üzere, birbirinden bağımsız olarak geliştirilen yapılarından oluşan bir platformdu. 6 | - Bu nedenle her bir yapının kendine ait farklı kütüphaneleri, frameworkleri ve runtime'ları vardı. 7 | - Ayrıca bu yapılar sadece belirli bir işletim sistemi üzerinde (çoğunlukla Windows) çalışıyordu. 8 | - Geliştirilen kütüphaneler de genel olarak yapıya özgü geliştiriliyordu. 9 | 10 |

    11 | 12 |

    13 | 14 | - Hem Cross-platform uygulama geliştirmenin hem de open-source projelerin yükselişi ile birlikte, .NET mimarisi de kökten bir dönüşüme girmiştir. 15 | - .NET Core ile birlikte .NET mimarisi; 16 | - Cross-Platform geliştirmeyi ve deployment'ı destekleyen, 17 | - [Açık kaynak kodlu](https://github.com/aspnet/home), 18 | - Web programları, web servisleri, IoT programları ve mobil program arka-planlaması yapılabilen, 19 | - Herhangi bir editör ile herhangi bir işletim sisteminde (Windows, MacOS, Linux) geliştirme yapılabilen, 20 | - Docker desteği olan, 21 | - IIS dışında herhangi bir web server kullanıma uygun bir yapı haline gelmiştir. 22 | - .NET Core ile .NET Framework arasındaki temel farklar; 23 | - .NET Core aslında tek bir uygulama modeli içermektedir : Console Application. 24 | - Bu yapıya yeni servisler eklenerek, farklı yapılar ortaya çıkarılmaktadır. 25 | - Buna karşın, .NET Framewok üzerinde, yukarıdaki şekilde de görüldüğü üzere, her yapı birbirinden farklıdır. 26 | 27 | Aşağıdaki resimden de görüleceği üzere, .NET Core yapısı ortaya çıktıktan sonra da bazı sorunlar devam etti. Bu sorunların en temelinde, .NET Core ve diğer yapılar için kullanılan kütüphane yapılarının birbirinden bağımsız olmasıydı. Bu sorundan ötürü Microsoft, `.NET Standart` adlı yapıyı çıkarıp, tüm kütüphane yapılarını bu çatı altında toplamıştır. Bu sayede herhangi bir platform için sadece bir kütüphane yapısı kullanılabilir hale gelmiştir. 28 | 29 | |
    .NET Standart Öncesi
    |
    .NET Standart Sonrası
    | 30 | | --- | --- | 31 | |

    |

    | 32 | 33 | #### .NET Core ile .NET Framework Arasındaki Teknik Farklar 34 | 35 | - Artık Core yapısı içinde özel dizinler bulunmamaktadır. (Örn: App_Code, App_Data vs.) 36 | - Core yapısı içinde eskiden kullanılan html helper metotlar yerine `TagHelpers`'lar ve `ViewComponents` yapıları gelmektedir. 37 | - Statik dosya yapısı `wwwroot` dizini içine taşınmıştır. 38 | 39 | ### 02 - Core Geliştirme Ortamları 40 | 41 | - Windows 42 | - Visual Studio 2017 veya 2015 43 | - 2017 kurarken dil paketinin EN seçilmesine dikkat edilmelidir. 44 | - 2015 sürümünde default Core 1.1 gelmektedir, bunun upgrade edilmesi gerekir. 45 | - VS Code 46 | - NET Core 2.0 SDK 47 | - https://www.microsoft.com/net/download/ 48 | - Version görüntüleme 49 | - `dotnet --version` 50 | - VS üzerinden yeni proje açarken Core 2.0 seçeneği geliyorsa işlemler başlarıyla gerçekleşmiştir. 51 | 52 | - Mac ve Linux 53 | - VS Code 54 | - Kurulması tavsiye edilen eklentiler: 55 | - ASP.NET Core Snippets 56 | - C# 57 | - NET Core 2.0 SDK 58 | - https://www.microsoft.com/net/download/ 59 | 60 |

    61 | 62 |

    63 | 64 | ### 03 - MVC Pattern Nedir? 65 | 66 | - Design Pattern 67 | - Kurallar düzenidir / Kalıptır. 68 | - Belirli kurallar ve düzenleri sabitleyerek projenin işleyişini ve - takım çalışmasını kolaylaştırır. 69 | - İlk olarak 1979 yılında Trygve Reenskaug ortaya atılmıştır. - (Microsoft’un kurulumu 1975) 70 | - MVC nasıl çalışır? 71 | 72 |

    73 | 74 |

    75 | 76 | ### 04 - İlk Projeyi Oluşturma 77 | 78 | - Visual Studio ile örnek proje açma 79 | - VS Code ile proje oluşturma (Terminal üzerinden) 80 | - `dotnet new --help` 81 | - Şablonları gösterir. 82 | - `dotnet new <şablon ismi>` 83 | - Seçili şablon dosyalarını oluşturur. 84 | - `dotnet run` 85 | - Projeyi çalıştırır. 86 | - İlk projenin ayarlamalarının yapılması ve basit bir MVC sayfası 87 | - MVC yapısına uygun olarak ilk `Hello World` uygulaması yapılması. 88 | - İlk ayarlamada `Startup.cs` dosyasının içeriği aşağıdaki gibi olmalıdır: 89 | 90 | ```cs 91 | using Microsoft.AspNetCore.Builder; 92 | using Microsoft.AspNetCore.Hosting; 93 | using Microsoft.Extensions.Configuration; 94 | using Microsoft.Extensions.DependencyInjection; 95 | 96 | namespace WebApplication1 97 | { 98 | public class Startup 99 | { 100 | public IConfiguration Configuration { get; } 101 | 102 | public Startup(IConfiguration configuration) 103 | { 104 | Configuration = configuration; 105 | } 106 | 107 | public void ConfigureServices(IServiceCollection services) 108 | { 109 | // Mvc servisini aktifleştiriyoruz. 110 | services.AddMvc(); 111 | } 112 | 113 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 114 | { 115 | // Sadece development adımında aktif olmasını istediğimiz kısımları buraya yazıyoruz. 116 | if (env.IsDevelopment()) 117 | { 118 | // Hata gösterimini açan metottur. 119 | app.UseDeveloperExceptionPage(); 120 | } 121 | 122 | // wwwroot dizini altındaki statik dosyaları kullanmamızı sağlar. 123 | app.UseStaticFiles(); 124 | 125 | // Status kod sayfalarının gösterimini sağlar. 126 | app.UseStatusCodePages(); 127 | 128 | // MVC yapımız için default bir route tanımlaması yaparız. 129 | // Başka bir yöntem olarak aşağıdaki ifade de kullanılabilir. 130 | // app.UseMvcWithDefaultRoute(); 131 | app.UseMvc(routes => 132 | { 133 | routes.MapRoute( 134 | name: "default", 135 | template: "{controller=Home}/{action=Index}/{id?}"); 136 | }); 137 | } 138 | } 139 | } 140 | ``` 141 | 142 | ### 05 - Projenin Dosya Düzeni 143 | - `Controllers`, `Views`, `Models` 144 | - MVC yapısındaki dizinlerdir. 145 | - `wwwroot` 146 | - Bu dizin, bizim statik dosyalarımızın bulunduğu alandır. 147 | - Js, css ve resim dosyaları burada bulunur. 148 | - Bu kısmı erişime açmak için `Startup.cs` dosyası içindeki `Configure` metodunun içine aşağıdaki kod satırı girilmelidir. 149 | - `app.UseStaticFiles();` 150 | - Bu dizin içine eklenen herhangi bir öğeye `~/` üzerinden ulaşabiliriz. 151 | - Örn : `wwwroot>img>01.jpg` dosyasını eklemek için; 152 | - `` olarak cshtml dosyasına ekleme yapılabilir. 153 | - `Dependencies` 154 | - Projeye eklenen paketlerin bulunduğu kısımdır. 155 | - Her paket yönetim programı için bir tane dizin oluşturulur. 156 | - Paket yönetim programlarının oluşturduğu dosya değiştirilirse veya direk olarak paketler kendi arayüzlerinden indirilirse, buraya otomatik olarak eklenir. 157 | - Buradan paketlerin üzerine tıklanarak kaldırma ve güncelleme işlemleri yapılabilir. 158 | - `Program.cs` 159 | - Programın ilk çalışmaya başladığı dosyadır. 160 | - Program çalıştırılınca, `Program.cs` içinde bulunan `Main()` metodu çalışır ve devamında ayarlar vs. yüklenerek program tam çalışır hale gelir. 161 | - `Startup.cs` 162 | - Program içindeki tüm ana ayarlamaların yapıldığı dosyadır. 163 | - İçinde temel olarak iki metot bulundurur. 164 | - `ConfigureServices()` 165 | - Program servislerinin ayarlamalarının yapıldığı alandır. 166 | - Web host, `Configure()` metodunu çağırmadan önce, ayarlamaları yapması için bu metodu çalıştırır. 167 | - Opsiyoneldir. 168 | - `Configure()` 169 | - Programa gelen isteklerin (request) işlenmesi için gerekli yol haritasının çizildiği alandır. 170 | - Zorunludur. 171 | 172 | ### 06 - Paket Yönetimi 173 | 174 | #### NuGet Package Manager 175 | - .NET Framework yapısında biz paketleri Nuget Manager ile indiriyorduk ve temel paketlerin hepsi ayrı ayrı indiriliyordu. 176 | - .NET Core ile birlikte, bu temel paketlerin hepsi tek bir paket altında toplanıp projeye dahil edilmiştir. 177 | - Bu paketi `Dependencies > NuGet > Microsoft.AspNetCore.All` altından görebiliriz. 178 | - Bu paketler internet üzerinden indirilmiş değildir, sadece referans olarak durmaktadırlar. 179 | - Proje içinde kullanılan paketler otomatik algılanıp, publish edildiğinde sadece bu paketlerin dll dosyaları projeye dahil edilecektir. 180 | - Bu paketlerin ayar dosyasını, projeye sağ tıklayıp `Edit .csproj` altında da düzenleyebiliriz. 181 | 182 | #### Bower Package Manager 183 | - Harici paketleri NuGet ile kurmanın yanında, .NET Core ile gelen başka bir paket yöneticisi olan `Bower` paket yöneticisiyle de paketleri kurabiliriz. 184 | - `Project > Manage Bower Packages...` yolunu kullanarak bower paketlerini yükleyebiliriz. 185 | - Bunun dışında manuel olarak da yükleme yapılabilir. 186 | - Bunun için yapmamız gereken, öncelikle `bower.json` dosyasını oluşturmaktır. 187 | - Bunu iki şekilde yapabiliriz: 188 | 1. Projeye sağ tıklayıp `Add > New Item > Bower Configuration File` yolunu takip ederek dosyayı dahil edebiliriz. 189 | 2. Projeye sağ tıklayıp `Add > New Item > Json File` kısmından `bower.json` isminde bir dosya ekliyoruz. 190 | - Dosyanın içine aşağıdaki örnek kodları ekliyoruz. 191 | 192 | ```json 193 | { 194 | "name": "asp.net", 195 | "private": true, 196 | "dependencies": { 197 | "bootstrap": "4.0.0" 198 | } 199 | } 200 | ``` 201 | 202 | - Tüm kullanılabilir bower paketleri için : https://bower.io/search/ 203 | - Dosyayı kaydettiğimiz zaman otomatik olarak paketler projeye eklenecektir. 204 | - Eklenen paketleri `Dependences > Bower` altından görebiliriz. 205 | - Projeye eklenen bower dosyaları otomatik olarak `wwwroot/lib` altında oluşturulur. Dosyaların yükleneceği yolu değiştirmek için ; 206 | - `bower.json` dosyasının altında `.bowerrc` dosyasının içinden `directory` kısmını değiştiriyoruz. 207 | - Eğer proje içinde bu dosya yoksa; 208 | - Projeye sağ tıklayıp `Add > New Item > Json File` kısmından `.bowerrc` isminde bir dosya ekliyoruz. 209 | - Dosyanın içine aşağıdaki örnek kodları ekliyoruz. 210 | 211 | ```json 212 | { 213 | "directory": "wwwroot/lib" 214 | } 215 | ``` 216 | 217 | #### Node Package Manager (NPM) 218 | - Eklenecek. 219 | -------------------------------------------------------------------------------- /21 - ASP.NET Core In-Depth - Proje Geliştime Mimarileri.md: -------------------------------------------------------------------------------- 1 | ## PROJE GELİŞTİRME MİMARİLERİ 2 | 3 | - Database modellemesi yapılırken ve bu yapılar proje içinde kullanılırken kullanacağımız bu yöntemler, hem proje yönetilebilirliğini arttırmak hem de kod tekrarını engellemek için kullanacağımız yöntemlerdir. 4 | 5 | ### 01 - Kurumsal Mimari Yapısıyla Core Projesi Oluştumak 6 | 7 | - Buradaki amaç, projemiz içindeki her katmanı ayrı bir library içinde kullanarak, projenin yönetilebilirliğini arttırmaktır. 8 | - Bunun için, bir solution içinde açamız gereken temelde 3 tane proje vardır. Bunların biri `CoreMVC`, diğer ikisi ise `Class Library`'dir. 9 | - Projeler oluşturulduktan sonra, her projenin kullanılan projeye göre birbirine referans vermesi gerekmektedir. 10 | - Migration işlemleri yapılırken, assembly yolunun WebUI içinde olduğunu ayar olarak belirtmemiz gerekmektedir. 11 | 12 | ```cs 13 | public void ConfigureServices(IServiceCollection services) 14 | { 15 | services.AddMvc(); 16 | services.AddDbContext( 17 | option => option.UseSqlServer( 18 | Configuration.GetConnectionString("EfCoreDb"), 19 | b => b.MigrationsAssembly("Project.WebUI") 20 | )); 21 | } 22 | ``` 23 | 24 | 1. **Project.WebUI** (Core MVC Projesi) 25 | - Bu proje, bizim çalışacak main projemizdir. 26 | - Diğer projelerden referans alır ve kullanır. 27 | - Projenin çalışması için bu projenin start-up project olarak seçilmesi gereklidir. 28 | 2. **Project.Entity** (Class Library) 29 | - İçinde db modellerimizin olduğu sınıftır. 30 | 3. **Project.Data** (Class Library) 31 | - Database bağlantılarının bulunduğu alandır. 32 | - Database bağlantısı yapılacağı için içinde Entity Framework Core kütüphanesi bulunmalıdır. 33 | - NPM içinden `Microsoft.EntityFrameworkCore.SqlServer` kütüphanesi kurulabilir. 34 | - NPM Console üzerinden `Install-Package Microsoft.EntityFrameworkCore.SqlServer` komutu çalıştırılarak kurulabilir. 35 | - `Project.Data.csproj` dosyası içindeki `` tagları içine aşağıdaki satır eklenebilir. 36 | - `` 37 | - ya da 38 | - `` 39 | - İçinde 2 tane dizin bulundurur. 40 | 1. **Abstract** 41 | - Interface'lerin tanımlandığı alandır. 42 | 2. **Concrete** 43 | - Database bağlantıları için yazılacak `Context` ve `Repository` sınıflarının olacağı klasördür. 44 | - Projeye dahil edilecek her bir db ve orm teknolojisi için ayrı bir klasör oluşturur. 45 | - Bu klasörler içinde bağlantı için gereken Context ve Repository sınıfları oluşturulur. 46 | 47 | 48 | ### 02 - Generik Class Yapılarıyla Entegrasyon 49 | 50 | - Generik sınıfların oluşturulması, kod tekrarını engellemek ve DRY prensibine uygun olarak kod yapıları oluşturmamızı sağlar. 51 | - Proje içinde `Interface`'lerin ve `Repository` sınıflarının içeriği genel olarak birbirini tekrar eder. 52 | - Bunu engellemek için iki yapı için de birer generik sınıf oluşturulur. 53 | 54 | #### Generik Intarface oluşturma 55 | 56 | - Her repository için ayrı ayrı Interface oluşturmak yerine, eğer tüm interface içerikleri aynı olacaksa, tek bir tane `Generic Interface` oluşturulabilir. 57 | - Diğer interface'ler bundan türetilir. 58 | - Eğer interface'e özel eklemeler yapılacaksa bunlar kendi içinde yapılabilir. 59 | 60 | ```cs 61 | public interface IGenericRepository where T:class 62 | { 63 | T GetByID(int ID); 64 | IQueryable GetAll(); 65 | IQueryable Find(Expression> query); 66 | 67 | void Add(T entity); 68 | void Update(T entity); 69 | void Delete(int ID); 70 | void Save(); 71 | } 72 | 73 | public interface IPersonRepository : IGenericRepository 74 | { 75 | IQueryable PersonsWithAddress { get; } 76 | } 77 | 78 | public interface IAddressRepository : IGenericRepository
    79 | { 80 | IQueryable
    AddressesWithPeople { get; } 81 | } 82 | ``` 83 | 84 | #### Generik Repository oluşturma 85 | 86 | - Aşağıda da görüldüğü gibi, generi interface işlemleri aynı olduğu gibi, bunların repository işlemleri de aynı. Bu nedenle bu interface içindeki ifadelerin repo işlemleri generik bir sınıf içinde yapılmıştır. 87 | - **NOT:** Bu generik sınıf içinde kullanılan database sınıfının özel olmasına gerek yok. O yüzden bizim db bağlantı sınıfımız olan `EfProjectContext` sınıfını değil, bu sınıfın kalıtım aldığı ve EF içinden gelen `DbContext` sınıfını kullanmıştır. 88 | - Bu generik sınıfı kullanan diğer özel sınıflardan bu kullanılan `DbContext` ifadesi için ctor metot içinde `EfProjectContext` yapısı gönderilmiştir. 89 | - Bu saydede özel sınıf içine inherit edilen generik sınıf metotları bu özel db class yapısını kullanır. 90 | - Özel sınıflar içinde db işlemleri kullanılırken, generik sınıftan inherit edilen `context` nesnesi kullanılabileceği gibi, bu nesne farklı bir nesneye tür dönüşümü yapılarak atanıp da kullanılabilir. 91 | - Yeni bir nesneye atanmadan; 92 | - `context.Set().Include("Address");` 93 | - Yeni bir nesneye atanırsa; 94 | - `efProjectContext.Persons.Include("Address");` 95 | - Yeni nesneye atama yapılması, bu yapıyı kullanırken daha efektif kullanmamızı sağlar. 96 | 97 | ```cs 98 | public class EfGenericRepository : IGenericRepository where T : class 99 | { 100 | protected readonly DbContext context; 101 | 102 | public EfGenericRepository(DbContext ctx) 103 | => context = ctx; 104 | 105 | public T GetByID(int ID) 106 | => context.Set().Find(ID); 107 | 108 | public IQueryable Find(Expression> query) 109 | => context.Set().Where(query); 110 | 111 | public IQueryable GetAll() 112 | => context.Set(); 113 | 114 | public void Add(T entity) 115 | => context.Set().Add(entity); 116 | 117 | public void Delete(int ID) 118 | => context.Set().Remove(GetByID(ID)); 119 | 120 | public void Update(T entity) 121 | => context.Set().Update(entity); 122 | 123 | public void Save() 124 | => context.SaveChanges(); 125 | } 126 | 127 | public class EfPersonRepository : EfGenericRepository, IPersonRepository 128 | { 129 | public EfPersonRepository(EfProjectContext ctx) 130 | : base(ctx) { } 131 | 132 | public EfProjectContext efProjectContext 133 | { get { return context as EfProjectContext; } } 134 | 135 | public IQueryable PersonsWithAddress 136 | => efProjectContext.Persons.Include(k => k.Address); 137 | } 138 | 139 | public class EfAddressRepository : EfGenericRepository
    , IAddressRepository 140 | { 141 | public EfAddressRepository(EfProjectContext ctx) 142 | : base(ctx) { } 143 | 144 | public EfProjectContext _EfProjectContext 145 | { get { return context as EfProjectContext; } } 146 | 147 | public IQueryable
    AddressesWithPeople 148 | => _EfProjectContext.Addresses.Include(k => k.Persons); 149 | } 150 | ``` 151 | 152 | ### 03 - Unit Of Work Pattern 153 | 154 | - Bu yapının temel olarak amaçları; 155 | - Controller içine repoları ayrı ayrı DI yapmak yerine, tek bir yapı altında toplayıp enjekte etmek. 156 | - Ayrı ayrı enjekte edilen yapıların ayrı ayrı DbContext öğeleri oluşturmak yerine, sadece bir tane nesne oluşturup bunun üzerinde işlemler yapmak. 157 | - Burada asıl olarak yaptığımız, tüm repository öğelerini tek bir öğe halinde birleştirmek ve bu öğenin hizmetine tek bir tane DbContext öğesi atamaktır. 158 | 159 | |
    Wihtout UoW
    |
    With UoW
    | 160 | | --- | --- | 161 | |

    |

    | 162 | 163 | #### Interface yapılandırılması 164 | 165 | - Oluşturacağımız interface, 166 | - Proje içinde kullandığımız sanal interface tablolarını alan, 167 | - Dispose edilebilir, 168 | - İçinde tüm işlemler bittikten sonra db kaydını gerçekleştirebileceğimiz bir SaveChanges metodu bulunduran bir yapıda olmalıdır. 169 | 170 | ```cs 171 | interface IUnitOfWork : IDisposable 172 | { 173 | IPersonRepository People { get; } 174 | IAddressRepository Addresses { get; } 175 | 176 | int SaveChanges(); 177 | } 178 | ``` 179 | 180 | #### Interface üzerinden sınıf türetilmesi 181 | 182 | - Öncesinde oluşturduğumuz interface'i, mevcut kullandığımız db yapısına uyarlamak için yeni bir class oluşturuyoruz. 183 | - Bu yeni class içinde; 184 | - Mevcut database yapımızı DI ile enjekte ediyoruz. 185 | - Bu yapıyı kullanacak her controller, sınıf içinde birden fazla repo oluşturmasın diye, her repodan bir private nesne oluşturuyoruz ve her nesne için bir `get` property'si oluşturup bu field nesnelerini gönderiyoruz. 186 | - Bu propery'ler oluşturulurken, ilk ulaşıldığında field alanları null olacağından dolayı, bu field'lar için yeni bir nesne oluşturup gönderiyoruz. 187 | - Daha sonrasında db kaydı için `SaveChanges` metodunu ve işimiz bittikten sonra bunu silmek için `Dispose` metodunu dolduruyoruz. 188 | 189 | ```cs 190 | public class EfUnitOfWork : IUnitOfWork 191 | { 192 | // Database 193 | private readonly EfProjectContext context; 194 | 195 | public EfUnitOfWork(EfProjectContext _context) 196 | => context = _context; 197 | 198 | // Fields 199 | private IPersonRepository _people; 200 | private IAddressRepository _addresses; 201 | 202 | // Properties 203 | public IPersonRepository People 204 | => _people ?? (_people = new EfPersonRepository(context)); 205 | 206 | public IAddressRepository Addresses 207 | => _addresses ?? (_addresses = new EfAddressRepository(context)); 208 | 209 | // Functions 210 | public int SaveChanges() 211 | => context.SaveChanges(); 212 | 213 | public void Dispose() 214 | => context.Dispose(); 215 | } 216 | ``` 217 | 218 | #### Yapıların birbirine bağlanması 219 | 220 | - Repolarda olduğu gibi, `Startup.cs` dosyası içinde bu iki yapının birbirine bağlanması lazım. 221 | 222 | ```cs 223 | services.AddTransient(); 224 | ``` 225 | 226 | > **NOT!** Tüm repoları ve tüm interface'leri tek bir çatı altına toplayıp `Unit of Work` yapısıyla birbirine bağladığımız ve kullanacağımız alanlarda **diğer interfaceleri değil de UoW interface'ini enjekte edeceğimiz için** `Startup.cs` dosyası içindeki diğer bağlantıları kaldırabiliriz. 227 | 228 | ```cs 229 | // Öncesi 230 | services.AddTransient(); 231 | services.AddTransient(); 232 | ``` 233 | 234 | ```cs 235 | // Sonrası 236 | services.AddTransient(); 237 | ``` 238 | 239 | #### Son durum 240 | 241 | UoW öncesi Controller: 242 | 243 | ```cs 244 | public class Home2Controller : Controller 245 | { 246 | private IPersonRepository person; 247 | private IAddressRepository address; 248 | 249 | public Home2Controller(IPersonRepository _person, IAddressRepository _address) 250 | { 251 | person = _person; 252 | address = _address; 253 | } 254 | 255 | public IActionResult People() 256 | => View(person.PersonsWithAddressWithCountry); 257 | 258 | public IActionResult Addresses() 259 | => View(address.GetAll()); 260 | 261 | public IActionResult AddPerson(Person model) 262 | { 263 | person.Add(model); 264 | person.Save(); 265 | return RedirectToAction("People"); 266 | } 267 | } 268 | ``` 269 | 270 | UoW sonrası Controller : 271 | 272 | ```cs 273 | public class Home2Controller : Controller 274 | { 275 | private IUnitOfWork uow; 276 | 277 | public Home2Controller(IUnitOfWork _uow) 278 | => uow = _uow; 279 | 280 | public IActionResult People() 281 | => View(uow.People.PersonsWithAddressWithCountry); 282 | 283 | public IActionResult Addresses() 284 | => View(uow.Addresses.GetAll()); 285 | 286 | public IActionResult AddPerson(Person model) 287 | { 288 | uow.People.Add(model); 289 | uow.SaveChanges(); 290 | return RedirectToAction("People"); 291 | } 292 | } 293 | ``` 294 | 295 | 296 | ### 04 - Onion Architecture 297 | 298 | - Katmanların iç içe olduğu ve her katmanın sadece kendi üstündeki katmanı gördüğü tasarım mimarisidir. 299 | 300 |

    301 | 302 |

    -------------------------------------------------------------------------------- /12 - Durum Yönetimi.md: -------------------------------------------------------------------------------- 1 | ## DURUM YÖNETİMİ 2 | 3 | - HTTP, stateless bir protokoldür. 4 | - Kullanılan web server, her bir request'i ayrı ve birbirinden bağımsız olarak oluşturur ve önceki request üzerindeki veriler ve user bilgileri kullanılamaz. 5 | - Bu yüzden, belirli bir kullanıcıya ait bilgileri o kullanıcıya özel saklamak veya tüm isteklerin kullanabileceği bir havuz yapısı oluşturmak için, Session ve Cookie bağımlı yapılar kullanarak durum yönetimi yapabiliriz. 6 | 7 | ### 01 - Session 8 | 9 | - Sunucunun REMinde tutulur. 10 | - Her kullanıcı için bir ID oluşturur ve tutulacak verileri bu ID üzerinden saklar. 11 | - Bu oluşturulan ID’ler şifrelenerek kullanıcının bilgisayarında cookie olarak tutulur. 12 | - Farklı tarayıcılarda farklı kullanıcı gibi davranır. 13 | - Belirli bir süresi vardır, ayarlanabilir. Default : 20dk 14 | - Bu süre son request'ten sonrası için geçerlidir. (Sliding time) 15 | - Session nesnesi içine eskiden obje atayabilirken, Core 2.0 üzerinde sadece primitive değişkenler saklayabiliyoruz(int, string vb) 16 | - Bu durumu aşmak için model yapıları json nesnesine çevrilip saklanabilir. 17 | - Bu durumlar için bir kütüphane oluşturulup kullanılabilir. 18 | - .NET Core içinde session kullanılacaksa bunu aktifleştirmek gerekir. Bunu Startup.cs dosyası içinden; 19 | - Aktifleştirme yapılırken `UseSession` yapısının `UseMvc` yapısından önce kullanılmasına dikkat edilmelidir. 20 | - Aksi halde hata alınır. 21 | 22 | ```cs 23 | public void ConfigureServices(IServiceCollection services) 24 | { 25 | services.AddMemoryCache(); 26 | services.AddSession(); 27 | } 28 | 29 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 30 | { 31 | app.UseSession(); 32 | app.UseMvcWithDefaultRoute(); 33 | } 34 | ``` 35 | 36 | - Aktifleştime yapılırken, Session ayarlamaları da eklenebilir: 37 | - Buradaki `IdleTimeout` ile, Session süresi ayarlanabilir. 38 | - `TimeSpan` olarak belirtilir. 39 | - Session middleware'i üzerinden geçen her request bu zamanı sıfırlar. 40 | - `options.Cookie` üzerinden, session'ın oluşturduğu cookie ile ilgili ayarlamalar yapılabilir. 41 | 42 | ```cs 43 | services.AddSession(options => { 44 | options.Cookie.HttpOnly = true; 45 | options.IdleTimeout = new TimeSpan(0, 0, 10); 46 | options.Cookie.Name = ".AdventureWorks.Session"; 47 | }); 48 | ``` 49 | 50 | #### Session kullanımı 51 | 52 | - Session oluşturma: 53 | - `HttpContext.Session.Set (string key, byte[] value)` 54 | - `HttpContext.Session.SetString(string key, string value)` 55 | - `HttpContext.Session.SetInt32 (string key, int value)` 56 | - Session çekme: 57 | - `byte[] HttpContext.Session.Get(string key)` 58 | - `bool HttpContext.Session.TryGetValue(string key, out byte[] value)` 59 | - `string HttpContext.Session.GetString(string key)` 60 | - `int? HttpContext.Session.GetInt32(string key)` 61 | - Sessionların silinmesi 62 | - `void HttpContext.Session.Remove(string key)` 63 | - `void HttpContext.Session.Clear()` 64 | 65 | #### Modellerin Json yapısına çevrilip session yönetiminde kullanılması 66 | 67 | ```cs 68 | // Library/Extensions/SessionExtensions.cs 69 | using Microsoft.AspNetCore.Http; 70 | using Newtonsoft.Json; 71 | 72 | public static class SessionExtensions 73 | { 74 | public static void SetJson(this ISession session, string key, T value) 75 | { 76 | session.SetString(key, JsonConvert.SerializeObject(value)); 77 | } 78 | 79 | public static T GetJson(this ISession session, string key) 80 | { 81 | var value = session.GetString(key); 82 | return value == null ? default(T) : 83 | JsonConvert.DeserializeObject(value); 84 | } 85 | } 86 | ``` 87 | 88 | ```cs 89 | // Controller 90 | using System.Collections.Generic; 91 | using Microsoft.AspNetCore.Http; 92 | using Microsoft.AspNetCore.Mvc; 93 | using Project.Library.Extensions; 94 | using Project.Models; 95 | public class SessionController : Controller 96 | { 97 | public IActionResult Index() 98 | { 99 | // FakeData ile örnek bir model listesi oluşturma 100 | List list = new List(); 101 | 102 | for (int i = 0; i < 20; i++) 103 | list.Add(new Person { 104 | Name = FakeData.NameData.GetFirstName(), 105 | Surname = FakeData.NameData.GetSurname() 106 | }); 107 | 108 | // Listeyi session üzerine kaydetme 109 | HttpContext.Session.SetJson("people", list); 110 | 111 | return RedirectToAction("Index2"); 112 | } 113 | 114 | public IActionResult Index2() 115 | { 116 | // Session'ı çekme ve modele dönüştürme 117 | // Eğer gelen değer null ile boş bir liste gönderme 118 | List list = HttpContext.Session.GetJson>("people") 119 | ?? new List(); 120 | return View(list); 121 | } 122 | } 123 | ``` 124 | 125 | ### 02 - Cookie 126 | 127 | - String türünde değişkenler saklar. 128 | - Cookie'ler kullanıcının bilgisayarında saklanır. 129 | - Kullanıcının bilgisayarında saklandığı ve görülebildiği için hassas verilerin saklanmaması gereklidir. 130 | - Eğer önemli veriler saklanacaksa ve bu verilerin görünmesi istenmiyorsa, şifrelenerek gönderilebilir. 131 | - Ömürleri dolana kadar browser tarafından saklanmaya devam eder 132 | - Her request ve response üzerinde taşınır. 133 | - Bu taşınmanın performansının düşmemesi için cookie boyutunu minimum tutmak önemlidir. 134 | - Genellikle kullanıcıya özel bilgiler server üzerinde barındırılıp, bunu tanımlayan unique bir değer cookie ile kullanıcıya gönderilir. 135 | - Çoğu browser, cookie boyutunu 4096 byte olarak sınırlandırmıştır. 136 | - Eklenme için `Response` okuma için ise `Request` objeleri kullanılır. 137 | 138 | #### Cookie Kullanımı 139 | 140 | - Cookie oluşturma: 141 | - `void Response.Cookies.Append(string key, string value);` 142 | - `void Response.Cookies.Append(string key, string value, CookieOptions options);` 143 | 144 | ```cs 145 | Response.Cookies.Append("name", "serhat", new CookieOptions 146 | { 147 | HttpOnly = true, 148 | Expires = DateTime.Now.AddDays(1) 149 | }); 150 | ``` 151 | 152 | - CookieOptions : 153 | - **Domain** - Cookie ile birleştirilmek istenen domain ismi 154 | - **Path** - Cookie yolu 155 | - **Expires** - Cookie silinme zamanı 156 | - **HttpOnly** - Client-Side scriptlerin cookie kullanıp kullanmayacağının ayarlanması 157 | - **Secure** - Sadece HTTPS üzerinden çalışmayı desteklemek için true yapılabilir. 158 | 159 | - Cookie Okuma: 160 | - Controller üzerinden : 161 | - `Request.Cookies[]` 162 | - View üzerinden : 163 | - `Context.Request.Cookies[]` 164 | - Herhangi bir dış class veya middleware üzerinden : 165 | - https://stackoverflow.com/questions/38571032/how-to-get-httpcontext-current-in-asp-net-core 166 | 167 | ```cs 168 | // External Class : 169 | public class MyCookieExp 170 | { 171 | public static string ReadCookie(HttpContext context, string key) 172 | { 173 | return context.Request.Cookies[key]; 174 | } 175 | } 176 | 177 | // Controller : 178 | var cookie = MyCookieExp.ReadCookie(HttpContext, "name"); 179 | ``` 180 | 181 | - Cookie Silme: 182 | - `Response.Cookies.Delete()` 183 | 184 | #### Önemli bir not! 185 | 186 | > İnternet standartlarına göre request headers içerisinde non-ascii değerlerin taşınması uygun görülmemektedir. Bu tür bir zorunluluk taşıyorsanız ilgili değerleri encode-decode yöntemleri ile işleyebilirsiniz. 187 | 188 | - Bu sebepten ötürü, .NET Core Cookies içinde ASCII değerlerine uygun olmayan karakterler taşındığında, request Controller yapısına uğramadan direk 400 hatası döndürür. 189 | 190 | ### 03 - Cache 191 | 192 | - Caching mekanizması, herhangi bir veriyi cevap olarak daha hızlı döndürmek için, bu veriyi RAM üzerinde saklama ve gerektiğinde geri döndürme işlemidir. 193 | - Ayrıntılı bilgi için şu kaynağa bakılabilir: 194 | - https://www.devtrends.co.uk/blog/a-guide-to-caching-in-asp.net-core 195 | - Globaldir. Her kullanıcı aynı bilgileri görür. 196 | - Statik değişkenlerden farkı, burada süre belirtebiliyoruz. 197 | - İsteğimiz dışımızda, server alan açmaya zorlandığında yine bu cache’ler silinebilir. 198 | - Bu silinmeler önceliğe göre yapılır. 199 | - ASP.NET Core içinde caching mekanizaması bir servis olarak bulunmaktadır. 200 | - Bu nedenle bu servisi kullanmadan önce `Startup.cs` içine eklemek gerekmektedir. 201 | 202 | ```cs 203 | public void ConfigureServices(IServiceCollection services) 204 | { 205 | services.AddMvc(); 206 | services.AddMemoryCache(); 207 | } 208 | ``` 209 | 210 | - Caching mekanizmasını kullanacağımız herhangi bir yerde, bu servis DI ile enjekte edilip kullanılır. 211 | 212 | ```cs 213 | private IMemoryCache cache; 214 | public IDGCacheController(IMemoryCache cache) 215 | { 216 | this.cache = cache; 217 | } 218 | ``` 219 | 220 | #### Cache oluşturma 221 | 222 | ```cs 223 | public static TItem Set(this IMemoryCache cache, object key, TItem value); 224 | public static TItem Set(this IMemoryCache cache, object key, TItem value, DateTimeOffset absoluteExpiration); 225 | public static TItem Set(this IMemoryCache cache, object key, TItem value, TimeSpan absoluteExpirationRelativeToNow); 226 | public static TItem Set(this IMemoryCache cache, object key, TItem value, IChangeToken expirationToken); 227 | public static TItem Set(this IMemoryCache cache, object key, TItem value, MemoryCacheEntryOptions options); 228 | ``` 229 | 230 | #### Cache Options 231 | 232 | ```cs 233 | public DateTimeOffset? AbsoluteExpiration { get; set; } 234 | // 235 | // Summary: 236 | // Gets or sets an absolute expiration time, relative to now. 237 | public TimeSpan? AbsoluteExpirationRelativeToNow { get; set; } 238 | // 239 | // Summary: 240 | // Gets or sets how long a cache entry can be inactive (e.g. not accessed) before 241 | // it will be removed. This will not extend the entry lifetime beyond the absolute 242 | // expiration (if set). 243 | public TimeSpan? SlidingExpiration { get; set; } 244 | // 245 | // Summary: 246 | // Gets the Microsoft.Extensions.Primitives.IChangeToken instances which cause the 247 | // cache entry to expire. 248 | public IList ExpirationTokens { get; } 249 | // 250 | // Summary: 251 | // Gets or sets the callbacks will be fired after the cache entry is evicted from 252 | // the cache. 253 | public IList PostEvictionCallbacks { get; } 254 | // 255 | // Summary: 256 | // Gets or sets the priority for keeping the cache entry in the cache during a memory 257 | // pressure triggered cleanup. The default is Microsoft.Extensions.Caching.Memory.CacheItemPriority.Normal. 258 | public CacheItemPriority Priority { get; set; } 259 | // 260 | // Summary: 261 | // Gets or sets the size of the cache entry value. 262 | public long? Size { get; set; } 263 | ``` 264 | 265 | #### Cache okuma 266 | 267 | ```cs 268 | public static object Get(this IMemoryCache cache, object key); 269 | public static TItem Get(this IMemoryCache cache, object key); 270 | 271 | public static bool TryGetValue(this IMemoryCache cache, object key, out TItem value); 272 | 273 | public static TItem GetOrCreate(this IMemoryCache cache, object key, Func factory); 274 | [AsyncStateMachine(typeof(CacheExtensions.d__9<>))] 275 | public static Task GetOrCreateAsync(this IMemoryCache cache, object key, Func> factory); 276 | ``` 277 | 278 | - Basit olarak bir cache kontrolü, yoksa oluşturulması, varsa geri döndürülmesi şu şekilde oluşturulur: 279 | 280 | ```cs 281 | public string GetCacheValue(){ 282 | string key ="IDGKey"; 283 | string obj; 284 | 285 | if (!cache.TryGetValue(key, out obj)) 286 | { 287 | obj = DateTime.Now.ToString(); 288 | cache.Set(key, obj); 289 | } 290 | 291 | return obj; 292 | } 293 | ``` 294 | 295 | - Aynı işlemler daha basit olarak `GetOrCreate()` metoduyla da yapılabilir. 296 | - Bu metot varsa çeker, yoksa oluşturup geri döndürür. 297 | 298 | ```cs 299 | public string Get() 300 | { 301 | return cache.GetOrCreate(“IDGKey”, 302 | cacheEntry => { 303 | return DateTime.Now.ToString(); 304 | }); 305 | } 306 | ``` 307 | 308 | #### External class içinde cache kullanımı 309 | 310 | - Diğerlerinden olduğu gibi, `IMemoryCache` interface'i parametre olarak verilir ve kullanılıldığı controller üzerinde DI ile enjekte edilip, metoda parametre olarak verilir. 311 | 312 | ```cs 313 | // External class : 314 | public class MyCacheExp 315 | { 316 | public static T GetCache(IMemoryCache cache, string key) 317 | => cache.Get(key); 318 | } 319 | 320 | // Controller : 321 | ViewBag.date = MyCacheExp.GetCache(cache, "date"); 322 | ``` 323 | 324 | #### Cache Silme 325 | 326 | ```cs 327 | public IActionResult Delete() 328 | { 329 | cache.Remove("date"); 330 | return RedirectToAction("Index"); 331 | } 332 | ``` 333 | 334 | ### Diğer Durum Yönetim Yöntemleri 335 | 336 | - Yukarıdaki yöntemler dışında, bilgileri sayfalar arasında aktarma işlemleri yaparken kullanabileceğimiz yöntemler şunlardır : 337 | - TempData 338 | - QueryString 339 | - PostData içinde Hidden alanlar 340 | - Statik değişkenler kullanma 341 | - Dosyalara ve Database'e kayıt -------------------------------------------------------------------------------- /20 - ASP.NET Core In-Depth - Middleware.md: -------------------------------------------------------------------------------- 1 | ## MIDDLEWARE 2 | 3 | - Oluşturulan Middleware'ler, `Request`'ten `Response`'a kadar olan döngü arasına yazılan ve bu ikisi arasında manipülasyon işlemleri yapan elemanlardır. 4 | - Her bir component; 5 | - Pipeline üzerinde, sonraki elemana geçiş yapılmasını sağlayabilir veya geçişi kesebilir. 6 | - Sonra gelen component öncesinde ve sonrasında işlem yapılmasını sağlayabilir. (Encapsulation) 7 | - `RequestDelegate`, Request pipeline kurulmasında görevlidir. 8 | - Her gelen HTTP isteğiyle `RequestDelegate` ilgilenir. 9 | - `RequestDelegate` için tanımlanan `Run`, `Map` ve `Use` extension metotlarıyla, `In-Line` veya `Reusable Class` kullanılarak middleware eklemesi yapılabilir. 10 | - Sonraki pipeline'a geçiş işlemleri bu sınıf üzerinden yapılır. 11 | - Her middleware, pipeline üzerinde kendisinden sonra gelen componeti çalıştırmak veya `short-circuiting` ile direk response cevabı vermek ile görevlidir. 12 | 13 | ### 01 - IApplicationBuilder ile Middleware Pipeline oluşturma 14 | 15 |

    16 | 17 |

    18 | 19 | - Core üzerinde middleware'ler, `IApplicationBuilder` ile düzenlenir. 20 | - Bu yapının düzenlenmesi, `Starup.cs` içindeki `Configure` metodunda olur. 21 | - Yukarıdaki şekilden de görüleceği üzere, her middleware, kendisinden sonra gelen yapıdan önce ve sonra çalışır (kapsar). 22 | - Ayrıca her middleware, kendisinden sonra gelecek yapının çalışıp çalışmayacağına karar verir. 23 | - Bu karar yapısı, `next()` fonksiyonunun çalışıp çalışmamasıyla alakalıdır. 24 | - Eğer yapıda short-circuit isteniyorsa, next metodu çalıştırılmaz ve başka bir yönlendirme yapılır. 25 | 26 | #### Middleware Ekleme : IApplicationBuilder.Run() 27 | 28 | - `Run()` metoduyla eklenen middleware, pipeline'ı sonlandırır. 29 | - Bundan dolayı içinde `next()` metodu bulundurmaz. 30 | 31 | ```cs 32 | using Microsoft.AspNetCore.Builder; 33 | using Microsoft.AspNetCore.Hosting; 34 | using Microsoft.AspNetCore.Http; 35 | 36 | public class Startup 37 | { 38 | public void Configure(IApplicationBuilder app) 39 | { 40 | app.Run(async context => 41 | { 42 | await context.Response.WriteAsync("Hello, World!"); 43 | }); 44 | } 45 | } 46 | 47 | ``` 48 | 49 | #### Middleware Ekleme : IApplicationBuilder.Use() 50 | 51 | - Birden fazla middleware'i birbirine bağlamak için kullanılır. 52 | - `next()` metoduyla kendinden sonra gelen componenti çalıştırabilir. 53 | 54 | ```cs 55 | public class Startup 56 | { 57 | public void Configure(IApplicationBuilder app) 58 | { 59 | app.Use(async (context, next) => 60 | { 61 | // Do work that doesn't write to the Response. 62 | await next.Invoke(); 63 | // Do logging or other work that doesn't write to the Response. 64 | }); 65 | 66 | app.Run(async context => 67 | { 68 | await context.Response.WriteAsync("Hello from 2nd delegate."); 69 | }); 70 | } 71 | } 72 | ``` 73 | 74 | - Buradaki `next` parametresi öncesinde yazılan kodlar, sonra gelecek olan component çalıştırılmadan önce; `next` parametresi çalıştrıldıktan sonra yazılan kodlar, sonraki component çalıştırıldıktan sonra çalışır. 75 | - Başka bir deyişle **next parametresi öncesindeki kodlar `request` oluştuktan sonra, next parametresi sonrasındakiler ise `response` oluştuktan sonra** çalışır. 76 | - Bu yapıyla, önceki middleware'in, sonrakini **kapsadığını** anlayabiliriz. 77 | - Örnek vermek gerekirse; 78 | 79 | ```cs 80 | public class Startup 81 | { 82 | public void Configure(IApplicationBuilder app) 83 | { 84 | app.Use(async (context, next) => 85 | { 86 | Fn.LogYaz("Before Middleware 1"); 87 | await next.Invoke(); 88 | Fn.LogYaz("After Middleware 1"); 89 | }); 90 | 91 | app.Use(async (context, next) => 92 | { 93 | Fn.LogYaz("Before Middleware 2"); 94 | await next.Invoke(); 95 | Fn.LogYaz("After Middleware 2"); 96 | }); 97 | } 98 | } 99 | ``` 100 | 101 | ``` 102 | # ÇIKTI 103 | Startup sınıfı oluşturuldu. 104 | ConfigureServices metodu çalıştı. 105 | Configure metodu çalıştı. 106 | Main metodu çalıştı. 107 | 108 | Before Middleware 1 109 | Before Middleware 2 110 | After Middleware 2 111 | After Middleware 1 112 | ``` 113 | 114 | > **NOT** : Middleware'ler next parametreleriyle en son middleware'e ulaşınca `Response` oluşur ve middleware üzerinden geriye doğru tekrar geçer. Bu geriye geçişte Response üzerinde değişiklik yapılamaz. Yapılırsa değişiklik değişmez veya hata alınır. Bunu kontrol etmenin en iyi yolu `context.Response.HasStarted` ile kontrol sağlamaktır. 115 | 116 | ```cs 117 | public class Startup 118 | { 119 | public void Configure(IApplicationBuilder app) 120 | { 121 | app.Use(async (context, next) => 122 | { 123 | Fn.LogYaz("Before Middleware"); 124 | 125 | if (context.Response.HasStarted) 126 | Fn.LogYaz("Response oluştu!"); 127 | else 128 | Fn.LogYaz("Response bekliyor."); 129 | 130 | context.Response.Headers.Add("exp1", "value1"); 131 | 132 | await next.Invoke(); 133 | 134 | Fn.LogYaz("After Middleware"); 135 | 136 | if (context.Response.HasStarted) 137 | Fn.LogYaz("Response oluştu!"); 138 | else 139 | Fn.LogYaz("Response bekliyor!"); 140 | 141 | context.Response.Headers.Add("exp2", "value2"); 142 | }); 143 | } 144 | } 145 | ``` 146 | 147 | ``` 148 | # ÇIKTI 149 | Before Middleware 150 | Response bekliyor. 151 | After Middleware 152 | Response oluştu! 153 | 154 | # HEADERS 155 | exp1 : value1 156 | ``` 157 | 158 | #### Middleware Ekleme : IApplicationBuilder.Map() ve IApplicationBuilder.MapWhen() 159 | 160 | - `Map*`, verilen request url path ile, birbirinden farklı middleware çalıştırmamıza olanak sağlayan bir yapıdır. 161 | - Verilen url path kısmı ile **başlayan** tüm url isteklerinde, belli bir fonksiyonun middleware olarak kullanılması sağlanabilir. 162 | 163 | ```cs 164 | public class Startup 165 | { 166 | private static void HandleMapTest1(IApplicationBuilder app) 167 | { 168 | app.Run(async context => 169 | { 170 | await context.Response.WriteAsync("Map Test 1"); 171 | }); 172 | } 173 | 174 | private static void HandleMapTest2(IApplicationBuilder app) 175 | { 176 | app.Run(async context => 177 | { 178 | await context.Response.WriteAsync("Map Test 2"); 179 | }); 180 | } 181 | 182 | public void Configure(IApplicationBuilder app) 183 | { 184 | app.Map("/map1", HandleMapTest1); 185 | 186 | app.Map("/map2", HandleMapTest2); 187 | 188 | app.Run(async context => 189 | { 190 | await context.Response.WriteAsync("Hello from non-Map delegate.

    "); 191 | }); 192 | } 193 | } 194 | 195 | // RESULT 196 | // Request Response 197 | // localhost:1234 Hello from non-Map delegate. 198 | // localhost:1234/map1 Map Test 1 199 | // localhost:1234/map2 Map Test 2 200 | // localhost:1234/map3 Hello from non-Map delegate. 201 | ``` 202 | 203 | > **NOT** : `Map` fonksiyonu kullanıldığında, belirtilen path kısmı, `HttpRequest.Path` üzerinden silinir. 204 | 205 | ```cs 206 | private static void HandleMapTest1(IApplicationBuilder app) 207 | { 208 | app.Run(async context => 209 | { 210 | var url = context.Request.Path; 211 | await context.Response.WriteAsync("URL : " + url); 212 | }); 213 | } 214 | 215 | // RESULT 216 | // Request Response 217 | // localhost:1234/map1 URL : 218 | // localhost:1234/map1/exp URL : /exp 219 | ``` 220 | 221 | - `MapWhen` fonksiyonu ise, `Map` fonksiyonundan farklı olarak, bellirli bir durumu fonksiyon olarak vermemizi ve bu durum sağlandığı müddetçe, belirtilen middleware eklenmesini sağlar. 222 | 223 | ```cs 224 | public class Startup 225 | { 226 | private static void HandleBranch(IApplicationBuilder app) 227 | { 228 | app.Run(async context => 229 | { 230 | var branchVer = context.Request.Query["branch"]; 231 | await context.Response.WriteAsync($"Branch used = {branchVer}"); 232 | }); 233 | } 234 | 235 | public void Configure(IApplicationBuilder app) 236 | { 237 | app.MapWhen(context => context.Request.Query.ContainsKey("branch"), 238 | HandleBranch); 239 | 240 | app.Run(async context => 241 | { 242 | await context.Response.WriteAsync("Hello from non-Map delegate.

    "); 243 | }); 244 | } 245 | } 246 | 247 | // RESULT 248 | // Request Response 249 | // localhost:1234 Hello from non-Map delegate. 250 | // localhost:1234/?branch=master Branch used = master 251 | ``` 252 | 253 | - `Map` fonksiyonu nesting yapısını destekler: 254 | 255 | ```cs 256 | app.Map("/level1", level1App => { 257 | level1App.Map("/level2a", level2AApp => { 258 | // "/level1/level2a" 259 | //... 260 | }); 261 | level1App.Map("/level2b", level2BApp => { 262 | // "/level1/level2b" 263 | //... 264 | }); 265 | }); 266 | ``` 267 | 268 | ### 02 - Hazır Middleware Yapıları 269 | 270 | - Dotnet Core içinde gelen hazır middleware yapılarına [burdan](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.0&tabs=aspnetcore2x#built-in-middleware) ulaşılabilir. 271 | - Burda bilinmesi gereken önemli nokta, bu yapılar eklenirken sırasına dikkat edilmesidir. 272 | - Listede verilen sıralamaya göre eklenmesi gerekir. 273 | 274 | ### 03 - External Class Yapısında Middleware Oluşturma ve Kullanma 275 | 276 | - Middleware olarak kullanılabilecek iki çeşit class yapısı aşağıdaki gibidir: 277 | 278 | ```cs 279 | using Microsoft.AspNetCore.Http; 280 | using System.Globalization; 281 | using System.Threading.Tasks; 282 | 283 | namespace Culture 284 | { 285 | // Create Middleware (Request only) 286 | public class RequestCultureMiddleware 287 | { 288 | private readonly RequestDelegate _next; 289 | 290 | public RequestCultureMiddleware(RequestDelegate next) 291 | { 292 | _next = next; 293 | } 294 | 295 | public Task InvokeAsync(HttpContext context) 296 | { 297 | // Request Codes... 298 | 299 | // Call the next delegate/middleware in the pipeline 300 | return this._next(context); 301 | } 302 | } 303 | 304 | // Create Middleware (Request and Response) 305 | public class RequestCultureMiddleware 306 | { 307 | private readonly RequestDelegate _next; 308 | 309 | public RequestCultureMiddleware(RequestDelegate next) 310 | { 311 | _next = next; 312 | } 313 | 314 | public async Task InvokeAsync(HttpContext context) 315 | { 316 | // Request Codes... 317 | 318 | // Call the next delegate/middleware in the pipeline 319 | await this._next(context); 320 | 321 | // Response Codes... 322 | } 323 | } 324 | 325 | // Add the middleware to IApplicationBuilder as extension method (optional) 326 | public static class RequestCultureMiddlewareExtensions 327 | { 328 | public static IApplicationBuilder UseRequestCulture( 329 | this IApplicationBuilder builder) 330 | { 331 | return builder.UseMiddleware(); 332 | } 333 | } 334 | } 335 | ``` 336 | 337 | - Middleware oluşturulduktan sonra direk `Configure` içinde kullanılabileceği gibi, `IApplicationBuilder` içine extension metot olarak eklenip de kullanılabilir. 338 | - Bu yapılar : 339 | 340 | ```cs 341 | public class Startup 342 | { 343 | public void Configure(IApplicationBuilder app) 344 | { 345 | // Use directly 346 | app.UseMiddleware(); 347 | 348 | // Use as extension method 349 | app.UseRequestCulture(); 350 | 351 | app.Run(async (context) => 352 | { 353 | await context.Response.WriteAsync( 354 | $"Hello {CultureInfo.CurrentCulture.DisplayName}"); 355 | }); 356 | 357 | } 358 | } 359 | ``` 360 | 361 | ### 04 - Middleware Yapılarında Dependency Injection 362 | 363 | #### Conventional Middleware Activation 364 | 365 | - Middleware classları, **program başlangıcında**, configuration ayarları bittikten sonra oluşturulur. 366 | - Oluşum esnasında constructor metotlar çalıştırılıp nesne türetilir, fakat `invoke()` metodu, requestler geldiğinde çalıştırılır. 367 | - Her request için değil, program başlangıcında nesneler türetildiği için, `scoped` ömrüne sahip servisler constructor metotlar ile enjekte edilemez. Bunun yerine `Invoke()` metoda `parametre` olarak verilip alınabilir. 368 | 369 | ```cs 370 | public class RequestCultureMiddleware 371 | { 372 | private readonly RequestDelegate _next; 373 | 374 | public RequestCultureMiddleware(RequestDelegate next) 375 | { 376 | _next = next; 377 | } 378 | 379 | public async Task InvokeAsync(HttpContext context, IUnitOfWork db) 380 | { 381 | db.Logs.Add(new Models.Log{ LogName = "Example Log" }); 382 | db.SaveChanges(); 383 | 384 | await _next(context); 385 | } 386 | } 387 | ``` 388 | 389 | #### Factory-Based Middleware Activation 390 | 391 | - `IMiddleware` interface'i ile oluşturulmuş middleware yapılarıdır. 392 | - Avantajları: 393 | - Her request ile birlikte tekrar oluşturulurlar. 394 | - Her request oluşturulduğunda constructor metodu tekrar çalıştırılır. 395 | - `scoped` ömrüne sahip servisler, constructor metot içinde enjekte edilebilirler. 396 | - Factory-Based middleware kullanımı için, kullanmadan önce bu sınıfın servis olarak eklenmesi gerekmektedir. 397 | 398 | ```cs 399 | // Create Factory-Based Middleware 400 | public class IMiddlewareMiddleware : IMiddleware 401 | { 402 | private readonly AppDbContext _db; 403 | 404 | public IMiddlewareMiddleware(AppDbContext db) 405 | => _db = db; 406 | 407 | public async Task InvokeAsync(HttpContext context, RequestDelegate next) 408 | { 409 | _db.Logs.Add(new Models.Log { Area4 = "Deneme" }); 410 | await _db.SaveChangesAsync(); 411 | 412 | await next(context); 413 | } 414 | } 415 | 416 | // Use as extension method (optional) 417 | public static class MiddlewareExtensions 418 | { 419 | public static IApplicationBuilder UseIMiddlewareMiddleware( 420 | this IApplicationBuilder builder) 421 | { 422 | return builder.UseMiddleware(); 423 | } 424 | } 425 | ``` 426 | 427 | ```cs 428 | // Startup.cs 429 | 430 | public void ConfigureServices(IServiceCollection services) 431 | { 432 | services.AddDbContext(options => 433 | options.UseInMemoryDatabase("InMemoryDb")); 434 | 435 | services.AddTransient(); 436 | } 437 | 438 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 439 | { 440 | app.UseIMiddlewareMiddleware(); 441 | } 442 | ``` -------------------------------------------------------------------------------- /13 - Validation İşlemleri.md: -------------------------------------------------------------------------------- 1 | ## VALIDATION İŞLEMLERİ 2 | 3 | ### 01 - Giriş 4 | - Validation kontrolü yapmanın önemi 5 | - Web zaafiyetlerinin en büyük nedeni input validation eksikliğinden kaynaklanır. 6 | - Ayrıca kullanıcıdan alınan bilgilerin bazı kurallara uyması gerekir. Örn: Parolanın minimum uzunluğu gibi. 7 | - .NET kütüphanesi ile, alınan her verinin validation kontrolünün ayrı ayrı yapılma zorluğu ortadan kalkmış ve bu validationların model üzerinden attribute olarak tanımlanması sağlanmıştır. 8 | - Bu şekilde validation yapıldığıda, kontrol etmek için sadece `ModelState` üzerinde `IsValid` kontrolü yapmak yeterlidir. 9 | 10 | > **NOT:** .NET Framework sürümünde, inputa gidilen html kodları otomatik olarak elimine edilip zararlı kod olarak algılanıyordu. .NET Core sürümünde ise bu kontrol yapılmamaktadır. Buna dikkat edilmesi gerekir. 11 | 12 | - Validation işlemleri `Model Binding` tarafından yönetilir. 13 | - Model Binding, `ModelStateDictionary` ile çalışır. 14 | - Bu dictionary içinde temel olarak kullanacağımız 3 yapı vardır: 15 | 1. **AddModelError:** Model içindeki herhangi bir property üzerine error eklemeyi sağlar 16 | 2. **GetValidationStat:** Validasyon durumunu gösterir. Enum değer döndürür. 17 | 3. **IsValid:** Validasyon işlemi sonucunda `true` veya `false` döndürür. 18 | - ModelState ifadesi, programı debug modda çalıştırınca, `QuickWatch` penceresinden izlenebilir. 19 | 20 |

    21 | 22 |

    23 | 24 | İleriki kısımlarda kullanılacak model ve html yapısı yapısı: 25 | ```cs 26 | public class Register 27 | { 28 | public string UserName { get; set; } 29 | public string EMail { get; set; } 30 | public string Password { get; set; } 31 | public DateTime Birthday { get; set; } 32 | public bool TermsAccepted { get; set; } 33 | } 34 | ``` 35 | 36 | ```html 37 | @model Register 38 | 39 |
    40 | 41 |
    42 | 43 |
    44 | 45 | 46 | 47 |
    48 | 49 |
    50 | 51 | 52 | 53 |
    54 | 55 |
    56 | 57 | 58 | 59 |
    60 | 61 | 62 |
    63 | ``` 64 | 65 | ### 02 - Modele Error Mesaj Ekleme 66 | 67 | - Modele error mesaj eklemek için, `ModelState`'in `AddModelError` metodu kullanılır. 68 | - İlk parametre olarak eklenmesini istediğimiz property ismini, ikinci olarak da eklemek istediğimiz mesajı gireriz. 69 | - Property ismini `string` veya `nameof()` ifadeleriyle verebiliriz. 70 | - **NOT:** Model içindeki herhangi bir property'ye bu metot ile hata mesajı eklendiğinde, `IsValid` işlemi false döner. 71 | 72 | ```cs 73 | [HttpPost] 74 | public IActionResult Index(Register model) 75 | { 76 | if (model.Password != null && model.Password.Length < 6) 77 | ModelState.AddModelError("Password", "Parola en az 6 karakterli olmalıdır."); 78 | 79 | if (!model.EMail.Contains("@")) 80 | ModelState.AddModelError(nameof(Register.EMail), "Girilen değer email olmalıdır!"); 81 | 82 | return View(model); 83 | } 84 | ``` 85 | 86 | ### 03 - Form Üzerinde Validation Hata Mesajlarını Gösterme 87 | 88 | - Bir model üzerinde Validation kontrolü yapıldığında, model üzerine hata mesajları da eklenir. 89 | - Bu nedenle hata mesajlarının gösterilmesi için, *validation kontrolünden geçmiş modelin* tekrar sayfaya gönderilmesi gereklidir. 90 | - Bu model daha sonra tekrar View üzerine gönderildiğinde, inputlar `asp-for` ile tanımlanmışsa, input'un class yapısına `.input-validation-error` isminde bir class daha eklenir. 91 | - Bu class ismi kullanılarak, hatalı validation hatası yakalanmış inputlar üzerinde css düzenlemesi yapılabilir. Örn, input kırmızı border ile işaretlenebilir. 92 | - Validation işlemlerini her input için ayrı ayrı göstermek istiyorsak, `asp-validation-for` yapısı kullanılmalıdır. 93 | 94 | ```html 95 |
    96 | 97 | 98 | 99 |
    100 | ``` 101 | 102 | - Validation mesajlarının tamamının gösterilmesi için, `asp-validation-summary` yapısı kullanılmalıdır. Bu yapının 3 tane enum değeri vardır: 103 | - **All:** Property ve model errorların hepsi gösterilir. 104 | - **ModelOnly:** Property errorları dahil edilmez, sadece model'e manuel eklenen hata mesajları gösterilir. 105 | - **None:** Herhangi bir hata mesajı gösterilmez. 106 | 107 | ```html 108 |
    109 | ``` 110 | 111 | ### 04 - MetaData Etiketleri 112 | 113 | - MetaData etiketleri .NET içinde aşağıdaki `ComponentModel` ve `DataAnnotations` kütüphaneleri içinde bulunur. 114 | 115 | ```cs 116 | using System.ComponentModel; 117 | using System.ComponentModel.DataAnnotations; 118 | using Microsoft.AspNetCore.Mvc; 119 | ``` 120 | 121 | - **DiplayName()** : View içinde label tagı `asp-for` ile kullanıldığında otomatik olarak burdaki ismi çeker. 122 | - Bu sayede, tüm formlar üzerinde aynı ismi kullanmış oluruz ve düzenlemesi daha kolay olur. 123 | - **Required()** : Bir alanın girilmesini zorunlu kılmak için kullanılır. 124 | - **Range()** : Sayısal ifadelerin belirli bir double aralıkta girilmesini sağlamak için kullanılır. 125 | - ilk parametresine farklı bir type verilerek, double ifadeler dışında da bir aralık girilmesi sağlanabilir. 126 | - **NOT:** Bu, client-side bazen validation sorunları çıkarabiliyor. 127 | 128 | ```cs 129 | [Range(0, 100)] 130 | // veya 131 | [Range(typeof(bool), "true", "true")] 132 | ``` 133 | 134 | - **MinLength()** : String ifadenin min uzunluğunu belirlemek için kullanılır. 135 | - **MaxLength()** : String ifadenin max uzunluğunu belirlemek için kullanılır. 136 | - **DataType()** : Parametre olarak enum değerlerden biri seçilerek, client side validation hata gösterimleri için bir type yaratır. 137 | - **Compare()** : Bir property'i başka biriyle karşılaştırmak için kullanılır. Eğer uyumsuzluk varsa hata verir. 138 | - Genellikle parola kontrolü için kullanılır. 139 | - Parametre olarak, karşılaştırılacak property'nin string olarak ismi verilebileceği gibi, `nameof` ile otomatik olarak de çekilebilir. 140 | 141 | ```cs 142 | [Required] 143 | public string Password { get; set; } 144 | [Required, Compare(nameof(Password))] 145 | public string RePassword { get; set; } 146 | ``` 147 | 148 | - **RegularExpression()** : Bir alana regex kısıtlaması getirmemizi sağlar. 149 | - **HiddenInput()** : Belirtilen alanın, kullanıldığı yerde `type="hidden"` olarak işaretlenmesini sağlar. 150 | - Yukarıdakilerden farklı bir kütüphaneden gelir. 151 | - `using Microsoft.AspNetCore.Mvc;` 152 | - **DisplayFormat()** : Sayfaya bastırılacak fotmat bilgisi belirlenir. Genellikle Tarih, Saat, Sayı formatlama gibi durumlarda kullanılır. 153 | - `ApplyFormatInEditMode` özelliği varsayılan olarak false durumundadır. Eğer bu formatlı görüntünün input içerisinde de görünmesini istiyorsak true yaparız. 154 | - `NullDisplayText` özelliğini kullanarak NULL dönen sonuçlar yerine bir not gösterilmesini sağlayabilirsiniz. 155 | 156 | ```cs 157 | [DisplayFormat(ApplyFormatInEditMode=true, DataFormatString="{0:c}")] 158 | public decimal Ucret { get; set; } 159 | ``` 160 | 161 | - **Remote()** : Client side validation için ilgili js dosyaları projeye eklenmişse, belirtilen endpoint'e istek yollayarak (ajax yapısı ile) kontrol işlemi yapar. 162 | - Daha çok kullanıcı adı veya mail gibi alanların db üzerinde bulunup bulunmadığını kontrol etmek için kullanılır. 163 | - Verilecek parametreler : 164 | - **action** : Gideceği action ismi 165 | - **controller** : Gideceği controller ismi 166 | - **area** : Belirtilmesi gerekiyorsa area ismi 167 | - **HttpMethod** : Gideceği endpoint'e hangi türde bir istek yapılacağını string olarak belirtiriz. 168 | - **ErrorMessage** : Eğer gittiği endpointten herhangi bir ifade dönmezse, bu hata mesajı yazdırılır. 169 | - İstek yaptığı endpointten json olarak `true` veya hata mesajı bekler. True ifadesi gidildiğinde validation yapar, diğer durumlarda validation yapmaz ve hata mesajını yazdırır. 170 | - Endpoint üzerinden property ismi parametre olarak alınıp kullanılabilir. 171 | - Doc : https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation#remote-validation 172 | > - **NOT 1 :** Bu metodun çalışması için client-side validation kütüphanelerinin yüklenmesi zorunludur. 173 | 174 | > - **NOT 2 :** Eğer database tabloları MVC projesinin dışında başka bir proje içinde oluşturulmuşsa, ilgili > proje içine `Microsoft.AspNetCore.Mvc` kütüphanesinin eklenmesi gerekmektedir. 175 | > 176 | > ``` 177 | > 178 | > 179 | > 180 | > ``` 181 | 182 | ```cs 183 | // Model 184 | [Remote(action:"UserNameCheck", controller:"Validation", HttpMethod = "Post", ErrorMessage = "Remote control not checked!")] 185 | public string UserName { get; set; } 186 | 187 | // Controller 188 | [HttpPost] 189 | public IActionResult UserNameCheck(string UserName) 190 | { 191 | if (usernameCheck(UserName)) 192 | return Json(true); 193 | else 194 | return Json($"{UserName} does exists."); 195 | } 196 | ``` 197 | 198 | *Modelin son yapısı:* 199 | ```cs 200 | using Microsoft.AspNetCore.Mvc; 201 | using System.ComponentModel; 202 | using System.ComponentModel.DataAnnotations; 203 | 204 | namespace WebApplication1.Models 205 | { 206 | public class Register 207 | { 208 | [DisplayName("User Name"), Required, MinLength(4), MaxLength(10)] 209 | [Remote(action:"Check", controller:"Validation", HttpMethod = "Post", ErrorMessage = "Remote control not checked!")] 210 | public string UserName { get; set; } 211 | 212 | [DisplayName("E-Mail"), DataType(DataType.EmailAddress)] 213 | [RegularExpression("^[a-z0-9]+@mail.com$")] 214 | public string EMail { get; set; } 215 | 216 | [DisplayName("Password"), Required, DataType(DataType.Password)] 217 | public string Password { get; set; } 218 | 219 | [DisplayName("RePassword"), Required, DataType(DataType.Password), Compare(nameof(Password))] 220 | public string RePassword { get; set; } 221 | 222 | [DisplayName("Accepting Terms"), Required] 223 | public bool TermsAccepted { get; set; } 224 | 225 | [DisplayFormat(DataFormatString = "{0:MMM dd, yyyy}")] 226 | public DateTime BithDate { get; set; } 227 | } 228 | } 229 | ``` 230 | 231 | > - **NOT 3 :** Endpoint üzerinde kontrol edilecek parametre, doldurulan formun input alanındaki `name` ismiyle gönderilecek parametredir. Bu yüzden kullanılan formun name alanına dikkat edilmelidir. 232 | > - Örnek olarak aşağıdaki gibi ViewModel ile kullanılan bir form yapısı varsa, kontrol eden endpoint yapısı şu şekilde olmalıdır: 233 | > 234 | > ```cs 235 | >
    236 | > 237 | > 238 | > 239 | >
    240 | > ``` 241 | > 242 | > ```cs 243 | > [HttpPost] 244 | > public IActionResult Check_Kullanici_KullaniciAdi() 245 | > { 246 | > string kullaniciAdi = Request.Form["Kullanici.KullaniciAdi"]; 247 | > if (check(kullaniciAdi)) 248 | > return Json(true); 249 | > else 250 | > return Json($"{kullaniciAdi} daha önceden kullanılmış!"); 251 | > } 252 | > ``` 253 | 254 | ### 05 - Custom Error Message 255 | 256 | - Validasyon elemanlarının hepsinde default bir hata mesajı vardır. 257 | - Bu default değerler dışında kendimiz hata mesajı yazmak istediğimizde, MetaData'ların `ErrorMessage` parametresinden yararlanırız. 258 | - Bu parametre tüm MetaData'larda bulunur. 259 | - **NOT:** Hatalar gösterilirken, yazılma sırası dikkate alınır. İlk uyumsuzluk hatası gösterilir, düzeltilirse diğerleri gösterilir. 260 | - Hata mesajı içinde dinamik öğeler kullanabiliriz. Bunu, hata mesajının ilgili yerine `{}` ile yaparız. Bu yapıda; 261 | - `{0}` : Display name veya bu yoksa property ismini belirtir. 262 | - `{1}, {2}...` : Attribute içindeki değerlerin sırayla numaralandırmasıdır. 263 | 264 | ```cs 265 | [DisplayName("Age"), Range(18, 100, ErrorMessage = "{0} must be between {1} and {2}...")] 266 | public int Age { get; set; } 267 | 268 | // Result: 269 | // Age must be between 18 and 100... 270 | ``` 271 | 272 | ### 06 - Custom Property Validation Method 273 | 274 | - Default validation MetaData'ların yetmediği yerde kendi metotlarımızı yazabiliriz. 275 | - Bunun için `Attribute` ve `IModelValidator` sınıf ve interface'lerinden türeyen bir sınıfa ihtiyacımız var. 276 | - Bu sınıfın isminin `-Attribute` ile bitmesi gerekmektedir. 277 | - Interface'i implament ettiğimizda gelen `Validate` metodunu, aşağıdaki örneğe uygun yazdığımızda, artık bunu attribute olarak kullanabiliriz. 278 | - Model içinde kullandığımız attribute değerine `context.Model` üzerinden ulaşıp kontrol edebiliriz. 279 | - **NOT:** Bu yapı sadece server-side validation için kullanılabilir, client-side validation işlemleri bunu görmeyecektir. 280 | 281 | ```cs 282 | public class DateValidationAttribute : Attribute, IModelValidator 283 | { 284 | public string ErrorMessage { get; set; } 285 | = "Date cannot be bigger than today!"; 286 | 287 | public IEnumerable Validate(ModelValidationContext context) 288 | { 289 | var date = context.Model as DateTime?; 290 | 291 | // Block 292 | if (!date.HasValue || date > DateTime.Now) 293 | return new List 294 | { new ModelValidationResult("", ErrorMessage) }; 295 | 296 | // Allow 297 | else 298 | return Enumerable.Empty(); 299 | } 300 | } 301 | ``` 302 | 303 | Attribute olarak kullanımı : 304 | ```cs 305 | [DataType(DataType.Date), DateValidation] 306 | public DateTime BithDate { get; set; } 307 | ``` 308 | 309 | ### 07 - Validation Kontrolü 310 | 311 | - Formdan gelen verilerin, kaydedilmeden önce, validation işlemlerinden geçip geçmediğini kontrol etme yönetimidir. 312 | - Bunun için `ModelState` sınıfının `IsValid` özelliği kullanılır. 313 | - Formlarla yapılan her işlemde bu kontrol mutlaka yapılmalıdır. 314 | - Eğer validasyon işlemleri yeterli değilse, IsValid kontrolünden sonra if yapıları kullanılarak gerekli validasyonlar tekrar kontrol edilir. 315 | 316 | ```cs 317 | [ValidateAntiForgeryToken] 318 | [HttpPost] 319 | public ActionResult Index(Register model) 320 | { 321 | if (ModelState.IsValid) 322 | { 323 | // Save process 324 | } 325 | return View(model); 326 | } 327 | ``` 328 | 329 | ### 08 - Client Side Validation 330 | 331 | - Şu ana kadar yapılan işlemler, programın server-side validation işlemleri yapmaları için gerekli adımlardı. 332 | - Server-side validation yapıldığında, sayfanın formu server üzerine göndermesi ve doğal olarak sayfanın yenilenmesi gerekmekteydi. 333 | - Client-side validation yapıldığında ise, server üzerine bilgiler gönderilmeden önce validation işlemleri kontrol edilir ve bilgiler valid değilse form gönderilmez. 334 | - View içinde `asp-for` ile form verileri çekildiğinde, element içine aynı zamanda `data-val-` özellikleri otomatik gelir. 335 | - Bu elementler client-side validation için kullanılan attribute'lerdir. 336 | - Bu attribute'lerin kullanılması ve validation yapması için projemiz içine bazı js kütüphanelerini dahil etmemiz gerekmektedir. Bunlar; 337 | 1. JQuery 338 | 2. JQuery-Validation 339 | 3. JQuery-Validation-Unobtrusive 340 | - Bu kütüphanler projeye dahil edilip, html içine yolları verildikten sonra herhangi bir işlem yapmamıza gerek yoktur. Server-side validation kontrolü yapılacaktır. 341 | - **NOT:** Server-side validation güvensizdir. Tarayının js ayarları kapatıldığında veya tarayıcı dışında başka bir mekanizma ile bilgiler gönderildiğinde, bu validation çalışmayacaktır. Buradaki amaç sadece client tarafında daha efektif ve hızlı validation yapmaktır. **Server-side validation ve IsValid kontrolünün kesinlikle unutulmaması gereklidir!** -------------------------------------------------------------------------------- /17 - Deployment.md: -------------------------------------------------------------------------------- 1 | ## DEPLOYMENT 2 | 3 | - Core projesinin deployment süreci basit olarak 3 temel adımda gerçekleşir: 4 | 1. Projenin dizine publish edilmesi ve barındıracak host üzerine gönderilmesi. 5 | - Publish işlemi, projenin derlenip, Release sürümünün statik dosyalarla birlikte bir dizine veya ftp üzerinden belirlenen bir alana çıkarılması işlemidir. 6 | 2. Host üzerinde, servis oluşturulması 7 | - Dotnet Core projesi, temelinde bir konsol uygulaması olduğundan, server reboot veya programın çökmesi durumda tekrar başlatılması gerekmektedir. 8 | - Host üzerinde bu işlemler için bir servis yazıp, yukarıdaki durumlarda uygulamamızın tekrar başlatılmasını sağlamamız gerekmektedir. 9 | 3. Reverse Proxy kurulumu 10 | - Core uygulaması, kendi içinde `Kestel` adlı bir web server bulundurmaktadır. 11 | - Kestel, tüm web server işlemlerini ve statik dosya yönlendirmesi gibi işlemleri kendi içinde oluşturmaktadır. 12 | - Bununla birlikte, 5000 portundan dinleme yapan Kestel'i, herhangi bir proxy aracılığıyla istediğimiz bir portu (web için genellikle 80) dinlemeye ayarlamamız gerekmektedir. 13 | - Bunun için genellikle kullandığımız Reverse Proxy Server'lar: 14 | - IIS 15 | - Nginx 16 | - Apache 17 | 18 | ### 01 - Projeyi Yayınlama Yöntemleri 19 | 20 | Dotnet Core projeleri temel olarak iki şekilde yayınlanabilir: 21 | 22 | - **Framework Bağımlı Yayınlama (Framework-dependent deployments - FDD)** 23 | - Sadece uygulama ve 3. parti bağımlılıkların yayınlanmasına dayanır. 24 | - .NET Core runtime bağımlılığı vardır, bu yüzden deploy ettiğimiz hedef makinede .NET Core kütüphanesinin ilgili sürümü kurulu olması gerekmektedir. 25 | - İşletim sistemi belirtmeye gerek yoktur. Deploy ettikten sonra, her işletim kendi işletim sistemine özgü Core runtime üzerinden çalıştırılabilir haldedir. 26 | - Deployment paketi, sadece gerekli olan frameworkleri barındırdığı için boyutu küçüktür. 27 | 28 | - **Framework Bağımsız Yayınlama (Self-contained deployments - SCD)** 29 | - Uygulama, 3. parti bağımlılıklar ve dotnet core kütüphanelerinin birlikte deploy edilmesi yöntemidir. 30 | - Hedef kaynakta dotnet core kurulu olmasına gerek yoktur. 31 | - Dotnet core kütüphaneleri için işletim sistemi altyapıları farklı olduğundan, deploy ederken hangi işletim sistemi için deploy etmemiz gerektiğini belirtmemiz gerekmektedir. 32 | - [Runtime IDentifier Catalog](https://docs.microsoft.com/en-us/dotnet/core/rid-catalog) 33 | - Deployment paketi, FDD'ye göre daha büyük boyutludur. 34 | 35 | ### 02 - Projenin Yayınlanması 36 | 37 | - Proje, 4 farklı şekilde yayınlanabilir: 38 | - Framework-dependent deployment 39 | - Framework-dependent deployment with third-party dependencies 40 | - Self-contained deployment 41 | - Self-contained deployment with third-party dependencies 42 | 43 | #### i. CLI Araçları (Command-Line Interface Tools) ile yayınlama 44 | 45 | - Projeyi CLI ile yayınlarken `dotnet publish` komutunu kullanırız. 46 | - Bu komutun ayrıntılı opsiyonları aşağıdaki gibidir: 47 | 48 | ``` 49 | Usage: dotnet publish [options] 50 | 51 | Options: 52 | -h, --help Show help information. 53 | -o, --output Output directory in which to place the published artifacts. 54 | -f, --framework Target framework to publish for. The target framework has to be specified in the project file. 55 | -r, --runtime Publish the project for a given runtime. This is used when creating self-contained deployment. Default is to publish a framework-dependent app. 56 | -c, --configuration Configuration to use for building the project. Default for most projects is "Debug". 57 | --version-suffix Defines the value for the $(VersionSuffix) property in the project. 58 | --manifest The path to a target manifest file that contains the list of packages to be excluded from the publish step. 59 | --self-contained Publish the .NET Core runtime with your application so the runtime doesn't need to be installed on the target machine. Defaults to 'true' if a runtime identifier is specified. 60 | --no-restore Does not do an implicit restore when executing the command. 61 | -v, --verbosity Set the verbosity level of the command. Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]. 62 | --no-dependencies Set this flag to ignore project to project references and only restore the root project. 63 | --force Set this flag to force all dependencies to be resolved even if the last restore was successful. This is equivalent to deleting project.assets.json. 64 | 65 | ``` 66 | 67 | **Framework-dependent deployment** 68 | 69 | - Proje bağımlılıklarının güncellenmesi 70 | - `[proje-adi].csproj` dosyası içinde yazdığımız bağımlılıkların indirilmesi ve güncellenmesi işleminin yapılmasıdır. 71 | - `dotnet restore` komutu çalıştırılır. 72 | - Projenin derlenmesi 73 | - `dotnet build` komutu ile projenin son halinin derlenmesi işlemidir. 74 | - Projenin yayınlanması 75 | - `dotnet publish -f netcoreapp2.0 -c Release -o CorePublish` komutu projenin yayınlanacak dosyalarının oluşturulmasını sağlar. 76 | - `-o` parametresi ile publish edilecek dosyaların çıkarılacağı konumu belirtiyoruz. 77 | - `-c` parametresi ile derlenme ayarının belirtiyoruz. 78 | - `-f` parametresi ile projemizin framework versiyonunu belirtiyoruz. 79 | - Projenin çalıştırılması 80 | - `dotnet [app_name].dll` komutuyla, ilgili projenin dll dosyası dotnet aracılığıyla çalıştırılır. 81 | - Proje çalıştırıldığında, `localhost:5000` üzerinden yayın yapmaya başlar. 82 | 83 | **Self-contained deployment** 84 | 85 | - Projenin hedef platformlarının belirtilmesi 86 | - `[app_name].csproj` içine hedef platformların belirtilmesi gereklidir. 87 | - [Tüm platformlar için bakınız...](https://docs.microsoft.com/en-us/dotnet/core/rid-catalog) 88 | 89 | ```xml 90 | 91 | win10-x64;osx.10.11-x64 92 | 93 | ``` 94 | 95 | - Proje bağımlılıklarının güncellenmesi 96 | - `[proje-adi].csproj` dosyası içinde yazdığımız bağımlılıkların indirilmesi ve güncellenmesi işleminin yapılmasıdır. 97 | - `dotnet restore` komutu çalıştırılır. 98 | - Projenin derlenmesi 99 | - `dotnet build` komutu ile projenin son halinin derlenmesi işlemidir. 100 | - Projenin yayınlanması 101 | - `dotnet publish -r win10-x64 -f netcoreapp2.0 -c Release -o CorePublish` 102 | - `dotnet publish -r osx.10.11-x64 -f netcoreapp2.0 -c Release -o CorePublish` 103 | - `-r` parametresi ile hedef platformu belirtiyoruz. 104 | - `-o` parametresi ile publish edilecek dosyaların çıkarılacağı konumu belirtiyoruz. 105 | - `-c` parametresi ile derlenme ayarının belirtiyoruz. 106 | - `-f` parametresi ile projemizin framework versiyonunu belirtiyoruz. 107 | - Projenin çalıştırılması 108 | - Hedef platforma özgün olarak çıkarılmış `[app_name]` veya `[app_name].exe` dosyalarından biri çalıştrırılarak programa ulaşım sağlanır. 109 | - Proje çalıştırıldığında, `localhost:5000` üzerinden yayın yapmaya başlar. 110 | 111 | #### ii. Visual Studio ile Yayınlama 112 | 113 | **Framework-dependent deployment** 114 | 115 | - Projenin derlenmesi 116 | - Solution üzerine sağ tıklayıp `Build Solution` tıklanır. 117 | - Projenin yayınlanması 118 | - Araç çubukları üzerinden config kısmı `Debug > Release` olarak değiştirilir. 119 | - Proje üzerine sağ tıklanıp `Publish` tıklanır. 120 | - Buradan `Folder Publish` seçilip, dosyaların çıkarılacağı konum belirlenir. 121 | - Projenin çalıştırılması 122 | - `dotnet [app_name].dll` komutuyla, ilgili projenin dll dosyası dotnet aracılığıyla çalıştırılır. 123 | - Proje çalıştırıldığında, `localhost:5000` üzerinden yayın yapmaya başlar. 124 | 125 | **Self-contained deployment** 126 | 127 | - Projenin hedef platformlarının belirtilmesi 128 | - `[app_name].csproj` içine hedef platformların belirtilmesi gereklidir. 129 | - Projeye sağ tıklanıp `Edit [app_name].csproj` tıklanır. 130 | - [Tüm platformlar için bakınız...](https://docs.microsoft.com/en-us/dotnet/core/rid-catalog) 131 | 132 | ```xml 133 | 134 | win10-x64;osx.10.11-x64 135 | 136 | ``` 137 | 138 | - Projenin derlenmesi 139 | - Solution üzerine sağ tıklayıp `Build Solution` tıklanır. 140 | - Projenin yayınlanması 141 | - Araç çubukları üzerinden config kısmı `Debug > Release` olarak değiştirilir. 142 | - Proje üzerine sağ tıklanıp `Publish` tıklanır. 143 | - Buradan `Folder Publish` seçilip, dosyaların çıkarılacağı konum belirlenir. 144 | - Alt kısımdaki `Publish` kısmının yanındaki ayarlara tıklayarak, `Create Profile` olarak değiştirilir ve tıklanır. 145 | - Yeni gelen pencereden `Target Location > Settings > Target Runtime` kısmından ilgili platform seçilir. 146 | - Pencere kapatılıp `Start` butonuna tıklanır. 147 | - Projenin çalıştırılması 148 | - Hedef platforma özgün olarak çıkarılmış `[app_name]` veya `[app_name].exe` dosyalarından biri çalıştrırılarak programa ulaşım sağlanır. 149 | - Proje çalıştırıldığında, `localhost:5000` üzerinden yayın yapmaya başlar. 150 | 151 | #### iii. Publish Dosyaları 152 | 153 | - `[app-name].deps.json` : 154 | - Projenin çalışma zamanındaki bağımlılıklarını bulunduran dosyadır. 155 | - Kompoentleri ve kütüphaneleri bulundurur. 156 | - Projenin çalışması için zorunlu dosyadır. 157 | - [Ayrıntılı Bilgi](https://github.com/dotnet/cli/blob/85ca206d84633d658d7363894c4ea9d59e515c1a/Documentation/specs/runtime-configuration-file.md) 158 | - `[app-name].dll` : 159 | - Application'ı bulunduran dosyadır. 160 | - Yayın yapılırken bu dosya çalıştırılır. 161 | - `[app-name].pdb` : 162 | - Debug sembollerinin bulundugu dosyadır. 163 | - Projenin çalışması için zorunlu değildir. 164 | - `[app-name].runtimeconfig.json` : 165 | - Uygulamanın çalışma zamanı ayarlarının bulunduğu dosyadır. 166 | - Projenin yazıldığı dotnet versiyonunu da barındırır. 167 | - [Ayrıntılı Bilgi](https://github.com/dotnet/cli/blob/85ca206d84633d658d7363894c4ea9d59e515c1a/Documentation/specs/runtime-configuration-file.md) 168 | - `bundleconfig.json`: 169 | - Bundle configuration ayarlarını bulundurur. 170 | - `appsettings.json`: 171 | - Bağlantı stringi, log ayaları vb gibi ayaların bulunduğu json dosyasıdır. 172 | - `wwwroot` 173 | - Statik dosyaların bulundugu dizindir. 174 | 175 | ### 03 - Linux Server Ayarlamaları (Ubuntu 16.04) 176 | 177 | #### Self-Contained Deployment 178 | 179 | 1. Proje dosyası yukarıda anlatıldığı şekilde, `Self-Contained` olarak dosyaya yayınlanır. 180 | 2. Yayınlanan dosyalar server üzerine gönderilir. 181 | - Bunun için sunucumuza [FTP Server kurabileceğimiz](BONUS%20-%20FTP%20Server%20Kurulumu.md) gibi, SSH üzerinden de FTP bağlantısı yapıp dosyalarınızı gönderebilirsiniz. 182 | 3. Proje kütüphanelerini ekleme ve çalıştırma 183 | - Proje `dotnet` dahil olmak üzere tüm kütüphane yapılarını içinde bulundurduğundan, server üzerine herhangi bir kütüphane kurmaya gerek yoktur. 184 | - Proje içinde gelen `libxxx.so` kitaplıklarının `ldd` komutu ile sisteme eklenmesi gerekmektedir. 185 | - Daha sonra uygulama dosyası direk çalıştırılarak dotnet projesinin çalıştığını görebiliriz. 186 | 187 | ```bash 188 | # Kütüphaneleri sisteme ekleme 189 | $ ldd lib*.so 190 | 191 | # İstenilirse çalıştırılacak dosya yolu path olarak eklenebilir. 192 | # "proje" > dotnet ana dosyasıdır. 193 | $ export PATH=$PATH:/var/www/CoreProje/ 194 | 195 | # Dotnet dosyasının çalıştırılması 196 | $ proje 197 | 198 | Hosting environment: Production 199 | Content root path: /var/www/CoreProje/proje 200 | Now listening on: http://localhost:5000 201 | Application started. Press Ctrl+C to shut down. 202 | ... 203 | ``` 204 | 205 | > **NOT:** Self-contained olarak server üzerine kopyalanmış dosyalar çalıştırıldığında hata ile karşılaşılırsa, aşağıdaki iki kütüphanenin kurulması önerilir. 206 | 207 | ``` 208 | $ ./proje 209 | Failed to load ***, error: libunwind.so.8: cannot open shared object file: No such file or directory 210 | Failed to bind to CoreCLR at '/var/www/libcoreclr.so' 211 | 212 | $ apt install libicu-dev 213 | $ apt install libunwind-dev 214 | 215 | $ ./proje 216 | warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35] 217 | No XML encryptor configured. Key {61d5203f-7b87-4911-bb68-126a09425473} may be persisted to storage in unencrypted form. 218 | Hosting environment: Production 219 | Content root path: /var/www 220 | Now listening on: http://localhost:5000 221 | Application started. Press Ctrl+C to shut down. 222 | ``` 223 | 224 | 4. Reverse Proxy kurulur ve ayarlamaları yapılır. 225 | 5. Herhangi bir nedenden ötürü server veya uygulama kapanırsa tekrardan başlaması için gerekli olan servis dosyası oluşturulur ve çalıştırılır. 226 | 227 | #### Framework-Dependent Deployment 228 | 229 | 1. Proje dosyası yukarıda anlatıldığı şekilde, `Framework-Dependent` olarak dosyaya yayınlanır. 230 | 2. Yayınlanan dosyalar server üzerine gönderilir. 231 | - Bunun için sunucumuza [FTP Server kurabileceğimiz](BONUS%20-%20FTP%20Server%20Kurulumu.md) gibi, SSH üzerinden de FTP bağlantısı yapıp dosyalarınızı gönderebilirsiniz. 232 | 3. Dotnet kütüphane kurulumları yapılır. 233 | - Kütüphaneler iki farklı yöntemle kurulabilir: 234 | 1. `Dotnet Runtime` + `Dotnet Hosting` kurulabilir. 235 | 2. Geliştirici araçları da dahil olmak üzere her şeyi bulunduran `Dotnet SDK` kurulabilir. 236 | - Son sürüm kütüphaneleri Linux üzerinde görüntülemek için basitçe `apt search dotnet` komutu çalıştırılabilir. 237 | 238 | ```bash 239 | $ apt search dotnet 240 | 241 | dotnet-hosting-2.0.8/xenial,now 2.0.8-1 amd64 [installed] 242 | Microsoft .NET Core 2.0.8 Linux Server Hosting 243 | 244 | dotnet-runtime-2.1.0-rc1/xenial,now 2.1.0-rc1-1 amd64 [installed] 245 | Microsoft .NET Core Runtime - 2.1.0 Release Candidate 1 Microsoft.NETCore.App 2.1.0-rc1 246 | 247 | dotnet-sdk-2.1.4/xenial 2.1.4-1 amd64 248 | Microsoft .NET Core SDK - 2.1.4 249 | 250 | ... 251 | 252 | # 1. Yöntem 253 | $ sudo apt install dotnet-runtime-2.1.0-rc1 254 | $ sudo apt install dotnet-hosting-2.0.8 255 | 256 | # 2. Yöntem 257 | $ sudo apt install dotnet-sdk-2.1.4 258 | ``` 259 | 260 | 4. Reverse Proxy kurulur ve ayarlamaları yapılır. 261 | 5. Herhangi bir nedenden ötürü server veya uygulama kapanırsa tekrardan başlaması için gerekli olan servis dosyası oluşturulur ve çalıştırılır. 262 | 263 | #### Reserve Proxy Kurulumu 264 | 265 | - Reserver proxy için **Nginx, ISS, Apache** vb. kurabilirsiniz. 266 | - Nginx kullanımı için öncelikle Nginx kurulumunu yapıyoruz. 267 | 268 | ``` 269 | sudo apt-get install nginx 270 | ``` 271 | 272 | - Nginx'i kurduktan sonra servisini başlatmamız gerekmektedir. 273 | 274 | ``` 275 | sudo service nginx start 276 | ``` 277 | 278 | - Servisi başlattıktan sonra, server ip adresine herhangi bir yerden bağlandığımızda, aşağıdaki gibi Nginx default sayfasını görmemiz gerekmetedir. Eğer bu sayfayı görüyorsak herhangi bir hata olmadan servisin kurulduğunu anlayabiliriz. 279 | 280 |

    281 | 282 |

    283 | 284 | - Nginx kurulumunu yaptıktan sonra, default olarak 5000 portundan dinleme yapan Core projemizi, Nginx ile 80 portuna proxy yönlendirmesi yapmamız gerekmektedir. 285 | - Öncelikle default Nginx ayarlarının dosya ismini değiştiriyoruz 286 | - `mv /etc/nginx/sites-available/default /etc/nginx/sites-available/defaultOriginal` 287 | - Daha sonra yeniden bir ayar dosyası oluşturup aşağıdaki kodları içine yapıştırıyoruz. 288 | - `nano /etc/nginx/sites-available/default` 289 | 290 | ``` 291 | server { 292 | listen 80; 293 | location / { 294 | proxy_pass http://localhost:5000; 295 | proxy_http_version 1.1; 296 | proxy_set_header Upgrade $http_upgrade; 297 | proxy_set_header Connection keep-alive; 298 | proxy_set_header Host $http_host; 299 | proxy_cache_bypass $http_upgrade; 300 | } 301 | } 302 | ``` 303 | 304 | - Ayarları yaptıktan sonra Nginx'i yeni ayarlarıyla test edip baştan başlatıyoruz. 305 | 306 | ``` 307 | $ sudo nginx -t 308 | nginx: the configuration file /etc/nginx/nginx.conf syntax is ok 309 | nginx: configuration file /etc/nginx/nginx.conf test is successful 310 | 311 | $ sudo nginx -s reload 312 | ``` 313 | 314 | - Nginx'i tekrar başlattıktan sonra herhangi bir hata yoksa, dotnet projemizi başlatıp, server ip adresine direk bağlanıp projeye ulaşıp ulaşamadığımızı kontrol edebiliriz. 315 | 316 | 317 | #### Servis Yazılması 318 | 319 | - Öncelikle servise dosyasını oluşturuyoruz. 320 | 321 | ``` 322 | $ sudo nano /etc/systemd/system/core.service 323 | ``` 324 | 325 | - Daha sonrasında dosyanın içine aşağıdaki satırları ekliyoruz. 326 | - **Description:** Servis açıklaması 327 | - **WorkingDirectory:** Çalışma dizini. App dosyalarımızın olduğu dizini vermemiz gerekmektedir. 328 | - **ExecStart:** Konsolda uygulamamızı çalıştırmak için kullandığımız `dotnet helloworld.dll` komutunun tam yol olarak belirtildiği yerdir. 329 | - 330 | ``` 331 | [Unit] 332 | Description=Example .NET Web API App running on Ubuntu 333 | 334 | [Service] 335 | WorkingDirectory=/var/aspnetcore/hellomvc 336 | ExecStart=/usr/bin/dotnet /var/aspnetcore/hellomvc/hellomvc.dll 337 | Restart=always 338 | RestartSec=10 339 | SyslogIdentifier=dotnet-example 340 | User=www-data 341 | Environment=ASPNETCORE_ENVIRONMENT=Production 342 | Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false 343 | 344 | [Install] 345 | WantedBy=multi-user.target 346 | ``` 347 | 348 | - Dosyayı kaydettikten sonra, servisi aktifleştirmemiz ve başlatmamız gerekmektedir. 349 | 350 | ``` 351 | $ systemctl enable kestrel-hellomvc.service 352 | $ systemctl start kestrel-hellomvc.service 353 | $ systemctl status kestrel-hellomvc.service 354 | 355 | ● kestrel-hellomvc.service - Example .NET Web API App running on Ubuntu 356 | Loaded: loaded (/etc/systemd/system/kestrel-hellomvc.service; enabled) 357 | Active: active (running) since Thu 2016-10-18 04:09:35 NZDT; 35s ago 358 | Main PID: 9021 (dotnet) 359 | CGroup: /system.slice/kestrel-hellomvc.service 360 | └─9021 /usr/local/bin/dotnet /var/aspnetcore/hellomvc/hellomvc.dll 361 | ``` 362 | 363 | - Servisi aktifleştirdikten sonra, web uygulamamız otomatik olarak başlayacaktır. 364 | - Servisin log dosyasına bakmak için `sudo journalctl -fu ` komutu kullanılabilir. -------------------------------------------------------------------------------- /14 - Routing.md: -------------------------------------------------------------------------------- 1 | ## ROUTING 2 | 3 | ### 01) Routing nedir? 4 | - `Routing Middleware`, gelen url isteklerinin yönledirilmesini düzenleyen kurallardır. 5 | - `Startup.cs` sınıfı içindeki `Configure` metotu içinde tanımlanır. 6 | - Neden routing ayarlarına ihtiyaç var? 7 | - SEO uyumluluğunu arttırır. Böylece default yapı dışında, SEO uyumlu url yapılarını oluşturmamıza izin verir. 8 | - Uzun ve anlaşılmaz url yapısı yerine, daha anlaşılır bir yapı kurmamıza olanak tanır. Örn: 9 | - `site.com/Haberler/Index?haberID=123` gibi bir url yerine, 10 | - `site.com/Haberler/123` veya `site.com/Haberler/istanbulda-son-durum` gibi daha anlaşılır url yapılarını oluşturabiliriz. 11 | - Microsoft Docs yolu : 12 | - https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/routing 13 | 14 | ### 02) Default Routing Ayarları 15 | - Default routing ayarları `site/{controller}/{action}` yapısında url yapıları oluşturmak için kullanılır. 16 | - İki şekilde default routing ayarlaması yapılabilir. 17 | 18 | ```cs 19 | app.UseMvcWithDefaultRoute(); 20 | ``` 21 | 22 | ```cs 23 | app.UseMvc(routes => 24 | { 25 | routes.MapRoute( 26 | name: "default", 27 | template: "{controller=Home}/{action=Index}/{id?}"); 28 | }); 29 | ``` 30 | 31 | ### 03) Custom Routing 32 | ```cs 33 | // Örnek bir custom routing 34 | routes.MapRoute( 35 | name: "CustomRoute", 36 | template: "Haberler/Kategori/{catID}", 37 | defaults: new { controller = "Haberler", action = "Index"} 38 | ); 39 | ``` 40 | 41 | - Parametreler : 42 | - **name** : Route yönlendirmemize bir isim vermemizi sağlar. Bu ismin tekrarlanmaması gereklidir. 43 | - **template** : Kullanıcı tarafından gelecek isteğin url tanımlanması burada yapılır. 44 | - **defaults** : Gelen isteğin hangi Controller ve Action tarafından karşılanacağını belirttiğimiz kısımdır. 45 | - **constraints** : Rota kısıtlamalarını tanımladığımız alandır. 46 | - **dataTokens** : (Açıklaması ayrı başlık olarak aşagıda yazılmıştır.) 47 | 48 | - Template kısmında tanımladığımız dinamik değerler, karşılayan action tarafından parametre olarak alınır. 49 | - Yine bu değerlerin opsiyonel olarak girilmesini istiyorsak yanına `?` işareti bıkakıp opsiyonel yapabiliriz. 50 | 51 | #### DataTokens 52 | - Burada tanımlanan değerlere action içinde `RouteData` üzerinden ulaşılarak, actiona hangi route düzeninden ulaşıldığı bilgisi alınabilir. 53 | - Genellikle, birden fazla route yolunun aynı actiona ulaşması ve bu action içinde bu ayrımın yapılmasına olanak vermek için kullanılır. 54 | - Örnek olarak; 55 | 56 | ```cs 57 | // Route Ayarlaması 58 | app.UseMvc(routes => 59 | { 60 | routes.MapRoute( 61 | name: "default", 62 | template: "{controller=Home}/{action=Index}/{id?}", 63 | defaults: null, 64 | constraints: null, 65 | dataTokens: new { Name = "default_route" }); 66 | }); 67 | 68 | // Bu değere action içinden ulaşım 69 | public class ProductController : Controller 70 | { 71 | public string Index() 72 | { 73 | var nameTokenValue = (string)RouteData.DataTokens["Name"]; 74 | return nameTokenValue; 75 | } 76 | } 77 | ``` 78 | 79 | #### Area Routing 80 | - Routing tanımlamasında default parametre değerine area tanımlaması da yapılabilir. 81 | 82 | ```cs 83 | defaults: new { area = Blog, controller = Users, action = AddUser } 84 | ``` 85 | 86 | #### RouteData 87 | - `RouteData` request içindeki route parametrelerinin tutulduğu alandır. 88 | - Bunlar action, controller ve diğer taşınan parametrelerdir. 89 | - RouteData içinde post veya get ile taşınan veriler taşınmaz! 90 | - Route içinde taşınan parametrelerin, action metodu içine parametre olarak alınmasına gerek yoktur. Direk `RouteData.Values` içinden çekilebilir. 91 | - İstenilirse, RouteData yerine, metot içine parametre olarak da alınabilir. 92 | 93 | ```cs 94 | [Route("Haberler/Spor/{haberID}")] 95 | public string Index3() 96 | { 97 | object hID = RouteData.Values["haberID"]; // 1 98 | object action = RouteData.Values["action"]; // Index3 99 | object controller = RouteData.Values["controller"]; // Home 100 | return "Haber Sayfası"; 101 | } 102 | ``` 103 | 104 | #### A catch-all parameters 105 | - Route değerlerindeki her bir parametre sadece bir segment alır. Eğer url olarak gönderilen segment sayısı, onu karşılayan route ayarlarındaki segment sayısından fazla olursa, url uyumsuzluğu olduğundan 404 hatası ile karşılaşırız. 106 | - Bazı durumlarda, route üzerinden kaç tane segment geleceğini sınırlandırmak istemeyiz. 107 | - Bu durumda route temasının en sonuna, gelecek tüm segmentleri alabilecek `Catch-All` parametresi ekleriz. 108 | - Bu yapı, metotlardaki `params` ifadesine benzerdir. 109 | - Bunun için parametre isminin önüne `*` işareti getirilir. 110 | - Parametre ismi olarak herhangi bir değer alınabilir. 111 | - Örnek vermek gerekirse; 112 | 113 | ```cs 114 | routes.MapRoute( 115 | name: "default", 116 | template: "{controller=Home}/{action=Index}/{*extra}"); 117 | ``` 118 | 119 | - Burada yapılan ayarlamada, ilk iki segmentten sonra gelen tüm segmentler, extra parametresi ile alınır. 120 | - Daha sonra bu parametre `/` işareti üzerinden parse edilebilir. 121 | - Örnek olarak aşağıdaki gibi bir controller yazıp değerleri çekersek; 122 | 123 | ```cs 124 | public IActionResult Index() 125 | { 126 | var model = new Dictionary(); 127 | 128 | model["controller"] = RouteData.Values["controller"]; 129 | model["action"] = RouteData.Values["action"]; 130 | model["extra"] = RouteData.Values["extra"]; 131 | 132 | return View(model); 133 | } 134 | ``` 135 | 136 | - Request Url yapısına göre aşağıdaki değerler elde edilecektir. 137 | - **NOT:** Catch-All parametresi her zaman opsiyoneldir. 138 | 139 | ``` 140 | >> URL : localhost/Route/Index/3/4/5 141 | Controller : Route 142 | Action : Index 143 | Extra : 3/4/5 144 | 145 | >> URL : localhost/Route/Index/3 146 | Controller : Route 147 | Action : Index 148 | Extra : 3 149 | 150 | >> URL : localhost/Route/Index 151 | Controller : Route 152 | Action : Index 153 | Extra : 154 | ``` 155 | 156 | ### 04) Route Constraints ( Rota Kısıtlamaları ) 157 | - Route yollarındaki parametrelerin belirli bir kuralda girilmesi ve bu kurallarda girilmediği takdirde yönlendirme yapılmamasını istediğimiz durumlarda kullanırız. 158 | - Rota kısıtlaması yapılan parametreler opsiyonel olarak kullanılmaz. 159 | - Rota kısıtlamaları iki yolla yapılabilir : 160 | 1. Inline Constraints 161 | 2. Maproute içinde Contraints argümanı ile 162 | 163 | ```cs 164 | // Inline Constraint 165 | routes.MapRoute( 166 | name: "default", 167 | template: "{controller=Home}/{action=Index}/{id:int:range(1,100)?}"); 168 | 169 | // Maproute parametresi - Single 170 | routes.MapRoute( 171 | name: "default", 172 | template: "{controller}/{action}/{id}", 173 | defaults: new { controller = "Home", action = "Index"}, 174 | constraints: new { id = new IntRouteConstraint()}); 175 | 176 | // Maproute parametresi - Multiple 177 | routes.MapRoute( 178 | name: "default", 179 | template: "{controller}/{action}/{id}", 180 | defaults: new { controller = "Home", action = "Index"}, 181 | constraints: new { id = new CompositeRouteConstraint( 182 | new IRouteConstraint[] 183 | { 184 | new IntRouteConstraint(), 185 | new RangeRouteConstraint(1,100) 186 | } 187 | )}); 188 | ``` 189 | 190 | #### Regex (Regular Expressions - Düzenli İfadeler) ile Rota Kısıtlaması 191 | - (.) -> Bir karakterin gelecebileceği ve karakteri tanımlamadığımız yerlerde kullanılır. 192 | - (+) -> Kendinden önce gelen karakterin en az bir kere tekrarlanması gerektiğini belirtir. 193 | - (*) -> Kendinden önce gelen karakterin sıfır veya daha fazla tekrarlanması gerektiğini belirtir. 194 | - (?) -> Kendinden önce gelen karakterin en fazla bir kere gelmesi gerektiğini belirtir. 195 | - ([ ]) -> İçindeki karakterlerden birinin geleceğini belirtir. 196 | - [ab] [0-9] [a-z] 197 | - ({ }) -> Kendinden önce gelen karakterin içinde yazılan sayı kadar tekrar edeceğini belirtir. 198 | - (^) -> Metnin başını ifade eder. Kendinden sonra gelen ifadeyi metnin başında arar. 199 | - ($) -> Metnin sonunu ifade eder. Kendinden önce gelen ifadeyi metnin sonunda arar. 200 | - (\s) -> Belirtilen yerde boşluk olması gerektiğini belirtir. 201 | - (\S) -> Belirtilen yerde boşluk olmaması gerektiğini belirtir. 202 | - (\d) -> Sayısal ifade geleceğini belirtir. 203 | - Örnekler: 204 | - Cep telefonu düzeni 205 | - (05)55-444-22-11 206 | - ^(05)\d{2}-\d{3}-\d{2}-\d{2}$ 207 | 208 | #### HTTPverb ile Rota Kısıtlaması 209 | - Route düzenine hangi HTTP methodlar ile ulaşılabileceğini belirtmek için kullanırız. 210 | - Birden fazla HTTP method yazılabilir. 211 | - `HttpMethodRouteConstraint` metodu kullanılır. 212 | 213 | #### Örnek: 214 | ```cs 215 | routes.MapRoute( 216 | name: "Haber Kategori", 217 | template: "Haber/Kategori/{catName}/{catID}", 218 | defaults: new { controller = "Home", action = "Kategori" }, 219 | constraints: new { 220 | catID = @"^\d{2}$", // Sadece iki basamaklı sayı 221 | catName = @"^[a-z]+$", // Sadece harflerden oluşacak 222 | metod = new HttpMethodRouteConstraint("GET","POST") }); 223 | ``` 224 | 225 | #### Custom Route Constraints 226 | - Kendi kuralımızı yazmak için öncellikle `IRouteConstraint` interface'inden türeyen bir sınıfa ihtiyacımız vardır. 227 | - Interface'i implement ettiğimizde içinde bir tane `Match` adlı metot gelir ve bu metodun geri dönüş tipi `bool` olmak zorundadır. 228 | - Bu metot içine kuralımızı yazıp, sonucunda, gelen değerin uyup uymadığını belirtmek için true veya false döndürürüz. 229 | - Match metodu içinde toplam 5 tane parametre bulunur : 230 | - **HttpContext:** Request, response, session vs gibi, http özel metotlarını bulunduran parametredir. 231 | - **IRouter:** Constraint'lere ait router metotlarını taşır. 232 | - **routeKey:** Kontrol edilecek route değerinin alındığı yerdir. Custom Constraint metodumuzu üzerinde çalıştırdığımız route elemanının kendisine bunla ulaşırız. 233 | - **RouteValueDictionary:** Url route parametrelerinin bulunduğu sözlük yapısıdır. 234 | - **RouteDirection:** Routing işleminin Http isteğinin URL'inden mi, yoksa custom oluşturulan URL'den mi geldiğini söyler. Enum yapısındadır. 235 | - IncomingRequest : Client tarafından gelen url isteği. 236 | - UrlGeneration : Route ayarları sonucu oluşturulan URL isteği. 237 | 238 | ```cs 239 | public class WeekDaysConstraint : IRouteConstraint 240 | { 241 | List WeekDays = new List() { "pzt", "sali", "car", "per", "cuma" }; 242 | 243 | public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) 244 | { 245 | return WeekDays.Contains(values[routeKey]); 246 | } 247 | } 248 | ``` 249 | 250 | - MapRoute parametresi olarak kullanımı 251 | 252 | ```cs 253 | routes.MapRoute( 254 | name: "default", 255 | template: "{controller}/{action}/{day}", 256 | defaults: new { controller = "Home", action = "Index"}, 257 | constraints: new { day = new WeekDaysConstraint()}); 258 | ``` 259 | 260 | - Eğer metot inline constraint olarak kullanılacaksa, bunun servis olarak eklenmesi gerekmektedir. 261 | 262 | ```cs 263 | public void ConfigureServices(IServiceCollection services) 264 | { 265 | services.AddMvc(); 266 | 267 | services.Configure(option => 268 | option.ConstraintMap.Add("weekday", typeof(WeekDaysConstraint)) 269 | ); 270 | } 271 | 272 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 273 | { 274 | app.UseMvc(routes => 275 | { 276 | routes.MapRoute( 277 | name: "default", 278 | template: "{controller}/{action}/{day:weekday}", 279 | defaults: new { controller = "Home", action = "Index" }); 280 | }); 281 | } 282 | ``` 283 | 284 | 285 | ### 05) Attribute Routing 286 | - Attribute Route ayarlaması kullanılan actionlara, `{controller}/{action}` üzerinden artık bağlanılınamaz. 287 | - Attribute Routing kullanılacak action üzerinde aşağıdaki gibi tanımlama yapılır: 288 | - `[Route(