Wednesday, February 21, 2018

[ASP.NET MVC] Hiển thị Delete View dưới kiểu modal
Khi tạo BooksController với lựa chọn [Controller with views, using Entity Framework], Một thư mục mới Books với 4 view (Create.cshtml, Edit.cshtml, Details.cshtml, Delete.cshtml) tương ứng với 4 action (Create, Edit, Details, Delete) trong BooksController.cs được MVC scaffolding tạo ra một cách tự động.

Screenshot_1
Khi ta bấm vào nút [Xóa], Delete view sẽ được load, cho phép người dùng kiểm tra lại thông tin của cuốn sách sẽ xóa và xác nhận xem có thực sự muốn xóa cuốn sách này hay không. Đương nhiên giao diện ban đầu được sinh ra là tiếng Anh nhưng mình đã chuyển sang tiếng Việt cho … vui 😀
Screenshot_2
Tuy nhiên, mình thấy việc chuyển sang và load một view mới chỉ để xác nhận thông tin cuốn sách sẽ xóa thực sự không cần thiết và không cool cho lắm. Thông thường cách hay được áp dụng là hiển thị popup cho phép người dùng xác nhận và thao tác mà không cần phải di chuyển sang view mới. Sau một hồi thỉnh giáo Google-sensei, mình cũng đã làm được điều này. Giờ thì đang ngồi note lại trên blog để cho khỏi quên, nếu có quên thì cũng biết đường mà tìm lại. Nhưng trên hết là để chống mốc, câu bài viết cho blog củ chuối này 😀
Thành quả thì nó như thế này.
Screenshot_3
Bạn có thể thấy rõ ràng là cool hơn rất nhiều 😀 Và để làm được điều này, chỉ cần thực hiện 2 bước đơn giản sau đây:
Bước 1: Cập nhật lại Delete.cshtml


@model BookInfo.Models.Book

@{
    Layout = null;
}

<div class="modal fade" id="deleteModal">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">
                    <span aria-hidden="true">&times;</span>
                    <span class="sr-only">Close</span>
                </button>
                <h4 class="modal-title">Xác nhận</h4>
            </div>
            <div class="modal-body">
                <h3>Bạn có chắc muốn xóa cuốn sách này?</h3>
                <div>
                <hr />
                    <table class="table table-bordered table-striped">
                        <tr>
                            <th>Tiêu đề</th>
                            <td>@Html.DisplayFor(model => model.Title)</td>
                        </tr>
                        <tr>
                            <th>Tác giả</th>
                            <td>@Html.DisplayFor(model => model.Author.Name)</td>
                        </tr>
                    </table>
                </div>
            </div><!-- /.modal-body -->
            <div class="modal-footer">
            @using (Html.BeginForm("Delete", "Books", FormMethod.Post))
            {
                @Html.AntiForgeryToken()
                <div class="form-actions no-color text-center">
                    <input type="submit" value="Xóa" class="btn btn-danger" />
                    <button type="button" class="btn btn-default" data-dismiss="modal">Hủy</button>
                </div>
            }
            </div><!-- /.modal-footer -->
        </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
</div><!-- /.modal>
Ở đây, mình dùng Bootstrap modal. Bạn có thể tìm hiểu kỹ hơn về Bootstrap modal tại đây.
Điểm cần lưu ý ở đây đó chính là dòng code Layout = null; dòng code này Delete view sẽ không sử dụng _Layout.cshtml (Views >> Shared) mà đơn giản chỉ là block div với id là deleteModal sẽ được load ngay trên Index.cshtml thông qua Bước 2 dưới đây:
Bước 2: Cập nhật lại Index.cshtml
Trước hết, ta cần cập nhật lại link [Xóa] của mỗi cuốn sách như sau.


<td>
    @Html.ActionLink("Sửa", "Edit", new { id=item.Id }) |
    @Html.ActionLink("Chi Tiết", "Details", new { id=item.Id }) |
    <a class="delete-link" href="@Url.Action("Delete", new { id = item.Id })"><span style="color: red">Xóa</span></a>
