Quantcast
Channel: 黑暗執行緒
Viewing all 2456 articles
Browse latest View live

【笨問題】Inline-Block元素多出來的間隙

$
0
0

一個很初級但常見的HTML問題 - 已將margin設為零,但兩個inline-block元素間存在消不掉的空隙。

實例如下:

<!DOCTYPEhtml>
<html>
<head>
<metacharset="utf-8">
<title>Inline-Block Test</title>
<style>
  .layout > span {
    display: inline-block;
    background-color: lightblue;
    width: 40px;
    height: 30px;
    margin: 0px;
    line-height: 30px;
    text-align: center;
  }
</style>
</head>
<body>
<divclass="layout">
<span>A</span>
<span>B</span>
<span>C</span>
</div>
</body>
</html>

使用網頁開發工具確認<span>的margin與border寬度均為零,但看到的<span>之間存在間隙。demo

display: inline不能指定元素寬度,display: block可指定寬度但會強制換行,為兼顧指定寬度及並排,<span>採用display: inline-block樣式。但在inline-block模式下,元素HTML標籤間的空白、換行及Tab字元將佔用一格空間(依HTML規範,連續多個空白只會保留一個),以上範例,</span>與下一個<span>間有換行符號及Tab定位字元,視為一個空白,即<span>間空隙的由來。

這問題頗為常見,解法有好幾種:

解法1:移除<span>間的空白與換行 demo

<divclass="layout">
<span>A</span><span>B</span><span>C</span>
</div>

解法2:將容器Font-Size設為0px,再明確指定子元素Font-Size(破壞繼承關係後需重設子元素字型大小,有點搞缸)demo

<style>
  .layout {
    font-size: 0px;
  }
  .layout > span {
    font-size: 12pt;
    display: inline-block;
    background-color: lightblue;
    width: 40px;
    height: 30px;
    margin: 0px;
    line-height: 30px;
    text-align: center;
  }
</style>

解法3:設定負值Margin(需視CSS樣式決定數值,無法一體適用) demo

<style>
  .layout > span {
    display: inline-block;
    background-color: lightblue;
    width: 40px;
    height: 30px;
    margin: 0px;
    margin-right: -4px; //右側加上負Margin
    line-height: 30px;
    text-align: center;
  }
</style>

解法4:取消block: inline-block; 改用float: left; 一樣可指定元素寬度及高度 demo

<style>
  .layout > span {
    font-size: 12pt;
    float: left;
    background-color: lightblue;
    width: 40px;
    height: 30px;
    margin: 0px;
    line-height: 30px;
    text-align: center;
  }
</style>

評估之下,float: left算是最省事的解法,就用它吧!


TIPS-清除CSS float設定

$
0
0

前篇文章提到用float: left解決inline-block元素間隙問題,感謝保哥提醒,發現我忘了提到它的副作用,設定float: left或float:right之後,後方元素必須明確宣告clear:float/right/both清除浮動設定以免繼續受影響。例如,沿用前文範例,後方再加一個<div>(顯示模式為display:block),將繼續套用float: left被接在A、B、C後方。demo

要解決問題,最直接的做法是為<div class="another">加上clear: both宣告,如下:demo

不過,此種設計邏輯並不算乾淨俐落!前方元素產生的後遺症留給後方元素善後,有違觀注點分離(SoC)理念,當後方元素搬動,換上其他元素,clear設定就得改設在新元素上。 更理想的設計應是「設定float的元素要負責消除自己的業障後遺症」,讓我們不需依特定前後關係加設CSS,如此會更簡便。而我們可以利用CSS的::after虛擬元素實現這點:demo

.layout::after是所謂的虛擬元素(或稱偽元素),瀏覽器依此設定會在<div class="layout">後方補上一個虛擬元素,其內容為空白(content:""),顯示方式為block(display: block),並指定clear: both。(註:這三條都要設定才能清除float設定)

如此,<div class="layout">後方形同多接了一個看不見的空白,其存在最重要的意義在於清除float: left設定。後方不管接上任何元素,都不需勞煩多加clear設定,是不是簡便多了?

但要留意,老IE(IE6/7/8)不支援::after!仍需要與老IE博鬥的朋友們,願原力與你們同在~

【同場加映】::after還有不少精彩的花式應用,有興趣的同學可參考Muki的介紹

TIPS-TypeScript類別無法模擬同名函式

$
0
0

文章標題讓人霧煞煞,不過也想不出更精準的形容,但看下去大家(我是指有選修TypeScript的同學,其餘同學請前往自己的選課教室)應該就明白了…

故事是-我在寫TypeScript單元測試,想做一個假物件模擬SingalR HubProxy的行為,由NuGet取得定義檔signalr.d.ts,其中HubProxy介面定義如下:

interface HubProxy {
    (connection: HubConnection, hubName: string): HubProxy;
    state: any;
    connection: HubConnection;
    hubName: string;
    init(connection: HubConnection, hubName: string): void;
    hasSubscriptions(): boolean;
    on(eventName: string, callback: (...msg: any[]) => void ): HubProxy;
    off(eventName: string, callback: (msg: any) => void ): HubProxy;
    invoke(methodName: string, ...args: any[]): JQueryDeferred<any>;
}

直覺想到的寫法是宣告一個新類別實做HubProxy介面,class fakeHubProxy implements HubProxy,加上state、connection、hubName屬性,init()、hasSubscriptions()、on()、off()、invoke()等方法,這些都不成問題,但在第一條宣告上我觸礁了。

(connection: HubConnection, hubName: string): HubProxy 並非建構式,而是指傳入connection及hubName,將HubProxy當成函式(Function)呼叫(不使用new關鍵字,術語為Callable Signature),該函式需傳回符合HubProxy介面的物件,例如: var hub = HubProxy(conn, "hubName");。

爬文後,得到結論:不可能!TypeScript類別不支援此功能,需改用函式。

這串stackoverflow討論中,我認同basarat的看法:

The reason is that an interface is primarily designed to describe anything that JavaScript objects can do. Therefore it needs to be really robust. A TypeScript class however is designed to represent specifically the prototype inheritance in a more OO conventional / easy to understand / easy to type way.
在TypeScript裡,「介面」被設計成具有很高的彈性,以包容任何JavaScript物件,再複雜都能用介面定義規範。而「類別」不同,它試圖以傳統OO嚴謹易懂的方式包裝JavaScript獨特的Prototype繼承概念。

結論是當interface出現(param, param): resultType形式的宣告,只能用函式滿足該interface,不可能用類別實做。以下是一個應用範例:Demo

interface Foo {
    (name: string): Foo;
/** 名稱 */
    Name: string;
}
//使用函式實現interface Foo
var foo1: Foo = <Foo>function(name: string) {
//小技巧:將self宣告為Foo型別,以享用Intellisense
var self: Foo = this;
    self.Name = name;
return self;
}
 
