.NET Core ile çok katmanlı mimari: Onion Architecture


Merhaba, bu makalemde Visual Studio 2017 ve .NET Core ile Onion Architecture (Soğan Mimarisi) adı verilen çok katmanlı mimarinin nasıl kurulduğunu anlatacağım.

Öncelikle biraz katmanlı mimariden bahsedelim. Katmanlı mimari denilince İngilizce’de bu anlamda iki ifade bulunuyor: n-tired architecture ve multi-layered architecture. Türkçe’de bu İngilizce ifadelerin her ikisi de çok katmanlı mimari anlamında kullanılsa da aslında bu ifadelerin anlamları farklı. multi-layered architecture dediğimiz çok katmanlı mimari bir Visual Studio çözümününün içerisinde birden fazla proje olması durumudur. Her projeye layer yani katman denilir. n-tired ifadesi ise bu layerlerın farklı sunucularda yayınlanması durumudur. Her sunucudaki katmana tier denilir.

Biz bu makalemizde katmanlı mimari derken multi-layered architecture’ı kastediyoruz.

Çok katmanlı mimari desenleri çeşitlidir. Bunlardan Onion Arhcitecture’ı yani Soğan Mimarisini anlatacağım.

Soğan Mimarisi 4 katmandan oluşur:

1. Model katmanı
2. Data katmanı
3. Service katmanı
4. Presentation katmanı

Model Katmanı

Model katmanı entity sınıflarımızı içeren bir katmandır. Her entity ayrı bir class dosyasında yazılır. Enum’lar da aynı şekilde ayrı dosyalarda yer alır. Entity’lerin neredeyse tamamının miras aldığı BaseEntity adında bir sınıf bulunur. Sadece many-to-many ilişkileri kurmaya yarayan ara entityler BaseEntity’i miras almazlar. Entitylerde Data Annotation attribute’ları kullanılmaz. Bu attribute’lar yerine Data katmanında Builder class’ları ile fluent-api kodları yazılacaktır.

Öncelikle ilk olarak yapılması gereken kısım Files>New Project>Other Project Types>Visual Studio Solutions>Blank Solution şeklinde bir çözüm açılır. Daha sonra açılan pencereden Solution Explorer penceresindeki projeye sağ tıklayıp Add>New Project>.NET Core>Class Library(.Net Core)şeklinde bir sınıf kütüphanesi ekleyip OnionArchitectureSample.Model şeklinde isim verilir. Daha sonra OnionArchitectureSample.Model e sağ tıklayıp Add>Class yapılarak BaseEntity şeklinde bir sınıf eklenir. BaseEntity sınıfının kodları aşağıdaki gibi yazılabilir.

 

public class BaseEntity
{
   public long Id { get; set; }
   public DateTime AddedDate { get; set; }
   public DateTime ModifiedDate { get; set; }
   public string AddedBy { get; set; }
   public string ModifiedBy { get; set; }
}

Daha sonra tekrar aynı şekilde Category sınıfı eklenir ve kodları aşağıdaki gibi yazılabilir.

public class Category:BaseEntity
{
   public string Name { get; set; }
   public virtual ICollection<Product> Products { get; set; }
}

Aynı şekilde Product şeklinde bir sınıf daha eklenip kodları aşağıdaki gibi yazılabilir.

  

public class Product:BaseEntity
{
public string Title { get; set; }
   public string Description { get; set; }
public decimal Price { get; set; }
public long CategoryId { get; set; }
public Category Category { get; set; }
}

Data Katmanı

Data katmanında model katmanında tanımlanan entitylerin veritabanı işlemlerini yapmaya yarayan repository’ler bulunur. Aynı zamanda projenin kalbi olan Unit Of Work, Generic Respository sınıf ve interface’leri de bu katmanda bulunur. Her repository için aynı .cs uzantılı dosyada hem interface hem de class tanımlaması yapılacaktır ve repository’ler eager loading yapabilmek için Entity Framework’teki Include metotlarını da destekleyecektir.

Data katmanında aynı zamanda DbContext’imiz ve Seed extension metodumuz da bulunmaktadır. DbContext’in çalışabilmesi için bu katmanı Entity Framework Core nuget pakedini yüklememiz gerekecektir.

