C# cơ bản .NET Core

Trong phần này sẽ tìm hiểu về Map ánh xạ URL request đến một Middleware xử lý, đọc các thông tin mà yêu cầu gửi đến server (Request), Xử lý upload file, đọc và ghi cookie, trả về nội dung Json.

Tạo dự án thực hành - ứng dụng Web với .NET Core - sử dụng Webpack đóng gói CSS, JS

Để thực hành tạo lại dự án một ứng dụng Web với .NET Core, ứng dụng Web này là dạng cơ bản để tìm hiểu chi tiết về các nguyên lý nên chưa sử dụng .NET Core MVC. Tạo một thư mục lưu code dự án, ví dụ WebApp, hãy vào thư mục đó, gõ lệnh sau để tạo cấu trúc dự án

dotnet new web

Mở thư mục đó ra bằng Visual Studio Code (code .), Tại VSC chọ menu View > Command Palette ... rồi chọn .NET: Generate Assets for Build and Debug để VSC sinh ra cấu hình build ở thư mục .vscode

Sử dụng Webpack để đóng gói JS, CSS, SCSS

Ở ví dụ trước bạn đã sử dụng BuildBundlerMinifier để gộp CSS, JS. Tuy nhiên để linh hoạt hơn từ phần này sẽ sử dụng Webpack với .NET Core (về Webpack xem chi tiết tại: Sử dụng Webpack ), sẽ thực hiện từng bước để tích hợp BootStrap, JQuery và một file nguồn SCSS tự động build thành CSS.

Sử dụng Webpack

Gõ các lệnh sau

npm init -y                                         # tạo file package.json cho dự án
npm i -D webpack webpack-cli                        # cài đặt Webpack
npm i node-sass postcss-loader postcss-preset-env   # cài đặt các gói để làm việc với SCSS
npm i sass-loader css-loader cssnano                # cài đặt các gói để làm việc với SCSS, CSS
npm i mini-css-extract-plugin cross-env file-loader # cài đặt các gói để làm việc với SCSS
npm install copy-webpack-plugin                     # cài đặt plugin copy file cho Webpack
npm install npm-watch                               # package giám sát file  thay đổi


npm install bootstrap                               # cài đặt thư viện bootstrap
npm install jquery                                  # cài đặt Jquery
npm install popper.js                               # thư viện cần cho bootstrap

Sau các lệnh này các package trên được tải về lưu tại node_modules, giờ đến bước cấu hình Webpack để khi chạy nó có được mục đích sau:

  • Copy jquery.min.js từ package jquery ra thư mục wwwroot/js
  • Copy popper.min.js từ package popper.js ra thư mục wwwroot/js
  • Copy bootstrap.min.js từ package bootstrap ra thư mục wwwroot/js
  • Biên dịch file src/scss/site.scss thành file wwww/css/site.min.css (đã gộp cả CSS của Bootstrap)
1 soạn file nguồn src/scss/site.scss có nội dung cơ bản như sau:
//Gộp Bootstrap
// Có thể thiết lập các biến biến như màu $warning ...
@import '../../node_modules/bootstrap/scss/bootstrap.scss';

// Thêm code SCSS
.mainbackground {
    background-color: #673ab7;
  }
2 Tạo file cấu hình webpack.config.js có nội dung cơ bản như sau: Nội dung file webpack.config.js
3 Cập nhật package.json - mở file này, đảm bảo thêm vào những dòng bôi đậm sau:
{
    /...
    "main": "index.js", 
      "watch": {
        "build": "src/scss/site.scss"
      },
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1", 
        "build": "webpack",
        "watch": "npm-watch"
      },

      "keywords": [],
    /...
}

Nội dung file đầy đủ tại Package.json

4 Chạy Webpack: Với cấu hình như trên, mỗi lần gõ lệnh
npm run build
Nó sẽ sinh ra các file .js, .css tương ứng lưu ở wwwwroot/css hay wwwroot/js

Hoặc nếu muốn, tự động mỗi khi cập nhật site.scss thì Webpack tự chạy thì kích hoạt script

npm run watch
Chú ý, ở lớp Startup, phương thức Configure, cần có dòng code sau để truy cập được file tĩnh (nhờ middleware StaticFileMiddleware)
app.UseStaticFiles();

