ASP.NET Component-based Scalable Logical Architecture (CSLA)

Örnek projeyi github üzerinden indirmek veya görüntülemek için https://github.com/ayzdru/AspNetCSLAExamples adresine gidebilirsiniz.

Component-based Scalable Logical Architecture (CSLA) Nedir?

Rockford Lhotka tarafından yazılmış CSLA, yeniden kullanılabilir, bakımı yapılabilir, nesne yönelimli business katmanları oluşturmamızı sağlayan yazılım geliştirme yapısıdır.

CSLA Özellikleri

Smart data

Bir business object, temsil ettiği nesneyle ilişkili tüm verileri ve davranışı (business logic ve rules) encapsulate eder. Örneğin, bir SiparisDuzenle nesnesi, kullanıcının sipariş bilgilerini doğru bir şekilde düzenlemesine izin vermesi için gerekli verileri ve iş kuralı uygulamalarını içerecektir.

Rules engine

CSLA .NET framework, validation rules, business rules ve authorization kurallarını destekleyen bir rule engine sağlar. Bu kurallar nesne örneklerine veya özelliklerine eklenir ve gerektiğinde CSLA .NET tarafından otomatik olarak çağrılır. Validation rules, CSLA .NET rule engine kullanılarak veya Microsoft .NET'in DataAnnotations özelliği kullanılarak uygulanabilir. 

Object persistence

Veri oluşturma, alma, güncelleme ve silme (CRUD), veri testiyle ilişkili iş nesnesinin açıkça tanımlanmış yöntemleriyle gerçekleştirilir. Veri erişimi, repository pattern veya object-oriented programming teknikleri kullanılarak, business mantığından açık bir şekilde ayrılır.

Metastate maintenance

CSLA .NET her bir business object için metastate'i yönetir. Örneğin, her bir business nesnesinin ne zaman yeni olduğu (henüz kaydedilmemiş olduğunu) ve ne zaman değiştirildiğini bilgilerini yönetir.

n-Level undo

Yapılan değişiklikleri geri almamızı sağlar. Bu bir uygulamada birden çok kez geri alma işlemleri yaptığımız yerlerde, çok yararlı olabilir.

Business rule tracking

Örneğin, bir Account objesinin PhoneNumber property alanı varsa ve bu alana alfabetik karakterlerle bir telefon numarası atanmışsa, Account nesnesinin IsValid özelliği false olacak (veritabanına kaydetmeyi imkansız hale getirecek) ve ardından yeni bir BrokenRule objesi olacaktır. Account'un Broker Rules listesine eklenecektir. Geçersiz telefon numarası düzeltildiğinde, bu kural ortadan kalkar ve Account objesi kendisini veritabanına kaydedebilir.

Ek Özellikler

CSLA .NET ek olarak;

Basit kullanıcı arayüzü oluşturma, Dağıtılmış veri erişimine, Web Services desteği özelliklerine sahiptir.

 

CSLA, 1997 yılından bugüne geliştirilmeye devam etmektedir.

 

CSLA, Windows Forms, ASP.NET, WPF, UWP, iOS, Android ve MacOS platformlarını destekler.

Kodlamaya Başlamadan Önce

Örnek projeyi github üzerinden indirmek veya görüntülemek için https://github.com/ayzdru/AspNetCSLAExamples adresine gidebilirsiniz.

AspNetCSLAExamples.Core adlı .Net Standart projesi ve AspNetCSLAExamples.Infrastructure .Net projesini ortak kullanacağımız için bu katmanların ne işe yaradığını açıklayacağım.

AspNetCSLAExamples.Core katmanına Entities, Interfaces nesnelerini ekledik.

AspNetCSLAExamples.Infrastructure katmanına DbContext, Repositories ve altyapı için gereken nuget paketlerini yükledik.

AspNetCSLAExamples.Business katmanına CSLA .Net için gereken business nesnelerini ekledik.

Örnek PersonList.cs business nesnesi:

[Serializable]
  public class PersonList : ReadOnlyListBase<PersonList, PersonInfo>
  {
    [Create, RunLocal]
    private void Create() { }

    [Fetch]
    private void Fetch([Inject]IPersonRepository dal)
    {
      IsReadOnly = false;
      var data = dal.Get().Select(d => DataPortal.FetchChild<PersonInfo>(d));
      AddRange(data);
      IsReadOnly = true;
    }
  }

 

CSLA .NET ve Blazor Web Assembly

AspNetCSLAExamples.Blazor.Client SPA projemize Person tablosuna CRUD işlemleri için .razor sayfalarını (EditPerson.razor, ListPersons.razor, TextInput.razor) oluşturduk. Daha sonra

AspNetCSLAExamples.Blazor.Client > Program.cs dosyasını düzenliyoruz.

public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("app");

            builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
            builder.UseCsla((c) =>
                c.DataPortal().DefaultProxy(
                    typeof(Csla.DataPortalClient.HttpProxy), "/api/DataPortal"));
            await builder.Build().RunAsync();
        }
    }

