Open
Online Test Proje

Online Test Aşamaları

Otomasyon:Branşlar var, Branşların kursları, Kursların Dersleri var. Her bir kursunda sınavı olacak.

Visual Studio'yu açalım ve App adında bir solution (Çözüm) oluşturalım. (Projeye uygun dilediğiniz ismi verebiliriz)

Projemiz Soğan Mimarisi Prensibine uyum sağlayacaktır.
Solid prensibin, Bağımlılıkların Azaltılması prensibine uygun çalışacağız.Abstract ve Concrete metodlarımız olacak.
Projede bilgilere, Interfaceler'e sorgu vererek erişeceğiz.Interfaceler, üzerinden nesneler çağıracağız.
Bunda dolayı Ef, Dapper,Nhybernate gibi kullacağımız ORM aracının, pek önemli rolü olmayacaktır.

Projemize 5 katman oluşturalım.Bunlar;

 
     1.Core Katmanı - Çekirdek Katmandır.Tüm projelerde, kullanılacak ortak katmandır.
     Projenin en temel verilerini barıdıracak, her katmandan erişim sağlayacak.
     Generic Repository(depo) sınıfını bu katmanda tanımlayacağız.
     Projede, ilerde farklı bir Orm aracı kullanırsak, Core katmanının IRepository sini kullanacağız.(Dapper, Nhybernate vb.)
     IData adında bir arabirim sınıfımız olacak, oluşturduğumuz modeller eğer bu interfaceden kalıtım alıyorsa bu veritabanı modeli olduğu anlamına  

    2.Dal Katmanı - Dal Katmanı herzaman yazılımcıya özel bir katman olacaktır.
    DbContext ve Temel Repository metotlarımız bu katmanda olacaktır.

    3.Bll Katmanı - Ek Repository lerimiz burda tanımlanacak.
    Unity of Work prensibimiz bu katmanda yer alacaktır.
    
    4.Model Katmanı - Modellerimiz (Entity), gerekli ViewModellerimiz bu katmanda olacaktır.

    5.Ui(Web) Katmanı - Kullanıcının arayüzüdür.Kullanıcı bu katmanda işlemlerini görecek. Web katmanı diye de isimlendirebiliriz.
    Core daki IData için Model katmanını referans vermemiş oluruz. Döngü engellenir.



Bu katmanda temel bir modelimiz ve temel bir de Repository'miz olacak.
Temel Modelimiz, bildirim sağlayan bir sınıf olacaktır. E_Bildiri,E_Result,ResultMessage gibi isimler verebiliriz.
IData adında bir arabirimimiz(interface) olacak.Maksat,Bu interfaceden kalıtım alan sınıflarn, veritabanı için kullanıldığını bildirmek.

Temel bir Repositorymiz olacak.IRepository ve BaseRepository.Repoitory, Generic yapıda olacak isteilen tabloya kalıtım verecektir.
Core Katmanına 3 klasör oluşturalım. Abstract,Concrete ve Model isimlerini verelim.

Model klasörüne E_Result adında bir sınıf oluşturalım

    namespace Core.Model
    {
        public class E_Result<T>
        {
            public string Message { get; set; }  //Bilgilendirmek için  (hata ya da mesaj)
            public T Data { get; set; }  //Geriye data dönsün istersek, bu property'nin içerisini doldurcaz.
            public bool IsSuccess { get; set; }  //Datanın Başarı Durumu kontrolu için
        }
    }

Abstract klasörüne IData adında bir interface oluşturalım.

    public interface IData
    {
    }