Rẽ nhánh pipeline xử lý yêu cầu truy vấn

RequestDelegate và điểm cuối trong pipeline

Ở phần trước nói về Middleware Middleware và Pipeline C# NET CORE chúng ta đã biết khi một yêu cầu gửi đến ứng dụng thì một đối tượng HttpContext sẽ lần lượt đi qua các Middleware, tất nhiên nó có thể rẽ nhánh ở một Middleware nào đó, cho tới một Middleware cuối cùng.

RequestDelegate là một delegate có tham số là HttpContext bạn có thể tạo ra đối tượng này và cấu hình để nó trở thành điểm cuối của pipeline, điểm cuối của các nhánh trong pipeline. Ta thực hiện những điều này trong phương thức Configure của lớp Startup

Để có một phương thức kiểu RequestDelegate thường viết dưới dạng Anonymous như sau:

async (HttpContext context) => {
   /... code thi hành trong RequestDelegate
}
// Hoặc
async (context) => {
   /... code thi hành trong RequestDelegate
}

Trong đường pipeline bạn có thể thêm vào điểm cuối một RequestDelegate trong trường hợp không bị rẽ nhánh bởi EndpointMiddleware, ví dụ:

public void Configure (IApplicationBuilder app, IWebHostEnvironment env) {
        /.. các cấu hình khác

        // Điểm cuối của pipeline không bị rẽ nhánh, HttpContext đi qua tất cả các Middleware đến điểm cuối này
        // Thường là trường hợp yêu cầu truy vấn không đúng địa chỉ (not found)s
        app.Run (async (HttpContext context) => {
            context.Response.StatusCode = StatusCodes.Status404NotFound;
            await context.Response.WriteAsync ("Nội dung");
        });
}

Phương thức IApplicationBuilder.Run để tạo một điểm cuối trong pipeline

Rẽ nhánh pipeline bởi EndpointMiddleware

EndpointRoutingMiddleware có chức năng phân tích yêu cầu gửi đến (Url, Method ...) và chuyển hướng yêu cầu đến một RequestDelegate phù hợp định nghĩa bởi endpoint - là điểm cuối của nhánh, có nghĩa tại đây pipeline có thể được chia ra nhiều nhánh.

Để đưa EndpointRoutingMiddleware là một điểm trong pipeline sửa dụng

app.UseRouting();

Sau khi đưa EndpointRoutingMiddleware vào pipeline, các điểm rẽ nhánh được định nghĩa bằng sử dụng phương thức IApplicationBuilder.UseEndpoints với cú pháp

app.UseEndpoints ((IEndpointRouteBuilder  endpoints) => {

    // Tại đây là code, sử dụng endpoints (IEndpointRouteBuilder) tạo các điểm cuối
    // Hình thành lên các nhánh rẽ ra từ EndpointRoutingMiddleware

});

