Some MONO and ASP.NET questions.

  • Question 1: You got an error message like this:

    System.InvalidOperationException Assembly ‘System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ does not contain a Web resource with name ‘jquery’.

    Answer:
    You are trying to load script from the System.Web.Extensions. Some auto-generated code such as:

    <asp:ScriptReference Name="jquery" />

    will cause this error. Remove this kind of codes will solve this kind of questions.

  • Question 2: You got error messages like these:

    System.TypeLoadException
    Could not load type ‘System.Web.UI.IScriptResourceDefinition’ from assembly ‘System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’.
    or 
    System.InvalidProgramException
    Invalid IL code in System.Web.Handlers.ScriptModule:.ctor (): method body is empty.

    Answer:
    You use the wrong version of some assemblies. Currently known, mono has its own version for the following assemblies:
    System.Web.Extensions.dll
    System.Web.Entity.dll
    Remove them from your bin folder.
    ※ mono doesn’t support entity framework.

  • Question 3:
    You got error messages like this while hosting an MVC web on Apache with mono:

    System.Web.HttpException
    The resource cannot be found.
    Description: HTTP 404.The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
    Details: Requested URL: someurl

    Answer:
    It seems like a routing error, files and folders are all there, why “NOT FOUND"???
    You may find some solutions such as remove the targetFramework in Web.config, or ensure some libraries in the bin folder.
    But, all that not work for me.
    Finally, I found that this is a question relates to how you publish and deploy your site.
    I use the publish function in VS 2015, and I checked the “Precompile during publishing".
    Uncheck it, and publish again, everything done!!!
    System.Web.Routing.dll is not required to be deployed in the bin folder.vs publish

  • Question 4:
    You got an error message like this:

    System.UnauthorizedAccessException
    Access to the path “/etc/mono/registry" is denied.

    Answer:
    Ensure that the “/etc/mono/registry" exists. If not, create it.

    sudo mkdir /etc/mono/registry

    Change its privileges, and restart your apache.

    sudo chmod uog+rw /etc/mono/registry

Question 5:
You got an error message like this:

Application Exception
System.NullReferenceException
Object reference not set to an instance of an object
Description: HTTP 500.Error processing request.
Details: Non-web exception. Exception origin (name of application or object): SID.
Exception stack trace:
at SID.Controllers.HomeController.Index () <IL 0x00046, 0x00127> at (wrapper dynamic-method) object.lambda_method (System.Runtime.CompilerServices.Closure,System.Web.Mvc.ControllerBase,object[]) <IL 0x00006, 0x0004c> at System.Web.Mvc.ActionMethodDispatcher.Execute

And there are apache error logs like this:

Stacktrace:

at <unknown> <0xffffffff>
at SID.Business.SIDRepository/<>c__DisplayClass4.<GetContentOfDay>b__3 () <IL 0x0000d, 0x00017>
at myQuiz.Caching.CacheRepository.Update<T> (string,System.Func`1<T>,System.DateTime,System.TimeSpan) <IL 0x00003, 0x00044>
at myQuiz.Caching.CacheRepository.Get<T> (string,System.Func`1<T>,System.DateTime,System.TimeSpan) <IL 0x00026, 0x000c3>
at myQuiz.Caching.CacheRepository.Get<T> (string,System.Func`1<T>,System.TimeSpan) <IL 0x0000a, 0x00053>
at SID.Business.SIDRepository.GetContentOfDay (int,int) <IL 0x00044, 0x00187>
at SID.Controllers.HomeController.Index () <IL 0x0002f, 0x000db>
at (wrapper dynamic-method) object.lambda_method (System.Runtime.CompilerServices.Closure,System.Web.Mvc.ControllerBase,object[]) <IL 0x00006, 0x0004c>

And, if you use some logging tool such as log4net, you may got this:

System.BadImageFormatException: Could not resolve field token 0x04000005
File name: 'SID.DataAccess'
at SID.Business.SIDRepository+<>c__DisplayClass4.<GetContentOfDay>b__3 () [0x00000] in <filename unknown>:0
at myQuiz.Caching.CacheRepository.Update[String] (System.String key, System.Func`1 act, DateTime absoluteExpiration, TimeSpan slidingExpiration) [0x00000] in <filename unknown>:0

Answer:
I write an ASP.NET MVC web application using MySQL connector to communicate with MySQL database. According to MSDN BadImageFormatException said, this is because the DLL is not valid. But what MSDN not said is WHY NOT VALID!!!
Finally, I found that this is a dependency problem. My SID.DataAccess.dll requires MySql.Data.dll to run properly, but the default compile & publish doesn’t output MySql.Data.dll into target bin folder.
So, simply change the “Copy Local" property of MySql.Data.dll to “True" will solve this question.
the copy local property