var test: Foo = foo1("Jeffrey");
alert(test.Name);

兩點補充:

  1. function(name: string) { … }寫法與一般函式無異,透過<Foo>語法強制轉型即可指定給Foo型別變數。延伸閱讀:參見新手村心得第5點
  2. 在函式內部使用this.Name就能增加新屬性,但我用了一個小技巧「另外宣告var self: Foo = this」,以self代替this能享受強型別的好處;若要宣告Foo介面未定義的屬性方法,則可改用this(型別為any),魚與熊掌兼得~

【茶包射手日記】遠端桌面剪貼簿失效

$
0
0

到同事座位射茶包,常會有意外收獲-從別人的操作裡學到小密技。有許多小密技藏在主人身上多年,直到某天被人發現才開始交流,但埋沒多年倒不是要刻意留一手,而是因為:

  1. 自覺密技小到不足掛齒,不好意思分享,就跟「不會因為花盆種出一棵葱就請朋友來家裡吃飯品嚐」是一樣道理。(當然,也有一種人,也不知算哪根葱,老把雞毛蒜皮小事都PO上網還取名什麼XX射手日記…)
  2. 某些小技巧的學習跟使用都不花力氣,久而久之已成直覺反應,遇到狀況就會拿出來用,但硬要整理分享,你不會想到它。
  3. 小技巧使用多年,以為每個人都會,自然不覺得需要額外介紹。

要挖掘這些不足掛齒小密技,「觀察」似乎是唯一管道。(透過觀察交流學習的概念,讓人聯想到Pair Programming,老闆,我可以輪流搬椅子坐在同事後面當背後靈偷學武功嗎? :P)

前陣子幫同事用Terminal Service連線遠端主機查問題,要從本機複製URL貼到遠端瀏覽器,發現剪貼簿共用失效。本機剪貼內容無法傳到遠端主機,遠端主機的剪貼內容也無法傳到本機,但在遠端主機內部複製貼上則正常。這問題之前遇過,我知道的解法是登出再重新登入即可恢復,正當我跟同事討論這枚茶包時,另一位同事悠悠開口:那是剪貼簿程式當掉了,砍掉重啟就好。看過示範,我學會新密技!

開啟工作管理員,找到rdpclip.exe,按「結束工作」或刪除鍵砍掉它!

使用工作管理員的執行新工作,重新執行rdpclip,問題排除!

怎樣,這棵葱的味道還不錯吧?

SSRS報表瀏覽器相容議題

$
0
0

接獲報案,某使用HTML5技術的網頁以iframe內嵌SSRS報表,若以IE9開啟該網頁,報表排版走樣,但使用IE10開啟則正常。單獨開啟SSRS報表(URL /reportserver/viewer/..)測試,發現不同IE相容性檢視結果均不同,只有用IE5(Quirks)檢視正常,而IE7/8/9/10相容模式壞掉的地方都不相同。


IE5正常(IE9-遇到網頁未指定<!DOCTYPE>的預設模式)

IE7模式,報表寬度OK,下半部被截斷。

IE8模式,報表只出現一小塊,右邊出現雙下巴捲軸

IE9,報表只出現一小塊

IE10,報表變瘦又變高,變成姚明來著

由結果推測SSRS2005報表只支援Quirk模式,測試機版本為SQL 2005 SP3,本想升級SP4試試手氣,但在stackoverflow被澆一盆冷水:

I can tell you, I have 3 years experience with the damn thing (SSRS 2005, SSRS 2008 R1 & R2, and SSRS 2012).
Let me assure you that because SSRS HTML reports depend on IE5-Quirksmode, there is no chance in hell they will ever render correctly in any browser other than Internet Explorer (IE < 10 I might be inclined to add).

依據曾跟SSRS2005-2012博鬥多年苦主的證言,SSRS只適用IE並限定IE5 Quirks模式!就算升級也沒效,至於為什麼HTML5網頁以IFrame內嵌SSRS報表,用IE10檢視OK,用IE9卻不行?MSDN有答案

As of IE9 mode, webpages cannot display multiple document modes. For example, consider a standards-based webpage that contains a frame element that displays content in quirks mode. IE9 mode displays the child frame in standards mode (because the parent document is in standards mode). Starting with Internet Explorer 10, however, child frames can emulate quirks mode. For more info, see IEBlog: HTML5 Quirks mode in IE10. For best results, however, use document modes consistently.

在IE9(含)之前,網頁不能混合多種文件模式。IE10起,才允許網頁走標準模式,子Frame模擬Quirk模式,正是HTML5網頁內嵌SSRS報表的情境。

