Create first Facebook chatbot by api.ai

It is fun to create a facebook chatbot, following are steps to create a very simple chatbot using http://api.ai

1. Create facebook page

image

2 . Then go to https://developers.facebook.com/apps/, select “Add a New App”, select basic setup.

clip_image003

clip_image005

3. After create successful, select “Get Started” in Messenger, then select new page that you just create as following:

clip_image006

4. Then copy Page Access Token, go to http://api.ai, create new account then select New Agent \ Chatbot Demo

clip_image007

5. Select Domains

clip_image008

6. Enable Small Talk Domain

clip_image009

7. Go to Chatbot Demo, select Settings as following

clip_image010

8. Input your token name and pasted Facebook token as following

clip_image011

9. Copy Callback URL from http://api.ai

Go to facebook developer page, input following information:

clip_image012

10. When complete, select page name as following, then click “Subscribe”

clip_image013

clip_image015

11. After configure successful, go to your page and start send message:

clip_image016

Have fun!

ExtremeML

Trong bài lần trước, mình có giới thiệu về Linq2Excel.

Một trong các hạn chế của Linq2Excel là thư viện này chỉ cho phép query dữ liệu, và ta không thể thêm, thay đổi hay xóa sửa dữ liệu trong đó được.

Để giải quyết vấn đề cập nhập thông tin trong file excel. Từ phiên bản Excel 2007 trở đi, Microsoft đưa ra chuẩn OfficeOpenXML (gọi tắt là OpenXML), tất cả dữ liệu office được lưu giữ dưới dạng XML, để kiểm tra bạn chỉ cần đổi đuôi file của MS Office thành .zip và mở bằng Winzip bạn sẽ thấy được dữ liệu XML của file đó. Để hỗ trợ lập trình với OpenXML, MS đưa ra bộ Open XML SDK mà bạn có thể download tại đây.

Tuy nhiên, việc dùng Open XML SDK vẫn phức tạp, do đó Tim Coulter viết ra thư viện ExtremeML, một thư viện Opensource tuyệt vời để làm việc với Excel 2007.

ExtremeML được mô tả như sau:


Sau đây là các tính năng chính của ExtremeML:

  • Tạo mới hoặc mở 1 workbook.
  • Đọc và ghi dữ liệu từ stream.
  • Thêm, xóa, thay đổi các worksheet.
  • Thêm, xóa, sửa row và column.
  • Hỗ trợ strongly-typed.
  • Đọc và ghi các formula của cells.
  • Đọc, ghí và thay đổi dữ liệu ảnh, rich text.
  • Hỗ trợ footer và header.

Ngoài ra ExtremeML còn hỗ trợ các tính năng sau:

  • Hỗ trợ dữ liệu dựa trên dạng bảng của Excel table.
  • Hỗ trợ template.
  • Các tính năng nâng cao như: group, merge, macro và phiên bản mới nhất hỗ trợ Excel 2010.

Ví dụ đoạn code sau:

Đoạn code này insert dữ liệu vào bảng như sau:

Happy coding!

