官术网_书友最值得收藏!

3 ASP.NET核心對象

正如上一章所講的,ASP.NET的一個主要特征就是一切皆為對象。其中,有幾個對象非常重要,許多工作都需要使用到。本章將介紹這幾個影響ASP.NET應用工作的核心對象,包括Page、Server、Application,以及Session對象。

3.1 Page類

在用ASP.NET創建的Web系統中,每一個ASPX頁面都繼承自System.Web.UI.Page類,Page類實現了所有頁面最基本的功能,本節介紹其基本概念及一個最簡單的應用。

3.1.1 Page類概述

要理解Page類,首先需要了解Web服務器(IIS)是如何請求ASP.NET頁面,并顯示在瀏覽器上的。在瀏覽器顯示ASPX頁面的整個過程中,IIS負責處理與.NET Framework交互的大量工作。圖3.1所示的是用戶在瀏覽器上請求調用ASP.NET頁面的響應過程。

圖3.1 瀏覽器顯示ASPX頁面的響應過程

1 IIS 將接收這個請求,并識別出將要請求的文件類型為ASPX 文件,然后讓ASP.NET 模塊(aspnet isapi.dll)來處理它。

2 aspnet isapi.dll接收請求,將所請求的頁面實例化為一個ASPX對象,并調用該對象的顯示方法。該方法動態生成HTML,并返回給IIS。

3 IIS將HTML發送給瀏覽器。

這個過程中最重要的對象是ASPX對象,它繼承自.NET Framework類庫的Page類。也可以簡單把Page對象理解為.aspx文件,在頁面上,可以使用Page類的屬性和方法完成一定的功能。

Page類位于System.Web.UI命名空間下,其常用成員如圖3.2所示。

圖3.2 Page類常用成員

Page類常用成員簡單介紹如表3.1所示。

表3.1 Page類常用成員簡單介紹

其中,Request、Response、Server、Application、Session對象,都是Page類的屬性,將在本章后面各節中給予介紹。它們都依附于具體的一個Page對象,即依附于ASPX頁面,而不能單獨使用。

3.1.2 探索頁面生命周期

【本節示例參考:\示例代碼\C03\Page_LifeCycle】

一般來說,一個ASPX頁面從“生”到“死”,要經歷如圖3.3所示的生命周期。前面已經簡單介紹過,這里詳細說明。

圖3.3 ASPX頁面生命周期

(1)請求頁面:頁請求發生在頁生命周期開始之前。

(2)開始:在開始階段,將設置頁屬性,如Request和Response。在此階段,頁面還將確定請求是回發請求還是新請求,并設置IsPostBack屬性。

(3)初始化頁面:頁面初始化期間,可以使用頁中的控件,并將設置每個控件的UniqueID屬性。如果當前請求是回發請求,則回發數據尚未加載,并且控件屬性值尚未還原為視圖狀態中的值。

(4)加載頁面:加載期間,如果當前請求是回發請求,則將使用從視圖狀態和控件狀態恢復的信息加載控件屬性。

(5)驗證:在驗證期間,將調用所有驗證程序控件的Validate方法,此方法將設置各個驗證程序控件和頁的IsValid屬性。

(6)回發事件處理:如果請求是回發請求,則將調用所有事件處理程序。

(7)呈現頁面:在頁面呈現期間,視圖狀態將被保存到頁面,然后頁面將調用每個控件,以將其呈現的輸出提供給頁的Response屬性的OutputStream。

(8)卸載頁面:完全呈現頁、將頁發送至客戶端并準備丟棄時,將調用卸載。此時,將卸載頁屬性(如Response和Request)并執行清理。

與上面的生命周期相對應的Page類的生命周期事件如圖3.4所示。

圖3.4 Page類生命周期事件

Page類生命周期中各個事件的說明如表3.2所示。

表3.2 Page類的生命周期事件

下面的示例說明了Page類的生命周期事件觸發順序。示例的實現很簡單,在Default.aspx頁面的各個事件中,輸出其事件名稱即可。以PreInit事件為例,其默認的事件名為Page PreInit,其余事件與此相同。代碼3-1為PreInit事件的方法。