Şimdi, OnionArchitectureSample.Model i eklediğimiz gibi yeni bir proje daha ekleyip OnionArchitectureSample.Data ismini verelim. OnionArchitectureSample.Data ya sağ tıklayıp New Folder kısmından yeni klasör ekleyip ismine Builders verilir. Builders klasörüne sağ tıklayıp sınıf ekleyelim ve ismine de CategoryBuilder verebiliriz. Açılan CategoryBuilder sınıfının yapıcı metodu aşağıdaki gibidir:


public CategoryBuilder(EntityTypeBuilder<Category> entityBuilder)
{
   entityBuilder.HasKey(p => p.Id);
   entityBuilder.Property(p => p.Name).IsRequired().HasMaxLength(200);
}

Aynı şekilde ProductBuilder adından bir sınıf daha eklenir. ProductBuilder sınıfının kod kısmı aşağıdaki gibidir:


public ProductBuilder(EntityTypeBuilder<Product> entityBuilder)

{

entityBuilder.HasKey(p => p.Id);

entityBuilder.Property(p => p.Title).IsRequired().HasMaxLength(200);

entityBuilder.HasOne(p => p.Category).WithMany(c => c.Products)

.HasForeignKey(p => p.CategoryId);

}

Builders klasörünü eklediğimiz gibi Infrastructure isminde bir klasör daha ekleyelim. Infrastructure klasörüne sağ tıklayıp IRepository isminde bir interface ekleyelim. IRepository interface’inin kod kısmı aşağıdaki gibidir:


public interface IRepository<T> where T : class

{

void Add(T entity);

void Update(T entity);

void Delete(T entity);

void Delete(Expression<Func<T, bool>> where);

T GetById(long id, params string[] navigations);

T Get(Expression<Func<T, bool>> where, params string[] navigations);

IEnumerable<T> GetAll(params string[] navigations);

IEnumerable<T> GetMany(Expression<Func<T, bool>> where, params string[] navigations);

}

Aynı şekilde Infrastructure klasörünün altına IUnitOfWork adında bir interface daha ekleyelim. IUnitOfWork interface’inin kod kısmı aşağıdaki gibidir.


public interface IUnitOfWork

{

void Commit();

}

Aynı şekilde RepositoryBase isminde bir sınıf eklenir. RepositoryBase sınıfının kod kısmı aşağıdaki gibidir.


public abstract class RepositoryBase<T> where T : BaseEntity

{

#region Properties

private ApplicationDbContext dataContext;

private readonly DbSet<T> dbSet;

protected ApplicationDbContext DbContext

{

get { return dataContext; }

}

#endregion

protected RepositoryBase(ApplicationDbContext dbContext)

{

dataContext = dbContext;

dbSet = DbContext.Set<T>();

}

#region Implementation

public virtual void Add(T entity)

{

dbSet.Add(entity);

}

public virtual void Update(T entity)

{

dbSet.Attach(entity);

dataContext.Entry(entity).State = EntityState.Modified;

}

public virtual void Delete(T entity)

{

dbSet.Remove(entity);

}

public virtual void Delete(Expression<Func<T, bool>> where)

{

IEnumerable<T> objects = dbSet.Where<T>(where).AsEnumerable();

foreach (T obj in objects)

dbSet.Remove(obj);

}

public virtual T GetById(long id, params string[] navigations)

{

var set = dbSet.AsQueryable();

foreach (string nav in navigations)

set = set.Include(nav);

&nbsp;

return set.FirstOrDefault(f => f.Id == id);

}

public virtual IEnumerable<T> GetAll(params string[] navigations)

{

var set = dbSet.AsQueryable();

foreach (string nav in navigations)

set = set.Include(nav);

return set.AsEnumerable();

}

public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where, params string[] navigations)

{

var set = dbSet.AsQueryable();

foreach (string nav in navigations)

set = set.Include(nav);

return set.Where(where).AsEnumerable();

}

public T Get(Expression<Func<T, bool>> where, params string[] navigations)

{

var set = dbSet.AsQueryable();

foreach (string nav in navigations)

set = set.Include(nav);

return set.Where(where).FirstOrDefault<T>();

}

#endregion

}

Aynı şekilde UnitOfWork isminde bir sınıf daha eklenir. UnitOfWork sınıfının kod kısmı aşağıdaki gibidir.


public class UnitOfWork : IUnitOfWork

{

private ApplicationDbContext dbContext;

public UnitOfWork(ApplicationDbContext dbContext)

{

this.dbContext = dbContext;

}

public ApplicationDbContext DbContext

{

get { return dbContext; }

}

public void Commit()

{

try

{

DbContext.SaveChanges();

}

catch (Exception ex)

{

throw ex;

}

}

}