IEndpointRouteBuilder có nhiều phương thức để tạo ra điều hướng tức là thêm vào các đối tượng lớp RouteEndpoint phù hợp với yêu cầu gửi đến, một vài trong số đó là:

  • Map(pattern, requestDelegate) : pattern là chuỗi với Url gửi đến, requestDelegate là RequestDelegate thi hành. Ví dụy tạo RouteEndpoint phù hợp khi truy vấn đến địa chỉ /Abc
    endpoints.Map("/Abc", async httpcontext => {
        await httpcontext.Response.WriteAsync ("Truy cập /Abc");
    });
    

    Chuỗi /Abc định nghĩa là khi Url truy cập phù hợp với nó (bằng nó), tuy nhiên nó được định nghĩa còn phức tạp hơn gọi là các mẫu định tuyển (route template).

    Hãy xem ví dụ:

    endpoints.Map("/product/{productid:int}", async httpcontext => {
    
        // Đọc giá trị productid gửi đến
        var idproduct = httpcontext.Request.RouteValues["productid"];
    
        // Đọc giá trị Query
        var numberorder = httpcontext.Request.Query["order"];
    
         await httpcontext.Response.WriteAsync ($"Sản phẩm {idproduct}, order = {numberorder}");
    });
    

    Với định nghĩa trên thì các url truy cập tới có dạng /product/123, /product/567?order=10 ... là phù hợp với RouteEndpoint này. Trong đó productid là tên giá trị route nó như một biến, :int là ràng buộc (cho biết productid phải là một số nguyên), bạn có thể viết nhiều dàng buộc liên tiếp nhau, dàng buộc rất phong phú như :alpha, :regex ... - xem thêm tại: route-constraint-reference

  • Các phương thức MapGet(pattern, requestDelegate), MapDelete(pattern, requestDelegate), MapPost(pattern, requestDelegate), MapPut(pattern, requestDelegate) có cách sử dụng tương tự Map, chỉ có điều khác là nó phù hợp với phương thức truy vấn đến cụ thể get, delete, post, put
  • MapMethods(pattern, httpMethods, requestDelegate) dùng khi muốn chỉ định chấp nhận các phương thức cụ thể khai báo trong danh sách httpMethods. Ví dụ, chấp nhận yêu cầu có phương thức put, delete, post:

    endpoints.MapMethods("/cart", new string[] {"put", "post", "delete"},
    async context => {
    
        var method = context.Request.Method;
    
        await context.Response.WriteAsync ("Method: {method}");
    
    });

    Ngoài ra còn có các phương thức mở rộng khi dùng với MVC ... sẽ nói khi đến phần đó nhứ:

    • IEndpointRouteBuilder.MapControllers - ánh xạ URL tới Controller - tìm hiểu ở các phần sau
    • IEndpointRouteBuilder.MapRazorPages - ánh xạ URL tới trang Razor - tìm hiểu phần sau

Rẽ nhánh pipeline bởi IApplicationBuilder.Map

Bạn có thể tạo điểm rẽ nhánh trong pipeline bằng cách sử dụng trực tiếp phương thức Map trong IApplicationBuilder, điểm rẽ nhánh này tương tự cách sử dụng EndpointMiddleware ở trên. Cú pháp như sau:

app.Map(pathMatch, (IApplicationBuilder app) => {

    // Sử dụng app để xử lý yêu cầu, ví dụ tạo endpoint
    app.Run(async context => {

        await context.Response.WriteAsync ("Xin chào! (app.Map)");

    });
});

Trong đó pathMatch là chuỗi mẫu phù hợp cho Url

Ứng dụng Route, tìm hiều Request, Response, Upload File, Cookies, Json

Phần này ta sẽ xây dựng ứng dụng mẫu trên áp dụng các kỹ thuật Route đã trình bày, qua đó tìm hiểu thêm về HttpContext, HttpRequest, HttpReposee, thực hiệ upload file dữ liệu, sử dụng cookie và trả về nội dung JSON ...

Sử dụng Route xây dựng các địa chỉ Url gửi đến

Ứng dụng sẽ xây dựng với yêu cầu gồm các Urls nó phục vụ như sau:

URL Chức năng
/RequestInfo Đọc và hiện thị các thông tin về Request truy cập
/Encoding Demo tính năng encoding dữ liệu khi xuất HTML
/Cookies Demo - Đọc và ghi cookie
/Json Demo trả về dữ liệu JSON
/Form Demo - Hiện thị Form HTML, xử lý đọc thông tin từ Form, kể cả xử lý upload file

Với yêu cầu cho các Route trên là:

  • /RequestInfo, /Encoding, Cookies được điều hướng bởi EndpointMiddleware
  • /Json/Form được điều hướng do rẽ nhánh bởi app.Map