代碼3-1 PreInit事件方法:Default.cs

    1.   int i=1;
    2.
    3.   ///<summary>
    4.   ///1:PreInit事件
    5.   ///</summary>
    6.   ///<param name="sender"></param>
    7.   ///<param name="e"></param>
    8.   protected void Page_PreInit(object sender,EventArgs e)
    9.   {
    10.     Page.Response.Write(i+":PreInit...<br/>");
    11.     i++;
    12.  }

其余事件的方法與此非常類似,不再一一給出。運行程序后,結果如圖3.5所示。頁面上依次顯示了各個事件的觸發順序。

圖3.5 Page類各個生命周期事件的觸發順序

3.2 ASP.NET核心對象

本節將介紹ASP.NET中最重要的幾個對象:

(1)Response:向瀏覽器輸出信息。

(2)Request:管理訪問者對頁面的請求信息。

(3)Server:提供一些與Web服務器相關的信息。

這幾個對象總是依賴于具體的一個Page類,總是作為Page類的某個屬性出現,下面將逐一介紹它們的常用功能。

3.2.1 利用Response輸出信息

【本節示例參考:\示例代碼\C03\ Example_Response】

Response對象是System.Web.HttpResponse類的實例,主要功能是向瀏覽器輸出信息,常用的屬性和方法如圖3.6所示。

圖3.6 Response對象常用屬性和方法

Response對象常用成員簡單介紹如表3.3所示。

表3.3 Response對象常用成員簡單介紹

下面的示例中,將使用頁面的Response屬性向瀏覽器輸出字符串“Hello”,然后換行后再輸出“World”。

1 新建一個ASP.NET應用程序,雙擊自動添加的Default.aspx頁面,在自動生成的頁面加載事件中,輸入如下代碼。

代碼3-2 利用Response輸出字符串:Default.cs

    1.   protected void Page_Load(object sender,EventArgs e)
    2.   {
    3.      Response.Write("Hello<br/>");
    4.      Response.Write("World");
    5.   }

2 啟動程序,將出現頁面Default.aspx,如圖3.7所示。

圖3.7 使用Response對象向頁面輸出數據

可以看出,使用Response對象的Write方法可以向瀏覽器輸出HTML元素,這樣就有可能根據用戶的響應,動態構建網頁元素。

3.2.2 利用Request獲取頁面輸入

【本節示例參考:\示例代碼\C03\ Example_Request】

動態網頁的最主要特征就是用戶可以在網頁上進行操作,向系統提交各種數據。對于ASPX頁面來說,它利用其Request對象來接收和管理用戶對頁面的請求信息。

具體來說,當用戶打開Web瀏覽器訪問.aspx頁面時,Web服務器就會收到其HTTP請求。請求信息既包括用戶的請求方式(如POST、GET)、參數名、參數值等,又包括客戶端的基本信息(如瀏覽器類型、版本號、用戶所用語言及編碼方式等),這些信息將被整合在一起。通過Request對象,便可以訪問這些數據。Request對象的屬性和方法比較多,常用的如圖3.8所示。

圖3.8 Request對象常用屬性和方法

Request對象常用成員簡單介紹如表3.4所示。

表3.4 Request對象常用成員簡單介紹

Request對象的功能就是從客戶端得到數據。常用的兩種取得數據的方法是Request.Form和Request.QueryString,對應于Form提交時的POST和GET方法。

說明

GET方法將提交的數據構造成為URL的一部分傳遞給服務器,如常見的網址www.php.net/cal.php?id=1934中的“?id=1934”部分就是GET方法提交的數據。POST方法不會像GET那樣把提交的數據暴露在瀏覽器的地址欄中。

下面的示例中,將使用頁面的Request屬性輸出一系列用戶操作信息。為了便于說明,本節將使用到兩個常用的服務器控件:文本框(TextBox)和按鈕(Button),分別用于接收用戶的文本輸入和提交動作。本書將在第15章中詳細介紹這二者,此處,讀者只需掌握其基本功能即可。

○文本框():用于接收用戶輸入信息;

○ 按鈕():用戶結束輸入時的提交命令。

1 新建一個ASP.NET應用程序,然后從工具欄中拖放3個控件(1個文本框+2個按鈕)到默認頁面(Default.aspx)中,修改按鈕的Text屬性,將兩個按鈕的顯示文本分別改為“POST”和“GET”,如圖3.9所示。

圖3.9 Request示例中的控件

