2017年8月5日 星期六

【MVC】在IIS7.5中設定環境給MVC用

只是將ASP.NET WebForm發布到IIS時還挺順利的
我只有在設定讓區網內的其他電腦可以連到虛擬機中的IIS卡過,而且這問題主因在不熟VMWare,而不是IIS
但MVC光是這IIS這邊就麻煩不少了

測試環境: win7 pro & IIS 7.5
測試網站: 微軟提供的教學範本



前面的起手式與傳統網站相同,都是要開啟Windows功能 (IIS因為安全性關係,預設關閉)


1. 開啟「控制台」找到「開啟或關閉Windows 功能」,參考下圖將功能開啟
  • Web 管理工具 -> IIS管理主控台 (非必要,但強烈建議裝)
  • www服務 -> 應用程式開發功能 -> ASP.NET (必要)
  • www服務 -> 應用程式開發功能 -> ISAPI 篩選器 (必要)
  • www服務 -> 應用程式開發功能 -> ISAPI 擴充程式 (必要)



2. (不見得需要做)如果IIS比.NET Framework後裝,就要接著開啟cmd執行註冊(依OS選擇註冊方式),讓他跑一下(數秒而已)

  • OS為32bit「C:/Windows/Microsoft.NET/Framework/v4.0.30319/aspnet_regiis.exe -i」
  • OS為64bit「C:/Windows/Microsoft.NET/Framework64/v4.0.30319/aspnet_regiis.exe -i」
(大部分的開發環境可能都是後裝,除非一開始就確定要當AP Server)

3. 然後就能在「開始」輸入「IIS」把主控台叫出來
 



如果是WebForm,到這裡就可以開始Publish網頁跟指定路徑了,但是佈署mvc比普通網站更麻煩,所以從這裡開始要多設定一些!

4. 開啟「ISAPI及CGI限制」的功能視窗
 


4.1 然後將「限制」改為「允許」 (最低限度是啟動第三列的64bit就能執行了。)
 


5. 然後就可以Publish專案啦,方法可以參考這影片,這裡不細說。畢竟都要設定IIS了,應該... 不會不知道怎麼publish基本款的網站吧?
https://www.youtube.com/watch?v=FzwcD_XQ4ko


6. 回到IIS主控台,對「站台」右鍵 -> 點「新增網站」 然後參考下面設定

圖片太小的話,可以開新分頁去看
※應用程式集區就是「步驟4.1中『允許』的那個程式集區

※我偏好使用不同的連接port去設定網站,這樣就不用記一堆IP,但是注意要那條port有沒有被防火牆鎖起來就是了
 

7. 如果是VS預設的MVC範本,到此就可以執行了
用「瀏覽」或者直接在瀏覽器輸入網址



參考來源:iis部署asp.net mvc網站出錯的解決方法 




如果網站有使用到編譯為32bit的DLL,就還要多設定一小段

Extra 1. 看是哪個站台有需要用到32bit的DLL,對它指定的「應用程式集區」右鍵→點「進階設定



Extra 2. 將「啟用32位元應用程式」設定為True就可以了。
當然也能為了它新增個別的程式集區,但是這步一定要做!


Extra 3. 保險起見,將網站停止後,再啟動吧。

參考來源:在Windows7 x64的IIS使用32bit的odbc driver 

2017年7月30日 星期日

【WPF】執行背景工作時,讓畫面不會看起來像卡住


只是想在WPF中使用熟悉的Process Bar,那就別花時間看這篇了
到 youtube去搜尋比較快

這篇不會提到Process Bar,雖然同樣的原理也能用在Process Bar,甚至是自訂的任何進度條。這篇還順便迴避某些書中範例無法回傳string的問題。

原因是WPF畫面的呈現和背景工作是分開的
當程式在忙碌時,畫面會乖乖的一直等背景工作跟他說OK才刷新
(圖片看起來會動,就是因為畫面不斷的刷新喔!)

想像影片前半段,希望能夠「圖片會動、文字會逐項目顯示」,那就需要用到
Async 和 Await
來寫出非同步程式,這樣畫面就不會等到海枯石爛了!
沒聽過「非同步, await, async」的也不用擔心,可以先理解差異,有興趣再找資料吧

●先來一段失敗的程式碼

        private void test_Click(object sender, RoutedEventArgs e)
        {
            //沒使用async & await
            showLog.Text = "轉檔開始(2秒/個)\r\n";
            for (int i = 0; i < 3; i++)
            {
                showLog.Text += "開始第" + (int)(i + 1) + "個轉檔...";
                Thread.Sleep(2000); //模擬轉檔時會停頓的時間
                showLog.Text += "End\r\n";
            }
            showLog.Text += "轉檔全部結束\r\n";
        }
●然後這是成功的程式碼

        private async void test_Click(object sender, RoutedEventArgs e)
        {
            //使用async & await
            showLog.Text = "轉檔開始(2秒/個)\r\n";
            for (int i = 0; i < 3; i++)
            {
                showLog.Text += "開始第" + (int)(i + 1) + "個轉檔...";
                showLog.Text += await ConvertFile("End\r\n");
            }
            showLog.Text += "轉檔全部結束\r\n";
        }

        public Task<string> ConvertFile(string str)
        {
            return Task.Factory.StartNew(() => this._ConvertFile(str));
        }

        public string _ConvertFile(string para1) {
            Thread.Sleep(2000); //模擬轉檔時會停頓的時間
            return para1;
        }

