212 lines
6.7 KiB
C#
212 lines
6.7 KiB
C#
|
//------------------------------------------------------------
|
|||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|||
|
//------------------------------------------------------------
|
|||
|
|
|||
|
namespace System.ServiceModel.Channels
|
|||
|
{
|
|||
|
using System.Runtime.CompilerServices;
|
|||
|
using System.Runtime.InteropServices;
|
|||
|
using System.ServiceModel;
|
|||
|
using System.Transactions;
|
|||
|
using System.ServiceModel.Dispatcher;
|
|||
|
using System.Threading;
|
|||
|
using System.Runtime;
|
|||
|
|
|||
|
class MsmqReceiveContextSettings : IReceiveContextSettings
|
|||
|
{
|
|||
|
public MsmqReceiveContextSettings()
|
|||
|
{
|
|||
|
ValidityDuration = MsmqDefaults.ValidityDuration;
|
|||
|
}
|
|||
|
|
|||
|
public MsmqReceiveContextSettings(IReceiveContextSettings toBeCloned)
|
|||
|
{
|
|||
|
Enabled = toBeCloned.Enabled;
|
|||
|
ValidityDuration = toBeCloned.ValidityDuration;
|
|||
|
}
|
|||
|
|
|||
|
public TimeSpan ValidityDuration
|
|||
|
{
|
|||
|
get;
|
|||
|
private set;
|
|||
|
}
|
|||
|
|
|||
|
public bool Enabled
|
|||
|
{
|
|||
|
get;
|
|||
|
set;
|
|||
|
}
|
|||
|
|
|||
|
internal void SetValidityDuration(TimeSpan validityDuration)
|
|||
|
{
|
|||
|
ValidityDuration = validityDuration;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
class MsmqReceiveContext : ReceiveContext
|
|||
|
{
|
|||
|
long lookupId;
|
|||
|
DateTime expiryTime;
|
|||
|
MsmqReceiveContextLockManager manager;
|
|||
|
|
|||
|
public MsmqReceiveContext(long lookupId, DateTime expiryTime, MsmqReceiveContextLockManager manager)
|
|||
|
: base()
|
|||
|
{
|
|||
|
this.manager = manager;
|
|||
|
this.lookupId = lookupId;
|
|||
|
this.expiryTime = expiryTime;
|
|||
|
}
|
|||
|
|
|||
|
public long LookupId
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return this.lookupId;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public DateTime ExpiryTime
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return this.expiryTime;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public MsmqReceiveContextLockManager Manager
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return this.manager;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void MarkContextExpired()
|
|||
|
{
|
|||
|
base.Fault();
|
|||
|
}
|
|||
|
|
|||
|
protected override void OnComplete(TimeSpan timeout)
|
|||
|
{
|
|||
|
this.manager.DeleteMessage(this, timeout);
|
|||
|
}
|
|||
|
|
|||
|
protected override void OnAbandon(TimeSpan timeout)
|
|||
|
{
|
|||
|
this.manager.UnlockMessage(this, timeout);
|
|||
|
}
|
|||
|
|
|||
|
protected override IAsyncResult OnBeginComplete(TimeSpan timeout, AsyncCallback callback, object state)
|
|||
|
{
|
|||
|
return ReceiveContextAsyncResult.CreateComplete(this, timeout, callback, state);
|
|||
|
}
|
|||
|
|
|||
|
protected override void OnEndComplete(IAsyncResult result)
|
|||
|
{
|
|||
|
ReceiveContextAsyncResult.End(result);
|
|||
|
}
|
|||
|
|
|||
|
protected override IAsyncResult OnBeginAbandon(TimeSpan timeout, AsyncCallback callback, object state)
|
|||
|
{
|
|||
|
return ReceiveContextAsyncResult.CreateAbandon(this, timeout, callback, state);
|
|||
|
}
|
|||
|
|
|||
|
protected override void OnEndAbandon(IAsyncResult result)
|
|||
|
{
|
|||
|
ReceiveContextAsyncResult.End(result);
|
|||
|
}
|
|||
|
|
|||
|
class ReceiveContextAsyncResult : AsyncResult
|
|||
|
{
|
|||
|
MsmqReceiveContext receiver;
|
|||
|
TimeoutHelper timeoutHelper;
|
|||
|
static Action<object> onComplete;
|
|||
|
static Action<object> onAbandon;
|
|||
|
Transaction associatedTransaction;
|
|||
|
|
|||
|
ReceiveContextAsyncResult(MsmqReceiveContext receiver, TimeSpan timeout, AsyncCallback callback, object state, Action<object> target)
|
|||
|
: base(callback, state)
|
|||
|
{
|
|||
|
this.timeoutHelper = new TimeoutHelper(timeout);
|
|||
|
this.receiver = receiver;
|
|||
|
|
|||
|
if (Transaction.Current != null)
|
|||
|
{
|
|||
|
this.associatedTransaction = Transaction.Current;
|
|||
|
}
|
|||
|
|
|||
|
ActionItem.Schedule(target, this);
|
|||
|
}
|
|||
|
|
|||
|
public static IAsyncResult CreateComplete(MsmqReceiveContext receiver, TimeSpan timeout, AsyncCallback callback, object state)
|
|||
|
{
|
|||
|
if (onComplete == null)
|
|||
|
{
|
|||
|
onComplete = new Action<object>(OnComplete);
|
|||
|
}
|
|||
|
return new ReceiveContextAsyncResult(receiver, timeout, callback, state, onComplete);
|
|||
|
}
|
|||
|
|
|||
|
public static IAsyncResult CreateAbandon(MsmqReceiveContext receiver, TimeSpan timeout, AsyncCallback callback, object state)
|
|||
|
{
|
|||
|
if (onAbandon == null)
|
|||
|
{
|
|||
|
onAbandon = new Action<object>(OnAbandon);
|
|||
|
}
|
|||
|
return new ReceiveContextAsyncResult(receiver, timeout, callback, state, onAbandon);
|
|||
|
}
|
|||
|
|
|||
|
static void OnComplete(object parameter)
|
|||
|
{
|
|||
|
ReceiveContextAsyncResult result = parameter as ReceiveContextAsyncResult;
|
|||
|
Exception completionException = null;
|
|||
|
Transaction savedTransaction = null;
|
|||
|
try
|
|||
|
{
|
|||
|
// set the current transaction object for this worker thread as this operation could
|
|||
|
// have been scheduled by another worker thread. We do not want to complete in
|
|||
|
// worker threads ambient transaction. associatedTransaction can be null.
|
|||
|
savedTransaction = Transaction.Current;
|
|||
|
Transaction.Current = result.associatedTransaction;
|
|||
|
result.receiver.OnComplete(result.timeoutHelper.RemainingTime());
|
|||
|
}
|
|||
|
catch (Exception e)
|
|||
|
{
|
|||
|
if (Fx.IsFatal(e))
|
|||
|
{
|
|||
|
throw;
|
|||
|
}
|
|||
|
completionException = e;
|
|||
|
}
|
|||
|
finally
|
|||
|
{
|
|||
|
Transaction.Current = savedTransaction;
|
|||
|
}
|
|||
|
result.Complete(false, completionException);
|
|||
|
}
|
|||
|
|
|||
|
static void OnAbandon(object parameter)
|
|||
|
{
|
|||
|
ReceiveContextAsyncResult result = parameter as ReceiveContextAsyncResult;
|
|||
|
Exception completionException = null;
|
|||
|
try
|
|||
|
{
|
|||
|
result.receiver.OnAbandon(result.timeoutHelper.RemainingTime());
|
|||
|
}
|
|||
|
catch (Exception e)
|
|||
|
{
|
|||
|
if (Fx.IsFatal(e))
|
|||
|
throw;
|
|||
|
completionException = e;
|
|||
|
}
|
|||
|
result.Complete(false, completionException);
|
|||
|
}
|
|||
|
|
|||
|
public static void End(IAsyncResult result)
|
|||
|
{
|
|||
|
AsyncResult.End<ReceiveContextAsyncResult>(result);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|