</td>
Sau đó, để load deleteModal div trong Delete.cshtml, ta cần thêm vào script section đoạn code AJAX như sau.


$('.delete-link').click(function (e) {
    var a_href = $(this).attr('href'); /* Lấy giá trị của thuộc tính href */
    e.preventDefault(); /* Không thực hiện action mặc định */
    $.ajax({ /* Gửi request lên server */
        url: a_href, /* Nội dung trong Delete.cshtml cụ thể là deleteModal div được server trả về */
        type: 'GET',
        contentType: 'application/json; charset=utf-8',
        success: function (data) { /* Sau khi nhận được giá */
            $('.body-content').prepend(data); /* body-content div (định nghĩa trong _Layout.cshtml) sẽ thêm deleteModal div vào dưới cùng */
            $('#deleteModal').modal('show'); /* Hiển thị deleteModal div dưới kiểu modal */
        }
    });
});
Và cuối cùng bạn chỉ cần build lại project và chiêm ngưỡng thành quả 🙂

Thursday, February 15, 2018

Saturday, February 3, 2018

Tích hợp đăng nhập bằng tài khoản facebook ASP.NET MVC
Hôm nay mình làm một ví dụ nhỏ về cách sử dụng FB.login Javascript SDK của Facebook để xây dựng một chức năng đăng nhập trên website viết bằng Asp.Net MVC
Đầu tiên các bạn cần phải tạo 1 facebook app tại đây https://developers.facebook.com/
Sau khi tạo App thành công, bạn sẽ có Id ứng dụng (AppID), bạn cũng cần cấu hình tên miền ứng dụng sử dụng chức năng này. Khi đang trong quá trình phát triển bạn có thể ghi là localhost, khi deploy lên server thì sử dụng domain của website.


Chúng ta sẽ dựa vào hàm FB.login() để xác thực người dùng, sau khi xác thực thành công thì sẽ lấy thông tin xác thực trả về lưu vào Session trên website để bắt đầu một phiên làm việc mới của người dùng.

 

1. Javascript

Ta có phần mã javascript sẽ như sau
$(document).ready(function () {
    'use strict';
    // Load the SDK asynchronously
    (function (d) {
        var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
        if (d.getElementById(id)) { return; }
        js = d.createElement('script'); js.id = id; js.async = true;
        js.src = "//connect.facebook.net/en_US/sdk.js";
        ref.parentNode.insertBefore(js, ref);
    }(document));
    window.fbAsyncInit = function () {
        FB.init({
            appId: 'YOUR_APPID', // App ID
            status: true, // check login status
            cookie: true, // enable cookies to allow the server to access the session
            xfbml: true// parse XFBML
            version: 'v2.11'
        });
    };
    function Login() {
        FB.login(function (response) {
            if (response.authResponse) {
                getFacebookUserInfo();
            } else {
                console.log('User cancelled login or did not fully authorize.');
            }
        }, {
                scope: 'email,user_photos,publish_actions'
            });
    }
    function getFacebookUserInfo() {
        FB.api('/me?fields=email,name', function (response) {
            var token = $('input[name="__RequestVerificationToken"]').val();
            $.ajax({
                url: "/Home/Login",
                headers: { "__RequestVerificationToken": token },
                type: "POST",
                data: { 'name': response.name, 'email': response.email },
                success: function (data) {
                    if(data.success === "True")
                    {
                        location.reload();
                    }
                },
                error: function (data) {
                    console.log(data);
                }
            })
        });
    }
    function Logout() {
        FB.logout(function () { document.location.reload(); });
    }
    $('.lbtSignInFacebook').click(function () {
        Login();
    })
    $('.lbtLogOutFacebook').click(function () {
        Logout();
        var token = $('input[name="__RequestVerificationToken"]').val();
        $.ajax({
            url: "/Home/LogOut",
            headers: { "__RequestVerificationToken": token },
            type: "POST",
            success: function (data) {
                if (data.success === "True") {
                    location.reload();
                }
            },
            error: function (data) {
                console.log(data);
            }
        })
    })
});
Ở trên ta sẽ thấy khi gọi hàm FB.login() và việc xác thực thành công, chúng ta sẽ lấy thông tin của facebook trả về bao gồm response.email & response.name để đẩy về server thông qua ajax. Phía server sẽ lấy thông tin trả về đó để lưu vào session phục vụ cho phiên làm việc mới.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function getFacebookUserInfo() {
        FB.api('/me?fields=email,name', function (response) {
            var token = $('input[name="__RequestVerificationToken"]').val();
            $.ajax({
                url: "/Home/Login",
                headers: { "__RequestVerificationToken": token },
                type: "POST",
                data: { 'name': response.name, 'email': response.email },
                success: function (data) {
                    if(data.success === "True")
                    {
                        location.reload();
                    }
                },
                error: function (data) {
                    console.log(data);
                }
            })
        });
    }
