Tìm hiểu lớp từ cổ Việt-Hán
TÌM HIỂU VỀ LỚP TỪ CỔ VIỆT HÁN QUA CÁC CỨ LIỆU NGỮ ÂM LỊCH SỬ
(About the Viet-Han ancient words class through
the historical phonetic data)[1]
Phan Anh Dũng
Trung tâm Công nghệ Thông tin Thừa Thiên Huế
Tóm tắt:
Bài viết đưa ra bảng so sánh các từ cổ Việt-Hán trong tiếng Việt với các tư liệu phục nguyên âm thượng cổ Hán ngữ của các từ này theo các tác giả Bernhard Karlgren ( 高本漢 ), William H. Baxter ( 白一平 ) , Vương Lực ( 王力 ) … Từ đó rút ra một số nhận xét đánh giá về nguồn gốc lớp từ cổ Việt Hán này.
1. Khái quát.
Bài này tiếp tục một số bài viết trước của tác giả về mối quan hệ giữa Hán ngữ cổ đại với các ngôn ngữ họ Nam Á (Austro-Asia). Và đặt vấn đề xem xét lại nguồn gốc của Hán ngữ, phải chăng Hán ngữ có thể không phải chỉ có nguồn gốc Tạng Miến mà còn có một phần có gốc từ họ Nam-Á mà đại diện tiêu biểu là nhóm Mon-Khmer ?
Các nghiên cứu về xếp loại ngôn ngữ cho tiếng Việt đã chỉ rõ rằng, về lớp từ cơ bản tức là lời ăn tiếng nói hàng ngày thì tiếng Việt phải xếp vào họ Nam Á, nhóm Môn-Khmer, phản ánh “tiếng mẹ đẻ” của người Việt chính là tiếng nói của cư dân bản địa vùng châu thổ sông Hồng và xa hơn là miền Trung Việt Nam cổ xưa… nhưng các vấn đề như có thanh điệu phức tạp, xu hướng đơn âm hóa triệt để, kho từ vựng có nhiều từ chung chịu ảnh hưởng của họ Thái-Kadai và Hán-Tạng .v.v. thì lại cho thấy tiếng Việt có thể xếp vào họ Hán Tạng hay Thái-Kadai, đó cũng là cách phân loại của các nhà ngôn ngữ học khoảng năm 1950 về trước, chỉ sau này khi có các số liệu thống kê về số lượng từ cơ bản thì xu hướng xếp tiếng Việt vào họ Nam Á (Mon-Khmer) mới thắng thế.
Người viết cho rằng sau khi vất bỏ các yếu tố hoang đường thì truyền thuyết ghi trong sử Việt về Lạc long quân vốn là dòng dõi Thần Nông có thể phản ánh một sự thực lịch sử, đó là có một nhóm tộc thuộc thị tộc Thần Nông khoảng gần 5000 năm trước đã từ vùng Hồ Động đình dịch chuyển về phía Nam xuống vùng Lưỡng Quảng rồi đi tiếp xuống vùng đồng bằng sông Hồng khoảng hơn 4000 năm trước [2], đó là lúc đồng bằng sông Hồng vừa phát lộ trở lại sau sự kiện “đại hồng thủy” – biển tiến Flandri. Nhóm thị tộc Thần Nông này đã hợp huyết với cư dân bản địa gốc Mon-Khmer ở vùng Thanh Hóa, Hòa Bình cùng tiến xuống biển khai thác vùng đồng bằng vừa mới phát lộ. Cũng theo quan điểm của người viết thì chính cuộc thiên di của thị tộc Thần Nông (Lạc Long Quân) nói trên đã đem đến cho kho từ vựng của người Việt lớp từ “cổ Việt Hán”, lớp từ này tách biệt hẳn về thời gian tới khoảng hai nghìn năm so với lớp từ “Hán Việt” du nhập về sau trong hơn nghìn năm Bắc thuộc, nên cả người Hán lẫn người Việt bình thường (không phải người nghiên cứu về ngôn ngữ) nhìn qua thì khó hình dung ra nguồn gốc chung của chúng.
Về cội nguồn lớp từ cổ Việt Hán, xuất phát từ chỗ thị tộc Lạc Long Quân vốn là một trong các nhóm tộc Bách Việt thời thượng cổ ở lưu vực Trường Giang (phía Nam hồ Động Đình) chứ không phải nhóm Hán tộc phương Bắc ở lưu vực Hoàng Hà, nên người viết cho rằng lớp từ này có gốc Nam Á hay cận Nam Á, và có thể có pha trộn ít nhiều với họ ngôn ngữ Hán-Tạng và Thái-Kadai, vì vùng Hồ Bắc và Hồ Nam vốn là vùng bản lề tiếp xúc của các nhóm tộc Khương (phía Tây Bắc), Hán (phía Bắc và Đông Bắc) và Bách Việt (phía Đông và Nam), Thái-Kadai (Nam và Tây Nam). Các số liệu dẫn chứng dưới đây cũng cho thấy lớp từ cổ Việt Hán bảo lưu được nhiều vết tích ngữ âm cổ và gần với âm Hán thượng cổ hơn là âm Hán trung cổ, vì vậy người viết đã dùng cách gọi “lớp từ cổ Việt Hán” (đặt chữ Việt trước chữ Hán) để nhấn mạnh nguồn gốc cận phương Nam của lớp từ này.
Về sau khi có cuộc thiên di lớn về phía Bắc và “hòa hợp dân tộc” giữa nhóm thị tộc Thần Nông của Viêm Đế với nhóm Hán tộc “chính gốc” phương Bắc của Hoàng Đế ở lưu vực Hoàng Hà, lớp từ “cổ Việt Hán” này có thể đã tham gia hình thành Hán ngữ thượng cổ. Như vậy Hán Ngữ cổ không hẳn là “thuần Tạng-Miến” mà có thể có một phần pha trộn Mon-Khmer.
Về vấn đề các nhóm tộc cổ xưa ở lưu vực Trường Giang nói một thứ ngôn ngữ phương Nam, dẫn chứng mà các nhà nghiên cứu hay nhắc đến là chữ giang 江 vốn có biểu âm là chữ “công”, phù hợp với các ngôn ngữ phương Nam “krông”=”không”=”sông” … Trong bài viết dự Hội thảo nhân một năm ngày mất Giáo sư Nguyễn Tài Cẩn [15] người viết cũng có dẫn ra cứ liệu cho thấy từ “địa 地”, phục nguyên âm thượng cổ theo Baxter là “djejs” có thể cùng gốc với tiếng Mon-Khmer “đây” và tiếng Việt “đất”[3]. Hơn nữa nếu dựa vào bản đồ thiên di của người thượng cổ phát nguyên từ Châu Phi như dưới đây thì các nhóm tộc ở lưu vực Trường Giang vốn từ đồng bằng sông Hồng thiên di về phía bắc cách nay khoảng 1,5 vạn năm, nên việc họ nói một thứ ngôn ngữ phương Nam gần với họ tiếng Việt (Mon-Khmer) là việc khá tự nhiên (http://tieba.baidu.com/f?kz=724009126):
2. Số liệu thống kê và vài nhận xét ban đầu.
Xin xem hai bảng thống kê về lớp từ cổ Việt Hán ở phần phụ lục dưới đây, tuy chỉ là số liệu thống kê sơ bộ nhưng cũng thấy lớp từ này không phải là nhỏ, bảng 1 có hơn 250 chữ. Các số liệu đó đều rút từ tài liệu phục nguyên âm thượng cổ Hán của các nhà nghiên cứu nổi tiếng như Bernhard Karlgren[4] (高本漢 , Cao Bản Hán), William H. Baxter[5] (白一平 , Bạch Nhất Bình) , Vương Lực[6] (王力) … Lưu ý trong bảng đó chúng tôi chủ ý chọn những từ thuộc, hoặc khá gần, lớp từ cơ bản của tiếng Việt, và tránh những từ có vẻ quá gần với âm Hán Việt (âm Hán Trung cổ) để loại trừ khả năng nó là “đọc trại” của âm Hán Việt diễn ra sau khi VN đã giành lại độc lập.
Vài nhận xét sơ bộ:
- Những từ đã thống kê phần nhiều đều là những từ khá cơ bản và thông dụng của tiếng Việt.
- Số lượng từ có thể coi là “thượng cổ Việt Hán” khá lớn dầu mới chỉ thống kê sơ qua, điều đó đủ cho thấy trong tiếng Việt tồn tại một lớp từ còn lưu giữ dấu vết âm Hán thượng cổ cực kỳ xa xưa, theo người viết có thể là từ thời đại Tam Hoàng-Ngũ Đế hay giai đoạn từ Hạ tới đầu Thương.
- Từ các bảng thống kê thấy Baxter phục nguyên với nhiều tiền âm tố và phụ âm đầu kép nên chúng tôi cho rằng Baxter phục nguyên ở mức xưa hơn Karlgren và Vương Lực, có lẽ Baxter không dừng ở mức thượng cổ Hán ngữ mà đã gần tới mức proto-Tạng-Hán (tiền Hán Tạng ngữ), một số từ phải lần đến mức của Baxter mới nhận ra dấu vết tương quan với từ cổ Việt , như rồng (b-rjoŋ, k- rjoŋ), sông (kroŋ), lúa (luʔ=đạo 稻).
- So sánh tương đối trong phạm vi bảng thống kê thấy âm Việt hiện đại của các từ cổ Việt Hán có vẻ gần âm thượng cổ Hán nhất, sau đó mới đến âm Mân Nam rồi âm Quảng Đông, còn âm chính thống của tiếng Hán ngày ngay (Pinyin) lại xa âm Hán thượng cổ hơn cả. Điểm ngạc nhiên là xem trên bản đồ thì Quảng Đông gần VN hơn Mân Nam, nhưng nhiều từ cổ âm tiếng Việt có vẻ giống Mân Nam hơn Quảng Đông.
- Đối với nhóm từ “tươi, lười, tỏi” phục nguyên của 3 tác giả Karlgren, Vương Lực, Baxter đều không có -i cuối mà thống nhất là -n. Nhìn qua ví dụ đó thì tiếng Việt có vẻ như đã biến âm nhiều so với âm thượng cổ trong khi tiếng Hán (tiên 鮮, lãn 懶, toán 蒜) còn giữ khá gần. Nhưng xét kỹ hơn thấy phần biểu âm của chữ “lãn” là chữ “lại”, cho thấy chứng tích của âm cuối -i hay -j thời cổ. Theo GS Nguyễn Tài Cẩn thì thời Kinh Thi nhóm này còn gieo vần với -j , đến Đạo Đức Kinh thì chỉ còn vần với -n, gieo vần với -j còn có thể là -l, -r nhưng nói chung là -i xưa hơn cả -n.
3. Vấn đề niên đại lớp từ cổ Việt Hán:
1- Từ bảng phụ lục có thể thấy là âm tiếng Việt hiện đại của lớp từ cổ Việt Hán còn bảo lưu được nhiều ngữ âm Hán thượng cổ, thậm chí có vẻ còn gần âm Thượng cổ Hán hơn cả âm Hán Trung cổ tức âm Hán Việt định hình khoảng đời Đường.
- Ví dụ về phụ âm đầu (thanh mẫu) : nhóm từ buồng, buộc, búa, bùa, bay, buôn … còn giữ phụ âm đầu b- thời Thượng cổ, trong khi âm Hán Trung cổ đã chuyển thành f- (phòng, phọc, phủ, phù, phi, phán …)
- Ví dụ về vần (vận mẫu): các từ vốn vận bộ ca 歌 tiếng Việt vẫn còn giữ được âm cuối -i, phù hợp với vận bộ ca Thượng cổ vốn có âm cuối là -r, -l, -j. Như ngài (nga), vãi (bá), mài (ma), lưới (la), lái (đà), cái (cá), trái (tả) … Xin xem chi tiết hơn ở phần phân tích thống kê ở dưới về những từ cổ Việt Hán có âm cuối “-i” này, Giáo sư Nguyễn Tài Cẩn từng viết: “Ở trường hợp từ thuần Việt, tuổi của âm cuối *-i như vậy là rất cao, vì nó không những lên đến thời Việt Mường chung mà còn lên đến thời Proto Việt Chứt cách đây đã trên 3000 năm. Có thể có trường hợp -i còn có nguồn gốc xa hơn nữa …”, con số trên 3000 năm này ít nhiều gợi ý cho chúng ta mức độ cổ của lớp từ cổ Việt Hán.
2- Về đại để thì âm Hán Thượng cổ thường được hiểu là ngữ âm tiếng Hán thời Chu, tuy nhiên thời Chu dài đến hơn 800 năm, mà một số từ cổ Việt Hán có thể đến thời Tần-Hán vẫn còn giữ ngữ âm thời Chu, cho nên nếu chỉ dựa vào sự giống nhau nêu trên thì vấn đề niên đại lớp từ cổ Việt Hán vẫn còn khá mơ hồ. Để có định lượng chính xác hơn một chút, chúng tôi căn cứ vào một đoạn mà Giáo sư Nguyễn Tài Cẩn viết trong sách “Giáo trình Lịch sử ngữ âm tiếng Việt”, trang 323: “Những tiếng cổ Hán Việt như tươi, lười, tỏi, vãi chứng minh điều đó: đây là những tiếng có âm cuối -*r hay -*l có khả năng gieo vần với những tiếng có -*j ở giai đoạn Kinh Thi, nhưng đến Đạo Đức Kinh thì chúng chỉ còn gieo vần với những tiếng có -*n. Rõ ràng tươi, lười, tỏi, vãi … đã được du nhập trước quá trình diễn biến -r > -*n, nghĩa là trước thời Tây Hán khá lâu”.
Thời Đạo Đức Kinh là khoảng 600 năm trước CN, còn thời Kinh Thi là khoảng đầu thời Chu, 1000 năm trước CN, như vậy bước đầu chúng ta đã có những con số định lượng tương đối cụ thể cho niên đại lớp từ cổ Việt Hán, việc khảo sát chính xác hơn cần có thời gian.
3- Thêm một dẫn chứng có thể quy kết về niên đại, đó là phục nguyên âm cổ của chữ “chỉ” 趾 (chân), mà chúng tôi từng đưa ra ở bài viết trước [15]. Xin tóm tắt lại như sau: chữ chỉ趾nghĩa là chân, phục nguyên âm Thượng cổ theo Karlgren: ȶi ̯əg, trong khi từ “chân” của tiếng Việt theo Giáo sư Nguyễn Tài Cẩn thời cổ vốn có âm cuối -ŋ, trong sách “Giáo trình Lịch sử ngữ âm tiếng Việt” trang 199 Giáo sư viết: “… chúng ta chỉ có hai ví dụ là từ chân và lên (và liên quan tới lên là từ trên). Ở hai từ này có lẽ ta phải phục nguyên *-ŋ cho thời Proto Việt Chứt, hay chậm nhất thì cũng cho thời Proto Pọng Chứt chung”. Mà Proto Việt Chứt là khoảng hơn 3000 năm trước, tức là cuối đời Thương, tại thời điểm đó đã có sự đối ứng giữa âm cuối -g của Hán ngữ với -ŋ tiếng Việt cổ, còn thấy qua việc chữ “chi” 之 (là chữ vận bộ của chỉ 趾 , cũng có phục nguyên ȶi ̯əg) trong tiếng Việt được dịch thành “chưng”. Người viết ước đoán -g khi đó thực ra không đồng nhất đồng nhất hoàn toàn với -ŋ, mà thời điểm đồng nhất có thể còn xa hơn cả nghìn năm trước, tức là ứng với giai đoạn đầu thời đại Hùng Vương, có thể khi đó âm cuối -g và -ŋ của “chỉ” và “chân” đồng nhất vào âm cuối -ʔ, giống như phục nguyên của Baxter là : tjəʔ .
4- Mức độ “vượt thượng cổ” của lớp từ cổ Việt Hán còn có thể thấy ở một từ đặc biệt, đó là từ thoát 脫 (lọt):
Chữ Hán | Karlgren | Vương Lực | Baxter | Cổ Việt | HánViệt | pinyin |
(Đường âm) | ||||||
脫 | t’wɑt | thuat | hlot | lọt | thoát | tuo1 |
Nếu ai còn nghi ngờ việc phục nguyên của Baxter thì xin xem thêm tài liệu [9] của chính người TQ, cũng phục nguyên âm thượng cổ Hán của 脫 là *hluat và còn cho cả âm Proto Tạng-Miến của nó là *g-lwat như hình dưới, chụp từ tài liệu [9], tài liệu này cũng ủng hộ nhận xét của chúng tôi là Baxter đã phục nguyên rất xa, tới gần thời Proto Hán-Tạng:
4. Vấn đề nguồn gốc lan truyền lớp từ cổ Việt Hán:
Khoảng thời gian 1000-600 năm TCN tạm định ra ở mục trên tách xa hẳn với thời Bắc Thuộc, vậy những từ cổ Việt Hán truyền vào Việt Nam qua đường nào ? Giáo sư Nguyễn Tài Cẩn có đưa ra cách giải thích là nhiều từ gốc Hán người Việt mượn gián tiếp qua Thái-Kadai, ở trang 322 “Giáo trình Lịch sử ngữ âm tiếng Việt” Giáo sư viết : “Các từ như ngan, bừa, cuốc, vãi, phân, bánh, mùa, cam, quýt, tỏi, ao, đầm, chèo… cũng đều có thể là từ gốc Hán; nhưng rất có thể chúng được du nhập vào ngôn ngữ Việt-Mường thông qua Thái-Kadai”. Tuy nhiên các cứ liệu di truyền học Y-ADN mới công bố gần đây lại cho thấy các chỉ số di truyền Y-ADN của người Việt khá xa với nhóm Tày-Nùng ở biên giới Việt-Trung mà lại gần với người Hán Quảng Đông, Quảng Tây và nhóm Choang ở vùng Nam Ninh, thủ phủ Quảng Tây, phía bắc sông Châu Giang. Cho nên người viết đi đến nhận định rằng lớp từ cổ Việt Hán đó là của tổ tiên người Việt truyền lại từ rất xưa, nhiều từ gốc gác có thể trước cả thời Chu nữa, chứ không phải là mượn của Hán ngữ gián tiếp qua Thái-Kadai, và với mức cổ như thế thì cũng không thể nói là mượn của Hán tộc nữa, chẳng qua là quan hệ cùng một gốc xuất xứ thôi. Khoảng 1000-600 năm TCN tức là trước giai đoạn Bắc thuộc khá lâu nên khó có thể cho là người Việt “học” lại người Hán lớp từ này trong thời Bắc thuộc rồi đọc trại đi như ý kiến của một số người.
Từng có giả thuyết cho rằng người Việt (Kinh) vốn từ vùng trung Việt hay trung Lào tiến ra xâm chiếm vùng đồng bằng Bắc Bộ của dân Thái-Kadai, hòa trộn với Thái-Kadai và sau đó đã học nghề trồng lúa cùng với nền văn minh nông nghiệp của dân Thái-Kadai… từ đó nhận định rằng nhóm Thái-Kadai mà đại biểu hiện nay là người Choang, Tày, Nùng mới đúng là cư dân cổ xưa ở vùng đồng bằng sông Hồng chứ không phải dân Kinh. Nhưng niên đại của sự kiện trên có thể khoảng 3500 năm trước[7], tức là rất xa xưa, trước thời Bắc thuộc đến ngàn rưởi năm, trước cả lúc hình thành nền văn minh trống đồng của các nhóm tộc Lạc Việt, nên không thể tách rời người Việt (Kinh) khỏi nền văn minh Lạc Việt cổ với thể hiện tiêu biểu là trống đồng được. Sau đây là vài số liệu so sánh ngôn ngữ về các từ liên quan tới nghề nông giữa hai nhóm Việt-Mường và Thái-Kadai (gồm Tày và Thái đen là hai nhóm Thái-Kadai có địa bàn cư trú tiếp giáp với người Việt) cho thấy giả thuyết trên có điểm đáng ngờ:
Tiếng Việt | Tiếng Mường | Tiếng Tày | Thái đen | Tiếng Hán | Chữ Hán |
Trâu | Tlu | Vài | Quãi | Thủy ngưu | 水牛 |
Bò | Mò | Mò | Ngúa | Ngưu | 牛 |
Cày | Cằl | Thay | Thay | Canh | 耕 |
Bừa | Pừa | Phưa | Ban | Sừ | 耡 |
Ruộng | Nà | Nà | Nã | Điền | 田 |
Mạ | Mã | Chả | Cả | Miêu | 苗 |
Lúa | Lõ | Khẩu | Khảu | Hòa, Đạo | 禾稻 |
Thóc | ? | Khẩu | Khảu | Đạo, Mễ,Cốc | 稻米穀 |
Gạo | Cảo | Khẩu | Khảu | Mễ, Cốc | 稻米穀 |
Rơm | Thóc | Vàng | Phưỡng | Đạo can | 稻杆 |
Rạ | ? | ? | Phưỡng | Đạo can | 稻杆 |
Nhận xét bảng trên:
1- Các từ căn bản liên quan tới nghề trồng lúa tiếng Việt khác nhóm Thái-Kadai nhiều.
2- Tiếng Việt có các từ phân biệt rất chi tiết từ cây mạ cho tới cây lúa, hạt thóc, hạt gạo, rơm, rạ … trong khi Thái gọi chung thóc, lúa, gạo là “khảu”, gọi chung rơm, rạ là “phưỡng”. Tiếng Việt cũng có từ riêng “nghé” để gọi trâu con, còn bò con có tên riêng là “bê”.
3- Con trâu là đầu cơ nghiệp nhà nông nhưng tiếng Việt “trâu” hay tiếng Mường “tlu” lại khác hẳn tiếng Thái đen “kvai” (quãi) và tiếng Tày “vài” (còn đọc là “hoài”), còn con bò tiếng Việt (hay mò tiếng Mường) cũng khác hẳn tiếng Thái đen “ngúa” (có lẽ ngúa cùng gốc với ngưu của nhóm Hán-Tạng ?). Trong lúc đó người Di tận Quý Châu TQ lại gọi con bò là “lɯ” khá giống với tiếng Việt Mường cổ gọi con trâu là “t-lu” … Người Di có thể từng là cư dân cổ xưa vùng Hồ Bắc, Hồ Nam, trong đó có vùng Tương Giang ở Hồ Nam từng được các nhà nghiên cứu TQ gọi là “Cổ Lạc Việt chi địa”, người Di cũng là một trong số ít tộc gốc Hán Tạng nhưng lại có một phần M88, là nhóm nhiễm sắc thể Y-ADN đặc trưng của người Kinh.
4- Người Tày gọi con bò là “mò”, gọi bừa là “phưa”, gần giống tiếng Mường (là lưu ảnh của tiếng Việt cổ) nhưng có thể chính Tày đã mượn của Việt – Mường, vì so sánh thì Thái đen (ở vùng Tây Bắc VN, vốn từ Vân Nam thiên di xuống) gọi bò là “ngúa”, bừa là “ban”, có lẽ đó mới đúng là từ gốc Thái-Kadai.
5- Đặc biệt thú vị là vấn đề từ nguyên của cày/canh:
Từ “cày” trong tiếng Mường là “cằl” (theo từ điển Mường-Việt, Nguyễn Văn Khang chủ biên). Tiếng Việt không phát âm được phụ âm cuối -l nên ký âm “cằl” thường bị đọc ra “cằn”, nhưng xét cấu âm thì có lẽ “cằl” gần với “cănh” hay “canh” hơn, tức đọc gần giống từ Hán Việt “canh 耕” cũng có nghĩa là “cày” (Giáo trình Lịch sử ngữ âm tiếng Việt của GS Nguyễn Tài Cẩn cho biết có nhiều từ tiếng Việt có âm cuối -i, -y vốn gốc từ âm cuối -r, -l, -j tiếng tiền Việt-Mường). Nếu dựa theo các vết tích khảo cổ về nghề trồng lúa ở đồng bằng Bắc Bộ từ cả ngàn năm trước Công nguyên và hiện tượng là tiếng Việt không có từ nào khác thay thế cho “cày” cả thì phải mạnh dạn đặt giả thuyết cằl/cày là một từ mà tổ tiên Việt-Mường đã truyền lại từ thời xa xưa, trước thời kỳ Bắc Thuộc rất lâu, chứ không phải Việt-Mường mới đi mượn từ “canh” của Hán tộc sau khi bị đô hộ rồi đọc trại ra “cằl” rồi thành “cày”, và càng không phải là tiếp thu từ “thay” của nhóm Thái-Kadai.
Về nguồn gốc phương Nam của “canh”, “cằl”, “cày” tạm thời chưa bàn sâu vì vấn đề này dễ gây tranh cãi lạc đề. Tuy nhiên cũng phải nói thẳng ra rằng thời đại “Thần Nông”, ông tổ nghề trồng lúa, vốn cũng chỉ là truyền thuyết, chưa có cứ liệu khoa học chắc chắn nào chứng minh thị tộc Thần Nông là gốc Hán tộc ở Hoàng Hà, là gốc Khương ở Tứ Xuyên hay là gốc Bách Việt ở Trường Giang cả. Còn nếu đơn thuần căn cứ vào vị trí địa lý của lăng Viêm Đế thì lăng này ở huyện Viêm Lăng, tỉnh Hồ Nam, phía đông nam Hành Dương thị khá xa về phía nam của hồ Động Đình, lại nằm ngay trong vùng đất “Cổ Lạc Việt chi địa”, rất xa với vùng lưu vực Hoàng Hà, cội nguồn của Hán tộc. Vùng Tương Giang “Cổ Lạc Việt chi địa” này vốn là đất “man di”, mãi đến khoảng thế kỷ 3-4 trước CN mới bị nước Sở thôn tính, rồi sau đó nhập vào TQ thời Tần, Hán [8].
Using SOAP Headers
Using SOAP Headers
Communicating with an XML Web service method using SOAP follows a standard format. Part of this format is the data that is encoded in an XML document. The XML document consists of a root Envelope tag, which in turn consists of a required Body element and an optional Header element. The Body element comprises the data specific to the message. The optional Header element can contain additional information not directly related to the particular message. Each child element of the Header element is called a SOAP header.
Although the SOAP headers can contain data related to the message, as the SOAP specification doesn’t strictly define the contents of a SOAP header, they typically contain information processed by infrastructure within a Web server. An example of how a SOAP header can be used is to supply routing information for the SOAP message within the SOAP header.
Defining and Processing SOAP Headers
XML Web services created using ASP.NET can define and manipulate SOAP headers. Defining a SOAP header is accomplished by defining a class representing the data in a particular SOAP header and deriving it from the SoapHeader class.
To define a class representing a SOAP header
- Create a class deriving from the SoapHeaderclass with a name matching the root element for the SOAP header.
public class MyHeader : SoapHeader [Visual Basic] Public Class MyHeader : Inherits SoapHeader
- Add public fields or properties, matching the names and their respective data types for each element in the SOAP header.For instance, given the following SOAP header, the class following it defines a class representing the SOAP header.
public class MyHeader : SoapHeader { public DateTime Created; public long Expires; } [Visual Basic] Public Class MyHeader Inherits SoapHeader Public Created As DateTime Public Expires As Long End Class
To process SOAP headers within an XML Web service
- Add a public member to the class implementing the XML Web service of the type representing the SOAP header.
[WebService(Namespace="http://www.contoso.com")] public class MyWebService { // Add a member variable of the type deriving from SoapHeader. public MyHeader timeStamp; [Visual Basic] <WebService(Namespace:="http://www.contoso.com")> _ Public Class MyWebService ' Add a member variable of the type deriving from SoapHeader. Public TimeStamp As MyHeader
- Apply a SoapHeader attribute to each XML Web service method that intends to process the SOAP header. Set the MemberName property of the SoapHeaderattribute to the name of the member variable created in the first step.
[WebMethod] [SoapHeader("timeStamp")] public void MyWebMethod() [Visual Basic] <WebMethod, SoapHeader("TimeStamp")> _ Public Sub MyWebMethod()
- Within each XML Web service method that the SoapHeaderattribute is applied to, access the member variable created in the first step to process the data sent in the SOAP header.
[WebMethod] [SoapHeader("timeStamp", Direction=SoapHeaderDirection.InOut)] public string MyWebMethod() { // Verify that the client sent the SOAP Header. if (timeStamp == null) { timeStamp = new MyHeader(); } // Set the value of the SoapHeader returned // to the client. timeStamp.Expires = 60000; timeStamp.Created = DateTime.UtcNow; return "Hello World"; } [Visual Basic] <WebMethod,SoapHeader("TimeStamp", _ Direction:=SoapHeaderDirection.InOut)> _ Public Function MyWebMethod() As String ' Verify that the client sent the SOAP Header. If (TimeStamp Is Nothing) Then TimeStamp = New MyHeader End If ' Set the value of the SoapHeader returned ' to the client. TimeStamp.Expires = 60000 TimeStamp.Created = DateTime.UtcNow Return "Hello World" End Function
The following code example demonstrates how to define and process a SOAP header in an XML Web service created using ASP.NET. The MyWebService
XML Web service has a member variable named timeStamp
, which is of a type deriving from SoapHeader (MyHeader
) and set to the MemberName property of the SoapHeader attribute. In addition, a SoapHeader attribute is applied to the MyWebMethod
XML Web service method specifying myHeaderMemberVariable
. Within the MyWebMethod
XML Web service method, myHeaderMemberVariable
is accessed to set the value of the Created
and Expires
XML elements of the SOAP header.
<%@ WebService Language="C#" Class="MyWebService" %> using System; using System.Web.Services; using System.Web.Services.Protocols; // Define a SOAP header by deriving from the SoapHeader class. public class MyHeader : SoapHeader { public DateTime Created; public long Expires; } [WebService(Namespace="http://www.contoso.com")] public class MyWebService : System.Web.Services.WebService { // Add a member variable of the type deriving from SoapHeader. public MyHeader timeStamp; // Apply a SoapHeader attribute. [WebMethod] [SoapHeader("timeStamp", Direction=SoapHeaderDirection.InOut)] public string HelloWorld() { if (timeStamp == null) timeStamp = new MyHeader(); timeStamp.Expires = 60000; timeStamp.Created = DateTime.UtcNow; return "Hello World"; } } [Visual Basic] <%@ WebService Language="VB" Class="MyWebService" %> Imports System Imports System.Web.Services Imports System.Web.Services.Protocols ' Define a SOAP header by deriving from the SoapHeader class. Public Class MyHeader Inherits SoapHeader Public Created As DateTime Public Expires As Long End Class <WebService(Namespace:="http://www.contoso.com")> _ Public Class MyWebService Inherits System.Web.Services.WebService ' Add a member variable of the type deriving from SoapHeader. Public timeStamp As MyHeader ' Apply a SoapHeader attribute. <WebMethod(), _ SoapHeader("timeStamp", Direction:=SoapHeaderDirection.InOut)> _ Public Function HelloWorld() As String If (timeStamp Is Nothing) Then timeStamp = New MyHeader End If timeStamp.Expires = 60000 timeStamp.Created = DateTime.UtcNow Return "Hello World" End Function End Class
In the previous example, a SOAP response is returned to the client with the Expires
element set to 60000 (number of milliseconds, so 1 minute) and the Created
element to the current time in coordinated universal time. That is, the following SOAP response is sent to the client.
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Header> <MyHeader xmlns="http://www.contoso.com"> <Created>dateTime</Created> <Expires>long</Expires> </MyHeader> </soap:Header> <soap:Body> <MyWebMethod xmlns="http://www.contoso.com" /> </soap:Body> </soap:Envelope>
Building a Client that Processes SOAP Headers
An XML Web services client can send and receive SOAP headers when communicating with an XML Web service. When a proxy class is generated for an XML Web service expecting or returning SOAP headers using the Wsdl.exe utility, the proxy class includes information about the SOAP headers. Specifically, the proxy class has member variables representing the SOAP headers that correlate to those found in the XML Web service. The proxy class also has definitions for the corresponding classes representing the SOAP header. For example, proxy classes generated for the previous XML Web service will have a member variable of type MyHeader
and a definition for the MyHeader
class. For details on creating a proxy class, see Creating an XML Web Service Proxy.
Note: If the XML Web service defines the member variables representing the SOAP headers of type SoapHeader or SoapUnknownHeader instead of a class deriving from SoapHeader, a proxy class will not have any information about that SOAP header.
To process SOAP headers within an XML Web service client
- Create a new instance of the class representing the SOAP header.
Dim mySoapHeader As MyHeader = New MyHeader() [C#] MyHeader mySoapHeader = new MyHeader();
- Populate the values for the SOAP header.
header.Expires = 60000 header.Created = DateTime.UtcNow [C#] header.Expires = 60000; header.Created = DateTime.UtcNow;
- Create a new instance of the proxy class.
Dim proxy As MyWebService = New MyWebService() [C#] MyWebService proxy = new MyWebService();
- Assign the SOAP header object to the member variable of the proxy class representing the SOAP header.
proxy.MyHeaderValue = mySoapHeader [C#] proxy.MyHeaderValue = mySoapHeader
- Call the method on the proxy class that communicates with the XML Web service method.The SOAP header portion of the SOAP request sent to the XML Web service will include the contents of the data stored in the SOAP header object.
Dim results as String = proxy.MyWebMethod() [C#] string results = proxy.MyWebMethod();
The following code example demonstrates how to pass a SOAP header from a client to an XML Web service.
<%@ Page Language="VB" %> <asp:Label id="ReturnValue" runat="server" /> <script runat=server language=VB> Sub Page_Load(o As Object, e As EventArgs) Dim header As MyHeader = New MyHeader() ' Populate the values of the SOAP header. header.Expires = 60000 header.Created = DateTime.UtcNow ' Create a new instance of the proxy class. Dim proxy As MyWebService = New MyWebService() ' Add the MyHeader SOAP header to the SOAP request. proxy.MyHeaderValue = header ' Call the method on the proxy class that communicates ' with your XML Web service method. Dim results as String = proxy.MyWebMethod() ' Display the results of the method in a label. ReturnValue.Text = results End Sub </script> [C#] <%@ Page Language="C#" %> <asp:Label id="ReturnValue" runat="server" /> <script runat=server language=c#> void Page_Load(Object o, EventArgs e) { MyHeader header = new MyHeader(); // Populate the values of the SOAP header. header.Expires = 60000; header.Created = DateTime.UtcNow; // Create a new instance of the proxy class. MyWebService proxy = new MyWebService(); // Add the MyHeader SOAP header to the SOAP request. proxy.MyHeaderValue = header; // Call the method on the proxy class that communicates // with your XML Web service method. string results = proxy.MyWebMethod(); // Display the results of the method in a label. ReturnValue.Text = results; } </script>
Changing the SOAP Headers Recipients
By default, SOAP headers are sent by an XML Web service client to an XML Web service method when a SoapHeader attribute is applied to an XML Web service method. However, a SOAP header can also be sent by the XML Web service method back to the XML Web service client. It can also be sent both ways. Setting the Direction property of a SoapHeader attribute applied to an XML Web service method controls the recipient of the SOAP header. The Direction property is of type SoapHeaderDirection, which has four values: In, Out, InOut, and Fault. These refer to the recipient (whether it is the XML Web service server), to the client, or both the XML Web service server and client, and whether the SOAP header is sent to the client when an exception is thrown by the XML Web service, respectively.
Note: Version 1.0 of the .NET Framework SDK does not support the Fault value.
To change the SOAP header recipient
- Define the SOAP header.
public class MyHeader : SoapHeader { public DateTime Created; public long Expires; } [Visual Basic] Public Class MyHeader Inherits SoapHeader Public Created As DateTime Public Expires As Long End Class
- Add a member variable to the class implementing the XML Web service.
[WebService(Namespace="http://www.contoso.com")] public class MyWebService : WebService { public MyHeader myOutHeader; [Visual Basic] <WebService(Namespace:="http://www.contoso.com")> _ Public Class MyWebService Inherits WebService Public myOutHeader As MyHeader
- Apply a SoapHeader attribute to each XML Web service method that processes the SOAP header. Set the Direction property to each intended recipient, using the SoapHeaderDirection enumeration. The following example sets the XML Web service client as the recipient by setting Direction to SoapHeaderDirection.Out.
[WebMethod] [SoapHeader("myOutHeader",Direction=SoapHeaderDirection.Out)] [Visual Basic] <WebMethod, _ SoapHeader("myOutHeader",Direction:=SoapHeaderDirection.Out)>
- Process or set the SOAP header, depending on the recipient. The following code example sets the values of the SOAP header, as the recipient is the XML Web service client.
// Set the Time the SOAP message expires. myOutHeader.Expires = 60000; myOutHeader.Created = DateTime.UtcNow; [Visual Basic] ' Set the Time the SOAP message expires. myOutHeader.Expires = 60000 myOutHeader.Created = DateTime.UtcNow
The following code example defines a MyHeader
SOAP header that is sent from the XML Web service method to the client.
<%@ WebService Language="C#" Class="MyWebService" %> using System; using System.Web.Services; using System.Web.Services.Protocols; // Define a SOAP header by deriving from the SoapHeader class. public class MyHeader : SoapHeader { public DateTime Created; public long Expires; } [WebService(Namespace="http://www.contoso.com")] public class MyWebService : WebService { public MyHeader myOutHeader; [WebMethod] [SoapHeader("myOutHeader",Direction=SoapHeaderDirection.Out)] public void MyOutHeaderMethod() { // Set the time the SOAP message expires. myOutHeader.Expires = 60000; myOutHeader.Created = DateTime.UtcNow; } } [Visual Basic] <%@ WebService Language="VB" Class="MyWebService" %> Imports System Imports System.Web.Services Imports System.Web.Services.Protocols ' Define a SOAP header by deriving from the SoapHeader class. Public Class MyHeader Inherits SoapHeader Public Created As DateTime Public Expires As Long End Class <WebService(Namespace:="http://www.contoso.com")> _ Public Class MyWebService Inherits WebService Public myOutHeader As MyHeader <WebMethod, _ SoapHeader("myOutHeader",Direction:=SoapHeaderDirection.Out)> _ Public Sub MyOutHeaderMethod() ' Set the time the SOAP message expires. myOutHeader.Expires = 60000 myOutHeader.Created = DateTime.UtcNow End Sub End Class
Handling Unknown SOAP Headers
An XML Web service client can send a SOAP request with a SOAP header to an XML Web service method that the XML Web service might not have explicitly defined that it was expecting. In this case, it is important to determine whether the semantics of the SOAP header are understood and processed, as the SOAP specification states that an exception is thrown when SOAP headers have a mustUnderstand attribute set to true. For details on handling SOAP headers required by a client, see Handling SOAP Headers Required by an XML Web Service Client.
To handle unknown SOAP headers from an XML Web service client
- Add a member variable to the class implementing the XML Web service with a type of SoapUnknownHeader or SoapHeader, or an array of either, to handle multiple unknown SOAP headers.Declaring the type as either an array or a single instance of SoapUnknownHeader has the added benefit that SoapUnknownHeader has an Element property. The Element property is of type XmlElement and represents the XML document for the Header element of the SOAP request or SOAP response. Thus, an XML Web service method can determine the name of the SOAP header, along with the data passed by the SOAP header, by interrogating the Elementproperty.
public class MyWebService { public SoapUnknownHeader[] unknownHeaders; [Visual Basic] Public Class MyWebService Public unknownHeaders() As SoapUnknownHeader
- Apply a SoapHeader attribute to each XML Web service method that intends to process each unknown SOAP header.
[WebMethod] [SoapHeader("unknownHeaders")] public string MyWebMethod() [Visual Basic] <WebMethod, _ SoapHeader("unknownHeaders") > _ Public Function MyWebMethod() As String
- Add code to determine whether you can process any unknown SOAP headers.If the member variable is of type SoapUnknownHeader, an XML Web service method can determine the name of the SOAP header, along with the data passed by the SOAP header, by interrogating the Element property. The Name property of Elementproperty identifies the name of the SOAP header.
foreach (SoapUnknownHeader header in unknownHeaders) { // Check to see if this a known header. if (header.Element.Name == "MyKnownHeader") [Visual Basic] Dim header As SoapUnknownHeader For Each header In unknownHeaders ' Check to see if this is a known header. If (header.Element.Name = "MyKnownHeader") Then
- Set the DidUnderstand property of the member variable representing the unknown SOAP header to trueif it is known how to process a particular SOAP header.If an XML Web service method does process an unknown SOAP header and does not set the DidUnderstand property to true, a SoapHeaderException can be thrown. For more details, see Handling SOAP Headers Required by an XML Web Service Client
// Check to see if this is a known header. if (header.Element.Name == "MyKnownHeader") header.DidUnderstand = true; else // For those headers that cannot be // processed, set DidUnderstand to false. header.DidUnderstand = false; } [Visual Basic] ' Check to see if this a known header. If (header.Element.Name = "MyKnownHeader") Then header.DidUnderstand = True Else ' For those headers that cannot be ' processed, set DidUnderstand to false. header.DidUnderstand = False End If
Note The DidUnderstand property is used by XML Web services created using ASP.NET to communicate with the XML Web service method. It is not part of the SOAP specification. Its value does not appear in any part of the SOAP request or SOAP response.
Note When an XML Web service client builds a proxy class using the Web Services Description Language Tool (Wsdl.exe) and an XML Web service defines the member variable representing a SOAP header using the SoapUnknownHeader type, no reference to that SOAP header is added to the proxy class. If an XML Web service client decides to add that SOAP header to the SOAP request, they must modify the proxy class by adding a member variable and applying a SoapHeader attribute to the method making the call to the pertinent XML Web service method.
Handling SOAP Headers Required by an XML Web Service Client
A client can require an XML Web service method to interpret the semantics of the SOAP header correctly and process it accordingly for the SOAP request to succeed. To do so, clients set the mustUnderstand attribute of the SOAP header to 1. For instance, the following SOAP request requires the SOAP request recipient to process the MyCustomSoapHeader
SOAP header.
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" > <soap:Header> <MyCustomSoapHeader soap:mustUnderstand="1" xmlns="http://www.contoso.com"> <custom>Keith</custom> </MyCustomSoapHeader> </soap:Header> <soap:Body> <MyUnknownHeaders xmlns="http://www.contoso.com" /> </soap:Body> </soap:Envelope>
Whether the XML Web service defines the SOAP header or not determines how the XML Web service should handle SOAP headers required by the client. ASP.NET handles a lot of the work in the case where the XML Web service defines the SOAP header. In the procedure that follows, you can learn how to handle the two cases.
To handle SOAP headers not defined by the XML Web service, but required by an XML Web service client
- Follow the steps for handling unknown SOAP headers from an XML Web service client, paying particular attention to the DidUnderstandproperty of the SOAP header.For SOAP headers not defined by the XML Web service, the initial value of DidUnderstand is false. If ASP.NET detects SOAP headers with their DidUnderstand property set to false after the XML Web service method returns, a SoapHeaderException is automatically thrown.
To handle SOAP headers required by an XML Web service client and defined by the XML Web service
- Follow the steps for processing SOAP headers within an XML Web service created using ASP.NET within each XML Web service method.For SOAP headers defined by the XML Web service and processed in the XML Web service method receiving the SOAP header, ASP.NET assumes the XML Web service understands the SOAP header and sets the initial value of DidUnderstand to true.
The following MyWebService
XML Web service defines the MyHeader
SOAP header and requires it to be sent with any calls to the MyWebMethod
XML Web service method. Additionally, the MyWebMethod
processes any unknown SOAP headers. For the SOAP headers MyWebMethod
can process, DidUnderstand is set to true.
<%@ WebService Language="C#" Class="MyWebService" %> using System.Web.Services; using System.Web.Services.Protocols; // Define a SOAP header by deriving from the SoapHeader base class. public class MyHeader : SoapHeader { public string MyValue; } public class MyWebService { public MyHeader myHeader; // Receive all SOAP headers other than the MyHeader SOAP header. public SoapUnknownHeader[] unknownHeaders; [WebMethod] [SoapHeader("myHeader")] //Receive any SOAP headers other than MyHeader. [SoapHeader("unknownHeaders")] public string MyWebMethod() { foreach (SoapUnknownHeader header in unknownHeaders) { // Perform some processing on the header. if (header.Element.Name == "MyKnownHeader") header.DidUnderstand = true; else // For those headers that cannot be // processed, set DidUnderstand to false. header.DidUnderstand = false; } return "Hello"; } } [Visual Basic] <%@ WebService Language="VB" Class="MyWebService" %> Imports System.Web.Services Imports System.Web.Services.Protocols ' Define a SOAP header by deriving from the SoapHeader base class. Public Class MyHeader : Inherits SoapHeader Public MyValue As String End Class Public Class MyWebService Public myHeader As MyHeader ' Receive all SOAP headers other than the MyHeader SOAP header. Public unknownHeaders() As SoapUnknownHeader <WebMethod, _ SoapHeader("myHeader"), _ SoapHeader("unknownHeaders")> _ Public Function MyWebMethod() As String 'Receive any SOAP headers other than MyHeader. Dim header As SoapUnknownHeader For Each header In unknownHeaders ' Perform some processing on the header. If header.Element.Name = "MyKnownHeader" Then header.DidUnderstand = True ' For those headers that cannot be ' processed, set DidUnderstand to false. Else header.DidUnderstand = False End If Next header Return "Hello" End Function End Class
Note The DidUnderstand property is used by ASP.NET to communicate with the XML Web service method. It is not part of the SOAP specification; its value does not appear in any part of the SOAP request or SOAP response.
If an XML Web service forwards a SOAP header, it is very important to follow the rules in the SOAP specification, especially those pertaining to the value of the Actor. For details, see the W3C Web site (http://www.w3.org/TR/SOAP/).
Handling Errors That Occur While Processing a SOAP Header
When an XML Web service detects an error specific to the processing of a header, a SoapHeaderException should be thrown. Using this exception class allows XML Web services to correctly format the response. If the client is created using the .NET Framework, it will receive the SoapHeaderException with its contents, including the InnerException property, placed in the Message property. The InnerException property of the SoapHeaderException caught by the client will be null. This is a programming model supported by the .NET Framework, as the exception is sent over the network in a SOAP <Fault> XML element, as prescribed by the SOAP specification. For more details on exceptions, see Handling and Throwing Exceptions in XML Web Services.
The following code example throws a SoapHeaderException if a client makes a SOAP request to the MyWebMethod
XML Web service method setting the Expires
property to a date and time that occurs in the past by the time the SOAP request reaches the XML Web service.
<%@ WebService Language="C#" Class="MyWebService" %> using System.Web.Services; using System.Web.Services.Protocols; // Define a SOAP header by deriving from the SoapHeader class. public class MyHeader : SoapHeader { public DateTime Created; public DateTime Expires; public DateTime Received; } [WebService(Namespace="http://www.contoso.com")] public class MyWebService { // Add a member variable of the type deriving from SoapHeader. public MyHeader myHeaderMemberVariable; // Apply a SoapHeader attribute. [WebMethod] [SoapHeader("myHeaderMemberVariable")] public void MyWebMethod() { if (timeStamp == null) timeStamp = new MyHeader(); else { // Check whether the SOAP message is expired. if ((timeStamp.Expires.CompareTo(DateTime.UtcNow)) <= 0) { // The SOAP message is expired, so throw a SOAP header // exception indicating that. SoapHeaderException se = new SoapHeaderException( "SOAP message expired before reaching this node.", SoapException.ClientFaultCode, this.Context.Request.Url.ToString()); throw se; } } } } [Visual Basic] <%@ WebService Language="VB" Class="MyWebService" %> Imports System.Web.Services Imports System.Web.Services.Protocols ' Define a SOAP header by deriving from the SoapHeader class. Public Class MyHeader Inherits SoapHeader Public Created As DateTime Public Expires As DateTime Public Received As DateTime End Class <WebService(Namespace:="http://www.contoso.com")> _ Public Class MyWebService ' Add a member variable of the type deriving from SoapHeader. Public myHeaderMemberVariable As MyHeader ' Apply a SoapHeader attribute. <WebMethod, _ SoapHeader("myHeaderMemberVariable")> _ Public Sub MyWebMethod() If (TimeStamp Is Nothing) Then TimeStamp = New MyHeader Else ' Check whether the SOAP message is expired. If ((TimeStamp.Expires.CompareTo(DateTime.UtcNow)) <= 0) Then ' The SOAP message is expired, so throw a SOAP header ' exception indicating that. Dim se As New SoapHeaderException( _ "SOAP message expired before reaching this node.", _ SoapException.ClientFaultCode, _ Me.Context.Request.Url.ToString()) Throw se End If End If End Sub End Class
Note: The .NET Framework version 1.0 includes the SoapHeaderAttribute.Required property which enables an XML Web service to require that a client send a specific SOAP header when the property is set to true. ASP.NET indicates that the SOAP header is required in a generated WSDL document by setting the wsdl:required attribute to “true” on the soap:header element. .NET Framework clients of the XML Web service built from the WSDL document receive a SoapHeaderException if they do not send the required SOAP header and other clients receive a SOAP Fault. To interoperate with other SOAP implementations this functionality is removed in later versions.
The Required property is obsolete in version 1.1, and the wsdl:required attribute of a soap:header element in a WSDL document is ignored by the Web Services Description Language tool (Wsdl.exe). Because a SOAP header can no longer be required, an XML Web service should verify that the field or property representing the SOAP header is not null before accessing it.
See Also
SoapHeader | SoapHeaderAttribute | SoapHeaderException | SoapUnknownHeader | Building XML Web Services Using ASP.NET | Building XML Web Service Clients
Về Điền Hòa, Phong Hải du ký
Gió lộng biển xanh bờ cát trắng
Con đường vắng vẻ nắng ban trưa
Họp một bàn bạn hữu ngày xưa
Dễ mấy dịp anh em cùng chạm cốc ?
Kể sự nghiệp được chăng, chăng được
Thôi một ly dốc ngược lại huề
Hôm nay theo bạn về quê
Muốn lên thuyền nhỏ học nghề câu trăng
Vài vần thơ thẩn gọi rằng.
21/07/2013
Ghi chú:
Chiều 20/07 cao hứng theo cậu bạn trẻ Đặng Văn Xuân (ở TT Đào tạo từ xa, Đại học Huế) về quê Điền Hòa (vùng ven biển Phong Điền) chơi.
Xã Điền Hòa là quê thầy Nguyễn Sĩ Hồng nguyên Trưởng khoa Toán-Lý Đại học Tổng hợp Huế hồi mới thành lập, cách đây mấy năm tôi có về đây dự đám tang thầy Hồng, đi cùng với Lê Quý Thông, Lê Thọ, Lê Viết Dũng …. (Lý K1) và một số bạn khác bên khoa Toán.
Buổi chiều ngồi hỏi chuyện thì té ra Xuân là cháu gọi thầy Hồng là cậu.
Trưa hôm sau cả nhóm ra bờ biển, thuộc xã Phong Hải, ngồi nhậu chơi đến chiều, nhân có vài dòng du ký này …