Birlikte Geliştirdik

corba_739Merhaba Arkadaşlar,

Eğer benim gibi yaz kış kolayca grip oluyorsanız eminim ki bol limonlu çorbalara aşinasınızdır. Hele ki şanslıysanız ve eşinizin ya da annenizin yanındaysanız şöyle evde var olan tüm sebzelerden oluşan karma bir sebze çorbası süper rahatlatıcı olacaktır. E bazen .Net Framework tarafında da eldeki materyalleri bir araya getirip güzel bir çorba yapmak gerekir Göz kırpan gülümseme Güzel bir çorba hazırlamaya ne dersiniz?

Hazırlayacağımız çorbamızda çok kıymetli yardımcılarımız da var. Son katılımcılarımız ile gerçekleştirmekte olduğumuz Asp.Net eğitiminden çok güzel fikirler ve örnekler çıkmaya devam ediyor. Geliştireceğimiz örnek Solution içerisinde Entity Framework, WCF Service, LINQ, Asp.Net Web Application, Web User Control, LINQ gibi pek çok kavram yer almakta. Temel olarak başlangıçtaki senaryomuz ise şu : “Asp.Net web uygulamamızda yer alan bir Web User Control’ ümüz, AdventureWorks veritabanında yer alan herhangibir Product' satırına ait bazı alan bilgilerini gösterecek”

Pekala bu iş için hemen bir Web User Control geliştirebilir ve Load metodunda ilgili veri çekme işlemlerini gerçekleştirerek basitçe sonuca gitmeyi düşünebilirsiniz. Ama biz bu şekilde button arkası programlama yapmamayı tercih ediyoruz Gülümseme Bunun yerine aşağıdaki grafikte yer alan Solution içeriğini üreterek ilerleyeceğiz. (Dilerseniz yazının son satırından Solution’ ı indirip inceleyin)

bei_10

Gülümseme İlk olarak AdventureWorks veritabanındaki bazı tabloları içerecek olan Entity Model’ imizi tasarlayarak işe başlayalım. Söz konusu Class Library projesi içerisinde kullanacağımız Entity Model diagramının içeriğini ise başlangıçta aşağıdaki gibi oluşturabiliriz.

bei_11

Şimdilik Product ve ProductSubCategory tablolarının karşılığı olan Entity içeriklerinin yer aldığı bir diagram ile karşı karşıyayız. Diğer yandan Web User Control’ ümüzü geliştirene kadar kat etmemiz gereken daha çok yolumuz olacak. Öncelikle bir Product içeriğini dış ortama verecek olan iş fonksiyonelliklerini içeren bir katman daha yazacağız. Söz konusu katman tahmin edeceğiniz üzere bir Class Library olacak. Bu katmanda ekstradan bir Business Object daha kullanıyor olacağız. Çünkü Product tipinin tüm içeriğini dış ortama sunmak gibi bir niyetimiz olmadığını düşünmekteyiz. Bu sebepten Product tipi yerine geçecek olan bir Surrogate Type kullanımını ele alacağız. Dolayısıyla Company.Operations isimli Class Library içeriğini aşağıdaki sınıf çizelgesinde olduğu gibi tasarlayarak devam ediyoruz.

bei_12

Burada görülen ProductBusinessObject aslında dış ortama sunulacak olan Product içeriğini taşıyan bir POCO nesnesidir. Aslında bu tip Business Object türlerini başka bir katman içerisinde tutmayı da düşünebiliriz Göz kırpan gülümseme 

namespace Company.Operations 
{ 
    public class ProductBusinessObject 
    { 
        public int ProductId { get; set; } 
        public string Name { get; set; } 
        public decimal ListPrice { get; set; } 
        public string SubCategoryName { get; set; } 
        public string Color { get; set; } 
    } 
}

ProductionOperations isim sınıfımız ise şu an için tek bir operasyon sunmaktadır ve ProductId değerine göre ProductBusinessObject tipinden bir referans döndürmek üzere tasarlanmıştır.

using System.Linq; 
using AdventureWorksEntity;

namespace Company.Operations 
{ 
    public class ProductionOperations 
    { 
        public ProductBusinessObject GetProduct(int ProductId) 
        { 
            ProductBusinessObject result = null;

            using (AdventureWorksEntities context = new AdventureWorksEntities()) 
            { 
                result = (from p in context.Products 
                               where p.ProductID == ProductId 
                               select new ProductBusinessObject 
                               { 
                                    ProductId=p.ProductID, 
                                     Name=p.Name, 
                                      ListPrice=p.ListPrice, 
                                       Color=p.Color, 
                                        SubCategoryName=p.ProductSubcategory.Name 
                               }).FirstOrDefault<ProductBusinessObject>(); 
            }

            return result; 
        } 
    } 
}

Örneğimizi EF 4.0 versiyonu ile geliştirdiğimiz için bir Lazy Loading durumunun da söz konusu olduğunu ifade edelim. SubCategoryName özelliğine değer atanan satıra dikkat edin Göz kırpan gülümseme