Single responsibility principle

  • Giới thiệu

    SOLID là cách viết tắt của các nguyên lý cơ bản trong thiết kế hướng đối tượng, 5 nguyên lý này rất quan trọng trong lập trình hướng đối tượng.

    + Single Resposibility principle – SRP

    + Open Closed Principle – OCP

    + Liskov Substitution Principle – LSP

    + Interface Segregation Principle – ISP

    + Dependency Inversion Principle – DIP

    Bài viết này tôi sẽ trình bày về nguyên lý đầu tiên: Single respónibility principle

  • Định nghĩa SRP
    • Định nghĩa responsibility

      Robert C. Martin chỉ ra rằng responsibility là một lý do để thay đổi. Để dễ hiểu, ta hãy hình dung responsibility là mục đích. Mục đích là những thứ bạn cần trong class của bạn, do đó một class chỉ nên có một mục đích mà thôi!

    • Định nghĩa SRP

      SRP chỉ ra rằng tất cả các đối tượng (object) chỉ có một resposibility duy nhất, và responsibility đó được gói trong một lớp. Từ đó Martin chỉ ra rằng một lớp hoặc module chỉ được có một và chỉ một lý do để thay đổi.

    • Ví dụ: Một module tạo và in một report, module này bị thay đổi bởi một trong 2 lý do. Đó là nội dung của report thay đổi hoặc format của report bị thay đổi. 2 sự thay đổi này được sinh ra bởi các nguyên nhân khác nhau. SRP chỉ ra rằng 2 nguyên nhân thay đổi này chính là 2 phần liên quan tới 2 responsibility khác nhau. Vì vậy người lập trình không tốt nếu ghép cả 2 phần này vào một lớp (Class).
  • Lợi ích của SRP:
    • Dễ dàng dùng lại cho các responsibility
    • Mã lệnh rõ ràng
    • Dễ dàng chọn tên phù hợp với responsibility
    • Dễ dàng để đọc hiểu đoạn code
  • Ví dụ một class là RepositoryBase dùng để truy cập database, ta định nghĩa 1 function là GetAll để lấy về tất cả dữ liệu của một bảng nào đó:

     

    https://gist.github.com/hadoan/542d0972ecdf33ac47e48e464f584eba

  • Trong ví dụ này, chúng ta đã vị phạm nguyên tắc của SRP, class RepositoryBase làm việc có 2 mục đích khác nhau là DataAccess và DataMapping: Để tuân thủ nguyên tắc này, ta tạo ra một class riêng chịu trách nhiệm về DataMapper:

     

    https://gist.github.com/hadoan/2f56c0e8edb94b5786fadb675b8eb9f3

Validate winform bằng SpecExpress

SpecExpress là một Fluent validation framework, trong bài viết này, tôi xin giới thiệu cách validate Winform bằng SpecExpress và Error provider.

Xem giới thiệu về SpecExpress.

Trước hết tạo một Entity kế thừa từ IDataErrorInfo interface.

image

Sau đó tạo một dictionary đẻ lưu lại các message lỗi của các Property trong Entity đó.

   1: /// <summary>

   2:        /// Dictionary of validation errors, it contains Property and Error messages...

   3:        /// </summary>

   4:        public Dictionary<string, string> Errors

   5:        {

   6:            get;

   7:            set;

   8:        }

 

Việc tiếp theo là implement interface IDataError: index this và thuộc tính Error:

   1: public string Error

   2:        {

   3:            get

   4:            {

   5:                return lastError; 

   6:            }

   7:              

   8:        }

index this[propertyName] trả về Error message cho Error Provider

 

   1: /// <summary>

   2:     /// Gets the error of a specific property

   3:     /// </summary>

   4:     /// <param name="propertyName">The property name</param>d

   5:     /// <returns>The error message</returns>

   6:     public string this[string propertyName]

   7:     {

   8:         #region Doan Manh Ha commented for write new Error validation method by Specexpress

   9:         //get { return _propError[propertyName]; }

  10:         //set 

  11:         //{

  12:         //    _propError[propertyName] = value;

  13:         //    PropertyHasChanged(); 

  14:         //}

  15:         #endregion

  16:  

  17:         get

  18:         {

  19:             if (!IsNeedValidation)

  20:             {

  21:                 if (Errors!=null && Errors.ContainsKey(propertyName))

  22:                     return Errors[propertyName];

  23:                 else

  24:                     return string.Empty;

  25:             }

  26:  

  27:             var notification = this.ValidateProperty(propertyName);

  28:  

  29:             

  30:  

  31:             if (notification==null || notification.IsValid)

  32:             {

  33:                 lastError = string.Empty;

  34:                

  35:             }

  36:             else

  37:             { 

  38:                 // TODO: aggregate notification messages in readable form and assign to lastError 

  39:                 lastError = this.BuildErrorMessages(notification.ErrorSummary());

  40:             }

  41:  

  42:             AddError(propertyName, lastError);

  43:             return lastError;

  44:         }

  45:         set

  46:         {

  47:             AddError(propertyName, value);

  48:         }

  49:  

  50:     }

– IsNeedValidation là một thuộc tính xác định xem có cần phải validate không.

