我試圖在Exchange開發論壇發佈這個,並沒有得到任何答覆,所以我會在這裏嘗試。 Link to forum多PushNotification訂閱一些正常工作,有些不需要
我有一個windows服務,每15分鐘觸發一次,看是否有任何需要創建或更新的訂閱。我針對Exchange 2007 SP1使用託管API v1.1。我有一張表,用於存儲想要監視郵箱的所有用戶。因此,當通知進入「偵聽服務」時,我可以查找用戶並訪問消息以將其記錄到我們正在構建的應用程序中。在表中我有一個存儲訂閱信息以下列:
- SubscriptionId - VARCHAR(MAX)
- 水印 - VARCHAR(MAX)
- LastStatusUpdate - DATETIME
我的服務電話一個查詢所需數據的函數(根據它正在執行的功能)。如果用戶沒有訂閱,服務就會開始並創建一個。我正在使用模擬來訪問郵箱。這是我的「ActiveSubscription」方法,當用戶需要創建或更新的訂閱時觸發。
private void ActivateSubscription(User user)
{
if (user.ADGUID.HasValue)
{
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, Settings.ActiveDirectoryServerName, Settings.ActiveDirectoryRootContainer);
using (UserPrincipal up = UserPrincipal.FindByIdentity(ctx, IdentityType.Guid, user.ADGUID.Value.ToString()))
{
ewService.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SID, up.Sid.Value);
}
}
else
{
ewService.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, user.EmailAddress);
}
PushSubscription pushSubscription = ewService.SubscribeToPushNotifications(
new FolderId[] { WellKnownFolderName.Inbox, WellKnownFolderName.SentItems },
Settings.ListenerService, 30, user.Watermark,
EventType.NewMail, EventType.Created);
user.Watermark = pushSubscription.Watermark;
user.SubscriptionID = pushSubscription.Id;
user.SubscriptionStatusDateTime = DateTime.Now.ToLocalTime();
_users.Update(user);
}
我們也跑了以下cmdlet來給我們用假冒的Exchange服務器上的能力訪問EWS用戶。
Get-ExchangeServer | where {$_.IsClientAccessServer -eq $TRUE} | ForEach-Object {Add-ADPermission -Identity $_.distinguishedname -User (Get-User -Identity mailmonitor | select-object).identity -extendedRight ms-Exch-EPI-Impersonation}
上面的「ActivateSubscription」代碼按預期工作。或者我想。當我測試它時,我監控了我的郵箱,它運行得很好。我唯一需要解決的問題是,當收件箱中的項目是新郵件時,訂閱會兩次觸發,我收到NewMail事件和創建事件的通知。我實施了一項檢查工作,確保郵件尚未記錄在我的Listening服務中。這一切都很好。
今天,我們開始測試兩個同時在監控的郵箱。這兩個郵箱是我的和另一個開發人員的郵箱。我們發現了最奇怪的行爲。我的訂閱按預期工作。但他沒有,他的訂閱的傳入部分正常工作,但他發出的監聽服務的任何電子郵件從未被髮送通知。查看Exchange上的郵箱屬性我沒有看到他的郵箱和我的郵箱有任何區別。我們甚至比較了Outlook中的選項/設置。我看不到爲什麼它可以在我的郵箱上運行,而不是在他的郵箱上運行。
創建訂閱時是否存在缺少的內容。自從我的訂閱按預期工作後,我不認爲這是事實。
我的聽力服務代碼工作得很好。我已經將代碼放置在下面,以便有人希望看到它以確保它不是問題。
在此先感謝,特里
偵聽服務代碼:
/// <summary>
/// Summary description for PushNotificationClient
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class PushNotificationClient : System.Web.Services.WebService, INotificationServiceBinding
{
ExchangeService ewService = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
public PushNotificationClient()
{
//todo: init the service.
SetupExchangeWebService();
}
private void SetupExchangeWebService()
{
ewService.Credentials = Settings.ServiceCreds;
try
{
ewService.AutodiscoverUrl(Settings.AutoDiscoverThisEmailAddress);
}
catch (AutodiscoverRemoteException e)
{
//log auto discovery failed
ewService.Url = Settings.ExchangeService;
}
}
public SendNotificationResultType SendNotification(SendNotificationResponseType SendNotification1)
{
using (var _users = new ExchangeUser(Settings.SqlConnectionString))
{
var result = new SendNotificationResultType();
var responseMessages = SendNotification1.ResponseMessages.Items;
foreach (var responseMessage in responseMessages)
{
if (responseMessage.ResponseCode != ResponseCodeType.NoError)
{
//log error and unsubscribe.
result.SubscriptionStatus = SubscriptionStatusType.Unsubscribe;
return result;
}
var sendNoficationResponse = responseMessage as SendNotificationResponseMessageType;
if (sendNoficationResponse == null)
{
result.SubscriptionStatus = SubscriptionStatusType.Unsubscribe;
return result;
}
var notificationType = sendNoficationResponse.Notification;
var subscriptionId = notificationType.SubscriptionId;
var previousWatermark = notificationType.PreviousWatermark;
User user = _users.GetById(subscriptionId);
if (user != null)
{
if (user.MonitorEmailYN == true)
{
BaseNotificationEventType[] baseNotifications = notificationType.Items;
for (int i = 0; i < notificationType.Items.Length; i++)
{
if (baseNotifications[i] is BaseObjectChangedEventType)
{
var bocet = baseNotifications[i] as BaseObjectChangedEventType;
AccessCreateDeleteNewMailEvent(bocet, ref user);
}
}
_PreviousItemId = null;
}
else
{
user.SubscriptionID = String.Empty;
user.SubscriptionStatusDateTime = null;
user.Watermark = String.Empty;
_users.Update(user);
result.SubscriptionStatus = SubscriptionStatusType.Unsubscribe;
return result;
}
user.SubscriptionStatusDateTime = DateTime.Now.ToLocalTime();
_users.Update(user);
}
else
{
result.SubscriptionStatus = SubscriptionStatusType.Unsubscribe;
return result;
}
}
result.SubscriptionStatus = SubscriptionStatusType.OK;
return result;
}
}
private string _PreviousItemId;
private void AccessCreateDeleteNewMailEvent(BaseObjectChangedEventType bocet, ref User user)
{
var watermark = bocet.Watermark;
var timestamp = bocet.TimeStamp.ToLocalTime();
var parentFolderId = bocet.ParentFolderId;
if (bocet.Item is ItemIdType)
{
var itemId = bocet.Item as ItemIdType;
if (itemId != null)
{
if (string.IsNullOrEmpty(_PreviousItemId) || (!string.IsNullOrEmpty(_PreviousItemId) && _PreviousItemId != itemId.Id))
{
ProcessItem(itemId, ref user);
_PreviousItemId = itemId.Id;
}
}
}
user.SubscriptionStatusDateTime = timestamp;
user.Watermark = watermark;
using (var _users = new ExchangeUser(Settings.SqlConnectionString))
{
_users.Update(user);
}
}
private void ProcessItem(ItemIdType itemId, ref User user)
{
try
{
ewService.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, user.EmailAddress);
EmailMessage email = EmailMessage.Bind(ewService, itemId.Id);
using (var _entity = new SalesAssistantEntityDataContext(Settings.SqlConnectionString))
{
var direction = EmailDirection.Incoming;
if (email.From.Address == user.EmailAddress)
{
direction = EmailDirection.Outgoing;
}
int? bodyType = (int)email.Body.BodyType;
var _HtmlToRtf = new HtmlToRtf();
var message = _HtmlToRtf.ConvertHtmlToText(email.Body.Text);
bool? IsIncoming = Convert.ToBoolean((int)direction);
if (IsIncoming.HasValue && IsIncoming.Value == false)
{
foreach (var emailTo in email.ToRecipients)
{
_entity.InsertMailMessage(email.From.Address, emailTo.Address, email.Subject, message, bodyType, IsIncoming);
}
}
else
{
if (email.ReceivedBy != null)
{
_entity.InsertMailMessage(email.From.Address, email.ReceivedBy.Address, email.Subject, message, bodyType, IsIncoming);
}
else
{
var emailToFind = user.EmailAddress;
if (email.ToRecipients.Any(x => x.Address == emailToFind))
{
_entity.InsertMailMessage(email.From.Address, emailToFind, email.Subject, message, bodyType, IsIncoming);
}
}
}
}
}
catch(Exception e)
{
//Log exception
using (var errorHandler = new ErrorHandler(Settings.SqlConnectionString))
{
errorHandler.LogException(e, user.UserID, user.SubscriptionID, user.Watermark, user.SubscriptionStatusDateTime);
}
throw e;
}
}
}
好的,我們發現了差異,但是我們如何解決這個問題。事實證明,我的Outlook沒有使用緩存模式,而我們正在測試的那對夫婦。一旦我有他們其中的一個關閉緩存模式SentItems創建通知命中系統。我不明白它,並且不知道解決方法,因爲我相信當首次安裝Outlook時,緩存模式是默認值。有人有主意嗎? – 2011-03-24 13:52:59