Abstract klasörüne IRepository adında bir interface oluşturalım. Metodlarımızın imzalarını oluşturalım.(Gövdelerini concrete'te tanımlıycaz)
Kural olarak oluşturduğumuz değişkenler, farklı ORM araclarıyla da, crud işlemleri gerçekleştirilebilecek.
Where T : bir classdır, IData dan kalıtım alır, new lenebilir.

    using System.Linq.Expressions;
    public interface IRepository<T> where T:class,IData, new()
    {
    E_Result<T> Add(T prm);
    E_Result<T> Update(T prm);
    E_Result<T> Delete(int ID);
    E_Result<T> SoftDelete(int ID);
    E_Result<ICollection<T>> GetAll(Expression<Func<T, bool>> filter = null);
    E_Result<T> Get(Expression<Func<T, bool>> filter); //(Find)
    }

Concrete klasörüne, BaseRepository adında bir sınıf oluşturalım.Generic türünde olacak.
IRepository de kalıtım alacak (metotların imzalarını alıp metotların gövdesini oluşturacağız)
DbContext ten yararlanacağımız için bir de <TContext> ekleyelim.
Where T : bir classdır, IData dan kalıtım alır, new lenebilir.
where TContext : DbContext (TContext ise DbContextten türemiş bir nesnesidir.

    public class EFRepository<T, TContext> : IRepository<T> where T : class, IData, new() where TContext : class, new()
    {
      //TContext in üzerine gelip DbContext için oto. EF Core paketini projemize ekleyelim.
      //IRepository<T> yi implemente edelim (Ctrl+)Metotların imzaları gelecektir, gövdelerini dolduralım.
    }

BaseRepository'mizde metod eklerken, DbContext nesnesi oluşturmaya ihtiyacımız var.Bu da bir bağımlılık demek.
Şimdi en sağlıklı yöntemi, birlikte seçelim.

    //Her metodda DbContext nesnesi oluşturabiliriz.
        TContext ctx = new TContext();
        ctx.Add(prm);
        ctx.SaveChanges();
     //Ama  her metod için TContext ten yeni nesneler alırsak ramde kalır ve projemiz şişer.
    //işimiz bittiğinde dispose etsek (using kullansak).
    //nesne oluşacak,içindeki komutlar çalışacak,scope kapandığında nesne kendsini dispose edecek.
        using (var ctx= new TContext())  
        {
           ctx.Add(prm);  ...
        } 
    //Ram işini hallettik ama yine de bağımlılığı asıl bir sınıftan alan repository ler olacak. Bu da ilerde diğer ORM araçlarına sorun yaratır.
    //O zaman, Dependency Injection prensibine uyar ve Constructor ile bağımlılık alırız. 
    //TContext türünde ctx nesnemizin içi boştur. EfRepository çağrıldığında (doğum anında=constructor), bir parametre vererek içini bu nesne ile doldursun.
        readonly TContext ctx; 
        public EFRepository(TContext _prm) 
        {
            ctx = _prm;
        }  

namespace Core.Concrete
{
    public class BaseRepository<T, TContext> : IRepository<T> where T : class, IData, new() where TContext : DbContext, IData, new()
    {
        readonly private TContext context;
        public BaseRepository(TContext _prm)
        {
            context = _prm;
        }
        public E_Result<T> Add(T prm)  //fonksiyon metod geriye E_Result T> tipinde değer dönderecek (prm T türündendir)
        {
            try
            {
               var data = context.Entry(prm);
               data.State = EntityState.Added;
               return context.SaveChanges() > 0 ? new E_Result<T> { IsSuccess = true, Data =prm, Message = "Başarıyla kaydettiniz"}: new E_Result<T> { IsSuccess=false, Data=null, Message="Bir hata meydana geldi." };
            }
            catch (Exception ex)
            {
               return new E_Result<T> { IsSuccess = false, Data = null, Message = ex.Message };   
            }
        }

        public E_Result<T> Delete(int id)
        {
            try
            {
                var finddata = context.Set<T>().Find(id);
                var data = context.Entry(finddata);
                data.State = EntityState.Deleted;
                return context.SaveChanges()> 0 ? new E_Result<T> { IsSuccess = true,   Message = "Başarıyla sildiniz" } : new E_Result<T> { IsSuccess = false, Data = null, Message = "Bir hata meydana geldi." };
            }
            catch (Exception ex)
            {
                return new E_Result<T> { IsSuccess = false, Data = null, Message = ex.Message };
            }
        }

        public E_Result<T> Get(Expression<Func<T, bool>> filter)
        {
            var data = context.Find<T>(filter); //Find<>(expresion bekler bizde filter ekledik)bilgiyi yakaladık.
            return new E_Result<T> { Message = "Getirildi", Data = data, IsSuccess = true };
        }

        public E_Result<ICollection<T>> GetAll(Expression<Func<T, bool>> filter = null)
        {
            List<T> sonuc;
            if (filter == null)
            {
                sonuc = context.Set<T>().ToList();  // !using System Linq
            }
            else
            {
                sonuc = context.Set<T>().Where(filter).ToList();  // !using System Linq
            }
            return new E_Result<ICollection<T>> { Data = sonuc, IsSuccess = true, Message = "data listelendi" };
        }

        public E_Result<T> SoftDelete(int id)
        {
            try
            {
                var finddata = context.Set<T>().Find(id);
                var data = context.Entry(finddata);
                data.State = EntityState.Modified;
                return context.SaveChanges() > 0 ? new E_Result<T> { Message = "Veri güncellendi", Data = finddata, IsSuccess = true } : new E_Result<T> { Message = "hata", Data = null, IsSuccess = false };
            }
            catch (Exception ex)
            {

                return new E_Result<T> { Message = ex.Message, Data = null, IsSuccess = false };
            }
        }

        public E_Result<T> Update(T prm)
        {
            try
            { 
                var data = context.Entry(prm);
                data.State = EntityState.Modified;
                return context.SaveChanges() > 0 ? new E_Result<T> { Message = "Veri güncellendi", Data = prm, IsSuccess = true } : new E_Result<T> { Message = "hata", Data = null, IsSuccess = false };
            }
            catch (Exception ex)
            {

                return new E_Result<T> { Message = ex.Message, Data = null, IsSuccess = false };
            }
        }
    }
}

Oluşturduğumuz Model katmanına, ilk önce Base adında bir sınıf ekleyeceğiz.Temel propertyleri olacak.
Tüm ya da dilediğimiz modeller, bu modelden kalıtım alabilecek.



Dal Katmanında Migration oluşturalım.

Dal Katmanındaki ilk görevimiz:Veritabanı oluşturup Model Katmanında oluşturduğumuz modelleri, migration yardımıyla veritabanına eklemek.
EF ile Code First prosesini geliştireceğiz.
İlk görev Migration için bu katmana, birkaç kütüphane ekleyeceğiz. Migration esnasında bize yardımcı olacak araçlar.
Bağmlılıklar sağ click ve nuget paketlerini yönet tıklayalım.
ya da Araçlar->Nugget Paket Yöneticisini tıklayalım.
Yükleyeceğimiz paketler: Ef Core,Ef Core Design,Ef Core SqlServer, Ef Core Tools.

Dal Katmanında Ef adında bir klasör oluşturalım ve içerisine WebDbContext adında sınıf ekleyelim.
Sınıfımız DbContext ten kalıtım alsın. override yazıp space tuşuna basalım, karşımıza metodlar gelecek.
OnConfiguring() ve OnModelCreating() metodlarını seçelim.

    protected override  void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
       optionsBuilder.UseSqlServer("server=.; Database=OnlineTestDB; Integrated Security=True " ); 
    }
Not:eğer usesqlserver yazdığımızda server= / (slash) kullanmamız gerekirse , \\ iki ters slash koyarız.
Integrated Security=true -> Windows authentication ile giriş yapabilmeyi sağlar.
User authentication olsa, kullanıcı adı ve şifreyi yazmamız gerekecek, Integrated security ise false olacak

Bir alt satırına modellerimizi yazalım.
Veritabanında, Tablo olmasını istediğimiz tüm classları, DbSetin içinde parametre olarak vermemiz lazım.

      
        public DbSet<Brans> Brans { get; set; }
        public DbSet<Ders> Ders { get; set; }
        public DbSet<Kullanici> Kullanici { get; set; }
        public DbSet<KullaniciCevap> KullaniciCevap { get; set; }
        public DbSet<KullaniciDetay> KullaniciDetay { get; set; }
        public DbSet<KullaniciKurs> KullaniciKurs { get; set; }
        public DbSet<KullaniciRol> KullaniciRol { get; set; }
        public DbSet<KullaniciSinav> KullaniciSinav { get; set; }
        public DbSet<Kurs> Kurs { get; set; }
        public DbSet<KursDers> KursDers { get; set; }
        public DbSet<KursMerkezi> KursMerkezi { get; set; }
        public DbSet<Sikayet> Sikayet { get; set; }
        public DbSet<Rol> Rol { get; set; }
        public DbSet<Sinav> Sinav { get; set; }
        public DbSet<SinavSoru> SinavSoru { get; set; }
        public DbSet<Soru> Soru { get; set; }
        public DbSet<Yorum> Yorum { get; set; }

Sıra onModelCreating() metodunda. Entity Framework, modellerin, ara tablolarunu otomatik oluşuyordu fakat Entity Framework Core da ise ara tablolarıı kendimiz oluşturmak zorundayız.

  
           protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            //MANY-TO-MANY
            //ara tablonun iki tane keyi olduğunu söylüyor. (ikisi de aslında başka tabloların keyi )
            modelBuilder.Entity<KullaniciRol>()
        .HasKey(kr => new { kr.KullaniciId, kr.RolId });
            //ara tablonun kullanıcı tablosuyla arasındaki bire çok ilişkiyi söylüyor.
            modelBuilder.Entity<KullaniciRol>()
                .HasOne(kr => kr.Kullanici)
                .WithMany(k => k.KullaniciRoller)
                .HasForeignKey(kr => kr.KullaniciId);
            //ara tablonun rol tablosuyla arasındaki bire çok ilişkiyi söylüyor.
            modelBuilder.Entity<KullaniciRol>()
                .HasOne(kr => kr.Rol)
                .WithMany(r => r.KullaniciRoller)
                .HasForeignKey(kr => kr.RolId);


            modelBuilder.Entity<SinavSoru>().HasKey(ss => new { ss.SinavId, ss.SoruId });
            modelBuilder.Entity<SinavSoru>().HasOne(ss => ss.Sinav).WithMany(i => i.SinavSorulari).HasForeignKey(ss => ss.SinavId).HasPrincipalKey(x => x.Id).OnDelete(DeleteBehavior.Cascade);
            modelBuilder.Entity<SinavSoru>().HasOne(ss => ss.Soru).WithMany(o => o.SinavSorulari).HasForeignKey(ss => ss.SoruId).HasPrincipalKey(x => x.Id).OnDelete(DeleteBehavior.Cascade);

            modelBuilder.Entity<KullaniciSinav>().HasKey(ks => new { ks.SinavId, ks.KullaniciId });
            modelBuilder.Entity<KullaniciSinav>().HasOne(ks => ks.Sinav).WithMany(i => i.KullaniciSinav).HasForeignKey(ss => ss.SinavId).HasPrincipalKey(x => x.Id);
            modelBuilder.Entity<KullaniciSinav>().HasOne(ks => ks.Kullanici).WithMany(o => o.KullaniciSinavlari).HasForeignKey(ss => ss.KullaniciId).HasPrincipalKey(x => x.Id);


            modelBuilder.Entity<KullaniciKurs>().HasKey(kk => new { kk.KullaniciId, kk.KursId });
            modelBuilder.Entity<KullaniciKurs>().HasOne(kk => kk.Kullanici).WithMany(i => i.KullaniciKurs).HasForeignKey(kk => kk.KullaniciId);
            modelBuilder.Entity<KullaniciKurs>().HasOne(kk => kk.Kurs).WithMany(u => u.KullaniciKurs).HasForeignKey(kk => kk.KursId);

            modelBuilder.Entity<KursDers>().HasKey(kd => new { kd.KullaniciId, kd.DersId });
            modelBuilder.Entity<KursDers>().HasOne(kd => kd.Kullanici).WithMany(i => i.KullanicininDersleri).HasForeignKey(kd => kd.KullaniciId);
            modelBuilder.Entity<KursDers>().HasOne(kd => kd.Ders).WithMany(u => u.KullanicininDersleri).HasForeignKey(kd => kd.DersId);

            modelBuilder.Entity<Sinav>()
       .HasKey(s => new { s.OgretmenId, s.KaydedenKullaniciId });

            modelBuilder.Entity<Sinav>()
       .HasOne<Ogretmen>(e => e.Ogretmen)
       .WithMany(e => e.OgretmeniOlunanSinavlar)
       .HasForeignKey(e => e.OgretmenId)
       .HasPrincipalKey(x => x.Id)
       .OnDelete(DeleteBehavior.Restrict);

            modelBuilder.Entity<Sinav>()
                .HasOne<Yonetici>(e => e.KaydedenKullanici)
        .WithMany(e => e.KaydedilenSinavlar)
                .HasForeignKey(e => e.KaydedenKullaniciId)
                .HasPrincipalKey(x => x.Id)
                .OnDelete(DeleteBehavior.Restrict);


            modelBuilder.Entity<KullaniciCevap>()
              .HasOne<KullaniciSinav>(e => e.KullaniciSinav)
      .WithMany(e => e.KullaniciSinavCevaplari)
              .HasForeignKey(e => e.KullaniciSinavId)
              .HasPrincipalKey(x => x.Id)
              .OnDelete(DeleteBehavior.Restrict);

            modelBuilder.Entity<Kurs>()
        .HasOne(a => a.Sinav)
        .WithOne(b => b.Kurs)
        .HasPrincipalKey<Sinav>(x => x.Id)
        .HasForeignKey<Kurs>(b => b.SinavId);

            base.OnModelCreating(modelBuilder);
        }