– Validate chính là Virtual method để validate property đó, trả về ValidationNotification

   1: protected virtual ValidationNotification ValidateProperty(string propertyName)

   2:     {

   3:         throw new NotImplementedException();

   4:     }

AddError là hàm add nội dung Error vào Error dictionary:

   1: private void AddError(string propertyName, string error)

   2:         {

   3:             //lastError = value;

   4:             if (Errors == null)

   5:                 Errors = new Dictionary<string, string>();

   6:  

   7:             if (Errors.ContainsKey(propertyName))

   8:                 Errors[propertyName] = error;

   9:             else

  10:                 Errors.Add(propertyName, error);

  11:         }

 

Tiếp theo ta viết Entity cho User, kế thừa từ AbstractBaseData:

 

   1: public class User:AbstractBaseData<int>

   2:    {

   3:  

   4:        private int id;

   5:        private string name;

   6:        private string password;

   7:        private string rules;

   8:  

   9:        #region Public properties

  10:  

  11:        public int Id

  12:        {

  13:            get

  14:            {

  15:                return this.id;

  16:            }

  17:            set

  18:            {

  19:                if ((this.id != value))

  20:                {

  21:                    this.id = value;

  22:                    this.OnPropertyChanged("Id");

  23:  

  24:                }

  25:            }

  26:        }

  27:  

  28:        public string Name

  29:        {

  30:            get

  31:            {

  32:                return this.name;

  33:            }

  34:            set

  35:            {

  36:                if ((this.name != value))

  37:                {

  38:                    this.name = value;

  39:                    this.OnPropertyChanged("Name");

  40:  

  41:                }

  42:            }

  43:        }

  44:  

  45:        public string Password

  46:        {

  47:            get

  48:            {

  49:                return this.password;

  50:            }

  51:            set

  52:            {

  53:                if ((this.password != value))

  54:                {

  55:                    this.password = value;

  56:                    this.OnPropertyChanged("Password");

  57:  

  58:                }

  59:            }

  60:        }

  61:  

  62:        public string Rules

  63:        {

  64:            get

  65:            {

  66:                return this.rules;

  67:            }

  68:            set

  69:            {

  70:                if ((this.rules != value))

  71:                {

  72:                    this.rules = value;

  73:                    this.OnPropertyChanged("Rules");

  74:  

  75:                }

  76:            }

  77:        }

  78:  

  79:        public IList<Role> Roles

  80:        {

  81:            get;

  82:            set;

  83:        }

  84:  

  85:        #endregion

  86:  

  87:        #region Validations

  88:  

  89:        UserSpecification spec = new UserSpecification();

  90:  

  91:        protected override ValidationNotification ValidateProperty(string propertyName)

  92:        {

  93:  

  94:            try

  95:            {

  96:  

  97:                return ValidationCatalog.ValidateProperty(this, propertyName, spec);

  98:            }

  99:            catch (Exception)

 100:            {

 101:                return null;

 102:            }

 103:        }

 104:  

 105:        public override bool Validate()

 106:        {

 107:           

 108:            this.IsNeedValidation = true;

 109:           

 110:            this.PropertyHasChanged();

 111:            this.IsNeedValidation = false;

 112:            return this.IsValid;

 113:        }

 114:        #endregion

 115:    }

 

Và Specification cho User entity:

   1: public class UserSpecification:Validates<User>

   2:   {

   3:       public UserSpecification()

   4:       {

   5:           Check(user => user.Name).Required(ValidationConstants.USER_NAME_REQ);

   6:  

   7:           Check(user => user.Password).Required(ValidationConstants.PASSWORD_REQ)

   8:                                       .MinLength(6);

   9:  

  10:           Check(user => user.Roles).Required(ValidationConstants.USER_ROLE_REQ);

  11:       }

  12:   }

Xử lý ở Winform UI

image