2 雙擊“GET”按鈕,在自動生成的按鈕單擊事件中,輸入代碼:

    Response.Redirect("Default.aspx?value=TestGetValue");

其功能為將頁面重定向到“Default.aspx?value=1”。其中,頁面“Default.aspx”表示所要跳轉到的頁面,“?”后面的串“value=1”表示使用GET方法提交的用戶信息。

3 雙擊“POST”按鈕,可為其增加單擊事件,但無須在自動生成的按鈕單擊事件中輸入任何代碼。

4 雙擊Default.aspx頁面,在自動生成的頁面加載事件中,輸入代碼:

    1.   Response.Write(Request.Form["TextBox1"]);
    2.   Response.Write(Request.QueryString["value"]);

其中,第1行使用Request.Form屬性,輸出通過POST方式傳遞的用戶信息;第2行使用Request.QueryString屬性,輸出通過GET方式提交的信息。這兩個屬性都是一個數組,可以通過索引或鍵值來獲取數據。通常使用鍵值的方式,鍵值就是POST方式中的輸入按鈕ID(如TextBox1)或GET方式中的數據鍵值(如value)。

5 啟動程序,將出現頁面Default.aspx,在輸入框中輸入一些數據,然后單擊“POST”按鈕后,頁面將顯示所輸入的數據,如圖3.10所示。

圖3.10 使用POST方式向頁面提交數據

這個過程中,輸入的數據首先通過POST方式傳遞給IIS,IIS讓.NET來處理,.NET框架中的Request對象便接收這些數據,存儲在Page.Request對象內部。

除了提交的數據之外,Request對象還能夠得到其他的用戶信息,例如,在頁面加載事件中添加如下代碼:

    1.   //其他用戶信息
    2.   Response.Write(Request.Browser.Platform+"<br>");       //用戶操作系統
    3.   Response.Write(Request.UserHostAddress+"<br>");       //用戶網絡地址
    4.   Response.Write(Request.UserLanguages[0]+"<br>");      //用戶系統語言
    5.   ……

這樣,便能輸出相應的用戶客戶端信息。

6 單擊“GET”按鈕后,頁面將顯示“TestGetValue”,如圖3.11所示。

圖3.11 使用GET方式向頁面提交數據

3.2.3 利用Server獲取服務器信息

【本節示例參考:\示例代碼\C03\ Example_Server】

在開發ASP.NET應用時,需要對服務器進行必要的設置,如服務器編碼方式等;或者獲取服務器的某些信息,如服務器計算機名、頁面超時時間等。這可以通過Server對象來實現。Server對象是HttpServerUtility類的實例,其常用屬性和方法如圖3.12所示。

圖3.12 Server對象常用成員

Server對象常用成員簡單介紹,如表3.5所示。

表3.5 Server對象常用成員簡單介紹

下面的示例中將使用Server對象的UrlEncode/UrlDecode方法,對一個網絡地址URL進行編碼和解碼。

1 新建一個ASP.NET應用程序,在頁面Default.aspx中添加一個文本框控件和一個按鈕控件,如圖3.13所示。

圖3.13 Server對象示例頁面控件

2 雙擊“Button”按鈕,在自動生成的單擊事件中,添加代碼如下:

    string strName=TextBox1.Text;
    Response.Redirect("Default.aspx?name="+strName);

代碼使用Response對象的Redirect方法實現頁面跳轉,目標頁面為“P1.aspx”,并使用GET方式提交了一個數據“name”,其值為文本框的輸入。

3 雙擊“Default.aspx”頁面,在自動生成的頁面加載事件中輸入代碼:

    Response.Write(Request.QueryString["name"]);

這句代碼使用Request對象的QueryString屬性,在頁面上輸出所提交的用戶信息。

4 啟動程序,將出現頁面Default.aspx,在文本框中輸入數據并單擊“Button”按鈕后,頁面上將出現相應的輸出,如圖3.14所示。

圖3.14 在頁面輸出GET數據

5 如果在文本框中輸入“wang&zhang”時,示例將產生錯誤,只輸出了“wang”而沒有“zhang”,如圖3.15所示。

圖3.15 提交“wang&zhang”時出現錯誤

這是因為,符號“&”本身是GET方式傳遞信息中的特殊符號,用于連接多個傳遞的值,“name=wang&zhang”將被理解為“name=wang & zhang=''”,所傳遞的值變為了兩個,第一個為“wang”,而第二個為空。要解決這個錯誤,就需要使用Server對象的UrlEncode方法,來對URL進行編碼,以便于在網絡上傳遞。