設定 mono

本來,要在 linux環境中執行 Microsoft系列所開發出來的程式是不可行的。但是在 mono推出之後,這件事就不一樣了。這裡記錄採用最簡單的方法,把 mono架設在 apache中,並且實際部署執行一個 .net mvc 4的網站。
範例網站:荒漠甘泉

前提

  • 已經安裝架設好的 LAMP伺服器

內容

  1. 匯入mono GPG

    sudo apt-key adv –keyserver hkp://keyserver.ubuntu.com:80 –recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF

  2. 加入正確的來源,並更新資料庫

    echo “deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list

    echo “deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list
    sudo apt-get update

  3. 安裝 apache專用的 mono模組

    sudo apt-get install libapache2-mod-mono mono-apache-server

  4. mod_mono有一些已知的問題
    • 第一個是安裝的時候,可能會在最後停住。這個時候請用另一個 terminal下指令把 apache重啟即可。請參考 ModMono的 ubuntu官方文件
    • 第二個是 mod_mono安裝完成並部署了 .net網站之後,在 apache log中可能會見到這樣的錯誤訊息。請開啟 /etc/mono-Server4/mono-server4-hosts.conf修改下列設定MonoPath default /usr/lib/mono/4.0:/usr/lib
      改為MonoPath default /usr/lib/mono/4.5:/usr/lib
  5. mod_mono設定完成之後,還需要設定 apache伺服器,這邊我不採用所謂的 auto hosting,所以需要去修改 apache的站台設定。這邊參考了兩份文件:

    步驟上是這樣:

    • 先部署 .net網站程式, apache的預設網站路徑是 /var/www/html,但是我不會把程式混著部署在這個位置,我部署到 /var/www/mvc
    • 使用 Apache mod_mono configuration tool, Configuration Type選擇 Application。Application Name請自行輸入,這會成為你網址的一部份。比方說,我輸入mvcPath to Document Root,請輸入你 .net站台程式位置的完整路徑。以我的例子就是 /var/www/mvc 請注意最後不要有/其他選項不變。按下 Preview之後,在 Generate mod_mono Configuration中,把整個文字方塊中的文字複製起來。
    • sudo開啟 /etc/apache2/sites-available/000_default.conf並把剛才複製的內容貼到</VirtualHost>之前。
    • 複製的內容大約像這樣
      Alias /myweb “/var/www/myweb"
      MonoServerPath myweb “/usr/bin/mod-mono-server2″
      MonoDebug myweb true# The MONO_IOMAP environment variable can be configured to provide platform abstraction
      MonoSetEnv myweb MONO_IOMAP=allMonoApplications myweb “/myweb:/var/www/myweb"
      <Location “/myweb">
      Allow from all
      Order allow,deny
      MonoSetServerAlias myweb
      SetHandler mono
      SetOutputFilter DEFLATE
      SetEnvIfNoCase Request_URI “\.(?:gif|jpe?g|png)$" no-gzip dont-vary
      </Location>
      <IfModule mod_deflate.c> AddOutputFilterByType DEFLATE text/html text/plain text/xml text/javascript
      </IfModule>

      要記得修改MonoServerPath
      把它改為
      MonoServerPath myweb “/usr/bin/mod-mono-server4

    • 最後為你的 apache加入一些設定,讓網址輸入不再區分大小寫先啟用speling模組sudo a2enmod speling然後打開 /etc/apache2/sites-available/000_default.conf並在</VirtualHost>之前加入下列設定CheckSpelling ONCheckCaseOnly ON存檔關閉
    • 指示 apache重新載入sudo service apache2 reload
    • 用瀏覽器開啟網址 http://網站網址/你的Application Name

安裝及設定LAMP伺服器

這篇文章用來記錄我安裝LAMP伺服器的標準步驟(SOP)。這個SOP的產生是基於幾個理由:

  • 一般的LAMP伺服器在安裝的內容上有一些共通性,比方說ftp、ssh及防火牆等
  • 除了安裝的軟體具有一定程度的共通性之外,部份基本的設定也是共通的,比方說:防火牆開的port

所以,我把這些步驟及設定值整理起來,以免哪天自己忘了!