不打算深究搞Hacking,我想到幾種解決方式:

  1. 請使用者升級IE10
  2. 將報表改為RDLC,改用ReportViewer(瀏覽器支援度較廣
  3. 放棄HTML5,改成傳統Quirks網頁(走回頭路,不推)
  4. 用window.open取代iframe克服IE9不支援混用文件模式限制(彈出視窗很可能被瀏覽器封鎖,部署狀況較多)

個人投RDLC一票。

硬碟故障經驗一則

$
0
0

同事好心提醒,他的硬碟幾天前出現異狀,硬碟健檢程式回報健康度只剩55%,備份搶救已有部分檔案毁損。而最重要的,同一批採購的電腦前幾個月才有另一台也發生硬碟掛點!

依據多年搞電腦的經驗,同廠牌同期硬碟在某一時期集體暴斃時有所聞,不敢怠慢~ 執行Acronis Drive Monitor硬碟健檢程式,報告令人大驚失色,健康指數只剩5%!

解讀數據,最嚴重的問題出在Reallocated Sectors Count(因硬碟磁區損壞重新分配到備用碟區的數量)。SMART資料有三種值,Raw Value為原始數據,Value為原始數據換算的健康指數,最大值通常為100、200或253,愈高表示愈健康,Threshold則為製造商允許的下限,當Value低於Threshold,代表已達保固條款可更換的門檻。【參考

我的硬碟SMART 磁區重新配置數Value仍為100(門檻為36),但Raw Value已達120。我把它翻成白話文:硬碟已經有120個磁區損壞換到備用磁區,但廠商說備用磁區還很多不怕你壞,健康指標仍有100頭好壯壯,等低過36就會讓你換新硬碟哦!啾咪~ orz

依照另一份網路文件

重新配置的磁區計數 (Reallocated Sector Count)

是代表硬碟碟盤上的磁區有壞軌,被分配到備用磁區的數量。
由於硬碟是極為精密的機械裝置,磁頭與高速旋轉中磁盤之間的間隙比灰塵還小上許多,因此硬碟極易受到外在因素(碰撞、溫度…) 的影響而發生壞軌。目前市面上的硬碟,都會預留一部份備用磁區,將壞磁區以重新指派到備用磁區的方式,來達到修復的功能。這個數字並不代表硬碟一定有問題,但如果在正常情況下使用硬碟,數目仍無端增加,那就是硬碟開始老化或快故障的徵兆。一般來說,此數字如果在個位數,並且沒有再增加,都還算在正常範圍。但如果RAID等級是 JBOD、RAID 0或是 NAS 是應用在存放關鍵資料,此數值大於1 時,我們仍建議換一個硬碟,以降低資料損毀的風險。

若要採較謹慎的態度:重配置數大量增加通常是硬碟快掛掉的前兆,對於儲存重要資料的硬碟,建議只要數值大於1就該更換。大於1就該換硬碟,拎杯已經飆到120啦!!

對照另一台用了三年多的機器的HD Tune檢測結果,Reallocated Sectors Count Data(Raw Value)為零,這才是我認為的正常值。

好心同事們借我備用硬碟跟外接盒(發生硬碟集體暴斃的好處是急救裝備普及化,左右鄰居家就有心臟電擊器跟葉克膜),趕緊備份資料,要跟時間賽跑。

一旦全面複製資料,病入膏肓的硬碟再也瞞不住病情!一複製到特定檔案就會導致操作介面凍結,事件檢視器也可看到atapi嚴重錯誤The driver detected a controller error on \Device\Ide\IdePort1,代表讀檔時發出IO錯誤,硬碟真的病了!

放棄完整備份的希望,只求能搬愈多資料愈好,苦主同事介紹一套複製工具Unstoppable Copier,能忽略壞檔不中斷複製作業,盡可能保全最多檔案(記得要調成Fastest Data Recovery,搶時間救更多檔案)。複製1TB資料要超過6小時,下班放著執行等第二天看結果,未料隔天發現系統已重開機,複製作業只進行一半。好吧!再來一次,而這回我親眼目睹複製到特定檔案,進度停滯桌面凍結(Ctrl-Alt-Del也沒反應),數分鐘後出現Blue Screen… 這應該也是昨夜重開機的原因。

不得已,避開問題資料夾,依重要性排序,一次只複製一個,救多少算多少。最後,只捨棄了四五個資料夾,受損資料在版控伺服器或其他來源也可以找到,損失不算重大。但重新安裝作業系統、軟體及佈置環境是免不了,耗掉寶貴的專案時程。

今天,健檢報告出爐後第七天,發現硬碟已從系統上消失,再也回不來了。感謝同事提醒,躲過一次無預警硬碟掛點災難~

【心得整理】

  1. 一直以為SSD陣亡率比傳統HD高,所以大家都習慣把重要資料放在傳統HD,但接連三台使用兩年機器都是SSD安裝無羔,傳統HD掛點,令人頗為意外。
    (看來,HD不一定比SSD耐操!但SSD故障多是瞬間消失,連說再見的機會都沒有,HD一般在出怪聲,有異狀後,仍有一點時間能搶救資料,相較之下仁慈一點)
  2. 機器因作業需求得24小時開機,而故障HD機型非企業等級,可能是壽命不如預期的原因之一。
    註:硬碟可區分為一般級及企業級。企業級硬碟依7x24小時運轉情境要求MTBF(平均使用多少小時才會出現故障),並提供較長年限保固,依理較耐操。一般級硬碟設想情境為5x8小時,當使用量高於此標準,壽命就可能低於其號稱MTBF小時。
  3. 這回能在HD掛點前提早搶救資料,歸功於同事的警示(感謝!)。問題HD雖然重配置磁區數已達120,但掃瞄不到任何損壞磁區(壞掉部分應該都已改用備份磁區頂替),依廠商標準,它仍算健康不到需保固換新的標準。但依這次經驗,HD早已病入膏肓,只要讀到特定碟區就會有嚴重錯誤,且在七天後就歸西了~若非全碟備份讀到問題區域出現桌面凍結及IO錯誤,之前使用完全未察覺任何異狀。
    面對這種無形殺手,我想定期檢查SMART指標是唯一手段,文章提到的Acronis Drive Monitor及HD Tune都是可用工具。
  4. 試用USB 3.0硬碟外接盒寫入資料,極速可達150MB/s,已達HD寫入上限。對單一HD,USB 3.0很夠用,不一定要SATA。
  5. 備份才為王道
    重要專案資料有版控後援,不用太擔心,一些重要資料也會定期備分到其他主機上。 但一些資料如VM的磁碟映象檔(Image)動輒數十GB,除非備妥相同容量或更大容量的儲存媒體,沒什麼較好的解決方案。(NAS是不錯的解決方案,但工作設備購置受限較多,不若家裡自由,只能隨緣)
    系統碟裝在SSD,但沒做完整備份,導致無法快速重灌還原,值得改進。未來考慮在HD上保留SSD相同容量空間,定期完整備份,以求加速災難還原速度。

設定Windows 8網路喚醒(Wake On LAN)

$
0
0

經歷硬碟掛點,決定改變電腦使用習慣,防止悲劇重演。

學到一個教訓-非企業級硬碟只是一般兵,經不起7x24小時兩棲偵營魔鬼操練,有提早升天的風險!改善之道很簡單:只要由7x24待命責任制回歸5x8下班打卡制,就能有效延長硬碟乃至整台機器的使用壽命,另一方面還兼顧省電環保。

原本機器不關機是工作需要,方便從家裡走VPN連回公司機器遠端桌面處理,同時有些私有排程或服務也放在自己機器上跑。排程及服務可以重新評估規劃,集中到少數機器,大部分個人主機下班時便可睡眠或休眠,需要遠端連線時再開起來,這倒也不難,打電話給家離公司最近的同事,要他馬上衝去辦公室幫忙開機不就好了~ 喂!不要這樣陷害同事啦,有更高級的做法-網路喚醒(Wake On LAN,WOL)。在軟硬體支援的前題下,電腦在休眠(Hibernation)或睡眠(Sleep)期間,網路卡仍能接收及解讀封包,當接收特定內容封包(稱為Magic Paket,內含該網卡的MAC地址)就會叫醒電腦。透過WOL技術,即能達成「下班先休眠,需要連線再開」的目標。

原本工作機安裝Windows 2008 R2,啟用Hyper-V後得動點手腳才能休眠。趁著硬碟故障重灌,索性改換Windows 8.1,更符合其開發者客戶端性質,真需要伺服器,再跑Hyper-V VM模擬。

Windows要設定WOL,第一步得啟用網卡的WOL功能,如下圖由網卡內容找到「允許這個裝置喚醒電腦」及「只允許Magic封包喚醒電腦」選項勾選起來,一般多會限定Magic封包(封包內需包含該網卡MAC地址),以免意外被無關封包喚醒。

接著,我們需要網卡IP及MAC地址以便產生Magic封包,可透過ipconfig /all取得。

Windows 8及8.1要啟用WOL,還有一個額外步驟:停用快速啟動,理由是快速啟動會讓系統進入Hybrid Shutdown狀態(S4),而WOL功能只支援從Sleep狀態(S3)或Hibernation狀態(S4)被喚醒。如下圖所示,要使用WOL記得要在電源選項取消快速啟動。

最後一步是取得發送WOL Magic封包的軟體,WOL Magic Packet Sender是個介面簡潔易用的小程式,更重要的是,它是用.NET寫的, 二話不說,非它莫屬了。

輸入IP、MAC地址,按下送出鈕,程式會送出一個六個Byte 0xff外加MAC地址重複16次,共102個Byte的封包到指定IP。若此封包能順利送抵睡眠中的電腦,即可將其喚醒。而如何能將封包送達目的地,便是WOL成敗所在,公司的網路環境有些複雜,花了點功夫摸索外加溫習了當年考MCSE所學的Network Essentials,大略摸出輪廓,細節留待後面再提。先回到WOL軟體,我們可以在目標機器也執行該軟體的Receive功能進行測試,發送端按下送出鈕後,接收端應跳出訊息顯示MAC網址,代表發送成功。接著實測,讓目標電腦睡眠,在同一網段(Subnet,在本例中即為192.168.1.*的其他電腦)送出WOL封包,機器果然成功被喚醒。

不過,多做一些測試後發現結果不如預期:

  1. 目標機器為192.168.1.91,睡眠後由192.168.1.90送出Magic封包至192.168.1.91可將其喚醒,但等待一段時間後再送封包卻無效。
  2. 由另一個網段192.168.2.1送出Magic封包,192.168.1.91開機用軟體Receive功能測試OK,睡眠後隨即傳送可喚醒,但等待一段時間後喚醒功能亦會失效。
  3. 將發送目標IP改為192.168.1.255,睡眠後不管多久,都可順利喚醒。

由以上結果,推敲與網路交換器(Switch)特性有關,192.168.1.91在開機期間有網路活動,Switch會記錄並保留192.168.1.91對應MAC地址及實體插孔資料,當有傳給1.91的封包,Switch才知道要往哪個實體插孔傳送。機器睡眠後不再傳送封包,經一段時間後Switch認定該MAC所屬機器離線,便不再傳送給91的封包到該實體線路上。這可解釋剛關機時可喚醒,一段時間後Switch資料更新,便無法再用Magic封包喚醒主機。第三項實驗將目標IP設為192.168.1.255,末碼255會使Switch對全網段廣播,以MAC地址ff-ff-ff-ff-ff-ff送出封包,該網段所有網卡都會看到,睡眠電腦由封包內容識別出自己的MAC地址,就能被喚醒。

因此,WOL最容易實現的情境是在同一網段下以廣播方式(IP用*.*.*.255)傳送Magic封包。想跨網段傳送,需Switch或路由器配合,例如:設定一靜態IP 192.168.1.253 MAC定為ff-ff-ff-ff-ff-ff[參考],傳送Magic封包時將目標IP設為192.168.1.253,即可達到廣播效果。VPN連到主機是跨網段無誤,但公司Switch不在掌控範圍內,此路不通,最後只能繞路解決,不過這又是另一段故事了…

自製Wake On LAN Magic封包

$
0
0

前文提到計劃將辦公室的電腦改為下班休眠,需VPN連線時再透過網路喚醒,但遇到一點困難:WOL封包必須透過廣播方式送到休眠主機,最簡便的做法是在同一網段內(Subnet)發送IP末碼為255(例如:192.168.1.255)的封包,電腦會以MAC地址ff-ff-ff-ff-ff-ff發送,所有網卡都會收到。而問題出在使用VPN連線時,家中電腦取得的公司IP與休眠主機分屬不同網段,無法透過IP 255廣播,前文提過一種在Switch/NAT設定靜態IP對應MAC ff-ff-ff-ff-ff-ff的解法,但公司網路設備非掌控範圍,無法在上面動手腳,想到最直覺的做法-在同網段內找一台機器跑一個內應程式,接受來自跨網段要求,對網段內廣播WOL封包。

前文提到的WOL Magic Packer Sender軟體,需透過操作介面手動傳送,但Magic封包的構造很簡單,六個Byte 0xff,配上目標MAC地址(也是六個Byte)重複16次,共102 Bytes,用C#組byte[]再用UdpClient送出就能搞定,所以:

using System;
using System.Net;
using System.Net.Sockets;
using System.Linq;
 
publicclass MagicPacket
{
 
publicstaticvoid Send( string ipAddress, string macAddress)
    {
//UDP Port 9
        IPEndPoint pEndPoint = new IPEndPoint(IPAddress.Parse(ipAddress), 9 );
byte[] macAddrBytes =
//將aa:bb:cc:dd:ee:ff或aa-bb-cc-dd-ee-ff MAC地址轉成byte[]
            macAddress.Split('-' , ':')
            .Select(o => Convert.ToByte(o, 16)).ToArray();
//送出UPD封包
using (UdpClient udpClient = new UdpClient ())
        {
byte[] data = newbyte[102 ];
//最前方六個0xff
for (var i = 0 ; i < 6; i ++ )
                data[i] = 0xff ;
//重複16次MAC地址
for (int j = 1 ; j <= 16; j ++ )
            {
                macAddrBytes.CopyTo(data, j * 6);
            }
            udpClient.Send(data, (int)data.Length, pEndPoint);
            udpClient.Close();
        }
    }
}

就這樣,呼叫MagicPacket.Send("192.168.1.255", "aa-bb-cc-dd-ee-ff"); 即可正確送出Magic封包喚醒電腦,這段程式可以放進同網段其他主機的ASP.NET,改用瀏覽器叫電腦起床,也可以寫成服務接收從簡訊、Skype、HipChat傳來訊息代替Morning Call,運用上很有彈性。

補上這一小塊拼圖,我的跨網段網路喚醒計劃終於完成了~


號外!迎接開放原始碼與跨平台的.NET新時代

$
0
0

微軟這兩天有個Connect線上研討會(台灣時間11/12 23:00開始),由Scottgu領軍,介紹下一代的Visual Studio vNext、ASP.NET vNext以及Microsoft Azure,一開場就宣佈了重大消息(大家看到後會驚呆嗎? XD),隨後Scottgu也在部落格整理這次的.NET變革:

.NET核心Runtime及程式庫開放原始碼

繼ASP.NET、Visual Studio編譯核心Roslyn開放原始碼之後,一不做二不休,微軟決定將.NET核心也Open Source,一樣交給獨立組織.NET基金會管理經營。開放原始碼的目的在求與開發社群更密切融合,所有開發者能直接回饋,參與架構決定,甚至提交自己修改的程式變成.NET的一部分,日後才有機會跟孫子話當年勇:阿公寫的程式現在在好幾億台機器上跑呢!XD

.NET Core Runtime開放的範圍包含執行.NET程式所需的所有環節:CLR, Just-In-Time Compiler (JIT), Garbage Collector (GC), 以及.NET Base Class Libraries (BCL),大家可以在Github找到它們:https://github.com/dotnet/corefx (MIT授權)目前先開放一些新的核心程式庫模組,未來幾週會陸續將核心都送上去。

.NET Framework正式支援Linux及OS X

雖然.NET早就可以透過Mono在Linux平台上執行,但是終於,微軟正式將Linux納入.NET Framework的支援版圖,.NET開發人員從此能抬頭挺胸地說:我寫的程式在非Windows平台上也可以跑!(等這天等好久了~)

微軟將與Mono社群合作,引進Mono開發的一些進階功能,推出自己的Linux版本,而Mono社群也會因.NET開放原始碼,有助於開發。(但我個人覺得二者有互相替代性,未來或許會整合吧!)

Visual Studio社群版

地表上最強的開發工具,Visual Studio,一直是付費商業軟體,過去雖然有Visual Studio Express免費版本,但功能陽春,支援專案類型少,也無法使用擴充套件。這次所釋出的Visual Studio Community 2013免費版本,具有VS2013的完整功能,支援各種類型專案,可整合Xamarin、ReSharper、VsVim等各式擴充套件,讓Visual Studio好用到升天!

Visual Studio社群版適用的對象包含:

  • 開發商業或非商業專案的個人開發者
  • 參與開源專案的開發者
  • 學術研究或教育課程參與者(例如:老師、學生、教室電腦安裝、線上課程等)
  • 五名開發者以下的非企業組織

VS社群版現在已經開放下載囉!www.visualstudio.com

【心得】

這些改變影響有多大呢?分享我的一次推坑失敗案例:對象是大學的研究人員,準備投入一個中大型的科學研究計劃,需要開發涉及複雜數學運算,平行處理的程式。開發者有一些微軟開發經驗,C#原本是首選,當我被徵詢意見,自然是極力為.NET搖旗吶喊。但很遺憾地,該專案最後選擇了Java,理由是學術單位有很多Linux平台,未來跑網格運算需要大量機器,Linux成本較低,.NET雖有Mono可跨平台,但缺乏官方支援與背書,跑起來名不正言不順。另一方面,專案程式開發未來會開放其他研究者參與,.NET及Visual Studio固然威力強大,商業色彩卻讓許多學術人員卻步… 這番理由充分,怪不得最後專案選了Java。

如今,.NET開源並正式支援Linux平台,VS2013也推出免費社群版。物換星移,再次面臨相同抉擇,或許會有不同的結果吧!

微軟,幹得好!(雖然.NET for Linux晚了這麼久,但遲到總比缺席好)

【茶包射手日記】Windows 2003啟用失敗

$
0
0

Windows 2003 Hyper-V VM由Windows 2008 R2搬到Window 8.1,安裝新版整合驅動程式後,Windows 2003偵測到主機硬體異動,要求重新啟用Windows。

啟用時出現錯誤訊息:Unable to establish a connection with the activation server. Please check your network settings and confirm that you are able to connect to the Internet, then try again.

系統抱怨無法連線到啟用伺服器,要求確認網際網路連線無誤再試一次。回到桌面使用瀏覽器確認上網正常,排除網路不通的因素,重試數回訊息依舊。

召喚網路茶包一哥-Microsoft Network Monitor,觀察到啟用程式嘗試連線207.46.84.60 80 Port,但伺服器無回應。

爬文找到一篇啟用FAQ KB,其中提到將productactivation.one.microsoft.com加入Proxy排除清單的技巧,推測它就是啟用伺服器的FQDN,使用nslookup也驗證了這點。但DNS查詢回覆結果有兩個IP:94.245.126.128以及207.46.84.60,後者就是我由MNM查到的IP。

測試發現,兩個IP中,207.46.84.60 80 Port無法連線但94.245.126.128有回應。

 

不確定這是怎麼一回事?但我很快想到解決方法:在system32/drivers/etc/hosts裡將productactivation.one.microsoft.com強制指向94.245.126.128,重新嘗試啟用Windows,鋸箭過關!(撥瀏海)

PS:知道在Window 2003怎麼手動執行啟用Windows視窗?執行oobe/msoobe /a!(這是咒語吧?)參考

奇妙的.NET程式庫版本參考錯誤

$
0
0

遇到奇妙的.NET程式庫版本參考錯誤。

試用以下專案重現問題,主專案RefIssue參照類別程式庫Blah專案:

Blah專案有一個TextId列舉,一個TextRes類別,提供靜態方法將TextId列舉轉換成字串。

 
namespace Blah
{
publicenum TextId
    {
        TextPattern,
        MsgDismatch,
        MsgAbout
    }
 
publicclass TextRes
    {
publicstaticstring GetText(TextId id)
        {
switch (id)
            {
case TextId.TextPattern:
return"[0-9A-Za-z]{1,6}";
case TextId.MsgDismatch:
return"不符要求";
case TextId.MsgAbout:
return"別讓黑大不開心";
            }
returnstring.Empty;
        }
    }
}

RefIssue程式很單純,將字串"abc123"與TextId.TextPattern對應字串"[0-9A-Za-z]{1,6}"進行Reqular Expression比對,若格式不符則輸出TextId.MsgDismatch對應字串,符合時則輸出"OK"。在正常狀況下,應該要看到OK字樣。

using System;
using System.Text.RegularExpressions;
using Blah;
namespace RefIssue
{
class Program
    {
staticvoid Main(string[] args)
        {
string pwd = "abc123";
if (!Regex.IsMatch(pwd, TextRes.GetText(TextId.TextPattern)))
            {
                Console.WriteLine(TextRes.GetText(TextId.MsgDismatch));
            }
else
            {
                Console.WriteLine("OK");
            }
            Console.Read();
 
        }
    }
}

下一步來玩點小把戲:將整個bin/Debug的檔案複製到Test資料夾,接著修改TextId列舉,在最前方增加一個新項目NewValue:

 
namespace Blah
{
publicenum TextId
    {
        NewValue, //在最前方插入資料
        TextPattern,
        MsgDismatch,
        MsgAbout
    }
 
publicclass TextRes
    {
publicstaticstring GetText(TextId id)
        {
switch (id)
            {
case TextId.NewValue:
return"新資料";
case TextId.TextPattern:
return"[0-9A-Za-z]{1,6}";
case TextId.MsgDismatch:
return"不符要求";
case TextId.MsgAbout:
return"別讓黑大不開心";
            }
returnstring.Empty;
        }
    }
}

重新編譯後,測試結果仍顯示OK,很合理。有趣的部分來了:將重新編譯的RefIssue.exe複製到Test資料夾覆寫舊檔,但Blah.dll不要更新,執行Test下的RefIssue.exe,猜猜會有什麼結果?

好笑吧? 程式顯示一段莫名其妙的訊息。

問題出在列舉編譯後會儲存成數值,當變更TextId列舉在前方插入新值,會使原本的第0個項目變成第1個,第1個變成第2個。重新編譯RefIssue.exe,TextId.TextPattern將等於1,TextId.MsgDismatch會存成2,此時配上舊版Blah.dll,TextId.TextPattern(1)被轉換成"不符要求",TextId.MsgDimatch(2)被轉換成"別讓黑大不開心",下場便是Regex比對失敗,傳回錯亂訊息。

原因不難理解,但第一次「遇到漏更新程式庫,系統沒當掉或產生Exception,而是跑出莫名其妙的結果」。很新鮮,筆記留念。

TypeScript偵錯陷阱-中斷點位置不符

$
0
0

目前進行中的網站專案全面改用TypeScript,有顆地雷卻一忘再忘,踩了又踩,痛定思痛怒寫筆記,誓言戰勝末稍血液循環問題

TypeScript需編譯轉成JavaScript,不過Visual Studio預設TypeScript一存檔就自動編譯,因此過去邊測邊改的習慣仍能照舊。在瀏覽器用F12開發工具找出問題,回Visual Studio修改TypeScript存檔,回到瀏覽器重新載入網頁就能重測修改結果,不需重新編譯整個專案,開發節奏較快,卻也因此在JavaScript偵錯期間偶爾發生靈異現象。

以下是一個無敵簡單又沒營養的範例網頁,輸入兩個數字計算相減結果,JavaScript邏輯寫在test.ts,blah.calcSub():

接著請看示範。TypeScript編譯時會一併產生test.js.map檔,並會在test.js下行以sourceMappingURL標示map檔,瀏覽器就會用原始TypeScript檔(test.ts)取代test.js進行偵錯。我在test.ts的calcSub()函式設好中斷點,按下「=」計算鈕,理論上執行焦點應該停在calcSub(),但並沒有,它莫名其妙地停在calcAdd(),花惹發?

其實,一切是自己造孽!原始碼位置錯亂源於test.js、test.js.map、test.ts的不一致。直接下載test.js可以發現示範過程test.ts裡有一個class foo在test.js並沒有出現,那是TypeScript後來加的新程式,但test.js沒有。通常這是TypeScript語法出錯無法編譯的後果,test.js與test.js.map仍是修改前版本,test.ts是修改後的版本,舊版test.js指向新版test.ts,偵錯時便會出現程式行數錯亂。

在Visual Studio開啟test.ts,右側捲軸的小紅點提供了鐵證!what()函式的大括號後方多了分號,TypeScript儲存了卻無法編譯,因為採用「存檔-重新整理-測試」快速開發模式,一不小心遺漏TypeScript語法有誤的警訊,接下來就是偵錯階段鬼打牆,不斷碎唸為什麼程式行數亂跳一通…

跌倒數次後,現在我只要在偵錯時發現程式碼行數錯亂,優先檢查是否有TypeScript編譯錯誤準沒錯!(PS:此一現象在Scss也適用~)

升級Visual Studio 2013 Update 4後無法編譯SCSS

$
0
0

開開心心升級到VS2013 Update 4,對我而言,最大的好處是檢視網頁時VS2013不再對HTML裡的Angular語法鬼吼鬼叫,噴出成百上千條警告。

Support for custom elements, polymer-elements and attributes.
We no longer validate unknown attributes for custom elements, because there can be many custom-made tags in different frameworks. There will no longer be squiggles under the unknown elements. 參考

升級VS2013U4後,系統提示需一併升級成Web Essentials Update 4。更新完畢,先來個聞腋青年標準拉筋姿勢,打開專案準備接續昨天的工作,才加了兩行SCSS,SCSS就被搞壞了,編譯預覽視窗出現錯誤訊息:
/*
Compilation Error occurred (see error list to navigate to the error location):
*/

在錯誤清單找到眼睛快脫窗也沒看到足以導致編譯失敗的原因,更重要的,我發現就算取消今天的修改,仍無法通過編譯,感覺到事情不單純。很快地,我在套件討論區找到解答:

如圖,將Use Ruby Runtime設為True,問題消失!(PS:討論區有人提到,某些SASS仍會有問題)

【茶包射手日記】消失的nlasvc服務

$
0
0

家中的Windows 7,不知何時起開始找不到nlasvc服務,導致一連串相依服務失敗:

檢查Registry,真的找不到HKLM/STSTEM/CurrentControlSet/services/nlasvc機碼!幸好ControlSet001/services/nlasvc還在,將其匯出成nlasvc.reg檔,修改Registry路徑由ControlSet001改成CurrentControlSet再匯入。Registry補上了,但奇怪的是在服務清單仍找不到Network Location Awareness服務,用sc.exe query也找不到,糗了,這下連想測試都不得其門而入。

參考網路文章做了sfc /scannow,未發現系統檔案損壞,頓時萬念俱灰了無生趣,莫非只剩重灌一途?

隔了兩天心情稍微平復,打起精神繼續探勘。爬文找到一招:原來sc.exe不但可以啟動停止服務,還可以用"sc create svc_name binPath= x:\path\file"註冊服務。我想到一招,先sc create nlasvc binPath= x:\temp\null.exe(路徑亂打的)建立一個假的nlasvc,讓sc query nlasvc能查到服務項目,再以nlasvc.reg匯入覆寫正確機碼,我就能用sc start nlasvc啟動服務囉!此時,得到一個寶貴的錯誤訊息:

nlasvc 服務因服務特定的錯誤 %%-1073741288 而終止。

以錯誤代碼當關鍵字,找到一則Answers討論串,網友提到這是nlasvc/Parameters缺少SERVICE帳號的完全控制權限所致。

如圖補上SERVICE權限(圖中誤選SYSTEM,關鍵應為SERVICE),重新開機,一登入就出現選擇家用網路、工作場所網路或公用網路的選擇畫面(參考),意味著nlasvc修復成功,檢查事件檢視器,錯誤不見了,萬歲~

VS2013U4小確幸-HTML收合區塊(#region)

$
0
0

VS2013 Update 4新增一個小功能-HTML編輯器支援#region區塊。

不囉嗦,直接看示範:

VS2013U4起,HTML編輯器支援<!-- #region 區塊名稱 --> <!-- #endregion -->區塊表示語法,概念如同C#的#region、#endregion,允許開發人員將程式碼包成一段段可收合的區塊,增加一次閱讀的程式碼範圍,必要再展開特定區塊檢視編輯。

除了手動加入#region HTML註解,Visual Studio也支援快速鍵操作:先選取區塊包含範圍,按Ctrl-K後,Ctrl不放接著按S會出現提示視窗,敲"h"將焦點移至HTML,按Enter即展開HTML程式片段選項,輸入re後焦點會落在region項目,再按一次Enter,Visual Studio便會在選取範圍頭尾加上<!-- #region name -->及<!-- #endregion -->,並將文字游標移到名稱處,輸入區塊名稱,大功告成!


【茶包射手日記】在SPS2007站台安裝ASP.NET MVC4

$
0
0

應專案需求在SPS2007網站安裝ASP.NET MVC4,建立Web Application,設好萬用字元應用程式對應(IIS6之特殊需求,可參考保哥文章常見問題3),執行MVC網頁時出現權限錯誤:

Server Error in '/MyMVC' Application.
--------------------------------------------------------------------------------

Could not find permission set named 'ASP.Net'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Configuration.ConfigurationErrorsException: Could not find permission set named 'ASP.Net'.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:


[ConfigurationErrorsExc
eption: Could not find permission set named 'ASP.Net'.]
   System.Web.HttpRuntime.HostingInit(HostingEnvironmentFlags hostingFlags, PolicyLevel policyLevel, Exception appDomainCreationException) +378

[HttpException (0x80004005): Could not find permission set named 'ASP.Net'.]
   System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +9171632
   System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +97
   System.Web.HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr) +258

想起因為SPS要開放使用者外掛Web Part套件,為防止權限過大闖禍,Sharepoint有一套自訂的Trust Level原則。當ASP.NET MVC安裝在Sharepoint站台下,會繼承該設定,故在ASP.NET MVC web.config / <system.web> 加上<trust level="Full" />,以上問題即消失,但/controller/action路由仍為失效狀態,持續傳回HTTP 404。

爬文找到相關文章,其做法是同時修改Sharepoint及MVC的web.config,但經測試,我只在MVC web.config加上httpModules UrlRoutingModule設定路由就OK了!

<system.web>
<trustlevel="Full"/>
<httpModules>
<addname="UrlRoutingModule"
type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=4.0.0.0, 
Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</httpModules>
</system.web>

以上經驗供參。

瀏覽器圖檔開啟實驗:下載 vs 檢視

$
0
0

我們有個內部HipChat Server,疑似在升級後行為改變。以往在聊天室上傳圖檔,點選其連結 httqs://hipchat-server/files/x/x/xxxx/xxxx.png 可直接顯示圖檔內容,升級後則變成點選後一律先下載到本機才能開啟。透過Chrome F12 Dev Tools,還觀察到以下訊息:
Resource interpreted as Document but transferred with MIME type image/png: "httqs://hipchat-server/files/1/3/KN2SPYfn4GfsvJh/upload.png".

使用Fiddler側錄封包,發現問題關鍵。HipChat Server在回傳PNG圖檔時,雖然Content-Type為"image/png",但多了一條Header: Content-Disposition: attachment

依據RFC 6266

   If the disposition type matches "attachment" (case-insensitively),
   this indicates that the recipient should prompt the user to save the
   response locally, rather than process it normally (as per its media
   type).

   On the other hand, if it matches "inline" (case-insensitively), this
   implies default processing.  Therefore, the disposition type "inline"
   is only useful when it is augmented with additional parameters, such
   as the filename (see below).

   Unknown or unhandled disposition types SHOULD be handled by
   recipients the same way as "attachment"

當Header指定Content-Disposition: attachment時,瀏覽器需提示使用者儲存傳回內容,忽略其原有Content-Type之處理程序,這應是HipChat改版後新增Content-Disposition: attachment Header,導致瀏覽器的行為改變。一般來說,指定檔案下載時,多半會搭配Content-Type: application/octet-stream,HipChat傳回結果卻是Content-Disposition: attachement配上Content-Type: image/png,應是Chrome「Resource interpreted as Document but transferred with MIME type image/png」警示訊息的由來。

寫了一小段程式驗證這點。在以下ASP.NET網頁,我使用GDI+動態產生圖檔並傳回png,當Request["att"]傳入檔名參數,則再加上Content-Disposition: attachment Header並指定檔名。

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Drawing" %>
<%@ Import Namespace="System.Drawing.Imaging" %>
<scriptrunat="server">
void Page_Load(object sender, EventArgs e)
    {
        Bitmap bmp = new Bitmap(120, 35);
        Graphics g = Graphics.FromImage(bmp);
        Brush b = new SolidBrush(ColorTranslator.FromHtml("#444"));
        g.FillRectangle(b, 0, 0, bmp.Width, bmp.Height);
        b = new SolidBrush(Color.Orange);
        Font f = new Font("Courier New", 12);
        g.DrawString("darkthread", f, b, 6, 6);
        Response.ContentType = "image/png";
//依參數指示加上附檔Header及檔名
string attName = Request["att"];
if (!string.IsNullOrEmpty(attName))
        {
            Response.AddHeader("Content-Disposition",
"attachment;filename=" + attName);
        }
        bmp.Save(Response.OutputStream, ImageFormat.Png);
        Response.End();
    }
</script>

實驗結果如下,加上att參數,原本顯示png圖檔的動作就會變成下載圖檔,得證。

此一行為改變導致查看圖檔的步驟變多,很不方便,但又無法糾正HipChat的行。同事找到一個解決方案,在瀏覽器設定「一律開啟這類檔案」,則下載後會立即啟動圖檔檢視工具開啟圖檔,也算一次到位,但無法解決每次檢視會在下載資料夾殘留檔案的問題(而且是看一次多產生一個檔案)。

最後,我想到的解決方案是寫一個簡單Proxy,能接受httq://another-server/proxy/files/1/3/KN2SPYfn4GfsvJh/upload.png呼叫,轉手向HipChat取得該圖檔,傳回瀏覽器時只指定Content-Type而沒有Content-Disposition,就能直接顯示圖檔內容;再配合Chrome的URL轉換外掛(Switchroo Redirector),每次要開啟HipChat附檔時自動轉址改由Proxy間接取檔,總算解決惱人問題。

解決檔名結尾URL導致MVC路由失效問題

$
0
0

前篇文章提到為解決HipChat開啟圖檔變下載困擾,我計劃寫一個簡易Proxy,接受httqs://another-server/proxy/files/1/3/KN2SPYfn4GfsvJh/upload.png格式URL,轉手向HipChat伺服器取得httqs://real-hipchat-server/files/1/3/KN2SPYfn4GfsvJh/upload.png圖檔傳回以避開Content-Disposition: attachment的干擾。

由於URL路徑要完全比照HipChat的規則(/files/1/3/KN2SPYfn4GfsvJh/upload.png),我打算借重MVC很彈性路由功能。先從一個簡單雛型開始,宣告一個FilesController Index(string id) Action,對應路由files/{id},希望在URL為files/darkthread.png時,由id參數取得"darkthread.png"。

路由設定如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
 
namespace Proxy
{
publicclass RouteConfig
    {
publicstaticvoid RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
            routes.MapRoute(
                name: "Default",
                url: "files/{id}",
                defaults: new { controller = "Files", action = "Index", 
                    id = UrlParameter.Optional }
            );
        }
    }
}

