Bài viết mới:

Thứ Tư, 28 tháng 6, 2017

Hướng dẫn gắn "Flexible Responsive jQuery Image Slider Plugin" vào website



Bài viết này hướng dẫn bạn từng bước gắn Flexible Responsive jQuery Image Slider Plugin vào website của bạn. Đây là một plugin jquery có hiệu ứng rất mượt và hỗ trợ responsive tốt. Bạn có thể xem ngay demo về plugin này tại địa chỉ sau http://www.jqueryscript.net/demo/Flexible-Responsive-jQuery-Image-Slider-Plugin-Simple-Slider/.


Sau đây là các bước thực hiện:

 Bước 1: Tạo thư mục css, sau đó tạo file slider.css  trong thư mục này và dán đoạn lệnh bên dưới vào file slider.css.

/* ==========================================================================
        Slider core styles
===========================================================================*/
*,
*:before,
*:after {
  -webkit-box-sizing: border-box;
     -moz-box-sizing: border-box;
          box-sizing: border-box;
}

.slider-container {
  position: relative;

  overflow: hidden;

  width: 100%;
  margin: 0 auto;
}

.slider {
  position: relative;

  width: 9999px;
}
.slider:before,
.slider:after {
  display: table;

  content: ' ';
}
.slider:after {
  clear: both;
}
.slider div {
  position: relative;

  float: left;

  margin: 0;
  padding: 0;
}
.slider div img {
  display: block;

  max-width: 100%;
  height: auto;
}
.act,
#prev > span,
#next > span,
#slider-nav > a {
  background: url(../images/arrows.png) no-repeat;
}
#next > span,
#prev > span {
  display: block;

  width: 16px;
  height: 24px;
}
/* Arrows */
#next > span {
  background-position: -20px 0;
}
#prev > span {
  background-position: 0 0;
}
#next,
#prev {
  position: absolute;
  top: 50%;

  margin-top: -20px;
  padding: 10px 15px;

  cursor: pointer;
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;

  border-radius: 5px;
  background: rgba(0, 0, 0, .39);

  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#99000000', endColorstr='#99000000'); /* ie8 */
       -o-user-select: none;
}
#prev {
  left: 10px;
}
#next {
  right: 10px;
}
.caption {
  position: absolute;
  bottom: 0;

  display: block;

  width: 100%;
  padding: 0 10px 30px;

  color: #fff;
  background: rgba(0, 0, 0, .39);

  filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#99000000', endColorstr='#99000000'); /* ie8 */
}
.caption a {
  display: block;

  color: #fff;
}
.slider-nav {
  line-height: 30px;

  position: absolute;
  bottom: 0;
  left: 0;

  width: 100%;
  height: 30px;
  margin: 0;
  padding: 0;

  text-align: center;
  /*background: #323232;*/
  /*opacity: .9;*/

  filter: alpha(opacity=90); /* ie8 */
}
.slider-nav a {
  display: inline-block;

  width: 12px;
  height: 12px;
  margin: 0 3px;

  -webkit-transition: background .5s ease;
     -moz-transition: background .5s ease;
       -o-transition: background .5s ease;
          transition: background .5s ease;

  border: 2px solid #fff;
  border-radius: 50%;
  background: transparent;
}

.slider-nav .active {
  width: 12px;
  height: 12px;

  background: #fff;
}
@media (max-width: 580px) {
  .caption {
    display: none;
  }
}

Bước 2: Tạo folder js, sau đó tạo file slider.js và dán đoạn lệnh sau vào file slider.js

