2014年6月20日

ASP.NET MVC - ASP.NET MVC vNext ( MVC 6 ) 於MAC上跑ASP.NET MVC (後篇) Kruntime與MVC專案設定

開始前,還是要提醒大家,目前也還有很多問題,小弟測試下來,真的感受到,要用於正式環境還有一段路要走…

後篇與前篇相比起來,因該是簡單的多,基本上就是兩件事情,第一件事情是要建立Kruntime和KVM,第二件事情則是要針對OSX上,MVC的設定。

建立Kruntime與KVM

基本上,要建立Kruntime與KVM只要下以下這個指令就可以了…

curl https://raw.githubusercontent.com/aspnet/Home/master/kvminstall.sh | sh && source ~/.kre/kvm/kvm.sh && kvm upgrade

這個指令基本上做的事情和在Windows下安裝Kruntime和KVM是同樣的…他會做以下的事情。

  • 下載kvm.sh並且儲存在~/.kre/kvm/kvm.sh  
  • 使用kvm upgrade下載最新的KRE Package

完成之後,我們就可以使用kvm list來查看裝了哪些東西…

螢幕快照 2014-06-19 上午1.26.34

基本上,這樣Kruntime環境與KVM就設定完成了。

設定MVC

設定MVC專案有幾個地方需要設定,一個是NuGet.config,另外一個是project.json,最後Startup.cs也是要加上useMvc;另外建議也把一些不需要的東西砍一砍,基本上留下下面這些就夠了。

而比較特別的是Nowin.vNext這個相依的專案,這是國外的高手寫的,就是為了解決OSX上的問題;請注意,當初Scott在Demo的時候,也是有加入Nowin,但實際上,Nuget裡面是找不到Nowin的… ( 未來可能會有… ) 所以現在是由網友熱情自己撰寫一個~~

那大家可能會想,我要去哪找到這個Nowin.vNext這個專案,大家可以到這邊去下載

螢幕快照 2014-06-19 上午1.28.55

NuGet.Config的設定一樣,要加上ASP.NET vNext現在的dev版本下載位置,平常的NuGet只能取得比較穩定的版本,但畢竟現在版本衝得太快(因為在開發中),所以很容易版本不同匹配不起來,所以這邊還是建議使用最新的dev版本。

螢幕快照 2014-06-19 上午1.30.18

以下是NuGet.Config的code

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="AspNetVNext" value="https://www.myget.org/F/aspnetvnext/" />
    <add key="NuGet.org" value="https://nuget.org/api/v2/" />
  </packageSources>
  <packageSourceCredentials>
    <AspNetVNext>
      <add key="Username" value="aspnetreadonly" />
      <add key="ClearTextPassword" value="4d8a2d9c-7b80-4162-9978-47e918c9658c" />
    </AspNetVNext>
  </packageSourceCredentials>
</configuration>

另外,project.json的設定如下,要改command和加入Nowin.vNext這個相依,所以目錄下,一定要有Nowin.vNext這個專案。

螢幕快照 2014-06-19 上午1.30.23

以下是project.json的code

{
    "dependencies": {
        "Microsoft.AspNet.Mvc": "0.1-alpha-*",
        "Nowin.vNext": ""
    },
    "commands": {
        "web": "Microsoft.AspNet.Hosting --server Nowin.vNext"
    }
}

基本上Startup.cs沒甚麼改變,但現在大家應該還是不習慣vNext,所以也在這邊貼出來,提醒大家一下。

螢幕快照 2014-06-19 上午1.31.51

以下是Startup.cs的Code。

using System;
using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;

namespace WebApplication1
{
    public class Startup
    {
        public void Configure(IBuilder app)
        {
            // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
            app.UseServices(services =>
            {
                services.AddMvc();
            });

             app.Use(async (context, next) => 
             {
                Console.WriteLine(context.Request.Path);

                try
                {
                    await next();
                }
                catch(Exception ex)
                {
                    Console.WriteLine(ex);
                }
            });

            app.UseMvc();
        }
    }
}

然後在run之前,要先用kpm restore,在下指令之前,也別忘記,進入到專案的目錄下。

( 是專案,不是方案喔 )

螢幕快照 2014-06-19 上午1.44.51

