WebApi & AngularJS Game Shop

Selamlar;

Bugün online bir oyun mağzası için ürünlerin çekildiği webapi ile asenkron restful bir servis yazıcaz. Daha sonra angularJs javascript framework’ü kullanılan bir mvc ara yüzünde  bu ürünleri listeleyip, filitreleyip satın alıcaz.

Amaç angularJs’in restful servisler ile çalışma mantığını görmek ayrıca önceden bahsetmediğim diger özeliklerine derinlemesine incelemektir. Dilerseniz örneğimize geçelim.

Öncelikle database’den başlıyalım. DAL adı ile yeni bir CodeFirst projesi yaratılır. İlgili data modeller aşağıdadır. Görüldüğü gibi oyun kategorisi ve oyun tabloları vardır. Bir de games adında bir DbContext bulunmaktadır. Tüm database işlemleri bu dll üzerinden yapılmaktadır.

Şimdi de WebApi, cross domain restfull servisimizi WebApiAngular adında yeni bir projede yaratalım. Cross domain için NuGet’in Library Package Manager dan Package Manager Console’a :

Capture

yazılır.

download

Tabi henüz işimiz bitmedi. Projemizdeki /App_Start/WebApi.config içine aşağıdaki kod satırı eklenmesi gerekmektedir.

config.EnableCors();

Ayrıca GamesController class’ının  başına ya da kullanılacak tüm methodların başına tek tek aşağıda görülen attribute’un eklenmesi gerekir.

WebApi servisimizde kullanılan methodlar aşağıda görüldüğü gibidir:

  1. GetAllGames adında asenkron bir method vardır. Default olarak kategory’si 1 olan yani xbox360 kategorisine ait oyunlar çekilip listelenmektedir. Ayrıca yüklemenin seneryo gereği uzun sürmesi için 3sn lik bekleme yapılmıştır. Amaç datalar çekilirken loader.gif’in kullanıcıya gösterilmesi, yükleme bittikten sonrada saklanmasıdır.
  2. GetAllGames (int categoryID) adında ikinci bir method vardır. Amaç istenen kategorideki oyunların listesini gene asenkron olarak vermektir.
  3. BuyGames(int ID) adında  üçüncü bir method  daha vardır. Bu method sadece post durumunda çağrılabilmektedir. Burada amaç ID si gönderilen oyun sepete eklenmektedir. Dikkat ederseniz WebApi’da session mantığı pek yoktur. Yazmayı denerseniz herbir request’de yeni bir session açıldığını görebilirsiniz. Yani her request’de yeni bir sessionID oluşmaktadır. Bu nedenle önceden var olan user’a erişilememektedir. Buna çözüm olarak oyunların ID si ve adedi bir hastable’da tutulmuş ve bu hastable da global olarak applicationda saklanmıştır. Sepete yeni bir ürün eklendiğinde adet 1 olarak atanmıştır. Eğer zaten ürün var ise değeri 1 artırılmaktadır. Methodun sonunda ilgili ID’li oyunun adı çekilmekte ve sepetteki en son adedi oyun adı ile birlikte asenkron olarak string şeklinde gönderilmektedir.

Buy

Burada ufak bir terslik vardır. Herbir User için ayrıştırmaya gidilmemiştir. Yani iki farklı user aynı oyunu alırsa adet 2 gözükecektir. Yorumlar kısmına user bazında nasıl ayrıştırma yapabileceğimizi ve konu ile ilgili fikirlerinizi bekliyorum.

basket

WebApiAngular:

WebApi’dan gönderilen GamesModel aşağıdaki gibidir:

Ayrıca WebApi’dan sonuçları xml veya json olarak alabilmek için Global.asax’a alttaki kodları eklemek gerekir.

Şimdi de oyunların gösterildiği ara yüzü tasarlayalım:

AngularView adında yeni bir mvc projesi yaratıyoruz. Index.cshtml kodları aşağıda  görüldüğü gibidir.

  • Öncelikle siteye jquery ve angular.min.js scriptleri eklenir.
  • Ürünlerin listeleneceği ProductController yaratılır. ProductController’da $scope.loading property’si başta true atanır. Daha sonra data çekilince false atanır. Amaç aşağıda görüldüğü gibi view’da loader gif’i yükleme zamanında ng-show‘a bağlı olarak property’e true atanarak göstermek, yükleme bitince property’e false atanarak gizelemektir.

loader

<strong ng-show=”loading”><img ng-src=”/Content/ajax-loader.gif” /></strong>

  • Dropdown’ın dolacağı datalar categoryTypes property’si ile atanmaktadır. İlk başta default olarak xbox360 oyunlarının webapi servisinden $http.get ile çekilir ve products property’si doldurulur. Ayrıca dropdown değiştiği zaman ng-change=”getCategory()” şeklinde bir function tetiklenir. $scope.getCategory ile ilgili function ProductController’da tanımlanmakta categoryID’ye göre servisden çekilen oyun datası  $scope.products property’sine atanmaktadır.

