[ASP.net/IIS] 多個網站併成同一個WebSite專案開發、部署技巧
在進入正題前,先回顧一般情況下,如果有一個案子,須同時開發二個以上的網站
通常大概這樣做……(以下以WebSite專案當範例)
建立第一個WebSite,架構如下:
	
Comman.cs是所有WebSite都會用到的共同邏輯
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
public class Comman
{
	public Comman()
	{
		
    }
    public string getBanner()
    {
        return "廣告輪播 by AdRotator控制項";
    }
}
images/demo.png是第一個網站自己擁有的圖片資源(相對路徑)
index.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="index.aspx.cs" Inherits="index" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>第一個網站的首頁</title>
</head>
<body>
    <form id="form1" runat="server">
      <img src="images/demo.png" alt="Shadow與愉快的程式" />
    </form>
</body>
</html>
index.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Configuration;
public partial class index : System.Web.UI.Page
{
    string Conn_E = WebConfigurationManager.ConnectionStrings["Conn_E"].ConnectionString;//資料庫連線字串
    protected void Page_Load(object sender, EventArgs e)
    {
        Response.Write("Shadow1的網站,做Shadow1的事情..." + "<br/>");
        
        Comman com = new Comman();
        Response.Write(com.getBanner() + "<br />"); 
        
        Response.Write("連線字串:" + this.Conn_E);
    }
}
執行首頁結果:
	
再建立第二個WebSite:
	
Comman.cs是所有WebSite都會用到的共同邏輯
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
public class Comman
{
	public Comman()
	{
		
    }
    public string getBanner()
    {
        return "廣告輪播 by AdRotator控制項";
    }
}
images/demo.png是第二個網站自己擁有的圖片資源(相對路徑)
index.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="index.aspx.cs" Inherits="index" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>第二個網站的首頁</title>
</head>
<body>
    <form id="form1" runat="server">
      <img src="images/demo.png" alt="Yahoo奇摩" />
    </form>
</body>
</html>
index.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Configuration;
public partial class index : System.Web.UI.Page
{
    string Conn_E = WebConfigurationManager.ConnectionStrings["Conn_E"].ConnectionString;//資料庫連線字串
    protected void Page_Load(object sender, EventArgs e)
    {
        Response.Write("Shadow2的網站,做Shadow2的事情..." + "<br/>");
        
        Comman com = new Comman();
        Response.Write(com.getBanner() + "<br />");
  
        Response.Write("連線字串:" + this.Conn_E);
    }
}
執行首頁結果:
	
以上都是舉比較簡單的例子,如果WebSite有第三個、第四個……以此類推
這邊分享一下個人經驗,那時候我一個人維護4x個網站,架構都是這樣,一個WebSite有自己的Web.config,有自己的App_Code
但事實上那4x個網站的Web.config檔幾乎一模一樣,連線字串一樣,SMTP_SERVER設定一樣…
App_Code裡共同邏輯的類別檔也都一樣
有天客戶承辦人一聲下令,所有網站應該要像http://malsup.com/jquery/cycle/ ,廣告輪播Banner要能夠自己輪播,不要畫面重整一次才撈新的圖片
呃…( ̄▽ ̄|||),後來我先改其中一個WebSite的Comman.cs檔
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
public class Comman
{
	public Comman()
	{
		
    }
    public string getBanner()
    {
        return "廣告輪播 by jQuery";
    }
}
然後改完的Comman.cs檔就Copy-Paste貼到其他4x個WebSite的App_Code底下覆蓋
因為是遠端連線到客戶那邊的機器作業,所以光是Copy-Paste就花了我一個上午的時間
而且這種需求常常發生,導致我在思考,是不是哪天應該把App_Code底下共同邏輯的CS檔改成WebService的方式?
但改成WebService的方式,其他index.aspx.cs的程式碼就一定也要跟著改呼叫方式,以4x個網站來說,真是浩大工程…
經過此次的教訓,後來開發的新專案
我整理出一種
各網站可以共用Web.config檔,也可以共用App_Code,各網站自己的圖片資源還是歸自己,正式上線時的DomainName對應仍對應各自自己的網站
以User角度來看會覺得是多個網站,以Developer角度來看其實只有一個WebSite專案
重點是會這麼做,一切都是為了維護方便
請看以下建立步驟:
先在檔案總管新增一個資料夾
Step 1. shadowAll
	
Step 2.把共用的檔案全複製到此資料夾裡(Web.config、App_Code)
	
Step 3. 把剛剛建立的兩個WebSite資料夾也搬到此資料夾內
	
Step 4.把那兩個WebSite裡重覆的檔案都刪除
	
Step 5.開Visual Studio先執行shadow1和shadow2內的index.aspx看看有沒有問題
	
shadow1的index.aspx執行結果:
	
shadow2的index.aspx執行結果:
	