Đáp ứng yêu cầu trên, trước mắt cấu trúc Route xây dựng được như sau:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace _03.RequestResponse {
    public class Startup {

        // Đăng ký các dịch vụ sử dụng bởi ứng dụng, services là một DI container
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDistributedMemoryCache();
            services.AddSession();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure (IApplicationBuilder app, IWebHostEnvironment env) {
            if (env.IsDevelopment ()) {
                app.UseDeveloperExceptionPage ();
            }
            app.UseStaticFiles();
            app.UseSession();

            // Điều hướng route bởi EndpointMiddleware
            // Rẽ nhánh nếu Url phù hợp định nghĩa trong UseEndpoints,  nếu không chuyển đến Middleware tiếp
            app.UseRouting();
            app.UseEndpoints(endpoints => {

                endpoints.MapGet("/", async context =>
                {
                    await  context.Response.WriteAsync("Trang chủ");
                });

                endpoints.Map("/RequestInfo", async context => {
                    // xây dựng chức năng /RequestInfo ở đây
                    await context.Response.WriteAsync("/RequestInfo");
                });

                endpoints.MapGet("/Encoding", async context => {
                    // xây dựng chức năng Encoding  ở đây
                    await context.Response.WriteAsync("/Encoding");
                });

                endpoints.MapGet("/Cookies/{*action}", async context => {
                    // xây dựng chức năng Cookies ở đây
                    await context.Response.WriteAsync("/Cookies");
                });

            });

            // Điểm rẽ nhánh pipeline khi URL là /Json
            app.Map("/Json", app => {
                app.Run(async context => {
                    // code ở đây
                    await context.Response.WriteAsync("/Json");
                });
            });

            // Điểm rẽ nhánh pipeline khi URL là /Form
            app.Map("/Form", app => {
                app.Run(async context => {
                    // code ở đây
                    await context.Response.WriteAsync("/Form");
                });
            });


            app.Run (async (HttpContext context) => {
                context.Response.StatusCode = StatusCodes.Status404NotFound;
                await context.Response.WriteAsync ("Page not found!");
            });

        }
    }
}

Hãy truy cập các Url để kiểm tra

Xây dựng lớp tiện ích HtmlHelper

Để hỗ trợ sinh ra HTML nhanh chóng và có sử dụng Bootstrap trình bày, xây dựng lớp tĩnh với các phương thức phát sinh HTML như sau: Tạo file HtmlHelper.cs và định nghĩa lớp như tại HtmlHelper.cs (copy code này và lưu lại). Lớp tĩnh HtmlHelper xây dựng trên có vài phương thức để hỗ trợ sinh trang HTML nhanh hơn cho ví dụ này, gồm:

HtmlHelper.HtmlDocument(string title, string content) Trả về chuỗi HTML của trang, content là phần nằm trong thẻ body, trang đã tích hợp CSS Bootstrap
String.HtmlTag(string tag = "p", string _class = null) Tạo thẻ, nội dung trong thẻ chuỗi gốc.

Ngoài ra còn có các phương thức như: MenuTop, DefaultMenuTopItems, HtmlTrangchu ... xem chi tiết trong mã nguồn

Mở Startup, cập nhật ánh xạ khi truy cập trang chủ theo url là /