/* jQuery simple slider */
(function($) {

"use strict";

var
supportCss3 = function( value ) {
    var el = document.createElement('div');
    switch(value) {
        case "transform":
            var prefix = {
                transform       : "transform",
                webkitTransform : "-webkit-transform",
                mozTransform    : "-moz-transform",
                msTransform     : "-ms-transform",
                oTransform      : "-0-transform"
            }
        break;
        case "transition":
            var prefix = {
                transition       : 'transition',
                webkitTransition : 'webkitTransition',
                mozTransition    : 'mozTransition',
                oTransition      : 'oTransition'
            }
        break;
    }
    for(var name in prefix) {
        if(el.style[name] !== undefined) {
            return prefix[name];
        }
    }
    return false;
},
transform  = supportCss3("transform"),
transition = supportCss3("transition");


$.fn.sliderUi = function(o) {
    o = $.extend({
        autoPlay: true,
        delay: 3000,
        controlShow: true,
        arrowsShow: true,
        caption: false,
        speed: 300,
        cssEasing: "ease-out"
    }, o || {});

    return this.each(function() {
        var
            container    = $(this),
            slider       = container.find(".slider"),
            arrows       = container.find(".switch"),
            caption      = slider.find(".caption"),
            img          = slider.find("img"),
            imgLen       = img.length,
            imgWidth     = container.outerWidth(true),
            sliderWidth  = imgLen * imgWidth,
            controlPanel = null,
            current      = 0,
            offset       = null,
            busy         = false,
            timer        = null;

        slider.css("width", sliderWidth + "px");
        img.width( imgWidth );
        slider.show();

        $(window).on("resize", function() {
            if(transition) {
                slider.css(transition, "none");
            }
            imgWidth     = container.width();
            sliderWidth  = imgLen * imgWidth;
            img.width( imgWidth );
            if(transition && transform) {
                slider.css({
                    width: sliderWidth + "px",
                    transform: "translateX("+ -(imgWidth*current) + "px)"
                });
            } else {
                slider.css({
                    width: sliderWidth + "px",
                    "margin-left": -(imgWidth*current) + "px"
                });
            }
        })

        !o.caption && caption.remove();

        if( o.controlShow) {
            controlPanel = $("<div/>", {
                "class": "slider-nav"
            })
            .appendTo(container);

            // Control links
            var links = [];
            for(var i = 0; imgLen > i; i++) {
                var act = (current === i) ? "active" : "";
                    links.push("<a class='"+act+"' data-id='"+i+"'></a>");
            }
            controlPanel.get(0).innerHTML = links.join("");

            var navControl = controlPanel.find("a");
            navControl.on("click", function(e) {
                e.preventDefault();
                current = this.getAttribute("data-id");
                show("current");
            })
        }

        var show = function(side) {
            if(busy) return;

            if(side === "next") {
                if(current < imgLen - 1) {
                    offset = - (imgWidth*(++current)) + "px";
                }
                else {
                    offset = 0;
                    current  = 0;
                }
            }
            else if(side === "current") {
                offset = - (imgWidth*current) + "px";
            }
            else {
                if(current > 0) {
                    offset = - (imgWidth*(--current)) + "px";
                }
                else {
                    offset = - (imgWidth*(imgLen - 1)) + "px";
                    current  = imgLen -1;
                }
            }
            if(o.controlShow) {
                navControl.removeClass("active");
                navControl.eq(current).addClass("active");
            }

            if(transition && transform) {
                slider.css({
                    transition: transform + " " + o.speed + "ms " + o.cssEasing,
                    transform: "translateX(" + offset + ")"
                })
            }
            else {
                busy = true;
                slider.animate({"margin-left": offset}, o.speed, "linear", function() {
                    busy = false;
                })
            }
        }

        if(o.arrowsShow) {
            arrows.on("click", function(e) {
                e.preventDefault();
                var side = this.id;
                show(side);
            })
        }
        else {
            arrows.remove();
        }

        var auto = function() {
            if(timer) clearInterval(timer);
            timer = setInterval(function() {
                show("next");
            }, o.delay);
        }

        if(o.autoPlay) {
            auto();
            container.hover(function() {
                clearInterval(timer);
            }, function() {
                auto();
            });
        }

    });

}

})(jQuery);


 Bước 3: Khai báo lệnh sau trong thẻ <head></head> ở trang web của bạn.

<link href="css/slider.css" rel="stylesheet">

 Bước 4: Khai báo đoạn script sau ở cuối thẻ <body> ở trang web của bạn

<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
          <script src="js/slider.js"></script>
          <script>
            $("#demo").sliderUi({

            // Auto play when page loads
            autoPlay: true,

            // animation delay in ms
            delay: 3000,

            // display controls
            controlShow: true,

            // display arrows navigation
            arrowsShow: true,

            // display image captions
            caption: false,

            // animation speed
            speed: 300,

            // CSS3 easing effects
            cssEasing: "ease-out"

            });
          </script>


 Bước 5: Dán đoạn lệnh HTML sau vào nơi bạn muốn đặt plugin

       <div class="slider-container" id="demo">
                <!-- <a href="http://www.jqueryscript.net/slider/">Slider</a>  -->
                <div class="slider">
                    <div>
                    <img src="images/1.jpg" alt="">
                    <span class="caption">Image Caption 1</span>
                    </div>
                    <div>
                    <img src="images/2.jpg" alt="">
                    <span class="caption">Image Caption 2</span>
                    </div>
                    <div>
                    <img src="images/3.jpg" alt="">
                    <span class="caption">Image Caption 3</span>
                    </div>
                </div>
               
                <!-- Controls -->
                <div class="switch" id="prev"><span></span></div>
                <div class="switch" id="next"><span></span></div>

          </div>

