深入探究 Windows Phone 推送通知系统:从基础实现到自动化服务
1. 客户端应用基础设置
在开发 Windows Phone 推送通知客户端应用时,首先要确保代码能正确处理通知通道 URI 的更新。以下是相关代码示例:
{
//Display Message on error
Debug.WriteLine ( e.Message);
}
void httpChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
{
//You get the new Uri (or maybe it's updated)
ChannelUri = e.ChannelUri;
}
Uri channelUri;
public Uri ChannelUri
{
get { return channelUri; }
set
{
channelUri = value;
OnChannelUriChanged(value);
}
}
private void OnChannelUriChanged(Uri value)
{
Dispatcher.BeginInvoke(() =>
{
txtURI.Text = "changing uri to " + value.ToString();
});
Debug.WriteLine("changing uri to " + value.ToString());
}
完成客户端应用代码编写后,按下 F5 确保应用能正常编译和运行。接下来,我们将构建服务器端应用,向客户端发送原始通知。
2. 创建发送原始通知的服务器应用
发送原始通知比发送磁贴或吐司通知更简单,因为原始通知无需 XML 模板进行消息格式化。我们将复用之前创建的 PNServer 项目,并编辑按钮点击事件处理程序来处理原始通知。具体步骤如下:
1. 打开 PNServer 项目,打开 Form1.cs 文件的代码(在解决方案资源管理器中右键单击 Form1.cs,选择“查看代码”)。
2. 用以下代码替换 btnSendNotification_Click 事件处理程序:
private void btnSendNotification_Click(object sender, EventArgs e)
{
if (txtURL.Text == string.Empty)
{
MessageBox.Show("Please enter a url");
return;
}
if (txtTitle.Text == string.Empty || txtText.Text == string.Empty)
{
MessageBox.Show("Please enter text and title to send");
return;
}
HttpWebRequest sendNotificationRequest =
(HttpWebRequest)WebRequest.Create(txtURL.Text);
sendNotificationRequest.Method = "POST";
sendNotificationRequest.Headers = new WebHeaderCollection();
sendNotificationRequest.ContentType = "text/xml";
sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "");
sendNotificationRequest.Headers.Add("X-NotificationClass", "3"); //- raw
String str = string.Format(txtTitle.Text + "\r\n" + txtText.Text);
byte[] strBytes = new UTF8Encoding().GetBytes(str);
sendNotificationRequest.ContentLength = strBytes.Length;
using (Stream requestStream = sendNotificationRequest.GetRequestStream())
{
requestStream.Write(strBytes, 0, strBytes.Length);
}
HttpWebResponse response =
(HttpWebResponse)sendNotificationRequest.GetResponse();
string notificationStatus = response.Headers["X-NotificationStatus"];
string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"];
lblStatus.Text = "Status: " + notificationStatus + " : " + deviceConnectionStatus;
}
上述代码是向 Windows Phone 客户端发送原始通知所需的全部代码。现在,我们可以在 Windows Phone 模拟器上测试原始通知的发送。
3. 测试原始通知的发送
测试原始通知非常简单,无需将应用固定到开始屏幕。具体测试步骤如下:
1. 与吐司和磁贴通知一样,需要获取通知通道的 URI。打开 RawNotificationPNClient 项目,确保已连接到互联网,按下 F5 运行项目。点击“创建通道”按钮,看到屏幕上打印出 URI 后,从输出窗口将其复制到剪贴板。
2. 切换到 PNServer Windows 窗体项目,按下 F5 运行。在“推送通知 URL”文本框中粘贴步骤 1 中获取的 URI。在“推送通知标题”和“推送通知文本”文本框中分别输入“Hello”和“World”。点击“发送通知”按钮。
3. 此时,应该能在 Windows Phone 模拟器屏幕上看到已收到原始通知的消息以及“Hello World”消息。
通过以上步骤,我们可以看到实现原始通知与实现磁贴和吐司通知非常相似,但稍微简单一些。每种通知类型都有其用途,应根据具体情况选择最合适的通知类型。
4. 实现云服务以跟踪推送通知
在之前的演示中,我们使用了一种不太现实的方法,将 Windows Phone 客户端应用的推送通知 URL 复制到服务器应用中。为了使股票提醒应用更具现实意义,我们需要自动化这个 URL 通信过程。接下来,我们将使用 Microsoft Windows Communication Foundation (WCF) 技术栈构建云服务来实现这一目标。
4.1 创建用于跟踪通知接收者的 WCF 服务
为了增强之前构建的 PNServer 应用,我们将添加一个 WCF 服务。WCF 是一种强大的技术,具有多种配置选项,可用于创建和托管云服务。我们将构建一个自托管服务,即该服务将托管在 Windows 窗体应用中,并编写代码来初始化和启动该服务。此外,该服务是一个 RESTful 服务,这意味着可以通过格式正确的 URL 访问其操作。
在创建 RESTful WCF 服务之前,可能需要在 Visual Studio 环境中进行一些小的更改,以引用创建该服务所需的程序集。默认情况下,Visual Studio 为客户端应用(如 Windows 窗体或 Windows Presentation Foundation (WPF) 应用)创建轻量级配置文件,该配置文件默认会省略许多与 Web 相关的程序集。
控制程序集包含或排除的设置是“目标框架”设置,它位于项目的“属性”页面上。需要将此设置从“.Net Framework 4 客户端配置文件”更改为“.Net Framework 4”。具体操作如下:
1. 打开 PNServer 项目(如果尚未打开),右键单击项目名称,然后选择“属性”。
2. 找到“目标框架”设置,并将其设置为“.Net Framework 4”。
接下来,完成 WCF 服务的创建步骤如下:
1. 右键单击项目名称,选择“添加引用”。在列表中找到 System.ServiceModel.Web 程序集,选中它,然后点击“确定”。
2. 为项目添加 WCF 服务文件,这包括创建服务契约(以接口文件的形式出现)和定义一个类来实际实现服务契约中定义的方法。
- 右键单击项目名称,选择“添加” -> “新建项”,然后滚动到几乎底部,选择“WCF 服务”。将服务命名为 RegistrationService,然后点击“确定”。
- 在创建的 IRegistrationService.cs 文件顶部添加以下语句:
using System.ServiceModel.Web;
- 在 IRegistrationService.cs 文件中添加以下代码:
[ServiceContract]
public interface IRegistrationService
{
[OperationContract, WebGet]
void Register(string uri);
[OperationContract, WebGet]
void Unregister(string uri);
}
- 双击 Visual Studio 添加到项目中的 RegistrationService.cs 文件,使其内容如下:
public class RegistrationService : IRegistrationService
{
private static List<Uri> subscribers = new List<Uri>();
private static object obj = new object();
public void Register(string uri)
{
Uri channelUri = new Uri(uri, UriKind.Absolute);
Subscribe(channelUri);
}
public void Unregister(string uri)
{
Uri channelUri = new Uri(uri, UriKind.Absolute);
Unsubscribe(channelUri);
}
private void Subscribe(Uri channelUri)
{
lock (obj)
{
if (!subscribers.Exists((u) => u == channelUri))
{
subscribers.Add(channelUri);
}
}
}
public static void Unsubscribe(Uri channelUri)
{
lock (obj)
{
subscribers.Remove(channelUri);
}
}
public static List<Uri> GetSubscribers()
{
return subscribers;
}
}
- 仔细查看刚刚添加到 RegistrationService.cs 文件中的代码。注意,RegistrationService 类在第一行实现了 IRegistrationService 接口,这一点非常重要。此外,代码逻辑很简单:使用静态的 subscribers 变量维护一个推送通知 URI 集合,每个调用服务的 Register 方法的客户端都会被添加到该订阅者列表中。使用 lock 函数防止多个客户端同时更改相同的数据,从而避免数据不完整和不可预测的问题。
- WCF 服务需要初始化代码才能启动。可以将初始化代码放在 Form1 的加载事件中。以下是启动服务所需的代码,将其复制到 Form1 的加载事件中:
ServiceHost host;
host = new ServiceHost(typeof(RegistrationService));
host.Open();
- 还需要为 WCF 服务提供一些配置参数。打开 app.config 文件,在 元素中添加以下配置参数:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="EndpointPNServerServiceBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="PNServer.RegistrationService">
<endpoint address="http://localhost/RegistrationService"
behaviorConfiguration="EndpointPNServerServiceBehavior"
binding="webHttpBinding"
contract="WP7_Push_Notifications.IRegistrationService">
</endpoint>
</service>
</services>
</system.serviceModel>
通过这些设置,我们将服务配置为监听以下地址:http://localhost/RegistrationService,并指定对该服务的请求将通过 HTTP 协议进行。
最后,我们修改主应用窗体(Form1),添加一个“广播”按钮,用于向所有订阅客户端发送推送通知。具体操作如下:
1. 在设计视图中打开 Form1.cs,在“发送通知”按钮下方添加一个按钮。
2. 将按钮的文本更改为“广播”。
3. 将按钮的名称更改为 btnBroadcast,双击该按钮,确保按钮的 Click 事件包含以下代码:
private void btnBroadcast_Click(object sender, EventArgs e)
{
if (txtTitle.Text == string.Empty || txtText.Text == string.Empty)
{
MessageBox.Show("Please enter text and title to send");
return;
}
List<Uri> allSubscribersUri = RegistrationService.GetSubscribers();
foreach (Uri subscriberUri in allSubscribersUri)
{
sendPushNotificationToClient(subscriberUri.ToString());
}
}
- 在 sendPushNotificationToClient 函数中添加以下代码:
private void sendPushNotificationToClient(string url)
{
HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(url);
sendNotificationRequest.Method = "POST";
sendNotificationRequest.Headers = new WebHeaderCollection();
sendNotificationRequest.ContentType = "text/xml";
sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "toast");
sendNotificationRequest.Headers.Add("X-NotificationClass", "2");
string str = string.Format(TilePushXML, txtTitle.Text, txtText.Text);
byte[] strBytes = new UTF8Encoding().GetBytes(str);
sendNotificationRequest.ContentLength = strBytes.Length;
using (Stream requestStream = sendNotificationRequest.GetRequestStream())
{
requestStream.Write(strBytes, 0, strBytes.Length);
}
try
{
HttpWebResponse response =
(HttpWebResponse)sendNotificationRequest.GetResponse();
string notificationStatus = response.Headers["X-NotificationStatus"];
string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"];
lblStatus.Text = "Status: " + notificationStatus + " : " + deviceConnectionStatus;
}
catch (Exception ex)
{
//handle 404 (URI not found) and other exceptions that may occur
lblStatus.Text = "Failed to connect, exception detail: " + ex.Message;
}
需要注意的是,TilePushXML 变量在之前关于磁贴通知的讨论中已经定义。通过 WCF 服务跟踪订阅客户端并完成推送通知的发送后,接下来需要修改客户端应用,使其能够使用推送通知 URL 调用 Web 服务。
5. 修改客户端以调用 WCF 服务
Windows Phone 推送通知客户端应用需要进行修改,以便使用推送通知 URL 调用新实现的 Web 服务。由于 RESTful WCF 服务的操作可以通过 URL 访问,例如,URL http://localhost/RegistrationService/Register?uri={0} 可以访问上一节中创建的 Web 服务的 Register 函数,其中 uri 参数通过查询字符串提供。基于此,我们可以通过创建注册/注销 Windows Phone 客户端与服务器的函数来完成 Windows Phone 推送通知客户端的实现。具体步骤如下:
1. 启动 Visual Studio 2010 Express for Windows Phone,打开 PNClient 项目。
2. 找到 ChannelUri 属性的 getter 和 setter,并将其修改为以下内容(注意使用了两个新函数 RegisterUriWithServer 和 UnregisterUriFromServer):
public Uri ChannelUri
{
get { return channelUri; }
set
{
//unregister the old URI from the server
if (channelUri!=null)
UnregisterUriFromServer(channelUri);
//register the new URI with the server
RegisterUriWithServer(value);
channelUri = value;
OnChannelUriChanged(value);
}
}
- 添加以下两个函数来调用创建的 WCF 服务(注意,在将服务发布到生产环境时,可能需要将该服务部署到云端):
private void RegisterUriWithServer(Uri newChannelUri)
{
//Hardcode for solution - need to be updated in case the REST WCF
// service address changes
string baseUri = "http://localhost/RegistrationService/Register?uri={0}";
string theUri = String.Format(baseUri, newChannelUri.ToString());
WebClient client = new WebClient();
client.DownloadStringCompleted += (s, e) =>
{
if (e.Error == null)
Dispatcher.BeginInvoke(() => {
txtURI.Text = "changing uri to " + newChannelUri.ToString();
});
else
Dispatcher.BeginInvoke(() =>
{
txtURI.Text = "registration failed " + e.Error.Message;
});
};
client.DownloadStringAsync(new Uri(theUri));
}
private void UnregisterUriFromServer(Uri oldChannelUri)
{
//Hardcode for solution - need to be updated in case the REST WCF service
//address changes
string baseUri = "http://localhost/RegistrationService/Unregister?uri={0}";
string theUri = String.Format(baseUri, oldChannelUri.ToString());
WebClient client = new WebClient();
client.DownloadStringCompleted += (s, e) =>
{
if (e.Error == null)
Dispatcher.BeginInvoke(() =>
{
txtURI.Text = "unregistered uri " + oldChannelUri.ToString();
});
else
Dispatcher.BeginInvoke(() =>
{
txtURI.Text = "registration delete failed " + e.Error.Message;
});
};
client.DownloadStringAsync(new Uri(theUri));
}
在上述代码中,需要注意云服务的 URL 是硬编码的,该 URL 必须与 WCF 服务配置文件(app.config)中指定的 URL 相匹配。此外,还需要注意事件处理程序(client.DownloadStringCompleted)的连接方式,这些事件处理程序可以提供注册/注销操作是否成功的状态更新。
6. 验证自动化推送通知订阅者跟踪
为了测试自动化推送通知跟踪,首先要确保 WCF 服务能够正确启动并处理传入的请求。具体步骤如下:
1. 由于 WCF 服务在设计时考虑了安全性,因此有许多安全配置选项。为了绕过这些安全配置选项,避免它们干扰本章的主要内容,并允许测试构建的服务,需要以管理员身份运行 WCF 服务项目。最快的方法是退出 Visual Studio,右键单击 Visual Studio 快捷方式,选择“以管理员身份运行”。当 Visual Studio 启动后,打开 PNServer 解决方案,此时即可以管理员身份运行 PNServer。
2. 为了验证 WCF 服务是否准备好接受客户端连接,在 RegistrationService 类的 Register 函数的第一行设置断点,然后按下 F5 启动 PNServer 应用程序。
3. 如果应用程序正在运行,并且显示了图 17 - 10 中的 Windows 窗体,打开 Internet Explorer(或任何其他浏览器)并访问以下 URL:
http://localhost/RegistrationService/Register?uri=http://www.microsoft.com
如果访问此 URL 后断点被命中,说明服务正在运行,并且准备好接受客户端连接。如果断点未被命中,并且看到页面无法显示的消息,请验证 PNServer 项目的 app.config 文件中 部分的内容是否与创建 WCF 服务部分中描述的文件内容匹配。很可能是某种配置问题导致无法正确启动服务。
确认服务正在运行后,可以通过以下步骤观察自动化推送通知订阅者跟踪的实际效果:
1. 启动 PNClient 应用程序,点击“创建通道”按钮。如果 WCF 服务的 Register 函数中仍然设置了断点,该断点应该会被命中。按下 F5 继续执行调试器。
2. 为了能够在手机上看到吐司通知,需要将应用程序图标固定到开始屏幕。具体操作是点击手机的 Windows 按钮,然后点击箭头打开 Windows Phone 选项屏幕,按住鼠标左键弹出弹出菜单,然后点击“固定到开始”选项。
3. 将应用程序图标固定到开始屏幕后,就可以在手机上接收通知了。在 PNServer 应用程序窗口中,输入要发送的通知消息的标题和文本,然后点击“广播”按钮。一两秒后,应该能在手机上看到推送通知。
通过客户端和云服务动态交换推送通知 URL,并且客户端能够接受推送通知,我们完成了推送通知的演示。不过,我们构建的解决方案虽然提供了推送通知的完整生命周期实现,但在部署到生产环境之前,需要考虑一些限制。例如,Windows Phone 客户端应用程序关闭时不会自动从服务器注销,因此服务器可能会尝试向不存在的通道发送通知。
综上所述,我们通过一系列步骤实现了 Windows Phone 推送通知系统,从客户端应用的基础设置,到服务器端发送原始通知,再到使用 WCF 服务实现自动化的订阅者跟踪和通知发送,最后进行了验证测试。整个过程涉及到多个方面的知识和技术,包括客户端代码编写、服务器端代码编写、WCF 服务的创建和配置、以及测试和调试等。希望这些内容能帮助你更好地理解和实现 Windows Phone 推送通知系统。
以下是一个简单的 mermaid 流程图,展示了整个推送通知系统的主要流程:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B(客户端应用设置):::process
B --> C(服务器应用发送原始通知):::process
C --> D(测试原始通知发送):::process
D --> E(实现 WCF 服务):::process
E --> F(修改客户端调用 WCF 服务):::process
F --> G(验证自动化跟踪):::process
G --> H([结束]):::startend
通过这个流程图,我们可以更清晰地看到整个推送通知系统的构建和测试过程。同时,在实际开发中,我们可以根据具体需求对每个步骤进行进一步的优化和扩展。
深入探究 Windows Phone 推送通知系统:从基础实现到自动化服务
7. 推送通知类型总结与对比
在前面的内容中,我们介绍了多种推送通知类型,包括原始通知、磁贴通知和吐司通知。下面通过一个表格来总结它们的特点和适用场景:
| 通知类型 | 特点 | 适用场景 | 实现复杂度 |
| — | — | — | — |
| 原始通知 | 无需 XML 模板,格式简单 | 传递自定义数据,如应用内消息、更新提醒等 | 较低 |
| 磁贴通知 | 可更新开始屏幕上的磁贴内容 | 显示应用的实时信息,如天气、新闻等 | 中等 |
| 吐司通知 | 弹出式通知,吸引用户注意力 | 提醒用户重要事件,如消息提醒、任务到期等 | 中等 |
根据不同的业务需求和用户体验要求,选择合适的通知类型可以提高应用的实用性和用户满意度。
8. 优化与扩展建议
8.1 客户端优化
- 错误处理 :在客户端代码中,增加更详细的错误处理逻辑,例如在调用 WCF 服务时,除了显示错误信息外,还可以记录日志,方便后续排查问题。
- 性能优化 :对于频繁更新的通知,可以考虑使用缓存机制,减少不必要的网络请求,提高应用的响应速度。
8.2 服务器端优化
- 负载均衡 :当有大量客户端订阅时,为了避免服务器压力过大,可以采用负载均衡技术,将请求分发到多个服务器上。
- 数据存储 :使用数据库来存储订阅者信息,方便管理和查询,同时提高数据的安全性和可靠性。
8.3 服务扩展
- 多平台支持 :将现有的推送通知系统扩展到其他平台,如 Android 和 iOS,实现跨平台的通知服务。
- 定时通知 :增加定时发送通知的功能,满足用户在特定时间接收通知的需求。
9. 未来展望
随着移动应用的不断发展,推送通知系统也将不断演进。未来可能会出现以下趋势:
-
个性化通知
:根据用户的行为和偏好,提供更加个性化的通知内容,提高用户的参与度。
-
增强安全性
:采用更先进的加密技术,保护推送通知的内容和用户信息的安全。
-
与其他服务集成
:与社交媒体、支付系统等其他服务集成,提供更加丰富的功能和体验。
10. 总结
本文详细介绍了 Windows Phone 推送通知系统的实现过程,包括客户端应用的基础设置、服务器端发送通知、WCF 服务的创建和配置以及自动化订阅者跟踪的验证。通过这些步骤,我们实现了一个完整的推送通知解决方案。
在实际应用中,需要根据具体需求选择合适的通知类型,并对系统进行优化和扩展。同时,要关注未来的发展趋势,不断提升推送通知系统的性能和用户体验。
希望本文能够帮助开发者更好地理解和实现 Windows Phone 推送通知系统,为移动应用的开发提供有价值的参考。
以下是一个 mermaid 流程图,展示了优化和扩展的方向:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([当前系统]):::startend --> B(客户端优化):::process
A --> C(服务器端优化):::process
A --> D(服务扩展):::process
B --> E([优化后系统]):::startend
C --> E
D --> E
这个流程图清晰地展示了对现有推送通知系统进行优化和扩展的主要方向,有助于开发者更好地规划和实施改进措施。
超级会员免费看
1861

被折叠的 条评论
为什么被折叠?



