Open
Blog Aşamalar

Blog Aşamaları

(1) Visual Studio'yu açalım ve Core Empty Projesi oluşturalım.

(2) 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();
        }

  

İnceleme: EndPoints routing

 EndPoint route yöntemi de tıpkı MVC route yöntemine benzer.İncelersek;
        //public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        //{ 
        //    app.UseRouting();

        //    app.UseEndpoints(endpoints =>
        //    {
        //        endpoints.MapControllers();

        //        endpoints.MapControllerRoute(
        //            "default", "{controller=Home}/{action=Index}/{id?}");

        //        //1
        //        //endpoints.MapControllerRoute(
        //        //name: "default",
        //        //pattern: "{controller=Home}/{action=Index}/{id?}");

        //        //2 area için
        //        //endpoints.MapAreaControllerRoute(
        //        //    "admin",
        //        //    "admin",
        //        //    "Admin/{controller=Home}/{action=Index}/{id?}");

        //    });
        //}

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.

(3)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.


HomeController ile Index sayfası oluşturmuştuk.Index sayfasında, bir konteyner olacak ve sol-sağ kolonları olacak.Sol da ürünler,sağda menüler.

<div class="container">
    <div class="row">
        <div class="col-md-9"></div>
        <div class="col-md-3">  </div>
    </div>
</div>

https://getbootstrap.com/docs/4.4/components/list-group/ getbootstrap web sitesinden list-group aratıp alalım ve index sayfamızn sol tarafına yapıştıralm. Sonra da bir card aratıp tag kodlarını alalım ve index sayfamızın sağ orta bölümüne yapıştıralım.



    <div class="col-md-9">
    <div class="card" style="width: 18rem;">
    <img src="..." class="card-img-top" alt="...">
    <div class="card-body">
        <h5 class="card-title">Card title</h5>
        <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
        <a href="#" class="btn btn-primary">Go somewhere</a>
    </div>
    </div>

    </div>


<div class="col-md-3">
    <div class="list-group">
    <a href="#" class="list-group-item list-group-item-action active"> Cras justo odio </a>
    <a href="#" class="list-group-item list-group-item-action">Dapibus ac facilisis in</a>
    <a href="#" class="list-group-item list-group-item-action">Morbi leo risus</a>
    <a href="#" class="list-group-item list-group-item-action">Porta ac consectetur ac</a>
    <a href="#" class="list-group-item list-group-item-action disabled" tabindex="-1" aria-disabled="true">Vestibulum at eros</a>
    </div>
</div>






(8) 2 adet Entity miz var. Category ve Product. Bire çok ilişkisi olacak. 1Kategorinin birde fazla ürünü olacak. 1 ürünün 1 kategorisi.
    [Table("Tbl_Category")]
    public class Category
    {
        [Key]
        public int Id { get; set; }
        public string Name { get; set; }
        public ICollection<Product> CProducts { get; set; }
    }

    [Table("Tbl_Product")]
    public class Product
    {
        [Key]
        public int ProductID { get; set; }
        public string ProductName { get; set; }
        public string Body { get; set; }
        public string ImageUrl { get; set; }
        [BindNever]  //Form üzerinden gönderilmesin diye
        public DateTime AddedTime { get; set; }
        public bool IsActive { get; set; }
        [ForeignKey("Category")]
        public int CategoryID { get; set; }
        public Category Category { get; set; }
    }