/..
app.UseEndpoints (endpoints => {
    /..

    endpoints.MapGet ("/", async context => {
        string menu = HtmlHelper.MenuTop (HtmlHelper.DefaultMenuTopItems (), context.Request);
        string content = HtmlHelper.HtmlTrangchu ();
        string html = HtmlHelper.HtmlDocument ("Trang chủ", menu + content);
        await context.Response.WriteAsync (html);
    });
    /..
}
/..

Gõ lệnh dotnet run, kiểm tra http://localhost:5000

Trang trên có dùng Bootstrap, nên giao diện của nó cũng responsive (thay đổi phù hợp kích thức màn hình)

Đọc thông tin HttpRequest cơ bản

Tra truy vấn đến trang web, thông tin của nó sẽ chứa trong đối tượng lớp HttpRequest, đối tượng này lấy được từ HttpContext là tham số của RequestDelegate. Từ đối tượng lớp HttpRequest chỉ việc đọc các thuộc tính, ta sẽ biết được thông tin request như: Phương thức gì (POST, GET, UPDATE ...), Path, Query ...

Xây dựng một lớp, để đọc thông tin này như sau - lớp tĩnh đặt tên là RequestProcess, đầu tiên là định nghĩa phương thức RequestInfo:

RequestProcess.cs
using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Http;
namespace _03.RequestResponse
{
    public static class RequestProcess
    {

        // Đọc các thông tin cơ bản của Request
        // Trả về HTML trình  bày các thông tin đó
        public static string RequestInfo(HttpRequest request) {

            var sb = new StringBuilder();

            // Lấy http scheme (http|https)
            var scheme  =  request.Scheme;
            sb.Append(("scheme".td() + scheme.td()).tr());

            // HOST Header
            var host = (request.Host.HasValue ? request.Host.Value : "no host");
            sb.Append(("host".td() + host.td()).tr());


            // Lấy pathbase (URL Path - cho Map)
            var pathbase = request.PathBase.ToString();
            sb.Append(("pathbase".td() + pathbase.td()).tr());

            // Lấy Path (URL Path)
            var path = request.Path.ToString();
            sb.Append(("path".td() + path.td()).tr());

            // Lấy chuỗi query của URL
            var QueryString = request.QueryString.HasValue ? request.QueryString.Value : "no query string";
            sb.Append(("QueryString".td() + QueryString.td()).tr());

            // Lấy phương thức
            var method = request.Method;
            sb.Append(("Method".td() + method.td()).tr());

            // Lấy giao thức
            var Protocol = request.Protocol;
            sb.Append(("Protocol".td() + Protocol.td()).tr());

            // Lấy ContentType
            var ContentType = request.ContentType;
            sb.Append(("ContentType".td() + ContentType.td()).tr());

            // Lấy danh sách các Header và giá trị  của nó, dùng Linq để lấy
            // Header gửi đến lưu trong thuộc tính Header  kiểu Dictionary
            var listheaderString = request.Headers.Select((header) => $"{header.Key}: {header.Value}".HtmlTag("li"));
            var headerhmtl = string.Join("", listheaderString).HtmlTag("ul"); // nối danh sách thành 1
            sb.Append(("Header".td() + headerhmtl.td()).tr());

            // Lấy danh sách các Header và giá trị  của nó, dùng Linq để lấy
            var listcokie = request.Cookies.Select((header) => $"{header.Key}: {header.Value}".HtmlTag("li"));
            var cockiesHtml = string.Join("", listcokie).HtmlTag("ul");
            sb.Append(("Cookies".td() + cockiesHtml.td()).tr());


            // Lấy tên và giá trí query
            var listquery = request.Query.Select((header) => $"{header.Key}: {header.Value}".HtmlTag("li"));
            var queryhtml = string.Join("", listquery).HtmlTag("ul");
            sb.Append(("Các Query".td() + queryhtml.td()).tr());

            //Kiểm tra thử query tên abc có không
            Microsoft.Extensions.Primitives.StringValues abc;
            bool existabc = request.Query.TryGetValue("abc",  out abc);
            string queryVal = existabc ? abc.FirstOrDefault() : "không có giá trị";
            sb.Append(("abc query".td() + queryVal.ToString().td()).tr());

            string info =  "Thông tin Request".HtmlTag("h2") + sb.ToString().HtmlTag("table", "table table-sm table-bordered");
            return  info;
        }

    }
}

Tiếp theo, mở lớp Startup thêm vào RequestDelegate - chuyên xử lý Url truy vấn /RequestInfo thì gọi đến RequestInfo ở trên để lấy HTML chứa thông tin Request

app.UseEndpoints(endpoints =>
{
    /..
    endpoints.Map ("/RequestInfo", async context => {
        string menu = HtmlHelper.MenuTop (HtmlHelper.DefaultMenuTopItems (), context.Request);
        string requestinfo = RequestProcess.RequestInfo (context.Request).HtmlTag ("div", "container");
        string html = HtmlHelper.HtmlDocument ("Thông tin Request", (menu + requestinfo));
        await context.Response.WriteAsync (html);
    });
    /..

});

Truy cập http://localhost:5000/RequestInfo/abc/xyz?id=10

Đọc thông Post từ Form HTML và xử lý Upload File

Trước tiên tạo một file formtest.html chứa Form sẽ hiện thị, nội dung file đó như sau: Form Test (lưu file này lại). Nó sẽ được đọc vào bằng phương thức File.ReadAllTextAsync("formtest.html") khi cần nội dung của nó.

Khi Form submit, dữ liệu Form gửi đến biểu diễn bằng đối tượng kiểu IFormCollection tại thuộc tính HttpRequest.Form

Từ đối tượng này để đọc một dữ liệu có tên trên Form HTML nào đó thì sử dụng indexer để truy cập, ví dụ lấy giá trị phần tử Form tên abc

var abc = _form["abc"].FirstOrDefault() ?? null;

Đối với file, thì các file upload lưu tại thuộc tính HttpRequest.Files, nó là danh sách các phần tử kiểu IFormFile - có thể duyệt qua Files để xử lý tất cả các file upload đến.

Từ đối tượng IFormFile, toàn bộ dữ liệu file có thể chuyển vào một stream (file trên server, hay bộ nhớ .. tùy cách tạo ra stream) bằng

IFormFile.CopyToAsync(stream);

Tiếp tục, xây dựng phương thức FormProcess để xử lý khi Form gửi đến (submit) như sau:

public static class RequestProcess
{
    /..

    // Xử lý khi HTML Form post dữ liệu
    public static async Task<string> FormProcess(HttpRequest request) {
        //Xử lý đọc dữ liệu Form - khi post - dữ liệu này trình  bày trên Form
        string hovaten  = "";
        bool   luachon  = false;
        string email    = "";
        string password = "";
        string thongbao = "";

        // Đọc dữ liệu từ Form do truy vấn gửi đến (chỉ xử lý khi là post)
        if (request.Method ==  "POST") {
            IFormCollection _form = request.Form;

            email    = _form["email"].FirstOrDefault() ?? "";
            hovaten  = _form["hovaten"].FirstOrDefault() ?? "";
            password = _form["password"].FirstOrDefault() ?? "";
            luachon  =  (_form["luachon"].FirstOrDefault() == "on");

            thongbao = $@"Dữ liệu post - email: {email}
                          - hovaten: {hovaten} - password: {password}
                          - luachon: {luachon} ";


            // var filePath = Path.GetTempFileName();
            // Xử lý nếu có file upload (hình ảnh,  ... )
            if (_form.Files.Count > 0) {
                string thongbaofile = "Các file đã upload: ";
                foreach (IFormFile formFile in _form.Files)
                {
                    if (formFile.Length > 0)
                    {
                        var filePath = "wwwroot/upload/"+formFile.FileName;    // Lấy tên  file
                        if (!Directory.Exists("wwwroot/upload/"))  Directory.CreateDirectory("wwwroot/upload/");
                        thongbaofile += $"{filePath} {formFile.Length} bytes";
                        using (var stream = new FileStream(filePath, FileMode.Create)) // Mở stream để lưu file, lưu file ở thư mục wwwroot/upload/
                        {
                             await formFile.CopyToAsync(stream);
                        }
                    }

                }
                thongbao += "<br>" + thongbaofile;
            }

        }
        string format   =  await File.ReadAllTextAsync("formtest.html");   // Đọc nội dung HTML từ file
        string formhtml = string.Format(format, hovaten, email, luachon ? "checked" : "");
        return formhtml + thongbao;
    }

    /..

}

Tiếp theo, mở lớp Startup thêm vào:

// Điểm rẽ nhánh pipeline khi URL là /Form
app.Map ("/Form", app => {
    app.Run (async context => {

        string menu = HtmlHelper.MenuTop (HtmlHelper.DefaultMenuTopItems (), context.Request);
        string formhtml = await RequestProcess.FormProcess (context.Request);
        formhtml = formhtml.HtmlTag ("div", "container");
        string html = HtmlHelper.HtmlDocument ("Form Post", (menu + formhtml));
        await context.Response.WriteAsync (html);

    });
});

Truy cập http://localhost:5000/Form, điền thông tin và chọn file rồi bấm Submit kiểm tra:

Chú ý: mặc định kích thước file lớn nhất cho Upload là 30MB, nếu muốn điều chỉnh thì điều chỉnh tại lớp Program

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>()
                      .UseKestrel(options => {
                            options.Limits.MaxRequestBodySize = 104857600; // 100 MB - Cho phép upload
                      });
        });