FilesController邏輯如下(測試用途,故不真的取檔,僅回傳讀到的id參數):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
 
namespace Proxy.Controllers
{
publicclass FilesController : Controller
    {
public ActionResult Index(string id)
        {
return Content(id);
        }
    }
}

不過,事情沒這麼簡單,發現一旦後方串上包含".副檔名"的檔名參數,便會得到HTTP 404找不到檔案錯誤。

類似問題之前發生過!關鍵在於/files/darkthread.pdf被視為合法的靜態檔案URL,IIS優先將其解讀成網站資料夾相對位置的檔案處理,結局當然是查無此檔。要解決這個問題,只需在web.config中加上額外handler宣告,指定當path符合"/files/*"時,一律改由ASP.NET UrlRouting處理。

<system.webServer>
<handlers>
<!-- http://stackoverflow.com/questions/9273987/asp-net-mvc-url-route-supporting-dot -->
<addname="UrlRoutingHandler"
type="System.Web.Routing.UrlRoutingHandler, 
               System.Web, Version=4.0.0.0, 
               Culture=neutral, 
               PublicKeyToken=b03f5f7f11d50a3a"
path="/files/*"
verb="GET"/>
</handlers>
</system.webServer>

加上設定,看似直接下載PDF檔案的URL也被導引到FilesController處理囉!