6 將“Button”單擊事件中的代碼改為如下:

    string strName=Server.UrlEncode(TextBox1.Text);
    Response.Redirect("Default.aspx?name="+strName);

這時,strName不再是普通字符串形式的URL,而是進行了特殊的編碼,以避免類似于(5)中出現的歧義。相應地,再將頁面加載事件中的代碼改為如下:

    Response.Write(Server.UrlDecode(Request.QueryString["name"]));

Server對象的UrlDecode方法將反過來把編碼后的URL解碼為普通的字符串。這樣再重新編譯運行程序,就不會出現(5)中的錯誤了,如圖3.16所示。

圖3.16 使用Server.UrlEncode方法對URL進行編碼

除UrlEncode/UrlDecode之外,Server還可以使用HtmlEncode/HtmlDecode對HTML文本進行編碼/解碼操作,此處不再一一贅述。

3.3 共享數據

用戶在使用ASP.NET開發Web系統時,會在多個頁面間瀏覽,可能需要共享某些數據,如用戶登錄信息、數據庫連接字符串等。瀏覽器是沒有辦法存儲數據的,因此需要使用某些特殊對象來實現系統的數據共享。總的來說,包括兩個對象:

(1)Application對象:實現程序級別的數據共享;

(2)Session對象:實現會話級別的數據共享。

3.3.1 利用Application共享數據

【本節示例參考:\示例代碼\C03\ Example_Application】

當需要在整個程序的級別共享信息時,可以使用Application對象。例如,需要設置一個計數器來統計訪問系統的所有人數;或者在程序開始和結束時記錄時間,以計算系統的運行時間,這些都可以使用Application對象來實現。

Application對象是HttpApplicationState類的實例,它的生命周期起始于系統開始運行時,終止于系統關閉。其常用的屬性、方法及事件如圖3.17所示。

圖3.17 Application對象常用成員

Application對象常用成員簡單介紹如表3.6所示。

表3.6 Application對象常用成員簡單介紹

在下面的示例中,將創建兩個頁面,在第1個頁面P1.aspx中向Application對象中添加一個數據,然后在第2個頁面中將能夠訪問到這個數據。

1 新建一個ASP.NET應用,將默認頁面Default.aspx重命名為P1.aspx,然后通過“解決方案資源管理器”窗口添加一個新的頁面P2.aspx。

2 雙擊P1.aspx,在自動生成的頁面加載事件中輸入代碼:

    1.   Application.Add("key1","value1");
    2.   Response.Redirect(“P2.aspx”);

第1句代碼,將在P1頁面加載時向Application對象中添加一項數據,其鍵為“key1”,值為“value1”。第2句代碼將頁面跳轉到P2.aspx上。

3 雙擊P2.aspx,在自動生成的頁面加載事件中輸入代碼:

    Response.Write(Application.Contents["key1"]);

這句代碼使頁面P2加載時顯示Applicaion對象內部系統級別的共享數據,這通過其Contents屬性數組來獲取。

4 啟動程序,顯示頁面如圖3.18所示。

圖3.18 使用Application獲取程序級別共享數據

這時,如果在另外一個客戶端的瀏覽器中輸入P2.aspx地址,則同樣會顯示“value1”,即對于所有的用戶,都可以獲取Application中的數據。這與下面介紹的Session對象不同。

3.3.2 使用Global.asax文件

【本節示例參考:\示例代碼\C03\Example_Global】

在上一節中,介紹了使用Application對象在系統級別共享數據。Global.asax文件與Application對象具有緊密的聯系,它的主要功能是:設置一些在程序級別使用的變量及實現Application對象的OnStart和OnEnd等事件。

向工程中添加Global.asax文件的步驟為:右擊“解決方案資源管理器”中的工程,彈出快捷菜單,選擇“添加新項”命令,在彈出的對話框中選擇“全局應用程序類”圖標,然后單擊“添加”按鈕即可,如圖3.19所示。

圖3.19 添加Global.asax文件

在Global.asax文件中,可以實現Application的OnStart和OnEnd事件。下面的示例中,在Application Start和Application End事件中對其賦值。