最後,下k web這個指令,就可以run起來;而難得有OSX表現的機會,我們這次就讓safari來表現一下吧XDD

( 預設的port是8080 )

螢幕快照 2014-06-19 上午1.47.46

這樣就完成嚕,當然現階段這部分也還在開發,相信明年的這個時候,會更加的方便!!

參考資料

ASP.NET MVC - ASP.NET MVC vNext ( MVC 6 ) 於MAC上跑ASP.NET MVC (上篇) 安裝Mono

前篇介紹了用USB將編譯好的ASP.NET MVC網站丟到另外一台機器上,就算沒裝K環境,還是可以正常地跑;但是,大家這樣就滿足了嗎?;下一代的ASP.NET MVC vNext可不只是這樣而已,現在也支援了跨平台執行ASP.NET MVC的應用程式;所以小弟我,這次就來試驗一下,如何跨到Apple的MAC OS上!! ( 第一次覺得小弟的Macbook那麼有用… )

但Mac底下沒有CLR阿…那該怎麼辦呢??,沒錯,就是靠Mono啦…所以這篇,就來教大家,如何安裝Mono…

基本上,在Mac底下安裝Mono說難不難,說簡單也不簡單…基本上只要照著以下指令下,通常都可以成功~

警告!! 目前Mono這個版本,也並非正式釋出,所以也會有很多的bug,小弟是為了興趣而嘗鮮,如要用在正式環境,還是建議等推出正式版本,再來裝設。

PREFIX=/usr/local
 
# Ensure you have write permissions to /usr/local
mkdir $PREFIX
sudo chown -R `whoami` $PREFIX
 
# Downlaod and build dependencies
mkdir ~/Build
cd ~/Build
curl -O ftp://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
curl -O ftp://ftp.gnu.org/gnu/automake/automake-1.14.tar.gz
curl -O ftp://ftp.gnu.org/gnu/libtool/libtool-2.4.2.tar.gz
 
for i in *.tar.gz; do tar xzvf $i; done
for i in */configure; do (cd `dirname $i`; ./configure --prefix=$PREFIX && make && make install); done
 
PATH=$PREFIX/bin:$PATH
git clone https://github.com/mono/mono.git
cd mono
CC='cc -m32' ./autogen.sh --prefix=$PREFIX --disable-nls --build=i386-apple-darwin11.2.0
make get-monolite-latest
make
make install

好,現在開始,我們一步一步地做。

首先我們先設一下變數,PREFIX=/usr/local,這樣之後就不怕Key錯路徑了,而且未來的mono所包好的dll也會放到這個目錄之下。

接下來,要建立剛剛我們設定的那個路徑的目錄,並且將我們自己設為這個目錄的owner,所以會下這兩個指令;另外要注意,'whoami’記得換成自己的名稱喔 ( 連單引號都不用Key )。

mkdir $PREFIX
sudo chown -R `whoami` $PREFIX
下圖這邊因為我已經建立過usr/local了,所以他提示我,已經存在了。

SNAGHTML3a49bdd

接下來,我們要執行這些指令。

mkdir ~/Build
cd ~/Build
curl -O ftp://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
curl -O ftp://ftp.gnu.org/gnu/automake/automake-1.14.tar.gz
curl -O ftp://ftp.gnu.org/gnu/libtool/libtool-2.4.2.tar.gz   
for i in *.tar.gz; do tar xzvf $i; done
這些指令就是在家目錄建立一個Build目錄,並且下載三個要用到的套件;分別是autoconf、automake、libtool,這是因為編譯Mono需要這三個套件。
接下來,就用迴圈,將這三個壓縮檔通通解開。

SNAGHTML3a3a75b

完成後的圖如下;接下來就輸入以下指令編譯與安裝。

( 下圖的部分,指令key進去後沒截到圖,但我們可以從下圖看到,這三個套件都已經解開了 )

for i in */configure; do (cd `dirname $i`; ./configure --prefix=$PREFIX && make && make install); done
( 查資料的過程中有發現,有人這三個套件Build不起來,有人建議是要裝xcode…但小弟的Macbook本身就有裝xcode,所以過程是滿順利的…所以過程中有遇到問題,可以死馬當活馬醫,試試看吧… )