DbContext sınıfımızı düzenlediğmize göre migration yapabiliriz.
Çözümü derleyelim.(Hatalar varsa düzeltelim)
Araçlar->Nugget Paket Yöneticisi->Paket Yöneticisi Konsolunu açalım.
Varsayılan Projenin Dal olduğuna dikkat edelim ve yazalım;
Add-migration isim(versiyon 1 gibi) , update-database -verbose (verbose ne var ne yoksa ekle demektir)

Migration esnasında yaşanan birkaç hatalar ve çözümleri

add-migration : The term add-migration is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
çözüm :Paketlerinizi yüklediğinizden emin olun, büyük olasılıkla EF Core Tools paketini yüklememişsinizdir.
Startup project Develope.Dal targets framework .NETStandard . There is no runtime associated with this framework, and projects targeting it cannot be executed directly. To use the Entity Framework Core Package Manager Console Tools with this project, add an executable project targeting .NET Framework or .NET Core that references this project, and set it as the startup project; or, update this project to cross-target .NET Framework or .NET Core. For more information on using the EF Core Tools with .NET Standard projects, see https://go.microsoft.com/fwlink/?linkid=2034705
Paket Yöneticisi konsol araçları, .NET Core veya .NET Framework projeleriyle çalışır. .NET Standard Sınıf kitaplığı (Dal katmanımız) ile Konsolda migration yaparken üstteki hata gelebilir. Bunun için bir deneme test konsol uygulaması ekleyelim ya da We projesi ekleyebiliriz. O projeyi, startapp project yapıp tekrar deneyelim.
Başka bir seçenek olarak Web.Ui katmanımıza gidip, Startup.cs dosyasına şu komutları girbilriz.

    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(x => x.EnableEndpointRouting = false);
            services.AddDbContext<DeveloperContext>(); //startup dışında hiçbiryerde tanıtmıycaz.
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        { 

            using (var scope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
            {
                using (var context = scope.ServiceProvider.GetService<DeveloperContext>())
                {
                    //context.Database.EnsureDeleted(); //sildiğinden emin ol eğer varsa sil yarat.
                    //context.Database.EnsureCreated();  //yaratıldığından eminol.
                    context.Database.Migrate(); // yada b komutla bizim için bir veritabanı tasarlamış olucak.DB yarat, migrate et komutudur.
                }
            } 
    }

Dal Katmanında abstract ve concrete adında 2 klasör oluşturalım.
Abstract klasöründe soyut sınıfımız(metodların imzası), Concrete klasöründe ise somut sınıflarımız olacak.(metodların gövdesi)
Abstract klasöründe, Modellerimizin interface repositoryleri olacak ve hepsi Core katmanındaki Generic yapılı IRepositoryde kalıtım alacak.
Aynı şekilde Concrete klasöründe, modellerimizin repositoryleri olacak ve hepsi Core katmanındaki Generic yapılı BaseRepositoryden kalıtım alacak.

Abstract klasörümüzde IBransRepository interface oluşturalım ve IRepository den kalıtım alsın.

    public interface IBransRepository : IRepository<Brans>
    {
        ICollection<Brans> AnaBranslariGetir();
    }

Concrete klasörümüzde BransRepository sınıfı oluşturalım ve ilk BaseRepositorymizden daha sonra IBransRepository kalıtım alsın.

using Core.Concrete;
using Dal.Abstract;
using Model.Entity;
using Dal.EF; 
using System.Linq;

namespace Dal.Concrete
{
    public class BransRepository : BaseRepository<Brans,WebDbContext>, IBransRepository
    {
        public BransRepository(WebDbContext prm) : base(prm)
        {
        }
        public ICollection<Brans> AnaBranslariGetir()
        {
            using (WebDbContext context = new WebDbContext())
            {
              return context.Brans.Where(x => x.UstBransId == null).ToList();
            }
            
        }
    }
}

Not: Base modelinizin :IData dan kalıtım aldığına emin olun.

Dal Katmanında isteidğimiz veriyi, istediğimiz işlemi, istediğimiz ekstra metodlarıyle işledik.
Dal da tüm işlemler serbest iken, Bll katmanında bu serbestliği bozacağız.
Bll de yetkilere ve işlemlere sınır koyulacak.Web.Ui ile iletişim halinde olacak ve web, bll katmanının sınırlı kurallarından yararlanabilecek.
Bll de yetkiler kısıtlanacak, bu katmanda sadece projeye giren kullanıcıların yapmak istedikleri metodlar, hazırlanacak.
örneğin, Kullanıcı, güncelleme, ekleme yapsın ama silme işlemi yapamasın. Amacımız bu mantıktır.
Bll de Abstract ve Conrete klasörler olacak.Repository sonlarına Manager,Service gibi ekler ekleyebiliriz. Ya da size kalmış.

Bll Katmanının Abstract klasöründe IBransService adında interface oluşturalım.

   //Sadece kullanmak istediğimiz metodları yazıyoruz.
using Core.Model;
using Model.Entity; 
using System.Linq.Expressions; 

namespace Bll.Abstract
{
    public interface IBransService
    {
        E_Result<Brans> Add(Brans data);
        E_Result<Brans> Update(Brans data);
        E_Result<Brans> SoftDelete(int id);
        E_Result<ICollection<Brans>> GetAll(Expression<Func<Brans, bool>> filter = null);
    }
}

Bll Katmanının Concrete klasöründe BransService adında sınıf oluşturalım.
Crud işlemleini Dal Katmanında yapmıştık. O halde ordan constructor ile bağımlılık alalım ve nesnelere erişelim.
Unutmayalım ki Dal daki metotları istifade ederken biz sadece kendi Bll deki interface imzalarına göre erişim sağlayacağız.
Not:Dependency Injection da, nesnenin kendisini değil kuralını (interfaceni) bağımlılık alırız.

 using Bll.Abstract;
using Core.Model;
using Dal.Abstract;
using Model.Entity;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace Bll.Concrete
{
    public class BransService : IBransService
    {
        //nesne yarat"mış gibi yaptık".
        IBransRepository repository;
        public BransService(IBransRepository _repository)
        {
            repository = _repository;
        }

        public E_Result<Brans> Add(Brans data)
        {
            return repository.Add(data);
        }

        public E_Result<ICollection<Brans>> GetAll(Expression<Func<Brans, bool>> filter = null)
        {
            return repository.GetAll(filter);
        }

        public E_Result<Brans> SoftDelete(int id)
        {
            return repository.SoftDelete(id);
        }

        public E_Result<Brans> Update(Brans data)
        {
            return repository.Update(data);
        }
    }
}





Startup.cs Dosyası


Startup.cs dosyasını yapılandıralım, projemiz MVC yapısında olacaktır.
Servis Konfigür metoduna -> service.AddMvc() ekleyelim
Konfigüre metoduna -> app.useMVC( route açıklayalım) ekleyelim. Durum kodlarına ve static Files oluşumunu sağlayalım.
Not: AspNet Core Versiyonlara göre route değişiklikleri gösterebilir. Eğer varsayılan projeiz, endpoints route'u desteklemişse, MvcDeafaultRouting ile değiştereceğiz, projemizi mvc ile geliştireceğiz.

   public void ConfigureServices(IServiceCollection services)
        {
            //Mvc route kullanacaksak, default EndpointRouting yönlendirmeyi pasif'e çevimeliyiz.
            services.AddMvc(option => option.EnableEndpointRouting = false);
            services.AddControllers(options => options.EnableEndpointRouting = false);
            services.AddControllersWithViews(options => options.EnableEndpointRouting = false);
            services.AddRazorPages().AddMvcOptions(options => options.EnableEndpointRouting = false);
 
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            //2 şekilde MVC yöntemini kullanacağımızı belirtebiliriz. ya varsayılan ayarı getir deriz ya da kendimiz yazarız.
            //1.Şekil
            //app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}"  (controller=Home, diyerek default Home dur demek isteriz)
                    );

            //});
            //2.Şekil varsayılan halini kullanacağımızı bellirtiriz.
            app.UseMvcWithDefaultRoute();  
 

            //Birkaç faydalı Konfigür ayarları vardır. Bunlar;

            //env.IsDevelopment Metodu;Proje geliştirdiğimizde hataları gösterir,yayınlandığında hata görünmez,exception sayfalar gösterilir.
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();  
            }

            //UseStaticFiles() metoduyla, statik dosyalarımızı Asp.Net Core ile gösterebiliriz. Varsayılan klasör; wwwRoot'tur.
             app.UseStaticFiles();   


            //UseStatusCodePages() metoduyla; hata durum sayfaları, ufak bir mesaj olarak sayfada belirir.
             app.UseStatusCodePages();
        }

  

