這陣子有機會使用 Facebook SDK 3.0 來開發程式,在一開始先下載 Sample 熟悉一下程式的執行方式,無奈有時一執行就會出現日期解析失敗的訊息,或是第 1 次開啟頁面正常,按 F5 重整後就會出現錯誤訊息,後來下載原始碼來修改後解決。
這陣子有機會使用 Facebook SDK 3.0 來開發程式,一開始先下載 Sample 熟悉一下程式的執行方式,無奈有時一執行就會出現日期解析失敗的訊息,或是第 1 次開啟頁面正常,按 F5 重整後就會出現錯誤訊息,後來下載原始碼來修改後解決。
這程式是要放在 facebook 畫布(Canvas)以 iframe 方式呈現,例如以 http://apps.facebook.com/myapps 方式進入。
英文錯誤訊息:
中文錯誤訊息:
顯示出第 5 行執行錯誤:
因錯誤的地方是使用 Facebook Developer Toolkit 3.0 中提供的方法,因此需要下載原始碼來進行修改,先到這裡下載 SDK_Source.zip,解壓後:
1. 開啟專案:Facebook
2. 開啟檔案:Session\IFrameCanvasSession.cs
3. 要修改的函式:internal override CachedSessionInfo LoadCachedSession()
4. 找到下面這行就是程式錯誤的地方:
return new CachedSessionInfo(sessionKeyCookie.Value, long.Parse(userIdCookie.Value), DateTime.Parse(expiryTimeCookie.Value));
在將 expiryTimeCookie 值轉為 DateTime 時會因為格式錯誤而發生例外。
而 expiryTimeCookie 的值是在 CacheSession 函式中的這一行設定:
HttpContext.Current.Response.Cookies.Set(new HttpCookie(EXPIRY_TIME_COOKIE, sessionInfo.ExpiryTime.ToString()));
將 sessionInfo.ExpiryTime.ToString() 的值印出來後會有亂碼的文字「2009/12/22 銝? 08:00:00」,試著改為 sessionInfo.ExpiryTime.ToString("yyyy/MM/dd HH:mm:ss") 寫法仍然無效,後來試著用 DateTime.ParseExact() 可以正確的解析出來,因此修改後程式碼如下:
HttpContext.Current.Response.Cookies.Set(new HttpCookie(EXPIRY_TIME_COOKIE,
DateTime.ParseExact(sessionInfo.ExpiryTime.ToString("yyyy/MM/dd HH:mm:ss"),
"yyyy/MM/dd HH:mm:ss",
System.Globalization.CultureInfo.InvariantCulture).ToString("yyyy/MM/dd HH:mm:ss")));
重新編譯後再試就沒問題了。
但有朋友反應,即使用 DateTime.ParseExact() 還是會遇到同樣的問題,所以我再加上日期是否正確的檢查,若不是正確日期格式就以系統日期加上 8 個小時(注意,這方法不是好的方法,但我還沒看出來這時間是如何計算出來的,這日期我還看過取出來是「1969/12/31 16:00:00」),這樣就可以順利的往下執行了 ^^
後來朋友提出另一種解法,但這種解法只適用在第 1 次瀏覽不會出現錯誤,按 F5 重整後才會出現錯誤的情況。
做法:在第 1 次進入頁面(default.asx)時直接取出 facebook 的 uid 值,若發生例外則轉址到另 1 個頁面(login.aspx),在 login.aspx 中讓 User 同意應用程式的執行,同意完應用程式執行後再轉回 default.aspx 即可。
default.aspx.cs:
using System;
using Facebook.Web;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
CanvasIFrameBasePage trs = new CanvasIFrameBasePage();
try
{
long uid = trs.Api.Session.UserId;
}
catch
{
Response.Redirect("login.aspx");
}
finally
{
trs.Dispose();
}
}
}
login.aspx (全部就只放這3行即可):
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %>
<%@ Register TagPrefix="Facebook" Namespace="Facebook.Web" Assembly="Facebook.Web" %>
<Facebook:CanvasIFrameLoginControl runat="server" ID="login" RequireLogin="true" />
login.aspx.cs:
using System;
public partial class Login : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Redirect("default.aspx");
}
}
參考資料:
- DateTime.ParseExact 方法 (String, String, IFormatProvider)
- DateTime.ParseExact 方法 (String, String[], IFormatProvider, DateTimeStyles)
- TIPS-.NET DateTime Formating