螢幕快照 2014-06-17 下午11.21.48

正確安裝完成後,我們要設定PATH這個變數,然後使用git下載最新版本的mono;並且進入mono目錄,來下指令檢查與編譯前準備。

( 注意,mono的source也要放到剛剛上面下載下來的同一個目錄裡面,也就是Build裡面,不然會出錯 )。

PATH=$PREFIX/bin:$PATH
git clone https://github.com/mono/mono.git
cd mono
CC='cc -m32' ./autogen.sh --prefix=$PREFIX --disable-nls --build=i386-apple-darwin11.2.0

螢幕快照 2014-06-18 上午12.16.38

完成後,我們就可以使用make編譯了,編譯完成後可以再用make install安裝…

但正式開始使用make指令前,要先下make get-monolite-latest來取得最新的mcs compiler,不然會有錯誤make[6]: gmcs: No such file or directory的錯誤。

取得之後,就可以下make,當make跑了超久跑完之後,就可以下make install了。

( 下圖也沒截圖截到…反正就是跑很久就是了… )

螢幕快照 2014-06-18 上午12.22.05

接下來要調整一下預設的路徑位置,我們要去/private/etc/裡面的paths這個檔案去做修改;但因為這個檔案的權限是644 ( 644代表只有root可以讀寫,其他都只能讀,詳細可以去看Linux的權限設定 ),所以小弟先把它改成777,等改完檔案後,再調整回644。

( 指令如下圖,因為這算是基本的Linux指令,小弟就不多談了,請見諒~ )

螢幕快照 2014-06-18 上午12.37.01

這邊小弟是使用vi直接改了…如果不熟vi的朋友,可能會很吃力…看看能不能用ide的編輯器改…基本上,而如果是使用vi編輯的方法,就是進去vi後,按下i,就可以編輯內容,編輯好後,按下:wq,就可以儲存…如果編輯錯了,可以按下:!q來跳出VI,從新再來一次…

而這邊,我們要把/usr/local/bin放到/usr/bin之上,但這邊也要小心,如果原本/usr/bin有放大量的指令,這樣改,未來系統可能會有問題,不過基本上小弟本來就很少在OSX安裝那些東西,所以我是不怎麼怕啦XDDD。

螢幕快照 2014-06-18 上午12.36.25

編輯完成後,就把剛剛那個檔案改回644。

螢幕快照 2014-06-18 上午12.37.01

然後下Mono --version就可以看到mono的版本,一定要3.6.1以上…

螢幕快照 2014-06-18 上午12.38.12

基本上這樣就完成了~~初步就到這邊,後篇則是要改ASP.NET MVC的project.json檔,來達到可以run在OSX上的目的。

參考資料

ASP.NET MVC - ASP.NET MVC vNext ( MVC 6 ) 使用Source Code

經過前面兩回的亂玩XDD,而這回我們要體驗的東西,則是之前很難處理的"使用Source Code”…( 其實目前也沒好到哪去,但至少方便多了… )

很難處理!?是的,雖然MVC 5之前的Source Code都公開了,但要拿Source Code進行偵錯老實說真的還是很麻煩…而這一次的其中一個變革,除了ASP.NET的相關專案都放到Github公開Source Code外,MVC 6本身更提供了開啟關閉使用Source Code的偵錯功能!!

當然,前提之下,我們還是要先下載Source Code…這邊我們進入ASP.NET MVC的Github網站,另外,下圖的左邊( 小弟我忘記紅色框框了QQ.. )有一個branch : dev ,這代表的是分支的版本,也要選到對應的版本;然後小弟是使用Clone in Desktop來下載,但使用這個必須裝Github for Windows這套軟體。 ( 可以參考小弟的舊文 ) 如果看完文章,覺得麻煩,也可以直接Download ZIP。

image

當按下Clone in Desktop後,IE會呼叫Github for windows來處理。

image

下載完成後,我們可以從下圖的位置,得到Source Code放在哪邊..

image

以下是MVC的Source。

image

