# Đề số 1: Kiểm tra C# - SQL - Javascript (AngularJS - JQUERY) 1. Tạo dự án .NET MVC Core. Thực hiện viết Model cho bảng `KhachHang` bao gồm: - `Id int primary key` - `HoTen string` - `NgayThangNamSinh DateTime` - `IdCanCuoc string` - `DiaChi string` - `ImgPathCCCD string` 2. Tạo Database cho dự án bằng Codefirst 3. Tạo View với địa chỉ `/Home/QuanLyCanCuoc` và viết View theo cấu trúc HTML như ảnh ![anh-mau](https://cdn.anh.moe/c/pDMhQ.md.png) 4. Khi bấm vào nút UploadImage, cho phép người dùng tải lên hình ảnh CCCD và gọi vào action ở địa chỉ `/Home/ReadingOCR` 5. Viết action `ReadingOCR` trong controller `Home`, input đầu vào là ảnh được tải lên ở yêu cầu bên trên, thực hiện nghiệp vụ lưu ảnh vào thư mục `uploads` trong thư mục `wwwroot` của dự án **VÀ** gọi vào API tại fpt.ai với các thông tin sau: - `ApiUrl = "https://api.fpt.ai/vision/idr/vnm";` - `ApiKey = "OgjC5zaxxzQYOjyMPISY0CBT2zz1U0l8";` - Code mẫu: ```c# using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System; using System.IO; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; namespace YourWebApp.Controllers { [Route("api/[controller]")] [ApiController] public class FptApiController : ControllerBase { private const string ApiKey = "OgjC5zaxxzQYOjyMPISY0CBT2zz1U0l8"; private const string ApiUrl = "https://api.fpt.ai/vision/idr/vnm"; private readonly IWebHostEnvironment _hostingEnvironment; public FptApiController(IWebHostEnvironment hostingEnvironment) { _hostingEnvironment = hostingEnvironment; } [HttpPost] [Route("upload")] public async Task<IActionResult> UploadImage(IFormFile file) { if (file == null || file.Length == 0) { return BadRequest("File không hợp lệ."); } // Lưu ảnh vào thư mục 'upload' trong 'wwwroot' var uploads = Path.Combine(_hostingEnvironment.WebRootPath, "upload"); if (!Directory.Exists(uploads)) { Directory.CreateDirectory(uploads); } var filePath = Path.Combine(uploads, file.FileName); using (var fileStream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(fileStream); } using (var client = new HttpClient()) using (var content = new MultipartFormDataContent()) { // Thêm api-key vào header client.DefaultRequestHeaders.Add("api-key", ApiKey); // Thêm ảnh vào content từ file đã lưu var imageContent = new ByteArrayContent(System.IO.File.ReadAllBytes(filePath)); imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse(file.ContentType); content.Add(imageContent, "image", file.FileName); // Gửi yêu cầu POST var response = await client.PostAsync(ApiUrl, content); if (response.IsSuccessStatusCode) { var responseString = await response.Content.ReadAsStringAsync(); return Ok(responseString); } else { return BadRequest($"Lỗi: {response.StatusCode}"); } } } } } ``` 6. Sau khi nhận response từ API, nếu không có lỗi gì thì tiến hành đọc thông tin từ response và lưu vào các thông tin tương ứng - Mẫu response thành công: ```json { "errorCode" : 0, "errorMessage" : "", "data": [ { "id": "xxxx", "id_prob": "xxxx", "name": "xxxx", "name_prob": "xxxx", "dob": "xxxx", "dob_prob": "xxxx", "sex": "N/A", "sex_prob": "N/A", "nationality": "N/A", "nationality_prob": "N/A", "home": "xxxx", "home_prob": "xxxx", "address": "xxxx", "address_prob": "xxxx", "address_entities": { "province": "xxxx", "district": "xxxx", "ward": "xxxx", "street": "xxxx" }, "doe": "N/A", "doe_prob": "N/A", "type": "xxxx" } ] } ``` - Response thành công sẽ lưu các dữ liệu tương ứng vào database, với các trường tương ứng và trường `ImgPathCCCD` là địa chỉ ảnh đã được lưu. 7. Trên VIEW: - Hiển thị toàn bộ các khách hàng đã được lưu trong database ra bảng với thông tin tương ứng. Yêu cầu phân trang với độ dài 1 trang có 5 dòng, yêu cầu tính toán số trang - Hiển thị tìm kiếm: Khi nhập tìm kiếm, nếu ấn nút Enter trên bàn phím thì sẽ lọc ra toàn bộ các khách hàng có thông tin tương ứng. - Hiển thị thống kê: Thống kê tổng số khách hàng, tổng số khách hàng ở Hà Nội, HCM và Đà Nẵng (Có thể nhập mẫu dữ liệu để tính toán) - Hiển thị được hình ảnh CCCD trên bảng - Yêu cầu bổ sung: Khi Import nếu thành công thì sẽ tự động nhảy thêm ra dòng dữ liệu mới, không tiến hành load lại trang - Sử dụng công nghệ AngularJS hoặc Jquery AJAX