12/08/2018, 13:29

Làm quen với Web API 2 trong .Net

1. Web Api là gì Asp.net Web Api là một framework giúp cho việc xây dựng HTTP service một cách dễ dàng. Chúng có thể phát triển cho nhiều clients khác nhau như trình duyệt, mobile app. Web api là một nền tảng để phát triển các ứng dụng dựa trên Restfull service trong .Net. Các bạn có thể hình ...

1. Web Api là gì

Asp.net Web Api là một framework giúp cho việc xây dựng HTTP service một cách dễ dàng. Chúng có thể phát triển cho nhiều clients khác nhau như trình duyệt, mobile app. Web api là một nền tảng để phát triển các ứng dụng dựa trên Restfull service trong .Net. Các bạn có thể hình dung vị trí của Asp.net Api trong .Net như hình bên dưới:

h68-0.png

Để tìm hiểu sâu hơn về Asp.net Web API các bạn có thể tìm hiểu thêm tại link http://www.asp.net/web-api

2. Ứng dụng demo

Công nghệ sử dụng:

  • Visual studio 2013
  • .Net 4.6
  • Web Api 2.0
  • Entity framework 6.0
  • Knockout js

2.1. Tạo project

  • Mở Visual studio
  • Chọn New project
  • Tại cửa sổ dialog chọn Asp.net web applicaltion
  • Tiếp đến chọn Web API như hình bên dưới

CreateProject.jpg

2.2. Tạo data models

Trong ứng dựng demo này tôi sẽ tạo 2 model category và product. Để tạo một model mới, chúng ta click chuột phải tại thư mục Models chọn "New" sau đó chọn "class" như cách tạo các class thông thường.

CreateProducModels.jpg

- Category class :

using System.ComponentModel.DataAnnotations;

namespace WebAPIDemo.Models
{
    public class Category
    {
        public int Id { get; set; }

        [Required]
        public string Name { get; set; }
    }
}

- Product class:

using System.ComponentModel.DataAnnotations;

namespace WebAPIDemo.Models
{
    public class Product
    {
        public int Id { get; set; }

        [Required]
        public string Name { get; set; }

        public decimal Price { get; set; }

        public int CategoryId { get; set; }

        public virtual Category Category { get; set; }
    }
}

Lưu ý với Entity Framework 6.0, nó đã hỗ trợ cơ chế lazy loading. Trong demo này đối tượng Product có khóa ngoại là CategoryId, đồng thời nó có thể truy cập tới Category thông qua thuộc tính Category. Để có lazy loading chúng ta cần thêm keyword vitual cho thuộc tính này. Chúng ta có thể hiểu lazy loading trong trường hợp này như sau:

db.products.ToList() // đối tượng Category sẽ không được load cùng danh sách products
db.products[0].Category // chỉ khi truy suất vào một product cụ thể Category mới được load

2.3. Tạo controller

  • Click chuột phải tại thư mục Controller => chọn "Add" => chọn "Controller"
  • Tại cửa sổ "Add Scaffold" chúng ta chọn "Web API 2 Controller with actions, using Entity Framework".

ef06.png

Tại cửa sổ "Add controller"

  • Tại Model class dropdownlist, chọn Category class.
  • Tích chọn “Use async controller actions”.
  • Trong mục "Controller Name" tên controller tự động được điền vào.

CreateController.jpg

Tiếp đến click (+) button ở mục "Data context Class", tại cửa sổ "New Data Context" gõ tên Data context class theo mong muốn. Ở đây tôi tạo class có tên : WebAPIDemoContext. ProductsController được tạo tương tự như các bước trên.

2.4. Làm việc với Entity framework

Trong demo này tôi sử dụng Code First Migrations để init data và thao tác với Sql server. Trước tiên cần enable migration, để làm điều này chúng ta thực hiện như sau: Chọn Tool => chọn Nuget Package Manager => Chọn Package Manage Console. Trong cửa sổ Package Manage Console gõ lệnh:

Enable-Migrations

Một thư mục Migrations được tạo ra cùng một file có tên là "Configuration". Tiếp theo chúng ta sẽ update method "Seed trong class này để init data. Đây là method xây dựng sẵn trong class DbContext của Entity Framework và chúng ta hoàn toàn có thể ghi đè theo trường hợp sử dụng

protected override void Seed(WebAPIDemoContext context)
        {
            context.Categories.AddOrUpdate(x => x.Id,
               new Category { Id = 1, Name = "Mobile" },
               new Category { Id = 2, Name = "Tablet" },
               new Category { Id = 3, Name = "Smart watch" }
               );

            context.Products.AddOrUpdate(x => x.Id,
                new Product
                {
                    Id = 1,
                    Name = "Product 1",
                    CategoryId = 1,
                    Price = 9.99M,
                },
                new Product
                {
                    Id = 2,
                    Name = "Product 2",
                    CategoryId = 1,
                    Price = 12.95M,
                },
                new Product
                {
                    Id = 3,
                    Name = "Product 3",
                    CategoryId = 2,
                    Price = 15,
                },
                new Product
                {
                    Id = 4,
                    Name = "Product 4",
                    CategoryId = 3,
                    Price = 10,
                }

                );
        }

Ok, chúng ta đã có một số data test cho demo. Bây giờ chúng ta cần một class để tạo table và insert những bản ghi trên vào sql server, để làm điều đó ta gõ lệnh:

Add-Migration Initial
Update-Database

Một file migarion được tạo ra với code được tự động generate

namespace WebAPIDemo.Migrations
{
    using System;
    using System.Data.Entity.Migrations;

    public partial class Initial : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Categories",
                c => new
                    {
                        Id = c.Int(nullable: false, identity: true),
                        Name = c.String(nullable: false),
                    })
                .PrimaryKey(t => t.Id);

            CreateTable(
                "dbo.Products",
                c => new
                    {
                        Id = c.Int(nullable: false, identity: true),
                        Name = c.String(nullable: false),
                        Price = c.Decimal(nullable: false, precision: 18, scale: 2),
                        CategoryId = c.Int(nullable: false),
                    })
                .PrimaryKey(t => t.Id)
                .ForeignKey("dbo.Categories", t => t.CategoryId, cascadeDelete: true)
                .Index(t => t.CategoryId);

        }

        public override void Down()
        {
            DropForeignKey("dbo.Products", "CategoryId", "dbo.Categories");
            DropIndex("dbo.Products", new[] { "CategoryId" });
            DropTable("dbo.Products");
            DropTable("dbo.Categories");
        }
    }
}

Với đoạn code ở trên, Code First sẽ tự động kết nối, tạo database, table và insert data tới sql server trong lần khởi chạy đầu tiền của ứng dụng, những lần sau đó nếu có thay đổi migration DB sẽ được update ngược lại chúng sẽ không tạo lại nữa. Bây giờ chúng ta nhấn F5 để chạy web, sau đó kiểm tra database trong Server Exploer của Visual studio. Nếu có đầy đủ table và dữ liệu như hình bên dưới thì việc khởi tạo DB đã thành công.

sqlServerConnection.jpg

productTableData.jpg

2.5. Xây dựng client với với knockout js

Trong ứng dụng này, tôi sử dụng Knockout js để xây dựng phía client. Knockout js là một thư viện javascript sử dụng mô hình Model-View-ViewModel (MVVM). Các bạn có thể tìm hiểu thêm tại website Knockout. Có thể hình dung mô hình hoạt động của ứng dụng như sau:

ef31.png

Chúng ta sẽ xây dựng 3 chức năng cơ bản cho ứng dụng demo :

  • Show danh sách sản phẩm
  • Show chi tiết sản phẩm
  • Thêm mới sản

Trước tiên, chúng ta add knockout js tới ứng dụng. Trong Package manager console gõ lệnh:

Install-Package knockoutjs

Tạo view model:

Ở đây tôi sẽ tạo một file với tên là app.js trong thư mực Scripts của dự án để viết các hàm thao tác dự liệu với Server thông qua Knockout JS

var ViewModel = function () {
    var self = this;
    self.products = ko.observableArray();
    self.error = ko.observable();

    var productsUri = '/api/products/';

    function ajaxHelper(uri, method, data) {
        self.error('); // Clear error message
        return $.ajax({
            type: method,
            url: uri,
            dataType: 'json',
            contentType: 'application/json',
            data: data ? JSON.stringify(data) : null
        }).fail(function (jqXHR, textStatus, errorThrown) {
            self.error(errorThrown);
        });
    }

    function getAllProducts() {
        ajaxHelper(productsUri, 'GET').done(function (data) {
            self.products(data);
        });
    }

    // Fetch the initial data.
    getAllProducts();

    self.detail = ko.observable();

    self.getProductDetail = function (item) {
        ajaxHelper(productsUri + item.Id, 'GET').done(function (data) {
            self.detail(data);
        });
    }

    self.categories = ko.observableArray();
    self.newProduct= {
        Category: ko.observable(),
        Name: ko.observable(),
        Price: ko.observable(),
    }

    var categoriesUri = '/api/categories/';

    function getCategories() {
        ajaxHelper(categoriesUri, 'GET').done(function (data) {
            self.categories(data);
        });
    }

    self.addProduct = function (formElement) {
        var product = {
            CategoryId: self.newProduct.Category().Id,
            Name: self.newProduct.Name(),
            Price: self.newProduct.Price(),
        };

        ajaxHelper(productsUri, 'POST', product).done(function (item) {
            self.products.push(item);
        });
    }

    getCategories();
};

ko.applyBindings(new ViewModel());

Binding trên view:

<div class="panel panel-default">
            <div class="panel-heading">
                <h2 class="panel-title">Products</h2>
            </div>
            <div class="panel-body">
                <ul class="list-unstyled" data-bind="foreach: products">
                    <li>
                        <strong><span data-bind="text: CategoryName"></span></strong>: <span data-bind="text: Name"></span>
                        <small><a href="#" data-bind="click: $parent.getProductDetail">Details</a></small>
                    </li>
                </ul>
            </div>
        </div>

Ứng dụng demo sẽ như hình bên dưới:

finalResult.jpg

Trên đây tôi đã tạo một ứng dụng đơn giản dùng Asp.Net WebAPI 2.0, EF 6.0. Hy vọng rằng demo này sẽ giúp các bạn chưa biết có thể bắt đầu làm việc với Asp.net WebApi. Nó là quen thuộc nếu các bạn đã từng làm việc với Asp.Net Mvc, đồng thời nó cũng không quá phức tạp cho những ai mới làm quen. Chúc các bạn thành công.

Link code demo: WebAPIDemo

0