(9)Dal katmanı için, Dal klasöründe Abstract ve Concrete klasörlerini oluşturalım. Concrete klasöründe DbContext ten türüyen bir context sınıf oluşturacağız. Adının sonu Context ile biterse anlaşılır olması kolaylaşır.Öreğin; WebDbContext,P1BlogContext gibi
(a) Bağımlılıklar eklemek için paket klasörüne sağ tıklayıp nugget package sekmesinden EF Core all yükleyelim. İçerisinde EFCore,EfCore Design,EfCore SqlServer,Ef Core Tools gibi kütüphaneler dahildir. Eğer VS versiyonumuz , EfCore All kütüphanesine uygun değilse ayrı ayrı yükleyelim.
(b) P1BlogContext context sayfasına girelim.İlk önce ctor yazıp tab tuşuna basalım. Connection bilgisini ayarlamak için DbContext optionsuna bakalım.
Yapıcı fonksiyon tanımladık dışardan bir options parametre alacak. Bu option bize connection string getirecek.
Projemize appsettings.json yapılandırıcı dosya ekleyelim (asp.Net deki web config'in yerini almıştır.)
 
    public class P1BlogContext : DbContext   //Classı DbContext ten türettik.
    {
        public P1BlogContext( DbContextOptions<P1BlogContext> options) :base(options)
        {
                
        }

        public DbSet<Category> Tbl_Category { get; set; }
        public DbSet<Product> Tbl_Product { get; set; }

    //appsettings.json dosyası
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=.;Database=ArcDB;Trusted_Connection=True; "
  }
}
        public IConfiguration Configuration { get; }
        public Startup(IConfiguration _configuration)
        {
            Configuration = _configuration;
        }

        public void ConfigureServices(IServiceCollection services)
        {

            services.AddDbContext<P1BlogContext>(x => x.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        }
(10) startup.cs de services.AddDbContext<P1BlogContext>(x => x.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), b=>b.MigrationsAssembly("Web"))); // Migration yolunu belirttik
(11)a projemizin bulunduğu dizine gelip dotnet ef migrations add v1 dedik sonra dotnet ef update database dedik.
b eğer olmadıysa Paket Yöneticisi Konsolunu açıp, varsayılan Dal katmanını seçip add-migrations v1 , update-database diyelim.
(12) Bir SeedData sınıfı oluşturup, test verisi eklemek istersek;(Zorunlu değildir.)
namespace Web1.Models.Projects.blog.Dal.Concrete.Ef
{
    public class SeedData
    {
        public static void  Seed (IApplicationBuilder app)
        {
            P1BlogContext context = app.ApplicationServices.GetRequiredService<P1BlogContext>(); //using Microsoft.Extensions.DependencyInjection;

            context.Database.Migrate();
            if (!context.Tbl_Category.Any())
            {
                context.Tbl_Category.AddRange(
                    new Category () {CategoryName = "Category 1" },
                    new Category() { CategoryName = "Category 2" },
                    new Category() { CategoryName = "Category 3" }
                );
                context.SaveChanges();
            }

            if (!context.Tbl_Product.Any())
            {
                context.Tbl_Product.AddRange(
                    new Product() { ProductName = "Blog title 1",  Body = "Blog Body 1", ImageUrl = "na1.jpg", AddedTime  = DateTime.Now.AddDays(-5), IsActive = true, CategoryID = 1 },
                    new Product() { ProductName = "Blog title 2",  Body = "Blog Body 1", ImageUrl = "na2.jpg", AddedTime = DateTime.Now.AddDays(-7), IsActive = true, CategoryID = 1 },
                    new Product() { ProductName = "Blog title 3",  Body = "Blog Body 1", ImageUrl = "na3.jpg", AddedTime = DateTime.Now.AddDays(-8), IsActive = false, CategoryID = 2 },
                    new Product() { ProductName = "Blog title 4",  Body = "Blog Body 1", ImageUrl = "na4.jpg", AddedTime = DateTime.Now.AddDays(-9), IsActive = true, CategoryID = 3 }
                );
                context.SaveChanges();
            }
        }
    }



(13) Dal klasörümüzde Abstract ve concrete adında 2 klasör oluşturmuştuk.
(a)İlk önce Abstract klasöründe Interfacelerimizi hazırlayalım.Bizim asıl metodlarımızın imzası olarak görebiliriz. (Bir kitabın içindekiler kısmı);
  public  interface ICategoryRepository
    {
        void AddCategory(Category prm);
        void UpdateCategory(Category prm);
        void DeleteCategory(int ID);

        Category GetbyID(int ID); //Geri dönüş değeri Category Entity olsun.
        IQueryable<Category> GetAll(); 
    }