看起來沒問題
至目前為止多個網站併成同一個WebSite專案到這邊告一段落,如果客戶的要求會更改到共同邏輯的話,這次只要改一遍
全部資料夾裡的程式大家都一起套用,就不用再Copy-Paste 40幾次了
再來是部署上線問題
各網站自己的圖片資源還是歸自己:由於各資料夾裡的圖片路徑都是採用相對路徑,所以此部份不用擔心
正式上線時的DomainName對應仍對應各自自己的網站:
部署環境Window 7 (IIS7.5)
shadow1資料夾對應DomainName:shadow1.no-ip.info
shadow2資料夾對應DomainName:shadow2.no-ip.info
Step 1.先在IIS裡,新增一個shadow1的站台
	
Step 2. 再新增一個shadow2的站台,請注意兩個站台的實體路徑指到同一個「shadowAll」資料夾(因為都在同一個WebSite專案)
	
接下來是重點!
為了達到「正式上線時的DomainName仍對應各自自己的網站」此條件
先確認shadow1和shadow2資料夾底下都有index.aspx後
Step 3. 在shadowAll網站根目錄下新增一個index.aspx程式
	
此index.aspx負責做導向動作,所以UI端不寫Code
index.aspx.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class index : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (Request.Url.AbsoluteUri.Contains("shadow1.no-ip.info"))
        {
            Response.Redirect("shadow1/index.aspx");
        }
        else if (Request.Url.AbsoluteUri.Contains("shadow2.no-ip.info"))
        {
            Response.Redirect("shadow2/index.aspx");
        }
        else
        {
            Response.Redirect("shadow1/index.aspx");
        }
    }
}
Step 4. 回到IIS,確認shadow1和shadow2兩個站台的預設文件都是index.aspx且在最上面
	
	
Step 5. 測試&執行
在瀏覽器URL輸入http://shadow1.no-ip.info,執行結果:
	
在瀏覽器URL輸入http://shadow2.no-ip.info,結行結果:
	
執行起來沒問題,部署完成。
接著要測試幾種情況,看看這種開發方式經不經得起考驗
1.假設shadow1資料夾底下的index.aspx有兩個超連結,一個另開視窗連到http://www.google.com.tw
一個則是相對路徑連個另一資料夾的second.aspx程式
index.aspx
	
other/second.aspx.cs
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="second.aspx.cs" Inherits="shadow1_other_second" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
     <h1>你來到second.aspx了</h1>
    </form>
</body>
</html>
在URL輸入:shadow1.no-ip.info
	
點選第一個超連結:
	
正常。
接著再點選第二個超連結:
	
也正常。所以超連結這部份測試OK
2.再假設一種情況,我見過有些人會把圖片的URL寫成<%= 網站URL %>資料夾/images/圖片.jpg
這裡就利用shadow1/index.aspx做示範,先看Web.config設定
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <appSettings>
    <add key="shadow1Url" value="http://shadow1.no-ip.info/"/>
    <add key="shadow2Url" value="http://shadow2.no-ip.info/"/>
  </appSettings>
  <connectionStrings>
    <add name="Conn_E" connectionString=".\sqlexpress;Initial Catalog=NorthwindChinese;Integrated Security=True" />
    
  </connectionStrings>
    <system.web>
        <compilation debug="false" targetFramework="4.0" />
    </system.web>
    <system.webServer>
        <defaultDocument>
            <files>
                <add value="index.aspx" />
            </files>
        </defaultDocument>
    </system.webServer>
</configuration>
然後shadow1/index.aspx.cs裡宣告
    protected string shadow1Url = WebConfigurationManager.AppSettings["shadow1Url"];
    protected string shadow2Url = WebConfigurationManager.AppSettings["shadow2Url"];
接著shadow1/index.aspx,兩個設定都讀讀看
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="index.aspx.cs" Inherits="index" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>第一個網站的首頁</title>
</head>
<body>
    <form id="form1" runat="server">
      <img src="<%= shadow1Url %>shadow1/images/demo.png" alt="Shadow與愉快的程式" />
      <img src="<%= shadow2Url %>shadow1/images/demo.png" alt="Shadow與愉快的程式" />
    </form>
</body>
</html>
執行結果:
	
兩張圖片都正常顯示出來(因為兩個DomainName都對應到同一個WebSite專案)
不過這邊個人建議shadow1資料夾裡的程式,為了避免造成維護上的困擾,請儘量使用shadow1對應的DomainName:shadow1.no-ip.info
以上不管怎麼測,跑起來功能都和 多個獨立WebSite專案相同,但在維護性方面,只有一個WebSite專案當然是比較好維護
而且到部署上線階段,客戶想把多個網站當做一個網站,只給一個DomainName
或客戶想要多個網站各自擁有自己的DomainName
用這種開發方式都足以應付,如此好用的技巧分享給大家^_^