Chú ý: 3 giá trị ở attribute src images/1.jpg, images/2.jpg, images/3.jpg chỉ là mình ví dụ. Bạn tự lấy hình và sửa đường dẫn cho đúng nhé. Chú ý rằng 3 hình ảnh có size bằng nhau thì sẽ đẹp nhất.

Thứ Bảy, 20 tháng 5, 2017

Tìm hiểu về method RenderBody(), RenderSection() trong Asp.net MVC

1. Tìm hiểu về layout view


Một website có thể chứa các phần chung trong các giao diện người dùng mà vẫn giữ nguyên trong suốt ứng dụng chẳng hạn như logo, tiêu đề, thanh điều hướng bên trái,thanh điều hướng bên phải hoặc phần footer đó được gọi là layout web.

ASP.NET MVC giới thiệu Layout view là một view mà có thể dùng lại trong nhiều view khác để cung cấp một giao diện nhất quán trong nhiều trang của một site. Layout View giống như master page của ứng dụng ASP.NET Webform.

Ví dụ, một giao diện người dùng có thể chứa header, thanh menu trái, thanh menu phải và phần chân trang mà vẫn giống nhau trong tất cả các trang và chỉ có phần trung tâm thay đổi tự động theo từng trang trong website như hình dưới đây.



Khi tạo ứng dụng ASP.NET MVC, mặc định file layout có tên _Layout.cshtml trong thư mục Views/Shared.

File _Layout.cshtml giống với view khác ngoại trừ việc trong Layout view có chứa 2 lệnh gọi method @RenderBody và @RenderSection.

Layout chứa một và chỉ một lệnh @RenderBody() để giữ chỗ cho nội dung trong những view kế thừa layout.

Layout không có hoặc nhiều lệnh @RenderSection() để giữ chỗ cho những thành phần khác được đánh dấu thông qua khối @section tensection { } trong view kế thừa layout.


2. RenderBody()


Tất cả nội dung của những view mà kế thừa 1 layout nào đó sẽ chứa trong RenderBody().

3. RenderSection()


Hiển thị nội dung của 1 thành phần nhỏ trong layout


Ví dụ về RenderSection


Method RenderSection() có 2 tham số tham số thứ nhất là tên section tham số thứ 2 là required kiểu bool. Nếu các bạn không muốn sử dụng RenderSection trong tất cả các trang web thì thì truyến giá trị false vào tham số required.

Chủ Nhật, 14 tháng 5, 2017

Tìm hiểu LINQ và sử dụng LINQ trên C#


1.  Giới thiệu về LINQ


Language-Integrated Query (LINQ) là một sự đổi mới được giới thiệu trong Visual Studio 2008 và .NET Framework phiên bản 3.5.

Theo truyền thống, các truy vấn dữ liệu được thể hiện dưới dạng các chuỗi mà không cần kiểm tra kiểu tại thời gian biên dịch hoặc hỗ trợ IntelliSense và bạn phải học một ngôn ngữ truy vấn khác nhau cho từng loại nguồn dữ liệu ví dụ như: cơ sở dữ liệu SQL, tài liệu XML, dịch vụ web khác nhau, ... LINQ giúp nhúng truy vấn vào ngôn ngữ lập trình (đúng như tên gọi của nó). Tức là bạn có thể sử dụng C# hay Visual Basic để có thể truy vấn đến mọi nguồn dữ liệu mà không nhất thiết phải biết các loại ngôn ngữ truy vấn riêng biệt để có thể thao tác với chúng. Bạn sẽ viết truy vấn sử dụng từ khóa và toán tử quen thuộc của ngôn ngữ lập trình. Hình minh họa dưới đây cho thấy một truy vấn LINQ kết nối đến 1 cơ sở dữ liệu SQL Server trong C# và Visual Basic:




Trong Visual Studio, bạn có thể viết các truy vấn LINQ trong Visual Basic hoặc C# đến cơ sở dữ liệu SQL Server, các tài liệu XML, tập dữ liệu ADO.NET, và bất kỳ collections của của đối tượng có hỗ trợ interface IEnumerable hoặc IEnumerable<T>. LINQ cũng hỗ trợ cho ADO.NET Entity Framework, và các LINQ provider đang được viết bởi bên thứ ba cho nhiều dịch vụ Web và triển khai cơ sở dữ liệu khác.

Để sử dụng LINQ thì dự án của bạn phải đang chạy trên nền tảng .NET Framework 3.5 hoặc cao hơn.

2.  Sử dụng LINQ trên C#