知道怎麼套用await和async,讓畫面不會卡住了嗎?
還是不懂的話,再繼續往下看吧


1. 在可能會執行到需要花時間,但前後想加上其他程式碼的方法(method)的宣告加上「async」,這樣之後要加的await才有作用。只加async卻沒加await,也不會有作用的喔!
before:
private void test_Click(object sender, RoutedEventArgs e){...}
after:
private async void test_Click(object sender, RoutedEventArgs e){...}
2. 宣告一個回傳「數值或字串」的方法 (※不見得要寫成能傳參數,只寫"public string _ConverFile()"也行) 
before:
private async void test_Click(object sender, RoutedEventArgs e){
        ...
        Thread.Sleep(2000); //模擬轉檔時會停頓的時間
        ...
}
after:
private async void test_Click(object sender, RoutedEventArgs e){
        ...
        //Thread.Sleep(2000); //將要背景執行的function搬出這個method
        ...
}
public string _ConvertFile(string para1) {
    Thread.Sleep(2000); //模擬轉檔時會停頓的時間
    return para1;
}
3. 再宣告一個Task,要利用它awaitable的特性,同時利用方便的「Factory.StartNew(...)」來快速的建立與啟動新Task (※也可以不丟參數,直接寫成 "public Task ConverFile()")  
public Task ConvertFile(string str)
{
    return Task.Factory.StartNew(() => "action");
}
4. 將「步驟2」跟「步驟3」結合
public Task ConvertFile(string str)
{
    return Task.Factory.StartNew(() => this._ConvertFile(str+"只是個丟參數的地方")); 
}

5. 將組好的task放在method中使用,記得要加上「await
private async void test_Click(object sender, RoutedEventArgs e){
        ...
        showLog.Text += await ConvertFile("End\r\n"); //取代原本會拖時間的function
        ...
}

然後就...完成! 可以執行程式,體驗差異了!

【延伸】
有興趣的可以試試看:
1. 只加Async,卻沒用Await,是不是也能成功?
2. 只是把工作丟給Task,卻沒有用Async和Await,是不是也能成功?

如果好奇「await和async」的原理,可以看MSDN的介紹
使用Async 和 Await 設計非同步程式 (C# 和 Visual Basic)
然後找到段落「非同步方法中執行了哪些工作」,會有詳細的執行流程
圖看一次不懂沒關係,不需要刻意去記住,用多就會理解了

2017年3月10日 星期五

【C#】跨視窗傳遞集合

我預計的期望是:
  在「視窗A」點按鈕(Button) → 彈出「視窗B」→ 將「視窗B」更改後的數值回傳

由於「視窗B」的設定不是只有一項,要回傳的話一定是陣列(Array)或集合(Collections)
好處是彼此的變數並不直接干涉,不用因為改了變數名,另一個也要跟著改。

※我用的是WPF,會跟WinForm有一點差距,但是概念差不多。偏基礎的部分,下面介紹就省略了,畢竟需要跨視窗還很在意修飾詞(public, private...)的人,看廢話也覺得煩吧。


視窗A - MainWindow
        private Dictionary<stringstring> SetDic = new Dictionary<stringstring>();
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            SettingWindow sw = new SettingWindow(SetDic);
            if (sw.ShowDialog() == true//從設定中取值
                SetDic=sw.ApplySetting();
         }

視窗A的程式碼主要是
第一列:建立Dictionary的集合「SetDic」,作為接收與後續利用
第四列:在事件中用實做視窗B「SettingWindow」,視窗B的建構式看下面
第五、六列:如果在視窗B有點「確定」之類的,那就會執行「SettingWindow」中寫好的方法,將回傳的集合賦值給「SetDic」

視窗B - SettingWindow
    public partial class SettingWindow
    {
        private Dictionary<stringstring> _SetDic;
        public SettingWindow(Dictionary<stringstring> _SetDic)
        {
            //(不重要,中略)
            _SetDic=SetDic;
        }
        private void Apply_Click(object sender, RoutedEventArgs e)
        {
            //(不重要,中略)
            this.DialogResult = true;
            this.Close();
        }
        internal Dictionary<stringstring> ApplySetting() {
            //(不重要,中略)
            return _SetDic;
        }
    }

視窗B就是重頭戲了,分成
第一列:可以看到這個視窗的類別名稱是「SettingWIndow」
第三列:建立一個用來暫存從視窗A丟過來的集合「_SetDic」
第四~八列:由於要接視窗A丟過來的「SetDic」,所以在寫建構式時,要定義參數型別。然後在將接到「SetDic」賦予給「_SetDic」
第九~十四列:這個是點「確定」時,會觸發的事件。重點在第十三列與第十四列的「this.DialogResult = true; this.Close();」,功能分別是「要讓視窗A第五列的IF判斷能成功觸發、關閉視窗B」
第十五~十八列:寫一個會回傳數值的方法,把在視窗B變更過的「_SetDic」回頭賦予給「SetDic」