接下來,我們要在方案的目錄下,增加NuGet.Config檔案,這個檔案的目的,只要是設定現在MVC的NuGet位置;為什麼要這樣做呢??其實很簡單…因為目前官方的NuGet路徑,主要還是放比較穩定的版本,而現在如飛一樣的速度版本則是放在myget上面,而我們用github抓下來的一定是最新版本,但是這最新版本會需要很多同樣是最新版本的mvc lib,所以我們要設定myget路徑,讓NuGet自動透過myget路徑去取得最新的mvc lib。

image

主要是下面這一行,myget是第三方幫忙託管NuGet Package的雲端服務…目前MS把MVC開發中的Lib放在myget上。

image

完整的xml如下:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="AspNetVNext" value="https://www.myget.org/F/aspnetvnext/" />
    <add key="NuGet.org" value="https://nuget.org/api/v2/" />
  </packageSources>
  <packageSourceCredentials>
    <AspNetVNext>
      <add key="Username" value="aspnetreadonly" />
      <add key="ClearTextPassword" value="4d8a2d9c-7b80-4162-9978-47e918c9658c" />
    </AspNetVNext>
  </packageSourceCredentials>
</configuration>

接下來,我們要再方案的地方,增加一個global的資料夾。

image

並且在此資料夾加入一個global.json的檔案

image

如下圖。

image

接下來,我們編寫一下json,如下圖…...使用sources來指定source code的路徑。

image

然後過一陣子後,就會看到檔案載入了…

image

如下圖,我們可以看到,Visual Studio “14”自動的參考到Source Code的專案,而其他沒參考到的就還是package;而且我們可以發現,也自動的下載更新版的package。

imageimage

接下來,我們在ASP.NET MVC的Source Code裡面的ViewResult檔案裡面加入一個輸出Hello World,並且設定中斷點後執行。

執行後就可以發現,中斷點很有效地停在那邊了。

image

而實際輸出,也真的出現Hello World了!!

image

是的,這樣就可以了!!!,很簡單嗎!?,不,一點也不,現階段要使用這功能,會遇到踩不完的雷…理由很簡單…現在Github上面提供的是dev的分支,簡單的說,還沒有規劃出里程碑的分支,而dev的分支則大概幾小時就會有更新,並且出現新的版號…換言之…我們要讓所有MVC有用到的Lib,都吃到相對應的版號,才能讓功能正確的運作…

而這次小弟就遇到不少類似的坑,光是要湊集神之卡所有的版號,就搞掉我一天的時間了… ( 又不是收集七龍珠… )

而且不只MVC要用到的Lib…連KVM的版號也會有關… ( 畢竟這次的底層是用KVM ),除此之外,VS的版本又和KVM有關…所以現階段要成功,還真的要碰點運氣…

但相信未來正式版出來後,這種問題就可以迎刃而解了…

最後,官方這次有提到,會提供這功能的原因有幾個,一方面是提供Source Code給我們偵錯使用,其次,利用此功能,如果我們發現原本官方的Bug,我們也可以先自行改Source Code的方式撐著用… ( 抖抖…完全不想阿- - ),那等官方出新版的時候,再把專案移除,改用Nuget抓下來的package即可…當然,未來怎樣發展,還是要等到明年才知道嚕!!

ASP.NET MVC - ASP.NET MVC vNext ( MVC 6 ) Core CLR and .NET Core Framework

開始之前,還是要免責聲明一下…

這部分目前官方還是沒有提供很多詳細的敘述,所以多半是透過官方Blog的很多篇文章彙整起來的;其次,目前這都也還在Preview,未來依舊有可能會去改變和變化,所以這部份,大家參考看看就好。

Core CLR是這次ASP.NET vNext很重要的核心之一,官方這部分沒有講得很清楚,但基本上Core CLR就是一個精簡的CLR;拿掉了繪圖等等的一些功能,讓Server和Cloud有更高的效能,更低的記憶體使用,與高透通性。

另外,在講Core CLR的過程中,其實我覺得要和新的.NET Core Framework一起講;在官方的文章裡面,我看到的,通常Core CLR和.NET Core Framework是混再一起講;雖然目的上是一樣的 ( 也因為目的相同,所以我看到的文章都是混再一起說這件事情 ) ,但小弟實驗了一下,我覺得事有一些差異的,當然,這部份有沒有可能是小弟我自己腦補,未來也是要等官方證明。