Builders ve Infrastructure klasörlerini eklediğimiz gibi Repositories isminde bir klasör daha ekleyelim. Repositories klasörüne sağ tıklayıp CategoryRepository isminde bir sınıf ekleyelim. CategoryRepository sınıfının kod kısmı aşağıdaki gibidir.


public class CategoryRepository : RepositoryBase<Category>, ICategoryRepository

{

public CategoryRepository(ApplicationDbContext dbContext)

: base(dbContext) { }

public Category GetCategoryByName(string categoryName)

{

var category = this.DbContext.Categories.Where(c => c.Name == categoryName).FirstOrDefault();

return category;

}

}

public interface ICategoryRepository : IRepository<Category>

{

Category GetCategoryByName(string categoryName);

}

OnionArchitectureSample.Data projesine sağ tıklayıp ApplicationDbContext isminde bir sınıf ekleyelim. ApplicationDbContext sınıfının kodları aşağıdaki gibidir.


public class ApplicationDbContext:DbContext

{

public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)

:base(options)

{

}

public ApplicationDbContext()

{

}

public DbSet<Product> Products { get; set; }

public DbSet<Category> Categories { get; set; }

protected override void OnModelCreating(ModelBuilder builder)

{

base.OnModelCreating(builder);

new ProductBuilder(builder.Entity<Product>());

new CategoryBuilder(builder.Entity<Category>());

}

}

OnionArchitectureSample.Data projesine sağ tıklayıp ApplicationDbContextSeed isminde bir sınıf ekleyelim. ApplicationDbContextSeed sınıfının kodları aşağıdaki gibidir.


public static class ApplicationDbContextSeed

{

public static void Seed(this ApplicationDbContext context)

{

context.Database.Migrate();

if(context.Categories.Any())

{

return;

}

AddCategories(context);

AddProducts(context);

}

private static void AddCategories(ApplicationDbContext context)

{

context.AddRange(

new Category { Name = "Telefon" },

new Category { Name = "Tablet" },

new Category { Name = "Bilgisayar" },

new Category { Name = "Televizyon" }

);

context.SaveChanges();

}

private static void AddProducts(ApplicationDbContext context)

{

context.AddRange(

new Product { Title = "iPhone", Price = 4000, CategoryId = 1 }

);

context.SaveChanges();

}

}

Service Katmanı

Data katmanındaki repository’lerin bir ya da bir kaçını kullanan bussiness logic katmanımız olan service katmanında ProductService ya da CategoryService gibi class’lar tanımlanır. Bu serviceler genellikle kayıt ekleme, güncelleme, arama ve silme işlemleri yapmak için repository’leri kullanır ve değişiklikleri veritabanına aynı transaction ve context ile uygulayabilmek için unit of work’tan yararlanır.

Beraber yapalım…

OnionArchitectureSample.Model i eklediğimiz gibi yeni bir proje daha ekleyip OnionArchitectureSample.Service ismini verelim. OnionArchitectureSample.Service ya sağ tıklayıp yeni bir sınıf ekleyelim ve ismine CategoryService diyelim. CategoryService dosyasının içine aşağıdaki interface ve sınıfı ekleyelim:


public interface ICategoryService

{

Category GetCategory(long id);

IEnumerable<Category> GetCategories();

void CreateCategory(Category category);

void UpdateCategory(Category category);

void DeleteCategory(long id);

void SaveCategory();

}

public class CategoryService :ICategoryService

{

private readonly ICategoryRepository categoryRepository;

private readonly IUnitOfWork unitOfWork;

public CategoryService(ICategoryRepository categoryRepository, IUnitOfWork unitOfWork)

{

this.categoryRepository = categoryRepository;

this.unitOfWork = unitOfWork;

}

#region ICategoryService Members

public IEnumerable<Category> GetCategories()

{

var categories = categoryRepository.GetAll();

return categories;

}

public Category GetCategory(long id)

{

var category = categoryRepository.GetById(id);

return category;

}

public void CreateCategory(Category category)

{

categoryRepository.Add(category);

}

public void UpdateCategory(Category category)

{

categoryRepository.Update(category);

}

public void DeleteCategory(long id)

{

categoryRepository.Delete(pc => pc.Id == id);

}

public void SaveCategory()

{

unitOfWork.Commit();

}

#endregion

}