Artık söz konusu iş operasyonunu dış dünyaya sunacak bir uygulamayı da geliştirebiliriz. Bu uygulama favorimiz olan WCF tabanlı bir servis olarak düşünülmektedir. Böylece Entity modelimiz, Business Object’ lerimiz ve Business Operasyonlarımızın tamamı söz konusu servis uygulamasının arkasında kalacaktır. Yani asıl End User’ lar bu işlevselliklere erişebilmek için servis katmanı üzerinden geçmek zorunda kalacaklardır. WCF Service uygulamamızın içeriği aşağıdaki diagramda görüldüğü gibidir.

bei_13

IProductionService isimli servis sözleşmemiz(Service Contract) şu şekildedir;

using System.ServiceModel; 
using Company.Operations;

namespace AdventureWorksService 
{ 
    [ServiceContract] 
    public interface IProductionService 
    { 
        [OperationContract] 
        ProductBusinessObject GetProduct(int ProductId); 
    } 
}

Sözleşmemiz senaryomuza göre bir ürünün elde edilmesi ve ProductBusinessObject tipinden geriye döndürülmesi işlemini üstlenen basit bir operasyon sunmaktadır. Bu operasyonun uyarlaması ise ProductionService sınıfı içerisinde gerçekleştirilmektedir.

using Company.Operations;

namespace AdventureWorksService 
{ 
    public class ProductionService 
        : IProductionService 
    { 
        ProductionOperations productionOperator = new ProductionOperations();

        public ProductBusinessObject GetProduct(int ProductId) 
        { 
            return productionOperator.GetProduct(ProductId); 
        } 
    } 
}

Servis uygulamamızda dikkat edilmesi gereken noktalardan birisi de, AdventureWorks entity modelini kullanabilmesi için gerekli Connection String bilgisine sahip olma zorunluluğudur. Bildiğiniz üzere Entity Modelimizi bir Class Library içerisinde tutumaktayız ve çalışma zamanında ilgili mapping işlemlerini üstlenecek olan yürütücü uygulamanın söz konusu mapping için bir bağlantı bilgisine sahip olması gerekiyor. Dolayısıyla AdventureWorksEntity kütüphanesinde otomatik olarak üretilen connection string bilgisinin servis uygulamasındaki web.config dosyasında yer alması şart.

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
  <connectionStrings> 
    <add name="AdventureWorksEntities" connectionString="metadata=res://*/AdventureModel.csdl|res: 
//*/AdventureModel.ssdl|res://*/AdventureModel.msl; 
provider=System.Data.SqlClient;provider connection string="Data Source=.;Initial Catalog=AdventureWorks;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" /> 
  </connectionStrings> 
    <system.serviceModel> 
        <behaviors> 
            <serviceBehaviors> 
                <behavior name=""> 
                    <serviceMetadata httpGetEnabled="true" /> 
                    <serviceDebug includeExceptionDetailInFaults="false" /> 
                </behavior> 
            </serviceBehaviors> 
        </behaviors> 
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" /> 
    </system.serviceModel> 
</configuration>

Çorbamıza yeni baharatlar katarak devam edelim Göz kırpan gülümseme

Artık servis uygulamamız da hazır olduğuna göre bunu kullanacak olan Asp.Net Web Uygulamasını geliştirerek yol alabiliriz. Tahmin edileceği üzere Asp.Net Web uygulamamız, AdventureWorksService isimli WCF Servisini referans etmelidir.

bei_17

Yazımızın başında belirttiğimiz senaryomuzdan hatırlayacağınız üzere bir Web User Control’ den bahsediyorduk. Bu Web User Control’ ün Business Object’ imize göre tasarlanması gerekiyor. Bu amaçla aşağıdaki gibi bir tasarım gerçekleştirebiliriz.

bei_14

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ProductControl.ascx.cs" Inherits="CompanyPortal.ProductControl" %> 
<style type="text/css"> 
    .style1 
    { 
        width: 400px; 
        font-family: "Courier New", Courier, monospace; 
    } 
    .style2 
    { 
        width: 176px; 
    } 
    .style3 
    { 
        width: 176px; 
        font-weight: bold; 
    } 
</style>

<table border="1" cellpadding="5" cellspacing="1" class="style1"> 
    <tr> 
        <td class="style2"> 
             </td> 
        <td style="text-align: right"> 
            <asp:Label ID="ProductIdLabel" runat="server"></asp:Label> 
        </td> 
    </tr> 
    <tr> 
        <td class="style3"> 
            Name</td> 
        <td> 
            <asp:Label ID="ProductNameLabel" runat="server"></asp:Label> 
        </td> 
    </tr> 
    <tr> 
        <td class="style3"> 
            List Price</td> 
        <td> 
            <asp:Label ID="ProductListPriceLabel" runat="server"></asp:Label> 
        </td> 
    </tr> 
    <tr> 
        <td class="style3"> 
            Color</td> 
        <td> 
            <asp:Label ID="ProductColorLabel" runat="server"></asp:Label> 
        </td> 
    </tr> 
    <tr> 
        <td class="style3"> 
            Sub Category Name</td> 
        <td> 
            <asp:Label ID="ProductSubCategoryNameLabel" runat="server"></asp:Label> 
        </td> 
    </tr> 
