我目前正在使用C#Web应用程序,并且正在尝试使用PushSharp软件包来获取推送通知。我在项目的Global.asax文件中拥有用于推送通知的所有代码,但始终收到错误消息:
The collection has been marked as complete with regards to additions.
这是我的Global.asax文件:
using BYC.Models;
using BYC.Models.Enums;
using Newtonsoft.Json.Linq;
using PushSharp.Apple;
using PushSharp.Google;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace BYC
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
protected void Application_End()
{
PushBrokerSingleton pbs = new PushBrokerSingleton();
pbs.SendQueuedNotifications();
}
}
public sealed class PushBrokerSingleton
{
private static ApnsServiceBroker Apns { get; set; }
private static GcmServiceBroker Gcm { get; set; }
private static bool ApnsStarted = false;
private static bool GcmStarted = false;
private static object AppleSyncVar = new object();
private static object GcmSyncVar = new object();
private static readonly log4net.ILog log = log4net.LogManager.GetLogger
(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public PushBrokerSingleton()
{
if (Apns == null)
{
string thumbprint = (AppSettings.Instance["APNS:Thumbprint"]);
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
ApnsConfiguration.ApnsServerEnvironment production = Convert.ToBoolean(AppSettings.Instance["APNS:Production"]) ?
ApnsConfiguration.ApnsServerEnvironment.Production : ApnsConfiguration.ApnsServerEnvironment.Sandbox;
X509Certificate2 appleCert = store.Certificates
.Cast<X509Certificate2>()
.SingleOrDefault(c => string.Equals(c.Thumbprint, thumbprint, StringComparison.OrdinalIgnoreCase));
ApnsConfiguration apnsConfig = new ApnsConfiguration(production, appleCert);
Apns = new ApnsServiceBroker(apnsConfig);
Apns.OnNotificationFailed += (notification, aggregateEx) => {
aggregateEx.Handle(ex => {
// See what kind of exception it was to further diagnose
if (ex is ApnsNotificationException)
{
var notificationException = ex as ApnsNotificationException;
// Deal with the failed notification
var apnsNotification = notificationException.Notification;
var statusCode = notificationException.ErrorStatusCode;
log.Error($"Notification Failed: ID={apnsNotification.Identifier}, Code={statusCode}");
}
else {
// Inner exception might hold more useful information like an ApnsConnectionException
log.Error($"Notification Failed for some (Unknown Reason) : {ex.InnerException}");
}
// Mark it as handled
return true;
});
};
Apns.OnNotificationSucceeded += (notification) => {
log.Info("Notification Successfully Sent to: " + notification.DeviceToken);
};
}
if(Gcm == null)
{
GcmConfiguration gcmConfig = new GcmConfiguration(AppSettings.Instance["GCM:Token"]);
Gcm = new GcmServiceBroker(gcmConfig);
}
}
public bool QueueNotification(Notification notification, Device device)
{
if (!ApnsStarted)
{
ApnsStarted = true;
lock (AppleSyncVar)
{
Apns.Start();
}
}
if(!GcmStarted)
{
GcmStarted = true;
lock (GcmSyncVar)
{
Gcm.Start();
}
}
switch (device.PlatformType)
{
case PlatformType.iOS:
return QueueApplePushNotification(notification, device.PushRegistrationToken);
case PlatformType.Android:
return QueueAndroidPushNotification(notification, device.PushRegistrationToken);
default: return false;
}
}
private bool QueueApplePushNotification(Notification notification, string pushNotificationToken)
{
string appleJsonFormat = "{\"aps\": {\"alert\":" + '"' + notification.Subject + '"' + ",\"sound\": \"default\", \"badge\": " + notification.BadgeNumber + "}}";
lock (AppleSyncVar)
{
Apns.QueueNotification(new ApnsNotification()
{
DeviceToken = pushNotificationToken,
Payload = JObject.Parse(appleJsonFormat)
});
}
return true;
}
private bool QueueAndroidPushNotification(Notification notification, string pushNotificationToken)
{
string message = "{\"alert\":\"" + notification.Subject + "\",\"badge\":" + notification.BadgeNumber + "\"}";
lock (GcmSyncVar)
{
Gcm.QueueNotification(new GcmNotification()
{
RegistrationIds = new List<string>
{
pushNotificationToken
},
Data = JObject.Parse(message),
Notification = JObject.Parse(message)
});
}
return true;
}
public void SendQueuedNotifications()
{
if(Apns != null)
{
if (ApnsStarted)
{
lock(AppleSyncVar){
Apns.Stop();
log.Info("Sent Apns Notifications");
ApnsStarted = false;
}
}
}
if(Gcm != null)
{
if (GcmStarted)
{
lock (GcmSyncVar)
{
Gcm.Stop();
log.Info("Sent Gcm Notifications");
GcmStarted = false;
}
}
}
}
}
}
:当你尝试和重用服务代理(例如一个实例发生ApnsServiceBroker
这)Stop()
已经呼吁。
我猜您Application_End
在某个时候Application_Start
被调用并再次被调用,但是由于PushBrokerSingleton.Apns
它不为null(这是一个静态字段,因此即使应用程序已停止/启动,它也必须存在),因此永远不会重新创建它。
PushSharp很难使ASP.NET模式很好地工作,某种服务守护程序会更好。
主要问题是您的应用程序可能在您不期望的情况下被回收或终止。同一应用程序中不相关的请求可能会导致您的流程中断,或者您的AppDomain可能会被删除。如果发生这种情况,并且经纪人的Stop()
呼叫无法成功结束,则可能会丢失一些排队的消息。这是一篇有关一些警告的出色文章:http : //haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx/在实践中,这可能没什么大不了的,您当然可以减轻它的一部分,但请记住这一点。
说了这么多,我想一个简单的解决将是创建一个新的实例PushBrokerSingleton.Apns
,并PushBrokerSingleton.Gcm
在你的Application_Start
。这可能会给您带来其他问题,因此我不确定这是否是正确的解决方案,但可以解决在Stop()
调用代理后不应重用代理的问题。
我还将考虑添加某种方式来“重置”集合。我不确定在.Stop()
结束后自动执行此操作是否是个好主意,但我可能会考虑添加一种.Reset()
或类似类型的方法来实现此目的。无论如何,现在完全可以创建一个新的代理实例。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句