Program.cs, projemizin beynidir. Bu dosya ile proje ayağa kalkar. Webhosting oluşur.Server türü kestreldir.Proje derlenip çalışır.Burdaki ayarlara, bu proje için dokunmayacağız.

MVC klasörlerini ve Varsayılan gereklilikleri oluşturalım

Uygun klasörleri oluşturalım. Models,Controllers,Views ve wwwroot klasörü.(wwwroot klasörü Asp.Net Core da gösterilen tek klasördür.Adnı Startup.cs ile değiştirebiliriz.Lakin pek gerek yoktur.)
Views klasöründe 2 adet view dosyası oluşturalım.
(a) _ViewImports , içeriğine;
    _ViewImports sayfası, bizim import edeceğimiz dosyaları belirler.
    @namespace App.Web.Models //proje adı ve Models klasörümüzü tanıttık.
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers //Taghelper namespace'ini tanıttık.(Tüm sayfalara etkilenmiş oldu.)
    
    (b)  _ViewStart  , içeriğine    
       Proje çalıştığında sayfaları etkileyecek stil, webmaster sayfası,title burda tanımlanır.
    @{     ViewData["Title"] = "_ViewStart";  Layout = "_Layout";     }

    (c)Bu sefer bir klasör oluşturup içerisine view ekleyelim.Shared klasörü, _Layout view dosyası ekleyelim.
     Asp.Net WebForms daki web master sayfamızdır.Tüm sayfalar bu anasayfadan istediğimizde etkilenebilecek.
    @{  Layout = "~/Views/Shared/_Layout.cshtml"; }   