【茶包射手日記】Outlook信件偷拆疑雲

$
0
0

同事報案,某天不知從何時起,Outlook出現異樣,所有新信件進來時都呈現已讀,莫非被人偷拆?(但,哪有這麼笨的間諜,偷看完信封沒黏回去就丟回信箱?)

先前沒遇到這種狀況,上網爬文發現類似案例不少,但狀況各異,結果分歧,歸納出以下幾種:

  1. 預覽信件後被標示已讀
    Outlook設定有個選項,可讓信件經讀取窗格檢視過即標為已讀。

    這個可能性很快被排除,理由是「被讀取窗格標示已讀前應有幾秒時間差」,而同事的案例是新信件一進來直接呈現已讀,完全沒有未讀轉已讀的過程。另外我還做了測試,在收信匣中故意選取其他信件,當有新信件進來時,讀取窗格仍停在原選取項目,新信件內容從未在讀取窗格出現,仍被標為已讀,故一號嫌犯不在場證明充分,無罪開釋。
  2. 被其他收信軟體標為已讀
    二號嫌犯涉有重嫌,因同事有設定iPad同步Exchange信件,不過,如此搭配使用已久,過去即使郵件設定同步,也未發生Outlook信件收信被標成已讀的狀況。為了確認,特地打開iPad將郵件同步功能關閉,重新測試仍收到被讀過的新信件。不過,因為不排除是否仍有未知軟體在收信,未完全排除嫌疑,偵訊後因證據不足飭回候傳。
  3. 其他疑難雜症
    除了以上兩種主要狀況,還有一些零星個案:有人靠更改密碼排除問題、有人試著移除Exchange帳號後重建,最慘的一個是搞到重裝Outlook,問題依舊。