代碼3-3 添加Application數據:Global.asax

    1.   void Application_Start(object sender,EventArgs e)
    2.   {
    3.      // 在應用程序啟動時運行的代碼
    4.      Application.Add("StartTime",System.DateTime.Now.ToString());
    5.   }
    6.
    7.   void Application_End(object sender,EventArgs e)
    8.   {
    9.      //  在應用程序關閉時運行的代碼
    10.     Application.Add("EndTime",System.DateTime.Now.ToString());
    11.
    12.  }

這樣,不管在任何頁面中,都可以使用Application中的BeginTime值,通過在Default.aspx的加載事件中添加下面的代碼,可以輸出系統開始運行的時間。

    Response.Write(Application.Contents["StartTime"]);

運行結果如圖3.20所示。

圖3.20 使用Global.asax實現全局變量

用這種方法就可以將系統級別的數據共享。通常可以把數據庫連接字符串、系統配置參數等信息放在Application對象中。

3.3.3 利用Session共享數據

【本節示例參考:\示例代碼\C03\ Example_Session】

上面介紹的Application對象實現了程序級別的數據共享,對于多用戶使用的系統來說,有時候需要更細致的數據共享機制:每個用戶都可以共享自己的所有數據,而其他用戶則無法共享。要實現這種會話級別的共享,需要使用Session對象。

說明

Session意為“會話”,指從用戶進入系統到關閉瀏覽器離開系統的這段交往時間。對于該用戶來說,在Session中注冊的變量可以保留其值,并可在各個頁面中使用。由于這種特點,Session常用于用戶在頁面之間參數傳遞、用戶身份認證、記錄程序狀態等。

Session對象是HttpSessionState類的實例,其常用的屬性、方法及事件如圖3.21所示。

圖3.21 Session對象常用成員

Session對象常用成員簡單介紹,如表3.7所示。

表3.7 session對象常用成員簡單介紹

本節的實例和Application示例類似,它包含兩個頁面,在第1個頁面P1.aspx中向Session對象中添加一個數據,然后在第2個頁面中將能夠訪問到該數據。

1 新建一個ASP.NET應用,將默認頁面Default.aspx重命名為P1.aspx,然后通過“解決方案資源管理器”窗口添加一個新的頁面P2.aspx。

2 雙擊P1.aspx,在自動生成的頁面加載事件中輸入代碼:

    1.   Session.Add("key1","value1");
    2.   Response.Redirect("P2.aspx");

第1句代碼,將在P1頁面加載時向Session對象中添加一項數據,其鍵為“key1”,值為“value1”。第2句代碼將頁面跳轉到P2.aspx上。

3 雙擊P2.aspx,在自動生成的頁面加載事件中輸入代碼:

    Response.Write(Session.Contents["key1"]);

這句代碼使得頁面P2加載時顯示Session對象內部系統級別的共享數據,這通過其Contents屬性數組來獲取。

4 啟動程序,顯示頁面如圖3.22所示。

圖3.22 使用Session獲取會話級別共享數據

與Application不同的是,如果在另外一個客戶端的瀏覽器中輸入P2.aspx地址,則不會顯示“value1”,這是因為系統認為另一個客戶端為其他用戶,而Session只支持用戶內部的數據共享。

3.3.4 利用Session驗證用戶

【本節示例參考:\示例代碼\C03\Validate_User】

在Web系統中,必須保證用戶不能通過直接在瀏覽器中輸入URL直接進入,而必須要先登錄才能訪問到網頁,這時就需要在每個網頁中進行身份驗證。下面的示例使用【2.3.2】節介紹的Session來完成這個功能。

1 新建一個ASP.NET應用程序,包含兩個頁面P1.aspx和P2.aspx,并設置P1為起始頁。在P1.aspx上添加兩個文本框和一個按鈕,如圖3.23所示。

圖3.23 用戶登錄頁面控件

2 雙擊“登錄”按鈕,在自動生成的單擊事件中添加如下代碼。

代碼3-4 “登錄”按鈕單擊事件:Default.cs

    1.   ///<summary>
    2.   /// 登錄按鈕單擊事件
    3.   ///</summary>
    4.   protected void Button1_Click(object sender,EventArgs e)
    5.   {
    6.      //從頁面上獲取用戶輸入
    7.      string strUserName=this.TextBoxName.Text;
    8.      string strUserPwd=this.TextBoxPwd.Text;
    9.
    10.     //判斷用戶是否合法,如果合法,寫入Session中
    11.     if(IsValide(strUserName,strUserPwd)==true)
    12.     {
    13.         Session.Add("user",strUserName);
    14.
    15.         //跳轉到P2.aspx
    16.         Response.Redirect("P2.aspx");
    17.     }
    18.  }

