在Azure上構(gòu)建一個(gè)基于Facebook的營(yíng)銷式應(yīng)用程序(中)
原創(chuàng)本文接在Azure上構(gòu)建一個(gè)基于Facebook的營(yíng)銷式應(yīng)用程序(上) 和
請(qǐng)看下篇《在Azure上構(gòu)建一個(gè)基于Facebook的營(yíng)銷式應(yīng)用程序(下)》
在一個(gè)Canvas頁(yè)面
這個(gè)應(yīng)用程序在Facebook上的Canvas頁(yè)面會(huì)映射到這個(gè)應(yīng)用程序在Azure上的base URL(例如:http://azurefacebooksample.cloudapp.net/)。這是一個(gè)展示初始的聯(lián)系信息的窗體。這是基本的實(shí)現(xiàn):
Listing 1
[CanvasAuthorize(Perms = "user_birthday")]
public ActionResult Index()
{
FacebookApp app = new FacebookApp();
dynamic response = app.Api("me");
Contact contact = new Contact();
contact.FirstName = response.first_name;
contact.LastName = response.last_name;
string query = "select birthday_date from user where uid = me()";
response = app.Fql(query);
if (response.Count > 0)
contact.DateOfBirth = response[0].birthday_date;
return View(contact);
}
這看起來(lái)十分的簡(jiǎn)單,這主要得益于Facebook C# SDK。這個(gè)SDK通過(guò)“CanvasAuthorize”特性處理了Facebook OAuth身份驗(yàn)證和應(yīng)用程序的授權(quán),并且提供了一個(gè)“FacebookApp”對(duì)象。你應(yīng)該還記得,在一個(gè)新用戶運(yùn)行“AzureSample”以前,他們必須要給這個(gè)應(yīng)用程序授予可以訪問(wèn)這個(gè)用戶的出生日期的特殊權(quán)限。為了達(dá)到這個(gè)目的,我們需要做的所有事情就是,使用“CanvasAuthorize”特性,對(duì)任何一個(gè)需要授權(quán)的控制器操作進(jìn)行標(biāo)記,指定需要請(qǐng)求的擴(kuò)展權(quán)限是可選的(在這里,我們指定了“user_birthday”權(quán)限)。
“FacebookApp”對(duì)象可以訪問(wèn)經(jīng)過(guò)簽名的請(qǐng)求信息,也可以訪問(wèn)Facebook的Graph API和REST API。在這個(gè)控制器中,我們使用“FacebookApp”調(diào)用一個(gè)Graph API(“me”),來(lái)返回當(dāng)前用戶的信息(其中包括***個(gè)名字和***一個(gè)名字)。我們不能使用這個(gè)Graph API來(lái)獲取這個(gè)用戶的出生日期,但是,我們可以求助于Facebook FQL,創(chuàng)建一個(gè)查詢來(lái)找到當(dāng)前用戶的出生日期。我們可以通過(guò)“FacebookApp”來(lái)使用FQL(Formal Query Language) 。我們把這個(gè)用戶的信息添加到一個(gè)新的“Contact”對(duì)象中,這是一個(gè)來(lái)自于域?qū)ο蟮臄?shù)據(jù)模型對(duì)象。然后,我們把這個(gè)“contact”放到一個(gè)視圖中。
這是這個(gè)索引視圖的完整代碼:
Listing 2
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<AzureFacebookSample.Domain.Models.Contact>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Home
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<div>Please provide the following information. All fields are required.</div>
<% using (Html.BeginForm())
{%>
<%: Html.ValidationSummary(true)%>
<div class="editor-label">
<%: Html.LabelFor(model => model.FirstName)%>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.FirstName)%>
<%: Html.ValidationMessageFor(model => model.FirstName)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.LastName)%>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.LastName)%>
<%: Html.ValidationMessageFor(model => model.LastName)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Email)%>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Email)%>
<%: Html.ValidationMessageFor(model => model.Email)%>
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.DateOfBirth)%>
</div>
<div class="editor-field">
<%: Html.EditorFor(model => model.DateOfBirth)%>
<%: Html.ValidationMessageFor(model => model.DateOfBirth)%>
</div>
<div>You must be 18 or older to participate.</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Zip)%>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Zip)%>
<%: Html.ValidationMessageFor(model => model.Zip)%>
</div>
<p>
<input type="submit" value="Next"/>
</p>
<%} %>
</aspContent>
這個(gè)視圖指定了用于收集聯(lián)系信息的窗體字段。驗(yàn)證是通過(guò)“Contact”數(shù)據(jù)模型上的特定注解來(lái)實(shí)現(xiàn)的。當(dāng)用戶點(diǎn)擊“next”按鈕的時(shí)候,這些窗體字段會(huì)被發(fā)送到控制器的post操作中:
Listing 3
[HttpPost]
[CanvasAuthorize]
Public ActionResult Index(Contact contact)
{
FacebookApp app = new FacebookApp();
contact.PartitionKey = app.UserId.ToString();
if (ModelState.IsValid)
{
contactRepository.Save(contact);
return this.CanvasRedirectToAction("SelectStore");
}
Return View(contact);
}
除了從窗體返回的聯(lián)系信息之外,我們還會(huì)通過(guò)“FacebookApp”對(duì)象來(lái)抓取用戶的Facebook ID,然后放到“Contact”中,以便于我們可以跟蹤將來(lái)對(duì)這個(gè)應(yīng)用程序的訪問(wèn)(客戶只可以注冊(cè)一次,領(lǐng)取一次獎(jiǎng)品)。
#p#
在Azure Storage中存儲(chǔ)“Contact”
在上面那段代碼中,你可能已經(jīng)注意到了,存儲(chǔ)客戶的Facebook ID的“Contact”屬性叫作“PartitionKey”,而不是“FacebookId”。“Contact”是一個(gè)數(shù)據(jù)模型,這意味著它可以直接存儲(chǔ)到Azure Table Storage中。它繼承于“TableStorageEntity”,對(duì)于可存儲(chǔ)的實(shí)體來(lái)說(shuō),“TableStorageEntity”是一個(gè)方便的基類,在這個(gè)類中,包含了“PartitionKey”屬性和“RowKey”屬性。
“AzureFacebookSample”使用Azure Table Storage,因?yàn)樵贏zure Table Storage中,插入操作和主鍵查詢都很快,而且,它可以無(wú)限地?cái)U(kuò)展。在一個(gè)Azure表中,除了這些實(shí)體屬性所必須列之外,每行還包括一個(gè)partition key,一個(gè)row key,和一個(gè)時(shí)間戳。為了獲得***的性能,查詢應(yīng)該被嚴(yán)格地限制在那些基于主鍵的字段中,不應(yīng)該包括含他的屬性。
我們把Facebook ID作為partition key,把blank作為row key,然后把“contact”存儲(chǔ)到一個(gè)Azure表中。這樣做可以讓存儲(chǔ)的“contact”更容易使用(使用起來(lái)也更快),因?yàn)槲覀兛梢酝ㄟ^(guò)Facebook ID來(lái)查找或更新它們。
Web角色和Worker角色都可以通過(guò)域項(xiàng)目提供的“ContactRepository”來(lái)訪問(wèn)存儲(chǔ)的“contact”對(duì)象。通過(guò)Windows Azure Toolkit中的一些類,“ContactRepository”可以直接和Azure storage進(jìn)行交互,這可以讓實(shí)現(xiàn)變得更加簡(jiǎn)潔。
Listing 4
public class ContactRepository : IContactRepository
{
readonly AzureTable<Contact> _table;
public ContactRepository()
{
var factory = new AzureStorageFactory ();
_table = (AzureTable<Contact>) factory.GetTable<Contact>();
}
public Contact GetFromFacebookId(Int64 facebookId)
{
return this.Get(facebookId.ToString());
}
public Contact Get(string partitionKey)
{
return _table.Get(c => c.PartitionKey == partitionKey && c.RowKey == "");
}
public void Save(Contact contact)
{
_table.AddOrUpdate(contact);
}
public void Delete(Contact contact)
{
_table.Delete(contact);
}
}
這段代碼展示了“ContactRepository”的完整實(shí)現(xiàn)。在構(gòu)造函數(shù)中,我們創(chuàng)建了一個(gè)“AzureStorageFactory”對(duì)象,然后使用“factory”來(lái)獲取“Contact”表。“AzureStorageFactory”和“AzureTable”都是在WindowsAzureToolkit中定義的類,這兩個(gè)類可以讓使用Azure Table Storage變得更加容易。實(shí)際上,這個(gè)“contact”容器中的大多數(shù)方法都是“AzureTable”中的對(duì)應(yīng)方法的封裝。“Get()”方法直接通過(guò)“partition key”來(lái)查詢“contact”。
在這個(gè)處理程序的***,應(yīng)用程序使用這個(gè)容器把聯(lián)系信息寫入到Azure Storage中。因?yàn)樘幚磉^(guò)程還沒(méi)有完成,所以這個(gè)“contact”還不能標(biāo)記為已注冊(cè)(在選擇了商店以后,才應(yīng)該這么做)。在索引操作開始的時(shí)候,這個(gè)“contact”容器還可以用來(lái)驗(yàn)證。
Listing 5
if (AlreadyRegistered(app.UserId))
{
return this.CanvasRedirectToAction("SignupComplete");
}
驗(yàn)證的實(shí)現(xiàn)如下所示:
Listing 6
private bool AlreadyRegistered(Int64 facebookId)
{
Contact contact = contactRepository.GetFromFacebookId(facebookId);
Return (contact != null) && contact.Registered;
}
本文接在Azure上構(gòu)建一個(gè)基于Facebook的營(yíng)銷式應(yīng)用程序(上)
請(qǐng)看下篇《在Azure上構(gòu)建一個(gè)基于Facebook的營(yíng)銷式應(yīng)用程序(下)》
原文名:Building a Facebook Marketing App on Azure 作者:Steve Apiki
【本文乃51CTO精選譯文,轉(zhuǎn)載請(qǐng)標(biāo)明出處!】
【編輯推薦】
- 在Azure上構(gòu)建一個(gè)基于Facebook的營(yíng)銷式應(yīng)用程序(下)
- 在Azure上構(gòu)建一個(gè)基于Facebook的營(yíng)銷式應(yīng)用程序(下)
- 無(wú)需頂禮膜拜 三步打造經(jīng)濟(jì)高效的云基礎(chǔ)架構(gòu)