Tương tự khi gọi hàm FB.Logout() ta cũng cần gọi phương thức phía server để xóa session của phiên làm việc hiện tại của người dùng.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$('.lbtLogOutFacebook').click(function () {
        Logout();
        var token = $('input[name="__RequestVerificationToken"]').val();
        $.ajax({
            url: "/Home/LogOut",
            headers: { "__RequestVerificationToken": token },
            type: "POST",
            success: function (data) {
                if (data.success === "True") {
                    location.reload();
                }
            },
            error: function (data) {
                console.log(data);
            }
        })
    })

 

2. HTML

Ở phần view phía ngoài sẽ như sau.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    <div class="jumbotron">
        <h1>Demo Login facebook</h1>
        <p class="lead">The sample about how to integrated Facebook Login to your website</p>
        @if (string.IsNullOrEmpty(ViewBag.UserName))
        {
            <p><a href="javascript:;" class="btn btn-primary btn-lg lbtSignInFacebook">LOGIN FACEBOOK</a></p>
        }
        else
        {
            <table>
                <tr>
                    <td>User:</td>
                    <td>
                        @ViewBag.UserName
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        <a href="javascript:;" class="btn btn-danger lbtLogOutFacebook">Log Out</a>
                    </td>
                </tr>
            </table>
        }
    </div>
}
@section scripts{
    <script src="~/Scripts/FacebookLogin.js"></script>
}
Phần view sẽ chỉ bao gồm một button Login (.lbtSignInFacebook) để gọi hàm Login() javascript viết ở trên.
?
1
2
3
$('.lbtSignInFacebook').click(function () {
        Login();
    })
Một form hiện thị thông tin người dùng trả về từ server thông qua @ViewBag.UserName và một button Logout (.lbtLogOutFacebook) để thoát phiên đăng nhập bằng cách gọi hàm Logout() ở trên.
?
1
2
3
4
$('.lbtLogOutFacebook').click(function () {
       Logout();
      //clear session here
   })

 

3. C#

Phía server ta chỉ cần viết hai hàm để xử lý sự kiện login & logout được gọi từ phía client như sau.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public ActionResult Index()
        {
            ViewBag.UserName = Convert.ToString(Session["UserName"]);
            return View();
        }
        [HttpPost, ValidateJsonAntiForgeryToken]
        public JsonResult Login(string name, string email)
        {
            Session["UserName"] = email;
            return Json(new { success = "True" });
        }
        [HttpPost, ValidateJsonAntiForgeryToken]
        public JsonResult LogOut()
        {
            Session.Abandon();
            return Json(new { success = "True" });
        }

Trong ví dụ này mình cố gắng chỉ làm những bước cơ bản nhất để các bạn dễ hình dung cách thức hoạt động của chức năng này, các bạn có thể download ví dụ ở dưới để xem chi tiết hơn.