Controllers klasörüne, HomeController ekleyelim.Çıkan pencerede Layout kullanacağımızı sekmeye tıklayarak belirtelim.Bir index sayfası oluşturalım.(Not:Ekleme sırasında, proje otomatik olarak paketler yükleyebilir.efcore,Tools,Logging,Design vsb.)


(4) Projeye sağ click, istemci Tarafı Kitaplığını tıklyalım.Dilediğimiz css ve js yapılarını, bu araçla projemize indirelim.
Sağlayıcı=> Nugget kütüphanesi olsun (unpkg kısaltılmasıdır)
Arama paneline; "bootstrap css" yazıp ve wwwroot klasörü içerisinde oluşturucağımızı belirtelim.
Aynı araçla, "font awesome css", "Jquery" gibi dilediğimiz kütüphaneleri indirebiliriz.
Projemize bir template giydireceksek, template'i direk sürükle bırak yöntemi ile -wwwRoot klasörü içerisine atalım. css,js,images adında klasör oluşturalım. İstediğimiz dosyayı kopyalayıp, customs oluşturduğumuz klasör'e yapıştırabiliriz.Templates deki images klasörünü , wwwwroot klasörüne images adnda klasör oluşturup, kopyala/yapıştır yapalım.

Not:AspNet Core, proje içerisindeki herhangi custom yarattığınız klasörleri tanımaz. Url de bildirseniz bile size o klasörü içindeki herhangi bir dosyayı vermez.Tanıdığı klasörler wwwRoot içerisinde olmalıdır. ya da tanıtmak için startup.cs de staticfiles metodunda belirtmeniz gerekir.

Bundler ve Minifier aracını kullanmak istersek; https://marketplace.visualstudio.com/items?itemName=MadsKristensen.BundlerMinifier sitesini ziyaret edip bundler ve minifer özelliğini indirelim.Projeyi resetleyip açtığımızda artık css ya da js dosylarına sağ tıkladığımızda add bundler&minifier adında bir özellik gelecektir.İstediğiniz css ler'e ctrl ile seçip add bundler&minifier özelliğini tıklatarak wwwroot-> css klasöründe birleştirebiliriz.Burda Dikkat etmemiz gereken bir husus vardır. Templateki ilgili css ve ya jslerin üzerine ctrl seçerken, sırasına dikkat etmeliyiz.Aksi takdirde çakışmalar yaranır. Sağ click add bundler&minimizer özelliğini kullanıp wwwroot içerisindeki css klasörümüze bir dosya oluştrup birleştirelim.Bu dosyayı incelediğimizde,sırasının doğru olduğunu kontrol edelim,değilse düzenleyelim.

Yönetim işlerini, Web.Ui katmanında farklı bir alanda yaparız.
Add-Area ile katmanımıza yeni bir alan oluşturalm. Eğer Add-Area sekmesi yoksa kendimiz elle oluşturalım.
Areas - Admin ve içerisinde Models,Views,Controllers
Controllers da bir HomeController denetleyicisi oluşturalım.
Views katmanında Shared klasörü oluşturalım.İçerisine _Layout view ekleyelim ve normal bir html komutlarını içerisine girelim.
https://athemes.com/collections/free-bootstrap-admin-templates/ sitesinden star admini indirip tasarım oluşturalım.
Tasarım taslağını Admin dizininde, temp adında bir klasöre kopyalayıp yapıştıralım.
Admin alanında Controlersda HomeController ve Index sayfası oluşturalım. Projeyi başlatınca hata alırız çünkü iki HomeController varve startup.cs karıştırır.Bundan dolayı iki alternatifimiz var;
A-ya HomeController'a gelip başına [Area("Admin")] imleci koyarız.
B- ya da AdminBaseController adında bir controller oluşturur.Oraya [Area("Admin")] koyup diğer controller sınıflarını AdminBaseControllerdan türetiriz.

     [Area("Admin")]
    public class AdminBaseController : Controller
    {
    }

HomeContreollera da : AdminBaseden türediğni yazarız. Böyllikle    [Area("Admin")] 1 kere kullamış oluruz.
    public class HomeController : AdminBaseController
    {
        public IActionResult Index()
        {
            return View();
        }
    }

Startup.cs, configure metoduna girip ilk areas sonra default routing yapısını oluşturalım. İleride çatışma yaşamayalım.

            app.UseMvc(x =>
           {
              x.MapRoute( "areas", "{area:exists}/{controller}/{action}/{id?}", new {controller="Home",Action="Index" });//varsa çatışmasın
              x.MapRoute("default", "{controller}/{action}/{id?}", new { controller = "Home", Action = "Index" }); 
           });  



Dependency Injection (Bağımlılık Enjeksiyonu)
Martin Fowler'ın geliştirdiği bir prensipdir.
Dependency Injection (Bağımlılık Enjeksiyonu),bağımlı parçaların birbirinden ayrılıp bunların dışarıdan enjekte edilmesi ve böylelikle sistemdeki bağımlılıkların azaltılmasıdır. Aradaki ilişkiyi gevşek tutmak, ilerde yapacağınız değişiklikler açısından önemlidir.
Örneğin, A sınıfında, B sınıfı nesnesi üretildi.Böylelikle A , B'ye bağlı hale geldi.İlerde B sınıfında bir değişiklik yaparsanz, A sınıfında da yapmanız gerekir.İşte bu bağımlılığı olabildiğince minimuma indirgeyeceğiz.
//Hatalı yaklaşım
public class Student
{
   private DbFacade facade;
   public Student()
   {
    facade = new DbFacade();
   }
 ....
}

Dependency Inversion prensibine göre;

(a)Modüller birbirine bağlı olmamalı. Her ikisi de soyut (abstract) kavramlara bağlı olmalıdır. Bağımlılıklar, soyutlaştırılmalıdır.Bunun için interface veya abstract class kullanmalıyız.Interface ve ya abstract kullanarak sınıflar arasında geçiş yapmalıyız. Böylece sürdürülebilir bir yazılım projesi geliştirmiş oluruz.
(b)Inversion of Control(IoC) prensibine göre bağımlılıkları oluşturmanın kontrölü, dışarıdan olmalıdır. Dependency Injection, IoC prensibini implement eden bir design patern olduğu için bağımlılıklar class’a dışarıdan “enjekte” edilir. Kullandığımız sınıfta, farklı bir sınıfın nesnesini kullanıcaksk new anahtar sözcüğünü kullanmayız. Bu nesneyi Contructor ya da Setter metoduyla, parametre olarak alırız.
public class Student
{
  private IdbFacade _facade;
  public Student(DbFacade prm)
  {
   this._facade = prm;
  }
  ....
}

Hatırlatma