由蒐集到的資料,我建議當事人更改密碼,除了參考網路成功案例,更重要的理由是我始終沒有排除二號嫌犯涉案!改掉密碼,即使嫌犯沒現身也無法繼續犯案,一石二鳥。更改密碼前,苦主忽然想到一事,他的iPhone也有設定Exchange郵件同步,前一晚曾開iPhone讀信,「並且開啟附檔PDF讀取」!很有可能讀附檔動作導致郵件程式持續開啟收信,造成信件被標為已讀取。關閉iPhone郵件同步後,問題消失,水落石出。犯人iPhone依法應處極刑-當眾摔碎再浸水,因苦主求情力保,故特赦不再追究,結案。

IIS8之System.ServiceModel.Activation.HttpModule錯誤處理

$
0
0

經典老問題:在安裝ASP.NET 4.5後安裝.NET 3.0 WCF(或手動執行Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\ServiceModelReg.exe)後ASP.NET 4網站噴出以下錯誤:

Could not load type ‘System.ServiceModel.Activation.HttpModule’ from assembly
'System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
無法從組件 'System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' 載入型別 'System.ServiceModel.Activation.HttpModule'。

過去,這只需重新執行v4.0.30319\aspnet_regiis  -i就藥到病除(參考),但在Windows 8/IIS8上則行不通:

C:\Windows\Microsoft.NET\Framework\v4.0.30319>aspnet_regiis -i
Microsoft (R) ASP.NET RegIIS 版本 4.0.30319.33440
在本機電腦上安裝及解除安裝 ASP.NET 的管理公用程式。
Copyright (C) Microsoft Corporation.  著作權所有,並保留一切權利。
開始安裝 ASP.NET (4.0.30319.33440)。
這個作業系統版本不支援這個選項。系統管理員應該改用 [開啟或關閉 Windows 功能」對話方塊、[伺服器管理員] 管理工具或 dism.exe 命令列工具,隨著 IIS8 一起安裝/解除安裝 ASP.NET 4.5。如需詳細資訊,請參閱 http://go.microsoft.com/fwlink/?Link71。
完成安裝 ASP.NET (4.0.30319.33440)。

aspnet_regiis表示自己不適用Win8,在Windows 8+應改用「開啟或關閉Windows功能」安裝ASP.NET 4.5。

只是,試過移除並重裝ASP.NET 4.5,問題依舊。再來恐得考量移除重裝IIS8,重裝IIS網站應用程式重設工程浩大,動手前先爬爬文找找較不傷身體的解法,幸運找到一篇參考文件。程序如下:

由IIS管理員找到站台的「模組」項目:

開啟「模組」可發現ServiceModel及ServiceModel-4.0,第一筆為3.0版,第二筆為4.0版。

將ServiceModel(3.0版)移除,天下太平~

 

【後記】

本次禍首:IIS不認得SVC,手動執行ServiceModelReg.exe才惹出麻煩,在Windows 8/IIS8,要設定WCF請愛用「開啟及關閉Windows功能」。

Viewing all 2456 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>