drop

$scope.buyGame function’ı da ilgili oyunu sepete eklemek için webapi servisine ilgili oyun ID’yi post etmektedir. İlgili kayıt daha önceden eklenmiş ise adet 1 arttırılır yok ise yeni kayıt oluşturulup 1 değeri atanır.

View

  • View kısmında ng-app=”MyApp” ve ng-controller=”ProductController” olan bir div tanımlanır. İçine categoryTypes’dan dönen datalar ile oyun kategorilerinin belirlendiği dropdown list ng-repeat=”p in categoryTypes”  ile doldurulur.

  • Datalar çekilirken hata olması durumunda $scope.error propert’sine hatalar yazdırılır. Aşağıda görüldüğü gibi bu hatalar dropdownlist altında gösterilir. Ayrıca gene bunun altında yüklenme sırasındaki loader.gif gösterilir.

  • Oyun ismine göre filitreleme yapılabilecek  text aşağıda görüldüğü gibi  ng-model=”Name” ile ilgili kolona bağlanır.

  • Oyunların konucağı tablonun kolonları aşağıda görüldüğü gibi products property’sine göre tekrarlanır. Price’a göre azdan çoğa göre sıralanır. Ve Name’e göre filitrelenir.

<td ng-repeat=”product in products | orderBy:’Price’ | filter:Name “>

  • Kolonun içine ürünün Adı aşağıda görüldüğü gibi custom filter ile yazdırılır. Burada oyun isminin önüne ID’si de yazdırılmaktadır.<div><b>{{ product.Name | displayName : product.ID}}</b></div>

  • Oyunun resmi ng-src ile konur.  <img ng-src=”/Content/GamesImage/{{ product.ImageUrl }}” />
  • Oyunun fiyatı currency filter ile yazdırılır. {{ product.Price | currency :”€”}}
  • En sona da custom controller olarak adlandırabileceğimiz satın alma buttonu aşağıda görüldüğü gibi directive ile yaratılır. <btn-buy> </btn-buy> Directive’in önce ismi belirlenir.”btnBuy”. Daha sonra restrict :”E” ile element olarak tanımlanır. Bir başka yolda restirict:”A” olarak tanımlamaktır. Bu durumda directive nesneye attribute olarak konur. template ile konucağı yerdeki html çıktı belirlenir. Mesela burada bir div’in içine Buy textinde button konmuştur. Click event’inde buyGame() function’ı çağrılır ve id’si ‘Engin text’inin sonuna herbir kayıt için otomatik artan {{$index}} parametresi konmuştur.Örnek Engin1,Engin2 gibi. Ayrıca istenirse template yerine templateUrl kullanılarak belirtilen html çıktı başka bir html dosyasına konarak yolu belirlenebilir.Örnek : templateUrl: ‘my-customer.html’

Index.cshtml :

Yukarıdaki örnekten de anlaşılacağı gibi angularJs ile restful bir servisi konuşturulmuştur. İlgili datalar çeşitli parametrelere göre çekilmiş ve post işlemi yapılmıştır. Directive ile satın alma butonu olan custom bir kontrol yazılmıştır. Böylece tekrarlayan tüm oyunlarda aynı kodu tekrar tekrar yazmaktan ve kod kalabalığından kurtulunmuştur. Custom filter ile oyun isimleri id’si başına gelecek şekilde yazılmıştır. Böylece özel yazılan filterlar ile data gösteriminde isteğe bağlı bir çok customize yapılabileceği görülmüştür.  Koşula göre nesneleri göstermi ve gizlenmesine en güzel örnek olarak yükleme gifi verilmiştir. Bu çok daha farklı şekillerde kullanılabilir. Örneğin fiyatı 60€ dan fazla olan ürünlerin gösterilmemesi gibi düşünülebilir. Nesnelerde olan değişikliklere göre çeşitli functionların tetiklemesine örnek dropdownlist’in değişmesi durumunda ilgili kategorideki oyunların webapi servisi ile getirilmesi sağlanmıştır. Ayrıca webapi servislerinde asenkron kullanım ve dataların remde saklanması gibi konular üzerinde durulmuştur.

Geldik bir makalenin daha sonuna.

Yeni bir makalede görüşmek üzere.Hoşçakalın.

Source Code: http://www.borakasmer.com/projects/WebApiAngular.rar

Örnek WebApi Url (İptal): http://webapigames.azurewebsites.net/api/games?xml=true

Örnek GamesShop Url (İptal): http://gamesshops.azurewebsites.net/

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.