Hatırlarsak; Core Katmanında concrete klasöründe metodların gövdelerini oluşturuyorduk.
context nesnesi oluşturup durduk sonra using ile dispose ettik.Son scope, kapandığında dispose oluyordu ram de yer kaplamıyordu ve işimiz bitiyordu.
using ile context bağımlılığını indirgemek için constructor da bir kere TConext nesnesi oluşturduk ve her elemanda kullandık.

    public class BaseRepository<T, TContext> : IRepository<T> where T : class, IData, new() where TContext : DbContext, IData, new()
    {
        readonly private TContext context;
        public BaseRepository(TContext _prm)
        {
            context = _prm;
        }
        public E_Result<T> Add(T prm)  //fonksiyon metod geriye E_Result T> tipinde değer dönderecek (prm T türündendir)
        {
            try
            {
               var data = context.Entry(prm);
               data.State = EntityState.Added;
               return context.SaveChanges() > 0 ? new E_Result<T> { IsSuccess = true, Data =prm, Message = "Başarıyla kaydettiniz"}: new E_Result<T> { IsSuccess=false, Data=null, Message="Bir hata meydana geldi." };
            }
            catch (Exception ex)
            {
               return new E_Result<T> { IsSuccess = false, Data = null, Message = ex.Message };   
            }
        }
 

Dal Katmanında Concrete klasöründe de BaseRepository den kalıtım aldık ve burda da constructor oluşturup base deki context kullanılmasını belirttik.

namespace Develope.Dal.Concrete
{
  public  class BransRepository : BaseRepository<Brans, WebDbContext>,IBransRepository
    {
        public BransRepository(DeveloperContext prm):base(prm)
        {

        }
    }
}

Servislerimize bakarsak birden çok interfaceleri ve sınıfları var.Controller da bunları çağırırken constructor oluşturuyor ve bu controllerın elamanları, oluşturduğumuz IServis nesnesinden yararlansın, içi bu parametreyle dolsun diyoruz.Birden çok olduğu için bir sürü IServis kullanmış oluruz.Bunun için UnitOfWork kullanalım. herbirini tek tek kullanmak yerine, bunların hepsini bir yere bağlayalım.Bir paket olarak, kullanıcaya sunalım. Birden fazla servisi bir arada tutacak bir konteyner servisi hazırlayalım ve adını IUnitOfWork imzasında gösterelim. Not:DotNetin dispose metoduvar.IDisposable interface inden gelir. Bunu da kullanalım.


 public interface IUnitOfWork : IDisposable
    {
        IBransService Brans { get; }
        IDersService Ders { get; }
        IKullaniciCevapService KullaniciCevap { get; }
        IKullaniciService Kullanici { get; }
        IKullaniciSinavService KullaniciSinav { get; }
        IKursDersService KursDers { get; }
        IKursService Kurs { get; }
        IKursMerkeziService KursMerkezi { get; }
        IRolService Rol { get; }
        ISikayetService Sikayet { get; }
        ISinavService Sinav { get; }
        ISinavSoruService SinavSoru { get; }
        ISoruService Soru { get; }
        IYorumService Yorum { get; }
        E_Result<int> SaveChanges();
    }

Core da BaseRepository değiştirdik.

    public class BaseRepository<T, TContext> : IRepository<T> where T : class, IData, new() where TContext : DbContext,  new()
    {
        readonly  TContext context;
        public BaseRepository(TContext _prm)
        {
            context = _prm;
        }
        public E_Result<T> Add(T prm)  //fonksiyon metod geriye E_Result T> tipinde değer dönderecek (prm T türündendir)
        {
            try
            {
               var data = context.Entry(prm);
               data.State = EntityState.Added;
                //return context.SaveChanges() > 0 ? new E_Result<T> { IsSuccess = true, Data =prm, Message = "Başarıyla kaydettiniz"}: new E_Result<T> { IsSuccess=false, Data=null, Message="Bir hata meydana geldi." };
                return new E_Result<T> { IsSuccess = true, Data = null, Message = "Kayıt eklenmeye hazır." };
            }
            catch (Exception ex)
            {
                //return new E_Result<T> { IsSuccess = false, Data = null, Message = ex.Message };   
                return new E_Result<T> { IsSuccess = false, Data = null, Message = ex.Message };
            }
        }

        public E_Result<T> Delete(int id)
        {
            try
            {
                var finddata = context.Set<T>().Find(id);
                var data = context.Entry(finddata);
                data.State = EntityState.Deleted;
                //return context.SaveChanges()> 0 ? new E_Result<T> { IsSuccess = true,   Message = "Başarıyla sildiniz" } : new E_Result<T> { IsSuccess = false, Data = null, Message = "Bir hata meydana geldi." };
                return new E_Result<T> { IsSuccess = true, Data = finddata, Message = "Kayıt silinmeye hazır." };
            }
            catch (Exception ex)
            {
                //return new E_Result<T> { IsSuccess = false, Data = null, Message = ex.Message };
                return new E_Result<T> { IsSuccess = false, Data = null, Message = ex.Message };
            }
        }

        public E_Result<T> Get(Expression<Func<T, bool>> filter)
        {
            try
            {
                using (TContext context = new TContext())
                {
                    T data = context.Set<T>().FirstOrDefault(filter);
                    //ternary if
                    return data == null ? new E_Result<T> { IsSuccess = false, Message = "Aranan kriterlere uygun kayıt bulunamadı." } : new E_Result<T> { IsSuccess = true, Message = "Kayıt getirildi.", Data = data };
                }
            }
            catch (Exception ex)
            {
                return new E_Result<T> { IsSuccess = false, Message = ex.Message };
            }
        }

        public E_Result<ICollection<T>> GetAll(Expression<Func<T, bool>> filter = null)
        {
            try
            {
                using (TContext context = new TContext())
                {
                    ICollection<T> dataList;
                    if (filter == null)
                    {
                        dataList = context.Set<T>().ToList();
                    }
                    else
                    {
                        dataList = context.Set<T>().Where(filter).ToList();
                    }
                    return new E_Result<ICollection<T>> { IsSuccess = true, Data = dataList, Message = "Veriler listelendi." };
                }
            }
            catch (Exception ex)
            {
                return new E_Result<ICollection<T>> { IsSuccess = false, Message = ex.Message };
            }
        }

        public E_Result<T> SoftDelete(int id)
        {
            try
            {
                var finddata = context.Set<T>().Find(id);
                var data = context.Entry(finddata);
                data.State = EntityState.Modified;
                //return context.SaveChanges() > 0 ? new E_Result<T> { Message = "Veri güncellendi", Data = finddata, IsSuccess = true } : new E_Result<T> { Message = "hata", Data = null, IsSuccess = false };
                return new E_Result<T> { IsSuccess = true, Data = finddata, Message = "Kayıt silinmeye hazır." };
            }

            catch (Exception ex)
            {
                return new E_Result<T> { IsSuccess = false, Data = null, Message = ex.Message };
                //return new E_Result<T> { Message = ex.Message, Data = null, IsSuccess = false };
            }
        }

        public E_Result<T> Update(T prm)
        {
            try
            { 
                var data = context.Entry(prm);
                data.State = EntityState.Modified;
                //return context.SaveChanges() > 0 ? new E_Result<T> { Message = "Veri güncellendi", Data = prm, IsSuccess = true } : new E_Result<T> { Message = "hata", Data = null, IsSuccess = false };
                return new E_Result<T> { IsSuccess = true, Data = prm, Message = "Kayıt güncellenmeye hazır." };
            }
            catch (Exception ex)
            {

                //return new E_Result<T> { Message = ex.Message, Data = null, IsSuccess = false };
                return new E_Result<T> { IsSuccess = false, Data = null, Message = ex.Message };
            }
        }




Yönetimi, Web.Ui katmanında farklı bir alanda yaparız.
Add-Area ile katmanımıza yeni bir alan oluşturalm. Eğer Add-Area sekmesi yoksa kendimiz elle oluşturalım.
Areas - Admin ve içerisinde Models,Views,Controllers
Controllers da bir HomeController denetleyicisi oluşturalım.
Views katmanında Shared klasörü oluşturalım.İçerisine _Layout view ekleyelim ve normal bir html komutlarını içerisine girelim.
https://athemes.com/collections/free-bootstrap-admin-templates/ sitesinden star admini indirip tasarım oluşturalım.
Tasarım taslağını Admin dizininde, temp adında bir klasöre kopyalayıp yapıştıralım.
Admin alanında Controlersda HomeController ve Index sayfası oluşturalım. Projeyi başlatınca hata alırız çünkü iki HomeController varve startup.cs karıştırır.Bundan dolayı iki alternatifimiz var;
A-ya HomeController'a gelip başına [Area("Admin")] imleci koyarız.
B- ya da AdminBaseController adında bir controller oluşturur.Oraya [Area("Admin")] koyup diğer controller sınıflarını AdminBaseControllerdan türetiriz.

     [Area("Admin")]
    public class AdminBaseController : Controller
    {
    }

HomeContreollera da : AdminBaseden türediğni yazarız. Böyllikle    [Area("Admin")] 1 kere kullamış oluruz.
    public class HomeController : AdminBaseController
    {
        public IActionResult Index()
        {
            return View();
        }
    }

Startup.cs, configure metoduna girip ilk areas sonra default routing yapısını oluşturalım. İleride çatışma yaşamayalım.

            app.UseMvc(x =>
           {
              x.MapRoute( "areas", "{area:exists}/{controller}/{action}/{id?}", new {controller="Home",Action="Index" });//varsa çatışmasın
              x.MapRoute("default", "{controller}/{action}/{id?}", new { controller = "Home", Action = "Index" }); 
           });  

Areas klasörü-Admin klasörü - Views klasörü içerisine 2 dosya oluşturacağız.Bunlar _ViewImports ve _ViewStart


@using Web
@using Web.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Web

ViewStart dosyası


@{
    Layout = "~/Areas/Admin/Views/Shared/_AdminLayout.cshtml";
}

ViewImport dosyamız;


@using Web
@using Web.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Branş modelimizin Crud işlemlerini yapacağız.
İşe ilk önce Listelemekten başlayalım.
Controller denetleyicimize gelelim.


    public class BransController : AdminBaseController
    {
        IUnitOfWork uow; 
        public BransController(IUnitOfWork _prm)
        {
            uow = _prm;
        }
        public IActionResult Listele()
        {
            var listBrans = uow.Brans.GetAll(x => x.SilindiMi == false).Data;
            return View(listBrans);
        }
    }

View oluşturalım.
Dikkat edersek DisplayNameFor deyip model.UstBransId dememiz, Web alanında UtBrnsId diye gelmesine sebebiyet verir.
Bunu aradan kaldırıp güzel bir isim oluşturmak için Model entity sınıfına girer ve Display(Name=) data annotations veririm.

public class Brans
{
    [Display(Name="Üst Branşı")]
    public int? UstBransId { get; set; }
}

        <table class="table">
            <thead>
                <tr>
                    <th>
                        @Html.DisplayNameFor(model => model.UstBransId)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.Ad)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.LogoUrl)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.Id)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.SilindiMi)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.KayitTarihi)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.GuncellemeTarihi)
                    </th>
                    <th></th>
                </tr>
            </thead>
            <tbody>
                @foreach (var item in Model)
                {
                    <tr>
                        <td>
                            @(item.UstBransi == null ? "-": item.UstBransi.Ad )
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Ad)
                        </td>
                        <td>
                            <img src="@item.LogoUrl" width="100px" />
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Id)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.SilindiMi)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.KayitTarihi)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.GuncellemeTarihi)
                        </td>
                        <td>
                            @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
                            @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
                            @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
                        </td>
                    </tr>
                }
            </tbody>
        </table>