a. Giới thiệu về LINQ Queries (C#)


Một truy vấn là một biểu thức để lấy dữ liệu từ một nguồn dữ liệu. Các truy vấn thường được biểu thị bằng một ngôn ngữ truy vấn cụ thể. Trước đây với mỗi nguồn dữ liệu thì sẽ đi kèm với ngôn ngữ riêng để truy vấn trên nguồn dữ liệu đó, ví dụ SQL cho cơ sở dữ liệu quan hệ và XQuery cho XML. Do đó, các nhà phát triển đã phải học một ngôn ngữ truy vấn mới cho mỗi loại nguồn dữ liệu. LINQ đơn giản hoá vấn đề này bằng cách tích hợp truy vấn vào trong ngôn ngữ lập. Trong một truy vấn LINQ, bạn luôn làm việc với các đối tượng (object). Bạn sử dụng cùng một truy vấn và chuyển đổi dữ liệu trong các tài liệu XML, cơ sở dữ liệu SQL, ADO.NET Datasets, .NET collections và bất kỳ định dạng nào khác mà LINQ provider có sẵn. 

Truy vấn LINQ chia thành 3 thành phần sau:
  1. Chuẩn bị nguồn dữ liệu
  2. Tạo câu lệnh truy vấn LINQ
  3. Thực thi truy vấn để lấy kết quả

Ví dụ sau đây cho thấy cách hoạt động của 3 thành phần trên. Ví dụ sử dụng một mảng số nguyên như là một nguồn dữ liệu. Ví dụ này được sử dụng trong suốt phần còn lại của chủ đề này.

      
        //  1. Nguồn dữ liệu.
        int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };

        // 2. Tạo câu lệnh truy vấn:
        // Lấy ra các số chẵn trong mảng numbers
        var numQuery =
            from num in numbers
            where (num % 2) == 0
            select num;

        // 3. Thực thi truy vấn.
        foreach (int num in numQuery)
        {
            Console.Write("{0,1} ", num);
        }

Hình minh họa dưới đây cho thấy cách hoạt động của LINQ.