</table>

Kod tarafında ise aşağıdaki işlemleri gerçekleştirebiliriz.

using System; 
using CompanyPortal.Production;

namespace CompanyPortal 
{ 
    public partial class ProductControl 
        : System.Web.UI.UserControl 
    { 
        ProductionServiceClient proxy = new ProductionServiceClient(); 
        int productId;

        public int ProductId 
        { 
            get { return productId; } 
            set { productId = value; } 
        } 
        public string ProductName 
        { 
            get { return ProductNameLabel.Text; } 
        } 
        public decimal ProductListPrice 
        { 
            get { return Decimal.Parse(ProductListPriceLabel.Text); } 
        } 
        public string ProductColor 
        { 
            get { return ProductColorLabel.Text; } 
        } 
        public string ProductSubCategoryName 
        { 
            get { return ProductSubCategoryNameLabel.Text; } 
        }

        public void LoadContent() 
        { 
            ProductBusinessObject bO = proxy.GetProduct(ProductId); 
            if (bO != null) 
            { 
                ProductIdLabel.Text = bO.ProductId.ToString(); 
                ProductNameLabel.Text = bO.Name; 
                ProductListPriceLabel.Text = bO.ListPrice.ToString(); 
                ProductColorLabel.Text = bO.Color; 
                ProductSubCategoryNameLabel.Text = bO.SubCategoryName; 
            } 
        }     
    } 
}

Dikkat edileceği üzere Web User Control herhangibir ürün numarasına bağlı bir ProductBusinessObject içeriğini dış ortama özellikler(Properties) yardımıyla da sunmaktadır. Ayrıca içerisinde yer alan Label kontrollerinin çalışma zamanında yüklenmesi için LoadContent isimli bir metoddan yararlanılmaktadır.

Artık Web User Control bileşenimizi örnek bir aspx sayfasında kullanmaya çalışarak ilk testimizi gerçekleştirebiliriz. Bunun için aşağıdaki tasarıma ve kod içeriğine sahip bir sayfa eklediğimizi düşünelim.

bei_15

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CompanyPortal.Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"> 
<head runat="server"> 
    <title></title> 
</head> 
<body> 
    <form id="form1" runat="server"> 
    <div> 
    
        Ürün Numarasını Girin : 
        <asp:TextBox ID="ProductIdTextBox" runat="server"></asp:TextBox> 
        <br /> 
        <br /> 
        <asp:Button ID="GetProductButton" runat="server" 
            onclick="GetProductButton_Click" Text="Get Product" /> 
        <br /> 
        <br /> 
        <asp:PlaceHolder ID="ProductPlaceHolder" runat="server"></asp:PlaceHolder> 
    
    </div> 
    </form> 
</body> 
</html>

ve kod içeriği;

using System;

namespace CompanyPortal 
{ 
    public partial class Default : System.Web.UI.Page 
    { 
        protected void GetProductButton_Click(object sender, EventArgs e) 
        { 
            int productId; 
            if (Int32.TryParse(ProductIdTextBox.Text, out productId)) 
            { 
                ProductControl prdControl = LoadControl("ProductControl.ascx") as ProductControl; 
                if (prdControl != null) 
                { 
                    prdControl.ProductId = productId; 
                    prdControl.LoadContent(); 
                    ProductPlaceHolder.Controls.Add(prdControl); 
                } 
            } 
        } 
    } 
}

Sayfamızda sembolik olarak TextBox kontrolüne girilen sayısal değere göre Product bilgisinin çekilmesi ve bulunan ürüne ait bazı bilgilerin dinamik olarak yüklenen Web User Control içerisinde gösterilmesi sağlanmaktadır. Söz gelimi çalışma zamanında 774 numaralı ürüne ait bilgileri çekmek istersek aşağıdaki ekran görüntüsünde yer alan sonucu elde ederiz Açık ağızlı gülümseme

bei_16

Eğer örneği buraya kadar başarılı bir şekilde getirdiyseniz şöyle bir arkanıza yaslanın ve neler yaptığımızı bir düşünün Göz kırpan gülümseme

Son olarak Solution içerisinde yer alan Assembly’ lar arasındaki ilişkiyi göstererek yazımızı yavaş yavaş sonlandıralım.

bei_9

Örneği geliştirmek, farklı testler uygulayarak olası hataları düzeltmek, kodu tekrardan gözden geçirip iyileştirmek de sizin göreviniz olsun. Söz gelimi bir alt kategoriye bağlı ürünleri ProductBusinessObject tipinden çekip her biri için dinamik olarak ProductControl bileşeni üreten ve web sayfasına ekleyen bir senaryoyu çözümümüze ilave edebilirsiniz. Hatta alt kategori bilgilerinin Web uygulaması arayüzüne dahil edilmesi için gerekli geliştirmeleri de yapabilirsiniz. Eğer buraya kadar yaptıklarımızla kafanız çok karıştıysa aşağıdaki parçayı dinleyip kendinize gelmeyi de deneyebilirsiniz Gülümseme

Tekrardan görüşünceye dek hepinize mutlu günler dilerim.

Company.rar (153,21 kb)

Yorum ekle

Loading