174 lines
7.9 KiB
C#
174 lines
7.9 KiB
C#
|
//----------------------------------------------------------------
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//----------------------------------------------------------------
|
||
|
namespace System.ServiceModel.Activities
|
||
|
{
|
||
|
using System.Diagnostics;
|
||
|
using System.Globalization;
|
||
|
using System.ServiceModel;
|
||
|
using System.ServiceModel.Activities.Description;
|
||
|
using System.ServiceModel.Channels;
|
||
|
using System.ServiceModel.Description;
|
||
|
using System.Runtime;
|
||
|
using System.Threading;
|
||
|
using System.Security;
|
||
|
using System.Security.Permissions;
|
||
|
|
||
|
[Fx.Tag.XamlVisible(false)]
|
||
|
public class WorkflowControlEndpoint : ServiceEndpoint
|
||
|
{
|
||
|
static Uri defaultBaseUri;
|
||
|
|
||
|
// Double-checked locking pattern requires volatile for read/write synchronization
|
||
|
static volatile ContractDescription workflowControlServiceBaseContract;
|
||
|
static volatile ContractDescription workflowControlServiceContract;
|
||
|
static object workflowContractDescriptionLock = new object();
|
||
|
|
||
|
public WorkflowControlEndpoint()
|
||
|
: this(WorkflowControlEndpoint.GetDefaultBinding(),
|
||
|
new EndpointAddress(new Uri(WorkflowControlEndpoint.DefaultBaseUri, new Uri(Guid.NewGuid().ToString(), UriKind.Relative))))
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public WorkflowControlEndpoint(Binding binding, EndpointAddress address)
|
||
|
: base(WorkflowControlEndpoint.WorkflowControlServiceContract, binding, address)
|
||
|
{
|
||
|
this.IsSystemEndpoint = true;
|
||
|
}
|
||
|
|
||
|
internal static ContractDescription WorkflowControlServiceBaseContract
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (workflowControlServiceBaseContract == null)
|
||
|
{
|
||
|
lock (workflowContractDescriptionLock)
|
||
|
{
|
||
|
if (workflowControlServiceBaseContract == null)
|
||
|
{
|
||
|
foreach (OperationDescription operation in WorkflowControlServiceContract.Operations)
|
||
|
{
|
||
|
if (operation.DeclaringContract != WorkflowControlServiceContract)
|
||
|
{
|
||
|
workflowControlServiceBaseContract = operation.DeclaringContract;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return workflowControlServiceBaseContract;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal static ContractDescription WorkflowControlServiceContract
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (workflowControlServiceContract == null)
|
||
|
{
|
||
|
lock (workflowContractDescriptionLock)
|
||
|
{
|
||
|
if (workflowControlServiceContract == null)
|
||
|
{
|
||
|
ContractDescription tempControlServiceContract = ContractDescription.GetContract(
|
||
|
typeof(IWorkflowUpdateableInstanceManagement));
|
||
|
tempControlServiceContract.Behaviors.Add(new ServiceMetadataContractBehavior(true));
|
||
|
ApplyOperationBehaviors(tempControlServiceContract);
|
||
|
// For back-compat, need to support existing code which expects the old contract type
|
||
|
tempControlServiceContract.ContractType = typeof(IWorkflowInstanceManagement);
|
||
|
workflowControlServiceContract = tempControlServiceContract;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return workflowControlServiceContract;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[Fx.Tag.SecurityNote(Critical = "Critical because it retreives the Process Id via Process.Id, which has a link demand for Full Trust.",
|
||
|
Safe = "Safe because it demands FullTrust")]
|
||
|
[SecuritySafeCritical]
|
||
|
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
|
||
|
static void RetrieveProcessIdAndAppDomainId(out int processId, out int appDomainId)
|
||
|
{
|
||
|
processId = Process.GetCurrentProcess().Id;
|
||
|
appDomainId = AppDomain.CurrentDomain.Id;
|
||
|
}
|
||
|
|
||
|
static Uri DefaultBaseUri
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (defaultBaseUri == null)
|
||
|
{
|
||
|
// If we are running in full trust, use the ProcessId and AppDomainId. If partial trust, use a new guid to make the URI unique and avoid
|
||
|
// the usage of ProcessId and AppDomainId. We are doing this for back compat.
|
||
|
if (PartialTrustHelpers.AppDomainFullyTrusted)
|
||
|
{
|
||
|
int processId;
|
||
|
int appDomainId;
|
||
|
RetrieveProcessIdAndAppDomainId(out processId, out appDomainId);
|
||
|
defaultBaseUri = new Uri(string.Format(CultureInfo.InvariantCulture, "net.pipe://localhost/workflowControlServiceEndpoint/{0}/{1}",
|
||
|
processId,
|
||
|
appDomainId));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Uri tempUri = new Uri(string.Format(CultureInfo.InvariantCulture, "net.pipe://localhost/workflowControlServiceEndpoint/{0}",
|
||
|
Guid.NewGuid().ToString()));
|
||
|
// Using Interlocked.CompareExchange because new Guid.NewGuid is not atomic.
|
||
|
Interlocked.CompareExchange(ref defaultBaseUri, tempUri, null);
|
||
|
}
|
||
|
}
|
||
|
return defaultBaseUri;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static Binding GetDefaultBinding()
|
||
|
{
|
||
|
return new NetNamedPipeBinding(NetNamedPipeSecurityMode.None) { TransactionFlow = true };
|
||
|
}
|
||
|
|
||
|
static void ApplyOperationBehaviors(ContractDescription contractDescription)
|
||
|
{
|
||
|
foreach (OperationDescription operationDescription in contractDescription.Operations)
|
||
|
{
|
||
|
//Except "Abandon" all the operations in this contract are Async.
|
||
|
//All Transacted* operation are Transacted & Async.
|
||
|
switch (operationDescription.Name)
|
||
|
{
|
||
|
case XD2.WorkflowInstanceManagementService.Abandon:
|
||
|
case XD2.WorkflowInstanceManagementService.Cancel:
|
||
|
case XD2.WorkflowInstanceManagementService.Run:
|
||
|
case XD2.WorkflowInstanceManagementService.Suspend:
|
||
|
case XD2.WorkflowInstanceManagementService.Terminate:
|
||
|
case XD2.WorkflowInstanceManagementService.Unsuspend:
|
||
|
case XD2.WorkflowInstanceManagementService.Update:
|
||
|
EnsureDispatch(operationDescription);
|
||
|
break;
|
||
|
case XD2.WorkflowInstanceManagementService.TransactedCancel:
|
||
|
case XD2.WorkflowInstanceManagementService.TransactedRun:
|
||
|
case XD2.WorkflowInstanceManagementService.TransactedSuspend:
|
||
|
case XD2.WorkflowInstanceManagementService.TransactedTerminate:
|
||
|
case XD2.WorkflowInstanceManagementService.TransactedUnsuspend:
|
||
|
case XD2.WorkflowInstanceManagementService.TransactedUpdate:
|
||
|
EnsureDispatch(operationDescription);
|
||
|
EnsureTransactedInvoke(operationDescription);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void EnsureDispatch(OperationDescription operationDescription)
|
||
|
{
|
||
|
operationDescription.Behaviors.Add(new ControlOperationBehavior(false));
|
||
|
}
|
||
|
|
||
|
static void EnsureTransactedInvoke(OperationDescription operationDescription)
|
||
|
{
|
||
|
OperationBehaviorAttribute operationAttribute = operationDescription.Behaviors.Find<OperationBehaviorAttribute>();
|
||
|
operationAttribute.TransactionScopeRequired = true;
|
||
|
}
|
||
|
}
|
||
|
}
|