Các biểu thức truy vấn có chứa ba mệnh đề: from, where, select. (Nếu bạn đã quen thuộc với SQL, bạn sẽ nhận thấy rằng cách sắp xếp trật tự của các mệnh đề ngược lại với trật tự trong SQL). Mệnh đề from chỉ ra nguồn dữ liệu, mệnh đề where áp dụng để lọc dữ liệu theo 1 điều kiện nào đó, và mệnh đề select chỉ ra kiểu của kết quả trả về. Những mệnh đề này và một số mệnh đề khác được thảo luận chi tiết trong phần LINQ Query Expressions (C# Programming Guide).

Chú ý: Truy vấn LINQ cũng có thể được xây dựng bằng cách sử dụng phương thức mở rộng (method systax) thay vì  dùng theo kiểu Query syntax như ví dụ. Để biết thêm thông tin, xem Query Syntax and Method Syntax in LINQ (C#).

Trì hoãn thực thi


Các biến truy vấn mặc định chỉ lưu trữ các lệnh truy vấn. Các hoạt động truy vấn được hoãn lại cho đến khi bạn lặp qua các biến truy vấn trong một câu lệnh foreach. Khái niệm này được gọi là deferred execution (trì hoãn thực thi) và được thể hiện trong ví dụ sau:

//Khi vòng lặp được chạy thì truy vấn mới được thực thi và gán kết quả truy vấn qua biến num.
foreach (int num in numQuery)
{
    Console.Write("{0,1} ", num);
}


Câu lệnh foreach cũng là nơi mà các kết quả truy vấn được lấy ra. Ví dụ, trong truy vấn trên, mỗi lần lặp thì biến num giữ mỗi giá trị khác nhau (tại mỗi thời điểm) bởi vì mỗi lần lặp là mỗi lần trình biên dịch thực thi query và lấy dữ liệu từ CSDL.

Buộc thực thi ngay


Truy vấn thực hiện chức năng thống kê phải duyệt qua những phần tử. Ví dụ như các truy vấn Count, Max, Min, Sum, Average, First. Đó là những truy vấn mà sự thực thi truy vấn đó mà không có một câu lệnh foreach rõ ràng vì các truy vấn tự nó phải sử dụng ngầm foreach để trả lại kết quả. Ví dụ truy vấn dùng mệnh đề Sum sẽ ngầm dùng vòng lặp foreach để duyệt qua tất cả các phần tử để thực hiện tính tổng. Lưu ý rằng các loại truy vấn thống kê sẽ trả về 1 giá trị duy nhất do đó kiểu trả về không phải là 1 queryable. Các truy vấn sau đây trả về số lượng các số chẵn trong mảng numbers:

var evenNumQuery =
    from num in numbers
    where (num % 2) == 0
    select num;

int evenNumCount = evenNumQuery.Count();

Buộc thực thi ngay và lưu lại kết quả vào 1 collection hoặc generic collection, bạn có thể sử dụng phương thức ToList<TSource> hoặc ToArray<TSource> . Ví dụ:

List<int> numQuery2 =
    (from num in numbers
     where (num % 2) == 0
     select num).ToList();

// hoặc dùng cách này:
// numQuery3 sẽ có kiểu là 1 mảng int[]

var numQuery3 =
    (from num in numbers
     where (num % 2) == 0
     select num).ToArray();


Bằng cách gọi ToList hoặc ToArray bạn sẽ lưu trữ tất cả các dữ liệu trong một đối tượng collection nằm trong bộ nhớ để sử dụng dữ liệu đó và truy vấn tiếp về sau trên collection thay vì cứ phải truy xuất đến dữ liệu mỗi khi thực thi truy vấn.

b. LINQ và kiểu Generic


Truy vấn LINQ dựa trên các kiểu generic, mà được giới thiệu trong .NET Framework 2.0. Bạn không cần 1 kiến thức chuyên sâu về Generic để có thể bắt đầu viết truy vấn LINQ. Tuy nhiên, bạn cần phải biết 2 khái niệm cơ bản sau đây:
  1. Khi bạn tạo một đối tượng của một 1 class Generic Collection như List<T>, bạn sẽ thay thế chữ “T” với chính xác kiểu dữ liệu của đối tượng mà danh sách giữ. Ví dụ, List<string> đại diện cho một danh sách chuỗi hoặc 1 danh sách các Customer có thể được khai báo là List<Customer>. 
  2. IEnumerable<T> là interface cho phép các lớp Collection Generic có thể dùng câu lệnh lặp foreach. Các lớp Generic Collection hỗ trợ IEnumerable<T> cũng giống như các lớp non-generic như ArrayList hỗ trợ IEnumerable .
Để biết thêm thông tin về generics, xem Generics (C# Programming Guide).

c. Sử dụng kiểu var


Nếu bạn thích, bạn có thể tránh được cú pháp generic bằng từ khóa var. Từ khóa var chỉ thị trình biên dịch tự định kiểu theo giá trị được gán. Tuy nhiên nếu truy vấn LINQ trả về 1 kiểu vô danh (anonymos) thì bạn bắt buộc phải dùng kiểu var.

Ví dụ 1 (có thể dùng var):


    var customerQuery =
    from cust in customers
    where cust.City == "London"
    select cust;

Ví dụ 2 (bắt buộc dùng var):


    var customerQuery =
    from cust in customers
    where cust.City == "London"
    selet new { ID = cust.ID, CityName = cust.City };   // truy vấn trả về kiểu vô danh

3. Truy vấn cơ bản LINQ (C#)


Chủ đề này giới thiệu ngắn gọn các biểu thức truy vấn LINQ và một số mệnh đề điển hình mà bạn thực hiện trong một truy vấn. thông tin chi tiết hơn có trong các chủ đề sau:

LINQ Query Expressions (C# Programming Guide)
Standard Query Operators Overview
Walkthrough: Writing Queries in C# (LINQ)

Lấy 1 nguồn dữ liệu 


Trong một truy vấn LINQ, bước đầu tiên là xác định nguồn dữ liệu. Trong C# và hầu hết các ngôn ngữ lập trình khác một biến phải được khai báo trước khi nó có thể được sử dụng. Trong một truy vấn LINQ, mệnh đề from được viết đầu tiên để khai báo nguồn dữ liệu, đi kèm là biến phạm vi.

Trong ví dụ dưới đây nguồn dữ liệu là customers và biến phạm vi là cust: 

//queryAllCustomers is an IEnumerable<Customer>
var queryAllCustomers = from cust in customers
                        select cust;


Biến phạm vi giống như các biến lặp trong một vòng lặp foreach ngoại trừ việc không có 1 sự lặp lại thực sự xảy ra trong một biểu thức truy vấn. Khi truy vấn được thực thi, biến phạm vi sẽ có nhiệm vụ như là một tham chiếu đến từng phần tử kế tiếp trong customers. Bởi vì trình biên dịch có thể suy ra kiểu của biến cust , bạn không cần phải xác định kiểu tường minh.

Lọc (Filter)


Có lẽ 1 trong các hoạt động truy vấn phổ biến nhất là áp dụng một bộ lọc. Bộ lọc khiến cho truy vấn trả về chỉ những phần tử thỏa yêu cầu. Sử dụng mệnh đề where kèm theo một biểu thức boolean để thực hiện lọc. Trong ví dụ sau đây, chỉ những custommers có địa chỉ ở London được trả về.

var queryLondonCustomers = from cust in customers
                           where cust.City == "London"
                           select cust;

Bạn có thể sử dụng toán tử AND (&&)OR (||) quen thuộc trong C# để áp dụng nhiều biểu thức lọc khi cần thiết. Ví dụ, để trả về chỉ có khách hàng từ "London" có tên là "Devon" bạn sẽ viết đoạn code sau:

var queryLondonCustomers = from cust in customers
                           where cust.City=="London" && cust.Name == "Devon"
                           select cust;

Trả về chỉ những khách hàng đến từ London hoặc Pari bạn sẽ viết đoạn code sau:

var queryLondonCustomers = from cust in customers
                                                      where cust.City == "London" || cust.City == "Pari"                               select cust;

Để biết thêm thông tin, xem where clause (C# Reference)

Sắp xếp (Sorting)


Các mệnh đề orderby mặc định sẽ sắp xếp phần tử theo thứ tự tăng dần . Ví dụ, truy vấn sau đây thực hiện sắp xếp danh sách customers theo thứ tự tăng dần theo Name.

    var queryLondonCustomers3 =
    from cust in customers
    where cust.City == "London"
    orderby cust.Name ascending
    select cust;

Ngược lại, để sắp xếp giảm dần sử dụng mệnh đề orderby…descending

    var queryLondonCustomers3 =
    from cust in customers
    where cust.City == "London"
    orderby cust.Name descending
    select cust;

Gom nhóm (Group)


Mệnh đề group cho phép bạn nhóm kết quả trả về dựa trên một khóa (key) mà bạn chỉ định. Ví dụ bạn có thể chỉ định kết quả trả về sẽ được nhóm theo City để có thể phân các khách hàng ở London và Paris thành các nhóm riêng. Trong trường hợp này Cust.City là 1 khóa (key).

  // queryCustomersByCity is an IEnumerable<IGrouping<string, Customer>>
  var queryCustomersByCity =
      from cust in customers
      group cust by cust.City;

  // customerGroup is an IGrouping<string, Customer>
  foreach (var customerGroup in queryCustomersByCity)
  {
      Console.WriteLine(customerGroup.Key);
      foreach (Customer customer in customerGroup)
      {
          Console.WriteLine("    {0}", customer.Name);
      }
  }


Khi bạn kết thúc truy vấn với mệnh đề group, kết quả trả về của bạn mang hình thức như một danh sách của danh sách.

Nếu bạn cần tham chiếu các kết quả của một group operation, bạn có thể sử dụng từ khóa into để tạo ra một định danh có thể được truy vấn thêm. Các chỉ truy vấn sau trả về những nhóm có chứa nhiều hơn hai khách hàng.

// custQuery is an IEnumerable<IGrouping<string, Customer>>
  var custQuery =
    from cust in customers
    group cust by cust.City into custGroup
    where custGroup.Count() > 2
    orderby custGroup.Key
    select custGroup;
  }

Để biết thêm thông tin, xem group clause (C# Reference).

Nối (Joining)


Sử dụng mệnh đề join để có thể trả về 1 kết quả được tổng hợp từ nhiều nguồn lại với nhau. Ví dụ, bạn có thể sử dụng join để tìm tất cả các khách hàng và nhà phân phối có cùng một vị trí.

    var innerJoinQuery =
    from cust in customers
    join dist in distributors on cust.City equals dist.City
    select new { CustomerName = cust.Name, DistributorName = dist.Name };


Để biết thêm thông tin, xem join clause (C# Reference).

Chọn (Selection)


Mệnh đề select xác định kiểu trả về của truy vấn LINQ. Ví dụ, bạn có thể xác định xem kết quả của bạn sẽ trả về 1 đối tượng Customer hoàn chỉnh với đầy đủ các thuộc tính hoặc một số loại kết quả hoàn toàn khác nhau dựa trên tính toán hay tạo đối tượng mới.

Khi bạn dùng mệnh select để trả về 1 kiểu dữ liệu mới thì đó được gọi là chiếu( projection). Việc sử dụng projection để chuyển đổi dữ liệu là một khả năng mạnh mẽ của các biểu thức truy vấn LINQ. 

Để biết thêm thông tin, xem Data Transformations with LINQ (C#)select clause (C# Reference).

4. Lời kết


LINQ là 1 công nghệ rất mạnh trong .NET Framework, nhờ LINQ thì việc truy vấn dữ liệu từ bất cứ nguồn dữ liệu nào đều dễ dàng và thống nhất 1 cú pháp chung. Người ta ví rằng 1 developer học C# nhưng không biết đến LINQ cũng giống như khi bạn sang Trung Quốc nhưng không đến Vạn Lý Trường Thành :)). Hi vọng qua biết viết này đã giúp bạn hiểu rõ về LINQ và sử dụng thành thạo nó trong nhiều dự án sắp tới. 

Thứ Năm, 11 tháng 5, 2017

Sử dụng class NOCSRF để ngăn chặn tấn công CSRF trong PHP


Giới thiệu


Khi xây dựng 1 ứng dụng hoặc 1 website sử dụng PHP, bạn cần quan tâm đến vấn đề bảo mật.

Một trong nhiều cách thức tấn công được sử dụng bởi những tin tặc (hackers) là Cross-Site Request Forgery (CSRF) chúng ta có thể hiểu là tấn công bằng cách mạo danh 1 website hay ứng dụng nào đó. Để hiểu rõ về CSRF thì bạn có thể đọc bài viết SERIES BẢO MẬT NHẬP MÔN – CSRF – NHỮNG CÚ LỪA NGOẠN MỤC của tác giả Phạm Huy Hoàng.

Bài viết này sẽ hướng dẫn bạn sử dụng class NOCSRF, 1 class đơn giản viết bằng PHP5 nhằm phòng chống CSRF.

Download


Trước hết bạn tải class NOCSRF ở địa chỉ https://github.com/BKcore/NoCSRF

Sử dụng


Bước 1: Giả sử mình có file test.php và giờ mình muốn dùng class NOCSRF trong file đó thì nội dung bên trong file sẽ như sau:

// Token được lưu trữ ở session nên bạn phải khởi tạo session
session_start();
// Khai báo file nocsrf.php từ mã nguồn tải về. Đường dẫn bạn có thể thay đổi tùy
// vào nơi bạn đặt file nocsrf.php
require_once('nocsrf.php');

Bước 2: Sử dụng method NoCSRF::generate() để sinh ra 1 token và gán qua biến $token

$token = NoCSRF::generate( 'csrf_token' );



 Giá trị chuỗi 'csrf_token' thực chất là key của session sẽ được tạo ra.

Bước 3: Cuối cùng bạn đặt giá trị $token vào thẻ input hidden trong form của bạn

<form name="csrf_form" action="#" method="post">
    <input type="hidden" name="csrf_token" value="<?php echo $token; ?>">
    ...Other form inputs...
    <input type="submit" value="Send form">
</form>

Bước 4: Bên code xử lý khi form được submit bạn đặt khối try catch như sau:

try
{
    NoCSRF::check( 'csrf_token'$_POST, true, 60*10, false );
    // lệnh của bạn
}
catch ( Exception $e )
{
    // Bị tấn công CSRF
}

Method NoCSRF::check() để kiểm tra tính hợp lệ của token. Cú pháp tổng quát của method này như sau:

NoCSRF :: check ($key, $origin [, $throwException [, $timespan [, $multiple]]]) 



  • Tham số $key (String): key của session lưu giữ token.
  • Tham số $origin (Mixed): đối tượng/mảng để truy xuất dữ liệu token (thường là $_POST)
  • Tham số $throwException (Boolean): ném ngoại lệ hoặc không ném ngoại lệ khi kiểm tra thất bại. Nếu gán true tức là sẽ ném ra ngoại lệ, false thì method sẽ trả về giá trị Boolean. Ở ví dụ này mình truyền giá trị true vào nên chúng ta mới xài khối try catch, nếu bạn truyền vào là false thì ko dùng try catch mà bạn gán giá trị trả về của method check qua 1 biến và kiểm tra xem biến đó giá trị true hay false mà xử lý.
  • Tham số $timespan (Integer): Giá trị token sẽ hết hạn sau 1 khoảng thời gian (giây). Mặc định là không bao giờ. 
  • Tham số $multiple (Boolean): Tái sử dụng token hoặc không (nên gán true nếu là 1 yêu cầu ajax nặng)
Ở ví dụ này mình chỉ định token được lưu giữ 60*10 s = 10 phút, dùng cách ném ngoại lệ khi lỗi kiểm tra token và không tái sử dụng token.  


Nếu nhảy vào khổi catch tức bạn đang bị tấn công CSRF từ 1 người dùng mạo danh website của bạn. Bạn có thể viết code xử lý tùy ý ví dụ như thông báo lỗi hoặc chuyển hướng người dùng đó về trang chủ.

Kiểm tra


Để kiểm tra xem mọi thứ đã hoạt động tốt chưa thì bạn có thể sử dụng POSTMAN để gửi 1 yêu cầu giả mạo đến trang web của bạn. 

Chúc bạn cài đặt thành công.

Thứ Năm, 4 tháng 5, 2017

Tạo AutoComplete TextBox trong ASP.NET MVC 5

Bài viết này hướng dẫn bạn tạo chức năng AutoComplete (gợi ý từ khóa search) trên textbox trong ASP.NET MVC 5 bằng cách dùng thư viện jQuery UI.

Hình minh họa


Ở hướng dẫn này mình demo bằng cách gợi ý danh sách thành phố (City) khi người dùng nhập tên thành phố vào ô textbox. Bạn làm tương tự với dữ liệu khác nhé.

Bắt đầu nào ^^

Bước 1: Tạo 1 project MVC Application và đặt tên là AutoCompleteInMVCJson.

Bước 2: Tạo class City.cs trong thư mục Models, nội dung như sau:

  1. public class City  
  2.   {  
  3.       public int Id { getset; }  
  4.       public string Name { getset; }  
  5.   
  6.   }  

Bước 3: Mở HomeController.cs và định nghĩa thêm 1 action method đặt tên là AutoCompleteCity như sau:

  1. using System.Collections.Generic;  
  2. using System.Linq;  
  3. using System.Web.Mvc;  
  4. using AutoCompleteInMVCJson.Models;   
  5. namespace AutoCompleteInMVCJson.Controllers  
  6. {  
  7.     public class HomeController : Controller  
  8.     {  
  9.         // GET: Home  
  10.         [HttpGet]  
  11.         public ActionResult Index()  
  12.         {  
  13.             return View();  
  14.         }  
  15.         [HttpPost]  
  16.         public JsonResult AutoCompleteCity(string Prefix)  
  17.         {  
  18.             //Note : you can bind same list from database  
  19.             List<City> ObjList = new List<City>()  
  20.             {  
  21.   
  22.                 new City {Id=1,Name="Latur" },  
  23.                 new City {Id=2,Name="Mumbai" },  
  24.                 new City {Id=3,Name="Pune" },  
  25.                 new City {Id=4,Name="Delhi" },  
  26.                 new City {Id=5,Name="Dehradun" },  
  27.                 new City {Id=6,Name="Noida" },  
  28.                 new City {Id=7,Name="New Delhi" }  
  29.   
  30.         };  
  31.             //Searching records from list using LINQ query  
  32.             var CityName = (from N in ObjList  
  33.                             where N.Name.StartsWith(Prefix)  
  34.                           select new { N.Name });  
  35.             return Json(CityName, JsonRequestBehavior.AllowGet);  
  36.         }  
  37.     }  
  1. }  

Đoạn lệnh trong action AutoCompleteCity thực hiện lấy danh sách City có Name bắt đầu bằng chuỗi Prefix lấy ra từ tham số. Giá trị của chuỗi Prefix chính là chuỗi người dùng nhập ở textbox. 

Sau khi lọc các City thỏa điều kiện thì chúng ta gán qua biến CityName là 1 danh sách các Name của các City thỏa điều kiện. Cuối cùng là trả về  kết quả dưới dạng Json. 

Lưu ý: tên tham số phải là Prefix, điều này là bắt buộc bạn không được đặt tên khác.

Bước 4: Khai báo thư viện jQuery và jQuery UI trong view _Layout.cshtml của bạn như dưới

  1. <link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">  
  2. <script src="//code.jquery.com/jquery-1.10.2.js"></script>  
  3. <script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>  


Bước 5: Đặt ID của textbox của bạn 1 tên bất kỳ. Ở bài viết này mình đặt là CityName.

<input type="textbox" name="CityName" id="CityName" />

Bước 6: Dán đoạn lệnh sau vào dưới lệnh khai báo ở bước 4

  1. <script type="text/javascript">  
  2.     $(document).ready(function () {  
  3.         $("#CityName").autocomplete({  
  4.             source: function (request, response) {  
  5.                 $.ajax({  
  6.                     url: "/Home/AutoCompleteCity",  
  7.                     type: "POST",  
  8.                     dataType: "json",  
  9.                     data: { Prefix: request.term },  
  10.                     success: function (data) {  
  11.                         response($.map(data, function (item) {  
  12.                             return { label: item.Name, value: item.Name };  
  13.                         }))  
  14.   
  15.                     }  
  16.                 })  
  17.             },  
  18.             messages: {  
  19.                 noResults: "", results: ""  
  20.             }  
  21.         });  
  22.     })  
  23. </script>  


Xong. Bạn thử build website và nhập ký tự l vào textbox thì sẽ nhận được kết quả như hình dưới là thành công

Cài đặt autocomplete thành công cho textbox CityName

Mọi thắc mắc bạn comment dưới bài viết để mình giải đáp nhé.