.NET Core Framework

如下圖所示,我們可以從專案這邊選擇是要原本的.NET Framework或是.NET Core Framework;.NET Framework顧名思義就是一大堆的Lib,提供給我們方便的用途,但實際上,我們開發Web應用程式的時候,可能不需要使用到那麼多的Lib;所以才會有精簡版本的.NET Core Framework;另外一個用意,之前我們使用.NET Framework,多半需要安裝完整的套件,例如ASP.NET MVC,就要安裝ASP.NET MVC的安裝包,才能去做執行;也就是說,以前我們使用.NET Framework的時候,專案參考到的是GAC。

image

而.NET Core Framework則不會再去參考GAC,他的另外一個變革就是,要用多少載多少;所以就如下圖的Package包 ( 未來都會自動打包,這牽涉到Kruntime的一些東西,我們後面會再看到,這邊我們先關注 Framework ),我們可以看到.NET Core Framework這個包裡面,其實包了一堆原本會在GAC底下的東西…;的確,這樣的Package會比.NET Framework包起來大得多,但實際上,透過這種方式,再也不用和GAC相依、一個Server則可以run不同的dll版本、甚至Server上不用再裝類似ASP.NET MVC這種套件包,只要整個複製過去,就可以順利執行。

另外,這邊會打包成KRE-svrc50-x86 ( svrc的c是代表core的意思 )

image

這邊下圖是.NET Framework的Package,我們可以看到,完全看不到system.dll的蹤影,因為sysytem.dll會去吃GAC;當然,這也比較小包,但是就會和系統相依。

這邊則是KRE-svr50-x86。

image

除此之外,我們看一下Visual Studio裡面的應用,也可以看到.NET Framework完整版,可以找到system.managment這個namespace。

image_thumb[2]

而.NET Core Framework 則找不到…

image_thumb[5]

另外一個例子,.NET Core Framework找不到System.xml的時候。

image_thumb[8]

可以透過NuGet取得XML包。

image_thumb[10]

這時候自然而然就找到了。

image_thumb[13]

從上面那個例子,我們也可以看到,其實.NET Core Framework就已經把一個一個常用的Lib獨立出來,有需要的情況下再去載入~

但是,請注意,上面那個例子,你就不會找到system.management的package包,我不確定這部份未來官方會再補上去,又或是這牽涉到Core CLR…

但不管如何,我們先來談一下 Core CLR

Core CLR

CLR是.NET最終運行的地方,基本上完整的CLR,自然提供了完整的功能,而Core CLR則拿掉了一些用不太到的功能,來達到精簡與加快速度的目的。

而就如前面一開始說的,從目前的文章看到,幾乎都是會把.NET Core Framework與Core CLR一起談,但就小弟的觀點來看,兩件算是同一件事也不算是同一件事情;.NET Core Framework、.NET Framework指的是可以用哪一種的.NET Framework產生出大包、小包的Package包…而Core CLR和DesktopCLR指的是整個CLR能支援.NET Framework程度的完整性…

所以剛剛找不到system.management不知道算不算是Core CLR不支援這個Lib,但可以確定的是,從官方的影片可以看到,目前Core CLR不支援System.Draw;所以反過來說,Core CLR拿掉了很多用不到的地方…

所以,.NET Core Framework必須搭配Core CLR…而.NET Framework則要搭配Desktop CLR。

繼續往下看,下面的圖是官方那邊出來的,顯示了“雲優化”的架構(不考慮跨平台的特性)

另外,也要注意一下,目前官方有指出以下這段話。

Also, current plug of the Core-CLR on top of IIS is “Helios”, but there will be an IIS Native Module in the future, too.

目前在IIS之上必須要有Helio (太陽神) 這個套件,這個主要是配合OWIN而產生出來的一層;未來這部份官方也會實作IIS Native Module。

image

另外一張官方的架構圖,我們可以看到中間會有Loader。

是的,這是前面沒提到的一個東西,未來整個ASP.NET vNex runtime,除了CLR外,還會在CLR外面包一個Kruntime;所以前面那邊大家才會看到自動打包成KRE-xxx這種Package包,用途就是在執行的時候,才去處理與載入。