Presentation Katmanı

MVC projemiz bu katmandadır. Startup sınıfında .NET Core ile birlikte gelen gömülü dependency injection özelliğinden yararlanarak DbContext ve Unit Of Work scoped service olarak eklenir. Repository ve Service’ler ise Transient service olarak eklenir.

AutoMapper pakedi yüklenerek Model->ViewModel ve ViewModel-> Model dönüşümleri konfigüre edilir.

MVC proje oluşturulurken .NET Core’un Empty yerine Web Application template’nin kullanılmasını tavsiye ederim. Böylece MVC dizin yapısı hazır olarak oluşacaktır ve işlemlerimizi daha hızlı tamamlayabiliriz.

Not: Bu makale öğrencim Ömer Örenç’in katkılarıyla hazırlanmıştır.

Creating .NET Core MVC and Angular 4 Single Page Application in Visual Studio 2017 from stratch


Hello everyone. This is my first English article. I will list the steps of creating an Angular 4 project on .NET Core MVC project using Visual Studio 2017 and Angular CLI.

  1. Install Visual Studio 2017 Community Edition on Windows. Use installer to install .NET Core and NodeJS workloads.
  2. Install latest version of NodeJS and NPM
  3. Install Angular CLI using npm
  4. Create a blank solution and add a .NET Core MVC Web Application to it using Visual Studio 2017. My project name is Admin. (do not use . (dot) and special characters in project name.)
  5. Open command prompt, go to solution directory using cd command, type the following command and press enter:
    ng new Admin --routing --skip-git --directory Admin

    Angular CLI adds an angular project to the the MVC project named Admin that we created at the previous step. After creation of the angular project, you can serve this angular project and test it.

  6. Open the .angular-cli.json at the root of the project, change the outDir as “wwwroot”
  7. Open the tsconfig.json and change the outDir as “./wwwroot/out-tsc”
  8. Open the Home/Index.cshtml change the content of it as follows:
@{
    Layout = null;
}
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Admin</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  	<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root>Loading...</app-root>
  <script type="text/javascript" src="~/inline.bundle.js"></script>
  <script type="text/javascript" src="~/polyfills.bundle.js"></script>
  <script type="text/javascript" src="~/styles.bundle.js"></script>
  <script type="text/javascript" src="~/vendor.bundle.js"></script>
  <script type="text/javascript" src="~/main.bundle.js"></script>
</body>
</html>

9. You should exclude node_modules directory from the project in Visual Studio.

10. Open Project Properties and go to tab Build Events write the following command at the textarea:

echo "building angular app" &&^
ng build

Now you can run the application from Visual Studio 2017. The angular app will be built and the you will see the app in browser. But this project does not support production build, so you have to manually build the angular app or restart the project again to see the changes.

The next step is to install and configure webpack to enable production build.

Happy coding.

jQuery DataTables ve ASP.NET MVC Entegrasyonu


ASP.NET MVC uygulamalarında yaygın olarak kullanılan bir grid var: DataTables. Bu grid normal bir tabloyu; arama, sıralama, sayfalama özellikleri bulunan jQuery ve AJAX ile çalışan responsive olabilen dinamik bir gride dönüştürüyor.

Kullanmak için jQuery DataTables’in javascript ve css dosyasını HTML sayfamıza eklemek ve konfigürasyonlarını yapmak gerekiyor.

Şimdi size geçen günlerde hazırladığım http://cvhavuzu.bilisimegitim.com adresinde yayınladığımız DataTables uygulamasını hazırlanışını tarif edeceğim.

Öncelikle sayfamıza jQuery’i eklemiş olmamız gerekiyor. jQuery eklendikten sonra sayfamıza jQuery DataTables plugin’i için aşağıdaki dosyaları ekliyoruz. (İndirip projemize ekleyebilir veya aşağıda olduğu gibi doğrudan CDN’den kullanabiliriz.)

<a href="//cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js">//cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js</a>
<a href="//cdn.datatables.net/responsive/2.1.0/js/dataTables.responsive.min.js">//cdn.datatables.net/responsive/2.1.0/js/dataTables.responsive.min.js</a>

Responsive özellikler eklemek için sondaki dataTables.responsive.min.js dosyasını ekleyebilirsiniz.

Sonra HTML’de tablomuzu oluşturalım. Tablomuzda belirlediğimiz sütun isimleri grid’imizdeki sütun isimleri oluyor:

<table id="myDataTable" class="display">
<thead>
<tr>
<th class="all">No</th>
<th class="all">Ad Soyad</th>
<th class="desktop">Cinsiyet</th>
<th class="desktop">Uzmanlık</th>
<th class="none">Notlar</th>
<th class="desktop">Üniversite</th>
<th class="desktop">Bölüm</th>
<th class="desktop">Doğum Tarihi</th>
<th class="desktop">Lokasyon</th>
<th class="desktop">CV</th>
</tr>
</thead>
</table>

Buradaki th etiketlerindeki css class’ları ile sütunların responsive olması sağlanabiliyor. all class’ı mobil ve desktop ekranların tümünde görünmesi için. desktop class’ı o sütun sadece masaüstü tarayıcılarda açık olarak görünsün, mobilde gizlensin. none ise her zaman gizli olsun demek. Gizli sütunlara soldaki + ikonuna tıklayarak ulaşabiliyoruz. Bu class’lar ile gridimizi her türlü ekrana sığacak şekilde tasarlayabiliyoruz.

Şimdi sırada JavaScript ile DataTables pluginimizi etkinleştirip konfigüre etmek var. DataTables script dosyalarını eklediğimiz satırın aşağısına aşağıdaki satırları yapıştırabilirsiniz:

$(document).ready(function () {
$("#myDataTable").DataTable({
responsive: true,
"aLengthMenu": [[10, 25, 50, 100], [10, 25, 50, 100]],
iDisplayLength: 10,
"oLanguage": {
"sZeroRecords": "Arama kriterinizle eşleşen kayıt yok.",
"sLengthMenu": "Sayfa başına _MENU_ kayıt göster",
"sInfo": "_TOTAL_ kaydın _START_ ile _END_ arası gösteriliyor ",
"sInfoEmpty": "0 kaydın 0 ile 0 arası gösteriliyor",
"sInfoFiltered": "(_MAX_ toplam kayıttan filtrelendi)",
"sSearch": "Ara:",
"oPaginate": {
"sPrevious": "Önceki",
"sNext": "Sonraki",
"sFirst": "İlk",
"sLast": "Son"
},
"sProcessing": "Yükleniyor..."
},
sPaginationType: "full_numbers",
"bServerSide": true,
"sAjaxSource": "/Home/AjaxHandler",
"bProcessing": true,
"aoColumns": [
{ "sName": "CVId"},
{ "sName": "FullName" },
{ "sName": "Gender" },
{ "sName": "ExpertiseName" },
{ "sName": "Notes" },
{ "sName": "University" },
{ "sName": "Department" },
{ "sName": "BirthDate" },
{ "sName": "Location" },
{
"sName": "CVFile",
"bSearchable": false,
"bSortable": false,
"mRender" : function ( data, type, row ) {
return '<a href="/CVler/' + data + '" target="_blank" rel="noopener noreferrer">İndir</a>';

}
}

]
});
});

Bu arada id’isni verdiğimiz HTML tablomuzu belirttiğimiz yapılandırmaya göre DataTables’a dönüştürüyoruz. DataTables’taki metinlerin Türkçe karşılıklarını yazıyoruz. Sütunları ve özelliklerini tanımlıyoruz. sAjaxSource parametresi ile de MVC Controller’da JSON döndüren bir action’ın adresini belirtiyoruz. Bu adresten gridimizin içeriği yüklenecek.

Şimdi grid’imizin verilerini arama, sıralama ve sayfalama işlemlerini yaparak JSON olarak döndüren Home controllerımızdaki AjaxHandler action’ınımızın içeriğini yazalım:

public ActionResult AjaxHandler(jQueryDataTableParamModel param)
{

string sSearch = "";
if (param.sSearch != null) sSearch = param.sSearch;
var allCVs = new CVService().GetAll(sSearch);
IEnumerable filteredCVs = allCVs;

var sortColumnIndex = Convert.ToInt32(Request["iSortCol_0"]);

var sortDirection = Request["sSortDir_0"]; // asc or desc
if (sortDirection == "asc") {
switch (sortColumnIndex)
{
case 0:
filteredCVs = filteredCVs.OrderBy(c => c.CVId);
break;
case 1:
filteredCVs = filteredCVs.OrderBy(c => c.FirstName).ThenBy(c => c.LastName);
break;
case 2:
filteredCVs = filteredCVs.OrderBy(c => c.Gender);
break;
case 3:
filteredCVs = filteredCVs.OrderBy(c => c.Expertise.ExpertiseName);
break;
case 4:
filteredCVs = filteredCVs.OrderBy(c => c.Notes);
break;
case 5:
filteredCVs = filteredCVs.OrderBy(c => (c.University != null) ? c.University.UniversityName : String.Empty);
break;
case 6:
filteredCVs = filteredCVs.OrderBy(c => (c.Department != null) ? c.Department.DepartmentName : String.Empty);
break;
case 7:
filteredCVs = filteredCVs.OrderBy(c => c.BirthDate);
break;
case 8:
filteredCVs = filteredCVs.OrderBy(c => c.Location);
break;
default:
filteredCVs = filteredCVs.OrderBy(c => c.CVId);
break;
}
}
else
{
switch (sortColumnIndex)
{
case 0:
filteredCVs = filteredCVs.OrderByDescending(c => c.CVId);
break;
case 1:
filteredCVs = filteredCVs.OrderByDescending(c => c.FirstName).ThenByDescending(c=>c.LastName);
break;
case 2:
filteredCVs = filteredCVs.OrderByDescending(c => c.Gender);
break;
case 3:
filteredCVs = filteredCVs.OrderByDescending(c => c.Expertise.ExpertiseName);
break;
case 4:
filteredCVs = filteredCVs.OrderByDescending(c => c.Notes);
break;
case 5:
filteredCVs = filteredCVs.OrderByDescending(c => (c.University != null) ? c.University.UniversityName : String.Empty);
break;
case 6:
filteredCVs = filteredCVs.OrderByDescending(c => (c.Department != null) ? c.Department.DepartmentName : String.Empty);
break;
case 7:
filteredCVs = filteredCVs.OrderByDescending(c => c.BirthDate);
break;
case 8:
filteredCVs = filteredCVs.OrderByDescending(c => c.Location);
break;
default:
filteredCVs = filteredCVs.OrderByDescending(c => c.CVId);
break;
}
}

var displayedCVs = filteredCVs.Skip(param.iDisplayStart).Take(param.iDisplayLength);
var result = from c in displayedCVs
select new[] { Convert.ToString(c.CVId), c.FirstName + " " + c.LastName, c.Gender.ToString(), c.Expertise.ExpertiseName, c.Notes ?? string.Empty, (c.University!=null?c.University.UniversityName:string.Empty), (c.Department!=null? c.Department.DepartmentName:string.Empty), (c.BirthDate.HasValue ? c.BirthDate.Value.ToString("YYYY"):String.Empty), c.Location ?? string.Empty, c.CVFile };
return Json(new
{
sEcho = param.sEcho,
iTotalRecords = allCVs.Count(),
iTotalDisplayRecords = filteredCVs.Count(),
aaData = result
},
JsonRequestBehavior.AllowGet);
}
}

CVService’ten kayıtları getirken sSearch te bulunana kelime ya da kelimeleri entity’lerimizin alanlarında Linq Where kullanarak kontrol ediyoruz. Yukarıdaki kodlar sıralama, sayfalama yaptıktan sonra JSON çıktı döndürüyor.

Son olarak jQueryDataTableParamModel yardımcı class’ımızın içeriğini de paylaşalım:

public class jQueryDataTableParamModel
{
///
/// Request sequence number sent by DataTable,
/// same value must be returned in response
/// </code>

public string sEcho { get; set; }

<code></code>

///
/// Text used for filtering
///

public string sSearch { get; set; }

///
/// Number of records that should be shown in table
///

public int iDisplayLength { get; set; }

///
/// First record that should be shown(used for paging)
///

public int iDisplayStart { get; set; }

///
/// Number of columns in table
///

public int iColumns { get; set; }

///
/// Number of columns that are used in sorting
///

public int iSortingCols { get; set; }

///
/// Comma separated list of column names
///

public string sColumns { get; set; }
}

İşte bu kadar. Mutlu kodlamalar!

Eurecert


Türkiye Beyazay Derneği’nin kurumlara Uluslar arası Erişilebilirlik Sertifikası vermeye yönelik bir projesi var, adı Eurecert. Bu projenin yönetim yazılımını ASP.NET MVC ve SQL Server ile geliştirdik. Yazılım şu an kullanımda. Kısa zamanda hazırladığımız yazılım kurumların, kurumlara verilecek sertifika ve eğitim hizmetlerinin yönetimini sağlıyor.