Sử dụng HtmlEncoder trong C#

Khi dữ liệu xuất không thuộc cấu trúc HTML đã kiểm duyệt, bạn cần encode để an toàn, hoặc bạn muốn in các chuỗi với những ký tự như <, > ...

Để Encode chuỗi nào đó, sử dụng

stringencode = HtmlEncoder.Default.Encode(stringvalue);

Tiếp tục cho phương thức sau vào lớp RequestProcess

public static string Encoding(HttpRequest request) {
    Microsoft.Extensions.Primitives.StringValues data;
    bool   existdatavalue = request.Query.TryGetValue("data",  out data);
    string datavalue      = existdatavalue ? data.FirstOrDefault() : "không có giá trị";

    Microsoft.Extensions.Primitives.StringValues e;
    bool   existevalue    = request.Query.TryGetValue("e",  out e);
    string evalue         = existevalue ? e.FirstOrDefault() : "không có giá trị";

    string dataout;
    if (evalue == "0") {
        // Không encode dữ liệu xuất
        dataout = datavalue;
    }
    else {
        // encode dữ liệu xuất
        dataout = HtmlEncoder.Default.Encode(datavalue);
    }
    string encoding_huongdan =  File.ReadAllText("encoding.html");

    return dataout.HtmlTag("div", "alert alert-danger") + encoding_huongdan;
}