   public interface IProductRepository
    {
        void AddProduct(Product prm); //dışardan Product parametresini alacak
        void UpdateProduct(Product prm);
        int DeleteProduct(int id);

        IQueryable<Product> GetAll();
        Product GetbyID(int ID);
    }
(b) Şimdi sıra Concrete klasörümüzdeki CategoryRepository ve ProductRepository de;

    public class CategoryRepository : ICategoryRepository
    {
        private P1BlogContext context;
        public CategoryRepository(P1BlogContext prm )
        {
            context = prm;
        }

        public void AddCategory(Category prm)
        {
            context.Tbl_Category.Add(prm);
            context.SaveChanges();
        }

        public void DeleteCategory(int ID)
        {
            var dltData = context.Tbl_Category.FirstOrDefault(x=> x.CategoryID==ID); //sorgulama yapıyoruz. 
            if (dltData != null)
            {
                context.Tbl_Category.Remove(dltData);
                context.SaveChanges();
            }
        }

        public IQueryable<Category> GetAll()
        {
            return context.Tbl_Category;
        }

        public Category GetbyID(int ID)
        {
            return context.Tbl_Category.FirstOrDefault(x => x.CategoryID == ID);

        }

        public void UpdateCategory(Category prm)
        {
            context.Entry(prm).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
            context.SaveChanges();
        }
    }

      public class ProductRepository : IProductRepository
    {
        protected P1BlogContext context;
        public ProductRepository(P1BlogContext _context)
        {
            context = _context;
        }
        public void AddProduct(Product prm)
        {
            context.Tbl_Product.Add(prm);
            context.SaveChanges();
        }

        public void DeleteProduct(int id)
        {
            var find = context.Tbl_Product.FirstOrDefault(x => x.ProductID == id);
            if (find !=null)
            {
                context.Tbl_Product.Remove(find);
                context.SaveChanges();
            }
         
        }

        public IQueryable<Product> GetAll()
        {
            return context.Tbl_Product;
        }

        public Product GetbyID(int ID)
        {
            return context.Tbl_Product.FirstOrDefault(x => x.ProductID == ID);
        }

        public void UpdateProduct(Product prm)
        {
            context.Entry(prm).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
            context.SaveChanges();
        }
    }






Index sayfamızda ürünler ve Kategoriler olacak. Kategorilere tıkladığımızda aynı sayfada kategorinin ilgili ürünleri gelecek.
Yani MVC route kullanılacak. http://localhost:64665/Blog/Index/1 1 dediğimizde 1 kategorili ürünler gelecek
ama kategori numarası olmadan da çalışması gerekecek o halde Index metodumuz public IActionResult Index (int? id) olacak.
Kategoriler için farklı bir model kullanacağız , Index sayfasına bağımlı bir modeli olmayacak onun için Component kullanacağız.
Şimdi BlogController dosyamızı açalım ve Index sayfasını oluşturalım.

    public class BlogController : Controller
    {
        private IProductRepository pRepository;  
        private ICategoryRepository cRepository;

      //Controler için Constructor oluşturacağız. Dışardan göndereceğimiz parametrenin içini pRepository ile dolduralım.
        public BlogController(IProductRepository prm1, ICategoryRepository prm2)
        {
            pRepository = prm1;
            cRepository = prm2;
        }

        //Sade biçimde yazalım.
        public IActionResult Index( int? id)
        {
            var query = pRepository.GetAll();     //.Where(i => i.IsActive) olabilirdi
            if (id !=null)
            {
                query = query.Where(i => i.CategoryID == id);
            }
            return View(query);     //.OrderByDescending(i => i.AddedTime) olabilir
        }

        public IActionResult Details( int id) //dışardan int id parametresi alacak AL
        {
            return View(pRepository.GetbyID(id));   //aldığı bilgiyle details view'i geri döndürücek (return) GERİDÖNDÜR
        }


IRepositorylerimiz sadece metodlarımızın imzalarıdır. Startup.cs dosyası ile bu sanal imzaların yerini, dolu metotlarla değişteceğiz. Service metodunda AddTransient metodunu çağrmayı unutmayalım.