Branş modelimiz için Ekleme işlemi yapalım.
Branş logo dosyamız olacak , bunun için admin panelinde bir klasör oluşturcam ve orda barındıracağım.
Areas klasörü-Admin klasörü-Images klasörü ve içerisinde BransLogo klasörü oluşturalım.
Statik bir dosya gördüğümüz gibi, Asp.Net core wwwroot ve M.V.C hariç klasör tanımlayamıyordu.O yüzden Startup.cs de biz tanımlayacağız.


    app.UseMvc(x =>
    {
        x.MapRoute("areas", "{area:exists}/{controller}/{action}/{id?}", new { controller = "Home", Action = "Index" });//varsa çatışmasın
        x.MapRoute("default", "{controller}/{action}/{id?}", new { controller = "Home", Action = "Index" });

    });
    //app.UseFileServer();
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
    Path.Combine(Directory.GetCurrentDirectory(), "Template")),
        RequestPath = "/tmp"
    });

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "Areas/Admin/Images/BransLogo")),
        RequestPath = "/branslogos"
    });


    app.UseStaticFiles();

Şimdi gelelim Controller sayfamıza ve Ekleme prosedürünü ekleyelim.
View görünümünde Token kullanacağız bundan doalyı Controllerda, Token'ı kontrol etmek için
BransEkle Post satırının üstüne [ValidateAntiForgeryToken] ekleyeceğiz.


  [HttpGet]
        public IActionResult Ekle()
        {
            var list = uow.Brans.GetAll(x => !x.SilindiMi).Data;
            //SelectList slct = new SelectList(list, "Id", "Ad");
            //ViewBag.BransList = slct;
            ViewBag.THBransList = list;
            return View();
        }
        [ValidateAntiForgeryToken]
        [HttpPost]
        public IActionResult Ekle(Brans model, IFormFile Foto)
        {
            if (Foto != null)
            {
                string uzanti = Foto.FileName.Split(".")[1];
                //var filePath = "/Areas/Admin/Images/BransLogo/" + Guid.NewGuid().ToString() +"."+uzanti;
                string dosyaAdi = Guid.NewGuid().ToString() + "." + uzanti;
                var filePath = "Areas/Admin/Images/BransLogo/" + dosyaAdi;
                using (var stream = new FileStream(filePath, FileMode.Create))
                {
                    Foto.CopyToAsync(stream);
                }

                model.LogoUrl = "/branslogos/" + dosyaAdi;

            }
            model.KayitTarihi = DateTime.Now;
            model.SilindiMi = false;
            uow.Brans.Add(model);
            var result = uow.SaveChanges();
            TempData["Mesaj"] = result.IsSuccess ? "Kayıt Eklendi." : result.Message;
            return RedirectToAction(nameof(Ekle));
        }

