private void OnPublishComplete(IAsyncResult result)
{
// extract state information.
object[] state = (object[])result.AsyncState;
NodeId sessionId = (NodeId)state[0];
SubscriptionAcknowledgementCollection acknowledgementsToSend = (SubscriptionAcknowledgementCollection)state[1];
RequestHeader requestHeader = (RequestHeader)state[2];
bool moreNotifications;
AsyncRequestCompleted(result, requestHeader.RequestHandle, DataTypes.PublishRequest);
try
{
// Utils.Trace("PUBLISH #{0} RECEIVED", requestHeader.RequestHandle);
// complete publish.
uint subscriptionId;
UInt32Collection availableSequenceNumbers;
NotificationMessage notificationMessage;
StatusCodeCollection acknowledgeResults;
DiagnosticInfoCollection acknowledgeDiagnosticInfos;
ResponseHeader responseHeader = EndPublish(
result,
out subscriptionId,
out availableSequenceNumbers,
out moreNotifications,
out notificationMessage,
out acknowledgeResults,
out acknowledgeDiagnosticInfos);
foreach (StatusCode code in acknowledgeResults)
{
if (StatusCode.IsBad(code))
{
Utils.Trace("Error - Publish call finished. ResultCode={0}; SubscriptionId={1};", code.ToString(), subscriptionId);
}
}
// nothing more to do if session changed.
if (sessionId != SessionId)
{
Utils.Trace("Publish response discarded because session id changed: Old {0} != New {1}", sessionId, SessionId);
return;
}
// Utils.Trace("NOTIFICATION RECEIVED: SubId={0}, SeqNo={1}", subscriptionId, notificationMessage.SequenceNumber);
// process response.
ProcessPublishResponse(
responseHeader,
subscriptionId,
availableSequenceNumbers,
moreNotifications,
notificationMessage);
// nothing more to do if reconnecting.
if (m_reconnecting)
{
Utils.Trace("No new publish sent because of reconnect in progress.");
return;
}
}
catch (Exception e)
{
if (m_subscriptions.Count == 0)
{
// Publish responses with error should occur after deleting the last subscription.
Utils.Trace("Publish #{0}, Subscription count = 0, Error: {1}", requestHeader.RequestHandle, e.Message);
}
else
{
Utils.Trace("Publish #{0}, Reconnecting={2}, Error: {1}", requestHeader.RequestHandle, e.Message, m_reconnecting);
}
moreNotifications = false;
// ignore errors if reconnecting.
if (m_reconnecting)
{
Utils.Trace("Publish abandoned after error due to reconnect: {0}", e.Message);
return;
}
// nothing more to do if session changed.
if (sessionId != SessionId)
{
Utils.Trace("Publish abandoned after error because session id changed: Old {0} != New {1}", sessionId, SessionId);
return;
}
// try to acknowledge the notifications again in the next publish.
if (acknowledgementsToSend != null)
{
lock (SyncRoot)
{
m_acknowledgementsToSend.AddRange(acknowledgementsToSend);
}
}
// raise an error event.
ServiceResult error = new ServiceResult(e);
if (error.Code != StatusCodes.BadNoSubscription)
{
PublishErrorEventHandler callback = null;
lock (m_eventLock)
{
callback = m_PublishError;
}
if (callback != null)
{
try
{
callback(this, new PublishErrorEventArgs(error));
}
catch (Exception e2)
{
Utils.Trace(e2, "Session: Unexpected error invoking PublishErrorCallback.");
}
}
}
// don't send another publish for these errors.
switch (error.Code)
{
case StatusCodes.BadNoSubscription:
case StatusCodes.BadSessionClosed:
case StatusCodes.BadTooManyPublishRequests:
case StatusCodes.BadServerHalted:
{
return;
}
}
Utils.Trace(e, "PUBLISH #{0} - Unhandled error during Publish.", requestHeader.RequestHandle);
}
int requestCount = GoodPublishRequestCount;
if (requestCount < m_subscriptions.Count)
{
BeginPublish(OperationTimeout);
}
else
{
Utils.Trace("PUBLISH - Did not send another publish request. GoodPublishRequestCount={0}, Subscriptions={1}", requestCount, m_subscriptions.Count);
}
}