代碼首先利用TextBox控件的Text屬性獲取了用戶的輸入;然后在第11行調用了一個方法IsValid()。這個方法的輸入為用戶輸入的姓名和密碼,通常需要通過查詢數據庫中是否存在匹配的記錄來判定用戶是否合法。此處對其不予實現,只簡單地用返回值為true來模擬。

代碼3-5 判定用戶是否合法:Default.cs

    1.   ///<summary>
    2.   /// 判定用戶是否合法
    3.   ///</summary>
    4.   ///<param name="_strUserName">用戶名</param>
    5.   ///<param name="_strUserPwd">密碼</param>
    6.   ///<returns>如果數據庫中含有該用戶:返回true;否則:返回false</returns>
    7.   private bool IsValide(string_strUserName,string_strUserPwd)
    8.   {
    9.      //查詢數據庫,此處暫不作實現
    10.     //...
    11.     return true;
    12.  }

最后,頁面將跳轉到P2.aspx。

3 雙擊P2.aspx頁面,在自動生成的頁面加載事件中添加如下代碼:

    1.   // 判斷用戶信息是否存儲在Session中,如果沒有,返回P1.aspx
    2.   if(Session.Contents["user"]==null)
    3.   {
    4.       Response.Redirect("P1.aspx");
    5.   }
    6.   Response.Write("歡迎進入系統!");

通過判斷Session對象中是否含有“user”值,來判斷訪問P2.aspx頁面的用戶是否是已經登錄的合法用戶。如果不是,則將頁面跳轉到P1.aspx;否則,輸出一行歡迎文字。

4 啟動程序,出現頁面P1.aspx,隨意輸入用戶名和密碼,然后單擊“登錄”按鈕,將進入P2.aspx,如圖3.24和圖3.25所示。

圖3.24 通過P1.aspx正常登錄

圖3.25 成功進入系統

5 重新打開一個瀏覽器,然后直接在瀏覽器地址欄中輸入P2.aspx的地址,以試圖進入系統,此時系統會自動跳轉到登錄頁面P1.aspx。

這樣,通過在每一個頁面上增加驗證Session對象的代碼,就可以保證系統只能從登錄頁面進入,而無法通過其他方式訪問。

承上啟下

■ 學完本章后,讀者需要回答:

1.ASPX頁面繼承于哪個類?

2.如何使用Response對象向瀏覽器輸出字符串?

3.如何使用Request對象接受用戶的POST方式和GET方式提交的數據?

4.如何使用Server對象獲取服務器的信息?實現URL字符串、HTML字符串的編碼和解碼?

5.如何使用Application對象實現程序級別的數據共享?

6.如何使用Session對象實現會話級別的數據共享?

■ 在下一章中,讀者將會了解:

1.使用String對象實現字符串的比較,判斷是否以特定子串開頭、結尾,判斷是否包含特定子串,定位,格式化,連接,分裂,插入|填充,刪除|剪切,復制,替換和大小寫轉換。

2.使用StringBuilder對象創建動態字符串,并完成字符串的追加、插入、刪除和替換操作。

3.了解正則表達式的概念,掌握.NET中構造正則表達式的技術,并使用Regex類進行字符串模式匹配。

4.了解字符的編碼標準,掌握利用System.Text控件對字符編碼的轉換操作。

主站蜘蛛池模板: 津南区| 原平市| 陆川县| 修水县| 鄯善县| 丹东市| 高陵县| 诏安县| 承德市| 合川市| 重庆市| 商都县| 凤山市| 怀来县| 马鞍山市| 赫章县| 贵阳市| 高平市| 奉节县| 宝丰县| 都安| 墨竹工卡县| 长子县| 三穗县| 华阴市| 岳池县| 凤阳县| 长岭县| 剑河县| 海安县| 南靖县| 广灵县| 德化县| 醴陵市| 白城市| 沙洋县| 永川市| 兰坪| 黔江区| 静乐县| 阿瓦提县|