步驟:

  1. 安裝Linux (這個步驟請參考其他文章)
  2. openssh
    • 安裝

      sudo apt-get install openssh-server

    • 設定

      打開/etc/ssh/sshd_config

      將 port = 22

      改為 port = 12345請自行指定port喔!!!

  3. 防火牆
    • 安裝

      sudo apt-get install iptables iptables-persistent

    • 設定

      iptables -A INPUT -i lo -j ACCEPT
      iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
      iptables -A INPUT -p tcp --dport mysshport -j ACCEPT
      iptables -P INPUT DROP

  4. 自動封鎖
    • 安裝

      sudo apt-get install fail2ban

    • 設定

      修改 /etc/fail2ban/jail.conf

      • bantime:設定要封鎖多久,以秒為單位
      • findtime:設定在多少時間內違反規則要封鎖,以秒為單位
      • maxretry:搭配 findtime,設定重試次數,超過即封鎖

      同一個檔案中,請找到 [ssh] 區段,沒有的話請自建,並確認下列參數:

      • enabled = true
      • port = 12345請使用您自行指定的ssh port
      • maxretry:如果有這個參數的話,那麼 ssh 就會採用這裡設定的重試次數,而不是上面那個

      設定完成之後,重新啟動fail2ban
      sudo service fail2ban stop
      sudo service fail2ban start

      檢視目前的防火牆規則
      sudo iptables -L -n


      iptables screen shot

  5. logrotate

    修正logrotate的問題

    logrotate -f /etc/logrotate.conf

    這個部份是參考這篇文章

  6. 其他工具 wget, nano
  7. 開始安裝Apache

    sudo apt-get install apache2

    安裝完之後在 /etc/apache2/conf_available 新增一個檔案叫做 ServerName.conf 並將其內容設定為

    ServerName localhost設定完成之後,啟用該設定檔
    sudo a2enconf ServerName

    接著指示 Apache 重新載入
    sudo service apache2 reload

    Apache設定完成!!!

  8. PHP的安裝及設定

    安裝相關的 Apache 模組

    sudo apt-get install libapache2-mod-php5 php5-cli php5-common php5-cgi

    編輯 /etc/apache2/sites-available/000_default.conf

    找到 DirectoryIndex 並把它改成

    DirectoryIndex index.php index.html

    接著在 /var/www/html/ 新增一個檔案 index.php

    檔案的內容如下:

    <?php
    phpinfo();
    ?>

    現在可以來進行測試了。在瀏覽器輸入 http://你的網址/

    你應該可以看到這樣的畫面,那就表示你的 php 安裝完成囉!

    php screen shot

    做完測試之後,為了安全性的考量,避免對外揭露過多的系統細節,記得把 index.php 刪除。
    sudo rm /var/www/html/index.php

  9. MySQL安裝
    • MySQL 網站下載 deb 檔案
    • 安裝剛剛下載的 deb 檔案,可以參考這篇文章,或是直接使用下面的指令sudo dpkg -i xxxxxxxx.deb
    • 執行套件更新sudo apt-get update
    • 開始安裝 MySQL,並安裝相關的套件sudo apt-get install mysql-server php5-mysql
    • 安裝完成後,必要執行的兩個步驟:資料庫路徑初始化,參考文件sudo mysql_install_db資料庫帳號保全,參考文件sudo mysql_secure_installation
    • 最後,進行資料庫的測試,可以參考文件,或是安裝 phpMyAdmin ,然後直接使用 phpMyAdmin 做測試。我習慣採用 phpMyAdmin。
  10. 安裝 phpMyAdmin
    1. 官網下載 phpMyAdmin
    2. 解壓縮檔案unzip phpMyAdmin-4.4.10-all-languages.zip
    3. 將解壓縮出來的資料夾 phpMyAdmin整個移動到目前 apache的網站目錄中sudo mv phpMyAdmin /var/www/html/
    4. 切換到 phpMyAdmin的目錄中cd /var/www/html/phpMyAdmin/
    5. 用 phpMyAdmin提供的預設範本來建立設定檔sudo cp config.sample.inc.php config.inc.php
    6. 修改設定檔內容,找到 $[‘blowfish_secret’]給它設定一組密鑰,以便用來加密 cookie,存檔完成!
    7. 打開瀏覽器,輸入 http://你的網址/phpMyAdmin/,正常的話會看到這樣的畫面phpMyAdmin screen shot

實用的Linux指令、套件

這邊記錄一些個人覺得好用的Linux指令、套件,以提供未來重新安裝系統的時候做為檢查列表之用。

screen

使用遠端管理系統的時候,遇到需要長時間執行的指令,不希望一直掛著session或是害怕session會斷線時,可以使用。

fail2ban

搭配iptables,用來封鎖IP,保護系統。

mkvmerge

將字幕檔合併到mkv檔案中。

使用方式 mkvmerge -o <output>.mkv –default-track 0 –language 0:<language> <subtitles>.srt <input mkv>

列舉語言代碼:使用參數 –list-languages。