Trong đó, file encoding.html có nội dung: encoding.html

Startup
app.UseEndpoints(endpoints =>
{
    /..
    endpoints.MapGet ("/Encoding", async context => {
        string menu = HtmlHelper.MenuTop (HtmlHelper.DefaultMenuTopItems (), context.Request);
        string htmlec = RequestProcess.Encoding (context.Request).HtmlTag ("div", "container");
        string html = HtmlHelper.HtmlDocument ("Encoding", (menu + htmlec));
        await context.Response.WriteAsync (html);
    });
    /..

});

Sử dụng Cookie

Định nghĩa về Cookie xem tại Cookie

Phương thức sau thêm vào lớp RequestProcess, có lưu và đọc Cookie

public static string Cookies(HttpRequest request, HttpResponse response) {

    string tb = "";
    switch (request.Path) {
        case "/Cookies/read":
            var listcokie = request.Cookies.Select((header) => $"{header.Key}: {header.Value}".HtmlTag("li"));
            tb = string.Join("", listcokie).HtmlTag("ul");
        break;
        case "/Cookies/write":
            response.Cookies.Append("masanpham", "12345",
                new CookieOptions {
                        Path = "/Cookies",
                        Expires = DateTime.Now.AddDays(1)}
            );
            tb = "Đã lưu Cookie  -  masanpham - hết hạn 1 ngày".HtmlTag("div", "alert alert-danger");
        break;
    }

    string cookies_huongdan =  File.ReadAllText("cookies.html");


    return tb + cookies_huongdan;
}

File cookies.html có nội dung cookies.html

Cập nhật lớp Startup
app.UseEndpoints(endpoints =>
{
    /..
    endpoints.MapGet("/Cookies/{*action}", async (context) => {
        string menu     = HtmlHelper.MenuTop(HtmlHelper.DefaultMenuTopItems(), context.Request);
        string cookies  = RequestProcess.Cookies(context.Request, context.Response).HtmlTag("div", "container");
        string html    = HtmlHelper.HtmlDocument("Đọc / Ghi Cookies", (menu + cookies));
        await context.Response.WriteAsync(html);
    });
    /..

});

Trả về nội dung Json

Trả về nội dung Json (nhất là khi xây dựng cá API ứng dụng), để làm việc với Json thì cần cài đặt thêm Newtonsoft.Json

dotnet add package Newtonsoft.Json

Sau đó để sử dụng cần nạp namespace

using Newtonsoft.Json;

Ở đây, để chuyển đối tượng lớp vô danh thành Json thì làm như sau với JsonConvert.SerializeObject:

public static string GetJson() {
    var productjson = new {
        name  = "IPhone 11",
        price =  1000
    };
    return JsonConvert.SerializeObject(productjson);
}

Một Respone thiết lập cho biết nó trả về Json thì cần gán ContentType của Response bằng "application/json"

Cập nhật lớp Startup
// Điểm rẽ nhánh pipeline khi URL là /Json
app.Map ("/Json", app => {
    app.Run (async context => {
        string Json  = RequestProcess.GetJson();
        context.Response.ContentType = "application/json";
        await context.Response.WriteAsync(Json);
    });
});

Chú ý, với .NET Core 3.0 có hỗ trợ xử lý JSON mà không cần cài đặt thêm các Package. Ví dụ System.Text.Json.JsonSerializer.Serialize(productjson) tương đương với JsonConvert.SerializeObject(productjson) ở trên.

Mã nguồn ASP_NET_CORE/03.RequestResponse hoặc tải về tại ex049


Đăng ký nhận bài viết mới