View panelinde ise


@model Model.Entity.Brans

@{
    ViewData["Title"] = "Ekle";
}

 
<div class="row">
<div class="col-md-4">
<div class="alert alert-info">  @TempData["Mesaj"]</div>
<div class="tab-content">
    <div class="tab-pane active" id="tab_1_1">
        <form role="form" asp-controller="Brans" enctype="multipart/form-data" asp-action="Ekle" asp-area="Admin" method="post">
            @Html.AntiForgeryToken()
            <div class="form-group">
                <label class="control-label">Üst Branşı</label>
                 
            <my-s-o asp-for="UstBransId" lst-for="ViewBag.THBransList as List<Brans>" ></my-s-o>

            </div>
            <div class="form-group">
                <label class="control-label">Branş Adı</label> 
                @Html.TextBoxFor(x => x.Ad, "text", new { @class = "form-control" })
                      
            </div>
            <div class="form-group">
                <label class="control-label">LogoUrl</label>
            
            <input type="file" name="Foto" value="" />
            </div>
            <input type="submit" name="name" value="Kaydet" />
        </form>
    </div>
</div>
</div>    
</div>
   

Branşın Kursları, Kursun Dersleri ve Her kursun Sınavı var

Anasayfada Branşlarımız görünecek ve üzerine tıkladığımızda altına İlgili derslerin çıkmasını istiyoruz.
Tıklandığında aşağıda açılacak liste için Js Toggleable Tabs oluşturuyoruz.
w3schools tan ilgili örnek site sayfasını inceledik.
ilk önce iki modeli birbirine bağlamak için bir Include metodu yazıcaz.
Dal katmanın IKursRepository abstract dosyasına erişelim.


    public interface IKursRepository : IRepository<Kurs>
    { 
        ICollection<Kurs> GetCoursesWithExams();
    }

ve Concrete klasöründe


    public class KursRepository : BaseRepository<  Kurs, WebDbContext>, IKursRepository
    {
        public KursRepository(WebDbContext prm) : base(prm)
        {
        }

        public ICollection<Kurs> GetCoursesWithExams()
        {
            return context.Kurs.Where(x => x.SilindiMi == false).Include(x => x.Sinav).ToList();  //using System.Linq ve EntityFrameworkCore
            //return context.Kurs.Where(x => x.SilindiMi == false).Include(x => x.Sinav).Include(x=> x.Sinav.Brans).Include(x=> x.Sinav.Ogretmen).ToList();
        }
      }

Tabi aynı şekilde Bll katmanında da tımlayacağız.Unutmaylım ki projeyi teslim ederken Dal katmanına biz müdahile edebilecektik, müşteri ise Bll katmanını.

namespace Bll.Abstract
{
    public interface IKursService
    { 
        ICollection<Kurs> GetCoursesWithExams();
    }
  }
  public class KursService: IKursService
    {
        IKursRepository repository;
        public KursService(IKursRepository _repository)
        {
            repository = _repository;
        }
        public ICollection<Kurs> GetCoursesWithExams()
        {
            return repository.GetCoursesWithExams();
        }

Web Ui katmanın ön dizin Controller katmanına ulaşalım ve KursController deetleyecisine Index sayfası oluşturalım.
Bir viewModel oluşturacağız ve Brans-Kurs Modelinin listelerini ekleyeceğiz.


    public class KursBransVM
    {
        public List<Kurs> Kurslar { get; set; }
        public List<Brans> Branslar { get; set; }
    }

    public class KursController : Controller
    {
        IUnitOfWork uow;
        public KursController(IUnitOfWork _uow)
        {
            uow = _uow;
        }
        public IActionResult Index()
        {
            var kurslar = uow.Kurs.GetCoursesWithExams().ToList();
            var branslar = uow.Brans.GetAll().Data.ToList();
            return View(new KursBransVM { Kurslar = kurslar, Branslar = branslar });
        }
    }
 
@model Web.Models.KursBransVM


<div class="tab">
    @foreach (var item in Model.Branslar)
    {
        <button class="tablinks" onclick="openCity(event, @item.Id)">@item.Ad</button>
    }


</div>


@foreach (var item in Model.Branslar)
{
    <div id="@item.Id" class="tabcontent">


        @foreach (var kurs in Model.Kurslar.Where(x => x.Sinav.BransId == item.Id))
        {
            @* @foreach (var kurs in Model.KursListesi)*@

            <div class="card" style="width: 18rem;">
                @*   <img class="card-img-top" src="@kurs.Sinav.Brans.LogoUrl" alt="Card image cap">*@
                <div class="card-body">
                    @*<h5 class="card-title">@kurs.Sinav.Brans.Ad Kursu</h5>
                        <p class="card-text">Eğitmen : @kurs.Sinav.Ogretmen.Ad @kurs.Sinav.Ogretmen.Soyad</p>*@
                    <p class="card-text">Başlangıç- Bitis Tarihleri : @kurs.BaslamaTarihi.ToShortDateString() - @kurs.BitisTarihi.ToShortDateString()</p>
                    <a href="/Kurs/Detay/@kurs.Id" class="btn btn-primary">Detay Gör</a>
                </div>

                <p>London is the capital city of England.</p>
            </div>

        }


    </div>
}


<script>
    function openCity(evt, cityName) {
        var i, tabcontent, tablinks;
        tabcontent = document.getElementsByClassName("tabcontent");
        for (i = 0; i < tabcontent.length; i++) {
            tabcontent[i].style.display = "none";
        }
        tablinks = document.getElementsByClassName("tablinks");
        for (i = 0; i < tablinks.length; i++) {
            tablinks[i].className = tablinks[i].className.replace(" active", "");
        }
        document.getElementById(cityName).style.display = "block";
        evt.currentTarget.className += " active";
    }
</script>
<style>
 
    .tab {
        overflow: hidden;
        border: 1px solid #ccc;
        background-color: #f1f1f1;
    }
 
        .tab button {
            background-color: inherit;
            float: left;
            border: none;
            outline: none;
            cursor: pointer;
            padding: 14px 16px;
            transition: 0.3s;
            font-size: 17px;
        } 
            .tab button:hover {
                background-color: #ddd;
            } 
            .tab button.active {
                background-color: #ccc;
            } 
    .tabcontent {
        display: none;
        padding: 6px 12px;
        border: 1px solid #ccc;
        border-top: none;
    }
</style>
@*

*@
02.02.2020