Sự kiện cho button Cập nhật:

   1: private void btnUpdate_Click(object sender, EventArgs e)

   2:    {

   3:        string typeOfUserViewData = typeof(UserViewData).Name;

   4:        UserViewData userViewData = this.GetSessionData(typeOfUserViewData) as UserViewData;

   5:        

   6:        var isValid = userViewData.User.Validate();

   7:        

   8:        //Récupération de la VSD

   9:        if (!isValid)

  10:        {

  11:            epUserView.DataSource = userViewData.User;

  12:            return;

  13:        }

  14:  

  15:        

  16:        userViewData.IsCreation = false;

  17:        //Transfert de l'exécution vers le controleur

  18:        //this.InvokeController(ControllerConstants.USER_CONTROLLER, ControllerActionConstants.SAVE_ACTION);   

  19:    }

Và đây là kết quả:

image

SpecExpress – A fluent validation

SpecExpress là một fluent API để validate dữ liệu có hợp lệ hay không.

SpecExpress không dùng các Custom attribute để decorator thuộc tính như các Validation framework khác (ví dụ: Validation application block,…), mà SpecExpress dùng riêng một lớp gọi là Specification, lớp này sẽ chứa các rule cho tất cả các thuộc tính cần validate. Việc này giúp cho code dễ đọc hơn (vì dùng Fluent API) và code cũng dễ maintaince hơn.

Ví dụ:

   1: public class UserSpecification:Validates<User>

   2:   {

   3:       public UserSpecification()

   4:       {

   5:           Check(user => user.Name).Required(ValidationConstants.USER_NAME_REQ);

   6:  

   7:           Check(user => user.Password).Required(ValidationConstants.PASSWORD_REQ)

   8:                                       .MinLength(6);

   9:  

  10:           Check(user => user.Roles).Required(ValidationConstants.USER_ROLE_REQ);

  11:       }

  12:   }

Class này kế thừa từ class Validates<T> của SpecExpress.

Constructor định nghĩa các rule để validate Entity User: Cần phải có Tên đăng nhập, cần phải có mật khẩu tối thiểu 6 ký tự, và User cần phải có ít nhất một Role.

Chi tiết hơn, các bạn xem tại đây.

Linq2Excel: Truy vấn Excel bằng Linq

Linq2Excel hỗ trợ bạn truy vấn dữ liệu Excel bằng Linq như sample sau:

   1: var repo = new ExcelQueryFactory();

   2: repo.FileName = "pathToExcelFile";

   3:  

   4: var peopleWithSiblings = from p in repo.Worksheet<Person>()

   5:                          where p.Siblings > 0

   6:                          select p;

Trong trường hợp này, các property name của class Person có header tương tự trong các columns của file excel tại Sheet1.

 

Trong trường hợp, header của các column trong file Excel tại sheet1 không giống như tên các property của class, bạn dùng hàm AddMapping như sau:

   1: public class ExcelStudentRepository

   2:    {

   3:        /// <summary>

   4:        /// Get all Student from excel file

   5:        /// </summary>

   6:        /// <param name="excelFile"></param>

   7:        /// <returns></returns>

   8:        public IList<ExcelStudent> GetAll(string excelFile)

   9:        {

  10:            var excel = new ExcelQueryFactory(excelFile);

  11:            excel.AddMapping<ExcelStudent>(student => student.MSV, "MSV");

  12:            excel.AddMapping<ExcelStudent>(student => student.HoDem, "Ho dem");

  13:            excel.AddMapping<ExcelStudent>(student => student.NgaySinh, "ngay sinh");

  14:            excel.AddMapping<ExcelStudent>(student => student.NienKhoa, "nien khoa");

  15:            excel.AddMapping<ExcelStudent>(student => student.Ten, "ten");

  16:            excel.AddMapping<ExcelStudent>(student => student.Phai, "phai");

  17:  

  18:            var students = from s in excel.Worksheet<ExcelStudent>()

  19:                           select s;

  20:  

  21:            return students.ToList();

  22:  

  23:  

  24:        }

  25:  

  26:    }

Linq2Excel sẽ Map thuộc tỉnh như: “HoDem” của class ExcelStudent với column có tên là “ho dem” trong sheet1 của Excel

 

Chi tiết hơn về LinqtoExcel, các bạn xem tại đây.