    public void ConfigureServices(IServiceCollection services)
        {  
            services.AddTransient<IProductRepository, ProductRepository>(); //IPrRe çağırdığımızda PrRe gelsin
            services.AddTransient<ICategoryRepository, CategoryRepository>();  






Index sayfasını oluşturalım. Ürünleri listeleyeceğiz. sağnda kategoriler olacak her birini tıkladığımızda ilgili ürünler gelecek. O yüzden ürünleri bir partilaview içerisine almak en mantıklısı olacaktır.
Views klasörü-Shared klsörü içerisinde Partialviews ya da Wuc adında bir klasör oluşturalım ve _ProductList view dosyası ekleyelim.

@using  App.Models.Projects.ProjeBlog.Entity
@model IEnumerable<Product>
  
    @foreach (var item in Model)
    {
        <div class="card mt-2"  >
         <div class="card-header">@item.ProductName</div>
         <img src="~/images/@item.ImageUrl" class="img-fluid" alt="@item.ProductName">
         <div class="card-body">
         <h5 class="card-title">@item.ProductName</h5>
        <p class="card-text">Some quick example text to build on the card title and make up the bulk of the cards content.</p>
        <a asp-action="Details" asp-controller="Blog"  asp-route-id="@item.ProductID" class="btn btn-primary">Detaylar</a>
        </div>
        </div>  

Şimdi onu Indx sayfasına yerleştirelim. Partialview olduğu için bulunduğu viewin modeline uyum sağlamak zorundadır.

@model IEnumerable<Product>

<div class="container">
<div class="row">

<div class="col-md-9">
<if (Model.Count() == 0)  //Model deki id sayısı 0'a eşittir demektir.
{
    <div class="alert alert-warning">İlgili Kategori ID'nin henüz bir sergisi yoktur.</div>
}
else
{
   @Html.Partial("Wuc/_ProductList",Model)
}     
</div>


<div class="col-md-3">
Component ile Caegori Listelenecektir.
</div>

 </div></div>

Detay Sayfasını ekleyelim

@model Product
<div class="container">
<div class="row">
         
    <div class="col-md-12">
    <div class="card mb-2" > 
    <img src="/images/@Model.ImageUrl" class="img-fluid" alt="@Model.ProductName">
    <div class="card-body">
    <h5 class="card-title">@Model.ProductName</h5>
    <p class="card-text">@Model.Body & lt;/p> 
    </div>
    </div> 
    </div> 
    </div></div>




Componentler partial view gibidir, yalnızca daha esnektir. Partial Viewler, dışardan bir veri alıp içeriğini, istenilen tüm viewlerde gösterebilen bir yapıdır. Ama Partial View'in modeli, yerleşeceği view'e özgü, bağımlı bir modeli olmalıdır,uyum sağlamalıdır.
Componentlerin, yerleşeceği view'in modeline, uyum sağlama zorunluluğu yoktur.O yüzden sık-sık tercih edilir.
Component yapısının, controller denetleyicisine ihtiyacı yoktur. MVC yöntemi gibidir.Bir Model vardır. Controller gibi Component modelden bilgiyi alır, işler ve Component adındaki View'e gönderir.envoke metodunu tetiklemek yeterlidir.Yerleşeceği View'in modeline, bağımlılığı yoktur.
Bunun için ViewsComponent adında bir klasör oluşturalım.(Dilerseniz farklı bir ad verebilirsiiz.)
RightBlogCategory adında bir sınıf oluşturalım.

    public class RightBlogCategory : ViewComponent   //using Microsoft.AspNetCore.Mvc;
    {
        private ICategoryRepository cRepository;
        public RightBlogCategory(ICategoryRepository _prm)
        {
            cRepository = _prm;
        }
        public IViewComponentResult Invoke()  //Dışardan bir parametreye ihtiyacımız yok
        {
            ViewBag.ActiveCategory = RouteData?.Values["id"];
            return View(cRepository.GetAll());
        }

        //Kategorilerden birini tıkladığımızda Route de ID=1 verecek ve kategori adı aktif olacak.
        //Bundan dolayı RouteData.Values["id"] alıyoruz, bunu Viewbag ile hfızada tutuyoruz.
        //RouteValue boş olabilir unutmayalım.
        //class="list-group-item <(ViewBag.ActiveCategory == item.CategoryID.ToString()? "active": "")">
    }

Şimdi de aynı isimde bir klasör oluşturup Default dosyası oluşturcaz. Tıpki MVC deki HomeController, Home klasöründeki Index gibi.
Views- Shared-Component adında klasör oluşturalım.Tüm componentleri,dilerseniz orda yazalım.
Şimdi bu Components klasörü içerisine, RightBlogCategory adlı klasör ve Default adında view oluşturalım.

 @model IEnumerable<Category>

<div class="list-group">
    @foreach (var item in Model)
    {
     <a asp-controller="Blog" asp-action="Index" asp-route-id="@item.CategoryID"  class="list-group-item  "> @item.CategoryName </a>
    }
</div>

Index sayfasına gelelim ve sol tarafta col-md-3 denilen div clasın alanına bu componenti çağıralım
@await Component.InvokeAsync("CategoryList")





Liste metodu yapıyoruz.Admin Kategori ve Admin Product Listesi
        public IActionResult AdminCategoryList()
        {
            return View(cRepository.GetAll());
        }

        public IActionResult AdminProductList()
        {
            return View(pRepository.GetAll());
        }



 
@model IEnumerable<Category>

    <div class="container">
    <div class="row">
    <div class="col">

    @if (Model.Count()>0)
    {
    <table  class="table table-bordered table-striped" >
    <thead>
    <tr>
        <th>ID</th>
        <th>Name</th>
        <th>İşlemler</th>
    </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>@item.CategoryID</td>
                <td>@item.CategoryName</td>
                <td>
                    <a class="btn btn-primary" asp-action="AdminCategoryCreateOrUpdate" asp-controller="Blog" asp-route-id="@item.CategoryID">Details</a>
                    <a class="btn btn-danger" asp-action="AdminCategoryDelete" asp-controller="Blog" asp-route-id="@item.CategoryID">Delete</a>
                </td>
            </tr>
        }
    </tbody>
    </table>
    }
    else
    {
    <div class="alert alert-danger">Category Eklenmemiş</div> 
    }
<a asp-action="AdminCategoryCreateOrUpdate" asp-controller="Blog" class="btn btn-sm btn-primary">Ekle</a>
 </div> </div> </div>


Projeye Istemci Tarafı Kitaplığı ile fontawesome css diye aratıp icon css lerini almıştık.Onları kullanalım.

//Product
@model IEnumerable<Product>
<div class="container">
<div class="row">
<div class="col">
    @if (Model.Count()>0)
    {
<table class="table table-bordered table-striped">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>ImageUrl</th>
            <th>Added Time</th>
            <th>Is Active</th>
            <th>İşlemler</th> 
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model) {
        <tr>
            <td> @item.ProductID </td>
            <td> @item.ProductName </td>
            <td> <img src="~/images/@item.ImageUrl" width="100" /></td>
            <td> @item.AddedTime </td>
            <td> @if (item.IsActive)
            {  <i class="fa fa-check-circle" aria-hidden="true"></i>  }
            else
            { <i class="fa fa-times-circle" aria-hidden="true"></i>} </td> 
            <td> 
                <a class="btn btn-primary" asp-controller="Blog" asp-action="ProductDetails" asp-route-id="@item.ProductID">Details</a> 
                <a class="btn btn-danger"  asp-controller="Blog" asp-action="AdminProductDelete" asp-route-id="@item.ProductID">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>
    }
    else
    {
        <div class="alert alert-info">Herhangi bir Ürün yoktur.</div> 
    }
      </div>
    </div>
</div>




Create Metodu

Controller sayfasına girelim ve Product için Create metodu oluşturalım.

        [HttpGet]
        public IActionResult AdminProductCreate()
        {
            ViewBag.Categories = new SelectList(cRepository.GetAll(), "CategoryID", "CategoryName");
                //üzerine geldiğinizde ICollectiln listesi istiyo zaten sonra string value field,string text field
            return View();
        }
        [HttpPost]
        public IActionResult AdminProductCreate(Product prm)
        {
            prm.AddedTime = DateTime.Now;
            if (ModelState.IsValid)
            {
                pRepository.AddProduct(prm);
                return RedirectToAction("AdminProductList");
            }
            return View();
        }

Views görünüm dosyasına girelim ve tasarım ile birlikte models kodlarını girelim.

@model Product
<div class="container">
    <div class="row">
        <div class="col">
        <form asp-controller="Blog" asp-action="AdminProductCreate" method="post">
        <div class="form-group">
            <label asp-for="ProductName"></label>
            <input asp-for="ProductName" class="form-control" >
        </div>
        <div class="form-group">
            <label asp-for="Body"></label>
            <textarea asp-for="Body" class="form-control" ></textarea>
        </div>
        <div class="form-group">
            <label asp-for="ImageUrl"></label>
            <input asp-for="ImageUrl" class="form-control" >
        </div>
        <div class="form-check">     //buttonstrap radiobutton için
            <label class="form-check-label">
                <input asp-for="IsActive" class="form-check-input" >IsActive
            </label>
        </div>
        <div class="form-group">
            <label asp-for="CategoryID"></label>
            <select asp-for="CategoryID" asp-items="ViewBag.Categories" class="form-control" >
                <option disabled selected value="">Select Category</option>

            </select>
        </div>
      
        <button type="submit" class="btn btn-primary">Submit</button>
        </form>
        </div>
    </div>
</div>
//Layout sayfasına gidelim ve RenderBody() metodunun bir üst satırına  alt komutu yazalım.     
@if (TempData["message"] != null)
    {
        <div class="alert alert-success">@TempData["message"]</div>
    }


Update Metodu


        [HttpGet]
        public IActionResult AdminProductUpdate(int ID)
        {
            ViewBag.Categories = new SelectList(cRepository.GetAll(), "CategoryID", "CategoryName");
            return View( pRepository.GetbyID(ID));
        }
        [HttpPost]
        public IActionResult AdminProductUpdate(Product prm)
        {
            prm.AddedTime = DateTime.Now;
            if (ModelState.IsValid)
            {
                pRepository.UpdateProduct(prm);
                TempData["message"] = $"{prm.ProductName} updated"; 
                return RedirectToAction("AdminProductList");
            }
            return View(prm);
        }




@model Product

Update yaptığımızda ID değerine de bir parametre gitmesi gerekir. (create de gerekmez veritabanı kendi oto ekler.)
Yeni bir kolon oluşmuyor Aynı kolon, güncelleniyor 

<div class="container">
    <div class="row">
        <div class="col">
        <form asp-controller="Blog" asp-action="AdminProductUpdate" method="post">
        <input asp-for="ProductID" type="hidden" />
        <div class="form-group">
            <label asp-for="ProductName"></label>
            <input asp-for="ProductName" class="form-control" >
        </div>
        <div class="form-group">
            <label asp-for="Body"></label>
            <textarea asp-for="Body" class="form-control" ></textarea>
        </div>
        <div class="form-group">
            <label asp-for="ImageUrl"></label>
            <input asp-for="ImageUrl" class="form-control" >
        </div>
        <div class="form-check">     //buttonstrap radiobutton için
            <label class="form-check-label">
                <input asp-for="IsActive" class="form-check-input" >IsActive
            </label>
        </div>
        <div class="form-group">
            <label asp-for="CategoryID"></label>
            <select asp-for="CategoryID" asp-items="ViewBag.Categories" class="form-control" >
                <option disabled selected value="">Select Category</option>

            </select>
        </div>
      
        <button type="submit" class="btn btn-primary">Submit</button>
        </form>
        </div>
    </div>
</div>


Amacımız, create ve update metodunu, tek bir form üzerinden gerçekleştirmek
Bunun için Dal daki Repository mize ek kod yazmamız gerekecek.Abstract ve Concrete dosyalarına erişip;

  //abstract 
  public  interface ICategoryRepository
    { 
      void SaveForm(Category prm);
    }
    
   //Concrete
    public class CategoryRepository : ICategoryRepository
    {
        public void SaveForm(Category prm)
        {
        //gelen parametrenin ID si 0 ise yeni bir işlem yapacağım demektir.
        //prm.DateTime = DateTime.Now; eğer datetime değişkenim varsa yeni eklendiğinde zamanı eklesin ama güncelleme sırasında gerek yok.
        if (prm.CategoryID==0)
        {
            context.Tbl_Category.Add(prm);
        }
        else
        {
            var findproduct = GetbyID(prm.CategoryID);
            if (findproduct != null)
            {
                findproduct.CategoryName = prm.CategoryName;
            }
        }
        context.SaveChanges();
        }

Dilerseniz,gözlemlemek adına Her scope (süslü parantez) başlarına breakpoint atıp IIS üzerinden çalıştırabilirsiniz.



        [HttpGet]
        public IActionResult AdminCategoryCreateOrUpdate(int? ID)
        {
            if (ID==null)
            {
              //yeni oluşturulacak. kendi yeni sayfası
              return View(new Category()); //boş bir nesne gönderelim CategoryID 0 değeri gelsin diye
            }
            else
            {
                return View(cRepository.GetbyID((int)ID)); //ID nullable olduğu için onu int'e çevirdik.
            }
        }

        [HttpPost]
        public IActionResult AdminCategoryCreateOrUpdate(Category prm)
        {
            if (ModelState.IsValid)
            {
                cRepository.SaveForm(prm);
                TempData["message"] = $"{prm.CategoryName} saved";
                return RedirectToAction("AdminCategoryList");
            } 
            return View(prm);
        }


Update yaptığımızda ID değerine de bir parametre gitmesi gerekir. (create de gerekmez veritabanı kendi oto ekler.)
Yeni bir kolon oluşmuyor Aynı kolon, güncelleniyor

@model Category
<div class="container">
    <div class="row">
        <div class="col">
        <form asp-controller="Blog" asp-action="AdminCategoryCreate" method="post">
        <input asp-for="CategoryID" type="hidden" />  //!important
        <div class="form-group">
            <label asp-for="CategoryName"></label>
            <input asp-for="CategoryName" class="form-control" >
        </div>
        <button type="submit" class="btn btn-primary">Submit</button>
        </form>
        </div>
    </div>
</div>



Category için
         [HttpGet]
        //Delete(int id) burdaki id parametresini, CategoryListesindeki Delete butonundaki asp-route-id=CategoryID gönderiyor,burdan elde edeceğiz.
        public IActionResult AdminCategoryDelete(int id)  
        {
            return View( cRepository.GetbyID(id)); //GetbyId ile kayıda alıcaz ve form üzerine aktarıcaz. 
        }

        [HttpPost,ActionName("AdminCategoryDelete")]
        public IActionResult CategoryDeleteConfirmed(int id) // isim çatışması yaşamamak için adını değiştik.Metodlar int döndürüyor
        {
            cRepository.DeleteCategory(id);
            TempData["message"] = $"{id} numbered data removed.";
            return RedirectToAction("AdminCategoryList");
        }
@model Category

<div class="container">
    <div class="row">
        <div class="col">
        <form asp-controller="Blog" asp-action="AdminCategoryDelete" method="post">
        <input asp-for="CategoryID" type="hidden" />  
        Do you want to delete  @Model.CategoryName  ?  <br />
        <button type="submit" class="btn btn-primary">Delete</button>
        </form>
         </div>
    </div>
</div>

Product içi
        [HttpGet] 
        public IActionResult AdminProductDelete(int id)
        {
            return View(pRepository.GetbyID(id));  
        }

        [HttpPost, ActionName("AdminProductDelete")]
        public IActionResult ProductDeleteConfirmed(int id)  
        {
            pRepository.DeleteProduct(id);
            TempData["message"] = $"{id} numbered data removed.";
            return RedirectToAction("AdminProductList");
        }
ve aynı category form, product'a da mevcuttur.


02.02.2020