AspNetCSLAExamples.Blazor.Server > Startup.cs dosyasını düzenliyoruz.

 public class Startup
    {
        private const string BlazorClientPolicy = "AllowAllOrigins";
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy(BlazorClientPolicy,
                    builder =>
                    {
                        builder
                            .AllowAnyOrigin()
                            .AllowAnyHeader()
                            .AllowAnyMethod();
                    });
            });
            services.AddMvc(
                    (o) => o.EnableEndpointRouting = false)
                .AddNewtonsoftJson();
            services.AddResponseCompression(opts =>
            {
                opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
                    new[] { "application/octet-stream" });
            });
            services.AddMvc((o) => o.EnableEndpointRouting = false);

            services.Configure<KestrelServerOptions>(options =>
            {
                options.AllowSynchronousIO = true;
            });

            services.Configure<IISServerOptions>(options =>
            {
                options.AllowSynchronousIO = true;
            });
            services.AddHttpContextAccessor();
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));
            services.AddControllersWithViews();
            services.AddRazorPages();
            services.AddTransient(typeof(IPersonRepository), typeof(PersonRepository));
            services.AddCsla();
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseResponseCompression();
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseWebAssemblyDebugging();
            }
            else
            {
                app.UseExceptionHandler("/Error");
            }

            app.UseBlazorFrameworkFiles();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
                endpoints.MapControllers();
                endpoints.MapFallbackToFile("index.html");
            });
            app.UseCsla();
        }
    }

AspNetCSLAExamples.Blazor.Server > DataPortalController.cs dosyasını oluşturduk.

[Route("api/[controller]")]
  [ApiController]
  public class DataPortalController : Csla.Server.Hosts.HttpPortalController
  {
    public DataPortalController()
    {
      UseTextSerialization = true;
    }

    [HttpGet]
    public string Get()
    {
      return "Running";
    }

    public override Task PostAsync([FromQuery] string operation)
    {
      return base.PostAsync(operation);
    }
  }

CSLA .NET ve Razor Pages

 AspNetCSLAExamples.RazorPages Web projemize Person tablosuna CRUD işlemleri için .cshtml sayfalarını (Delete.cshtml, Edit.cshtml, Index.cshtml) oluşturduk. Daha sonra

Startup.cs dosyasını düzenliyoruz.

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));
            services.AddRazorPages();
            services.AddHttpContextAccessor();
            services.AddCsla();
            services.AddTransient(typeof(IPersonRepository), typeof(PersonRepository));
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
            }

            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
            });
            app.UseCsla();
            Configuration.ConfigureCsla();
        }
    }

CSLA .NET ve MVC

 AspNetCSLAExamples.Mvc Web projemizde Ekleme, Çıkarma, Silme, Güncelleme, Detay Gösterme için Viewslerimizi (Create, Delete, Details, Edit) oluşturduk. Daha sonra

PersonController.cs dosyasını oluşturuyoruz.

public class PersonController : Csla.Web.Mvc.Controller
  {
    // GET: Person
    public async Task<ActionResult> Index()
    {
      var list = await DataPortal.FetchAsync<PersonList>();
      return View(list);
    }

    // GET: Person/Details/5
    public async Task<ActionResult> Details(int id)
    {
      var obj = await DataPortal.FetchAsync<PersonInfo>(id);
      return View(obj);
    }

    // GET: Person/Create
    public async Task<ActionResult> Create()
    {
      var obj = await DataPortal.CreateAsync<PersonEdit>();
      return View(obj);
    }

    // POST: Person/Create
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Create(PersonEdit person)
    {
      try
      {
        if (await SaveObjectAsync<PersonEdit>(person, false))
          return RedirectToAction(nameof(Index));
        else
          return View(person);
      }
      catch
      {
        return View(person);
      }
    }

    // GET: Person/Edit/5
    public async Task<ActionResult> Edit(int id)
    {
      var obj = await DataPortal.FetchAsync<PersonEdit>(id);
      return View(obj);
    }

    // POST: Person/Edit/5
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Edit(int id, PersonEdit person)
    {
      try
      {
        LoadProperty(person, PersonEdit.IdProperty, id);
        if (await SaveObjectAsync<PersonEdit>(person, true))
          return RedirectToAction(nameof(Index));
        else
          return View(person);
      }
      catch
      {
        return View(person);
      }
    }

    // GET: Person/Delete/5
    public async Task<ActionResult> Delete(int id)
    {
      var obj = await DataPortal.FetchAsync<PersonInfo>(id);
      return View(obj);
    }

    // POST: Person/Delete/5
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Delete(int id, PersonInfo person)
    {
      try
      {
        await DataPortal.DeleteAsync<PersonEdit>(id);
        return RedirectToAction(nameof(Index));
      }
      catch
      {
        return View(person);
      }
    }
  }

Startup.cs dosyasını düzenliyoruz.

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));
            services.AddControllersWithViews((c) =>
                c.ModelBinderProviders.Insert(0, new Csla.Web.Mvc.CslaModelBinderProvider()));

            services.AddHttpContextAccessor();

            services.AddCsla();
            services.AddTransient(typeof(IPersonRepository), typeof(PersonRepository));
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseStaticFiles();

            app.UseRouting();

            app.UseAuthorization();

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

Daha detaylı incelemek için, projeyi github üzerinden indirip, kendi lokalinizde çalıştırabilir, düzenleyebilirsiniz.

Mutlu kodlamalar

༼ つ ◕_◕ ༽つ

Yorumlar kapalı