所以我們其實可以從下面這簡單的架構圖看到,在KRuntime的時候來解決要讀取哪個CLR ( 其實上面也會有Loader,只是上面那張圖專注於雲優化這件事情 )。

image

最後,我再補上兩張,使用.NET Framework 和 .NET Core Framework佈署到Azure的情況。

我們可以看到使用.NET Framework時,是run DesktopCLR。

image

如果是使用.NET Core Framework 則會使用CoreCLR。

image

大致上就這樣了,如有錯誤,歡迎告知小弟… (但請鞭小力一點QQ )

下一篇,來看看Kruntime。

參考資料

ASP.NET MVC - ASP.NET MVC vNext ( MVC 6) 發佈與self host

此回介紹ASP.NET MVC的一個重大功能,self host與publish。

從MVC 5開始,ASP.NET MVC就開始計畫與實作傳說中的OWIN,OWIN的全名就是Open Web Interface for .Net;我們思索一下,從以前開始,ASP.NET都必須要掛載在IIS之上,而ASP.NET也從以前至今,都必須相依於system.web等等的Lib;換言之,沒有IIS,ASP.NET也就等於死翹翹…

而這個混亂的時代下,就出現了OWIN這種東西,將原本的相依性,透過定義好一個一個的介面,來達到未來抽換的一個目的。

好啦,講白一點,就是可以不用IIS就可以讓ASP.NET運作啦!!而所謂的self host,就是用命令模式的方式,讓程式在那邊監聽瀏覽器等的請求,而不用IIS啦!!

而到了新版的ASP.NET MVC這功能就更加強大了,所以第四回合,就來體驗一下吧!!

首先,我們要先透過NuGet載入一個監聽器,也就是底下的Microsoft.AspNet.Server.WebListener這個字串,當然我們要在project.json底下去新增… ( UI介面的趕快出來吧… );完成之後,我們再加上下面這段Commands,這個Commands可以定義要用哪個port監聽等等之類的命令列參數。

image

全部的json config如下,有需要的人就直接copy吧~

{
    "dependencies": {
        "Helios": "0.1-alpha-*",
        "Microsoft.AspNet.Mvc": "0.1-alpha-*",
        "Microsoft.AspNet.Server.WebListener": "0.1-alpha-*"
    },
    "commands": { /* Change the port number when you are self hosting this application */ 
        "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000"
    },
    "configurations": {
        "net45": {},
        "k10": { }
    }
}

完成後,我們就可以在命令列下使用k web這個指令來將常駐run起來 ( 可以參考KVM那篇 )。

( PS 因為我們Commands底下是"web" : xxxxx,所以用k web,如果是其他的字,例如"web8080" : xxx 那就要輸入k web8080,換言之,我們可以定義多個,來達到不同的目的。 )

好self host KVM那篇已經試驗過了,接下來我們看一下佈署。

基本上佈署的設定和之前沒啥兩樣。

image

但我們這邊準備要把WEB丟到USB ( 假設要丟到USB…實際上我是把他傳到另外一台電腦上面去RUN ),所以這邊選擇要佈署到File System。

image

就…打一下Customer Profile名稱…

image

然後選擇目錄。

image

完成後,其實可以發現,現在多了一個web.cmd這個檔案了;另外,大家可能會覺得…為啥有一堆MVC的Code…那是因為我們上一篇有把MVC的Source Code加入進來。

當然,這個這樣是不安全的,但大家也不用擔心啦,離整個發表,還有一年的時間(2015年),我們先體驗過程就好了~~

image

這時候,我們執行web.cmd,就可以得到如下圖的結果。

image

另外,如果copy到另外一台電腦,也不用做甚麼事情,就可以順利run了 ( 我的筆電上是沒有裝KVM的,但也是一樣可以跑得很開心~~ )

image

當然,能RUN起來的秘密,其實就是他把所有需要的東西,全部都放到Package裡面去了。( 當然,要run的電腦上還是要裝.Net Framework啦…不然空有dll,沒有環境可以Run,當然還是不行;而這次透過這方式,可以讓Server端不用安裝一堆Package,而變成動態下載,也因此,我們不用再去找相對應的版本對應包,更加的方便了!!

image

大致上就這樣!!以後網頁也可以帶著走了喔!!