Eurecert projesi hakkında bilgi almak için http://www.eurecert.com.tr/ adresine gidebilirsiniz.

ASP.NET MVC 5 (Veysel Uğur Kızmaz)


Bilge Adam’da Kariyer Koçu olarak işe başladığımda duyduğum heyecan ve işimin hakkını verme gayretiyle vereceğim eğitimlerle ilgili olabilecek kitapları temin etmeye çalıştım. Bunlardan biri olan ve 677 sayfalık KodLab’in ASP.NET MVC 5 kitabını kısa zamanda okuyup tamamladım. Kitapta bazı kod ve yazım hataları bulunuyor, ayrıca Web API konusu yüzeysel anlatılmış; bununla birlikte genellikle yararlı bir kitap diyebilirim. Öğrencilere tavsiye ediyor ve yazara teşekkür ediyoruz.

KaliteAkademi


Yeni tasarım ve teknoloji ile hazırlanan KaliteAkademi.com sitesi 3 Eylül 2013 tarihinde yayınlandı.  Yönetim paneli tamamen Microsoft Dynamics CRM olan site Adxstudio Portals adlı CRM çözümünü kullanıyor. Sitenin içerikleri CRM’den yönetiliyor. Site yayınlandı ama geliştirme çalışmalarımız devam etmekte.

kaliteakademi

DoktorTV


Son haftalar DoktorTV‘nin soru sor modülü ile ilgilendim.  Ancak son kararla DoktorTV’nin outsource olarak bir ekibe verilerek yenilenmesi kararlaştırıldı. DoktorTV ASP.NET ve SQL Server ile geliştirilen bir proje. MVC ve Web Forms’un her ikiside kullanılıyor ve Entity Framework kullanılıyor.

Avrupa Dilleri CRM


İngilizce, Almanca, Rusça, Fransızca, İtalyanca, İspanyolca, Hollandaca, Türkçe gibi dillerin eğitimini veren sektöründeki en eski kuruluşlardan biri olan Avrupa Dilleri’nin eğitim ve öğrenci işlerini yönetmeye yönelik hazırladığımız Avrupa Dilleri CRM yazılım çalışmasının ilk aşamasını bu ay içinde tamamladım. Bu ay içerisinde Avrupa Dilleri Grupfoni’de Online Eğitim kampanyasına çıktı ve kampanya katılım ve öğrenci ve eğitim işleri hazırladığım CRM yazılımıyla gerçekleştirildi. CRM yazılımı üzerinde çalışmalarımız devam etmekte, yeni kampanyalar için hazırlıklarımız sürüyor. CRM yazılımda ASP.NET ve SQL Server teknolojilerini kullandım. Avrupa Dilleriyle başka projelerimiz de olacak.

BeyazNet


Türkiye Beyazay Derneği’nin dernek çalışmalarını yönetebileceği web tabanlı bir yazılım geliştirdik. 32 modülden oluşan bu kapsamlı yazılım 3 aylık bir üretim süresinde genel olarak tamamlandı. Yazılımı ASP.NET ve SQL Server kullanarak hazırladık. Test ve bug düzeltme aşamasında olan bu yazılım için bir arayüz tasarımı hazırlamamız gerekiyor. BeyazNet’de dijital imza entegrasyonu, toplu eposta ve SMS gönderme gibi özellikler de olacak.

Türkiye Beyazay Derneği


Ocak ayı içerisinde yayına verdiğimiz Türkiye Beyazay Derneği’nin resmi sitesi www.beyazay.org.tr tamamlandı. ASP.NET ve SQL Server kullanarak hazırladığımız web sitesinin yönetim panelini kendi geliştirdiğimiz NeofferPress ile hazırladık. NeofferPress ASP.NET’le WordPress’ten esinlenerek hazırladığımız basit bir CMS. İçerikçiler için oldukça kullanımı kolay bir arayüze sahip olmasına rağmen NeofferPress’le site geliştirmek halen bir yazılımcı gerektiriyor. Türkiye Beyazay Derneği yeni açılan Şanlıurfa şubesiyle 48 şubeye sahip olan engellilere yönelik projeler geliştiren bir dernek olup yenilenen sitesiyle çalışmalarını daha etkili bir şekilde duyurmayı hedefliyor. Ayrıca sitede Google Analytics’le ziyaretçi analizi yapılmakta.