1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities
{
using System.Activities;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime;
using System.ServiceModel.Activities.Description;
using System.ServiceModel.Activities.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
public abstract class WorkflowHostingEndpoint : ServiceEndpoint
{
Collection<CorrelationQuery> correlationQueries;
protected WorkflowHostingEndpoint(Type contractType)
: this(contractType, null, null)
{
}
protected WorkflowHostingEndpoint(Type contractType, Binding binding, EndpointAddress address)
: base(ContractDescription.GetContract(contractType), binding, address)
{
this.IsSystemEndpoint = true;
this.Contract.Behaviors.Add(new ServiceMetadataContractBehavior(false));
this.Contract.Behaviors.Add(new WorkflowHostingContractBehavior());
Fx.Assert(!this.Behaviors.Contains(typeof(CorrelationQueryBehavior)), "Must not contain correlation query!");
this.correlationQueries = new Collection<CorrelationQuery>();
this.Behaviors.Add(new CorrelationQueryBehavior(this.correlationQueries));
// If TransactionFlowOption.Allowed or TransactionFlowOption.Mandatory is defined on an operation, we will set
// TransactionScopeRequired = true for that operation. The operation will become transacted (use transaction flow,
// or create one locally). For usability reason, we assume this is the majority usage. User could opt out by
// setting TransactionScopeRequired to false or remove the TransactionFlowAttribute from the operation.
foreach (OperationDescription operationDescription in this.Contract.Operations)
{
TransactionFlowAttribute transactionFlow = operationDescription.Behaviors.Find<TransactionFlowAttribute>();
if (transactionFlow != null && transactionFlow.Transactions != TransactionFlowOption.NotAllowed)
{
OperationBehaviorAttribute operationAttribute = operationDescription.Behaviors.Find<OperationBehaviorAttribute>();
operationAttribute.TransactionScopeRequired = true;
}
}
}
public Collection<CorrelationQuery> CorrelationQueries
{
get { return this.correlationQueries; }
}
// There are two main scenario that user will override this api.
// - For ResumeBookmark, User explicitly put or know how to extract InstanceId from Message. This enables user to provide
// customized and lighter-weight (no InstanceKeys indirection) correlation.
// - For Workflow Creation, User could provide a preferred Id for newly created Workflow Instance.
protected internal virtual Guid OnGetInstanceId(object[] inputs, OperationContext operationContext)
{
return Guid.Empty;
}
protected internal virtual WorkflowCreationContext OnGetCreationContext(
object[] inputs, OperationContext operationContext,
Guid instanceId, WorkflowHostingResponseContext responseContext)
{
return null;
}
[SuppressMessage(FxCop.Category.Design, FxCop.Rule.AvoidOutParameters,
Justification = "By design, return both Bookmark and its payload.")]
protected internal virtual Bookmark OnResolveBookmark(object[] inputs, OperationContext operationContext,
WorkflowHostingResponseContext responseContext, out object value)
{
value = null;
return null;
}
internal static FaultException CreateDispatchFaultException()
{
FaultCode code = new FaultCode(FaultCodeConstants.Codes.InternalServiceFault, FaultCodeConstants.Namespaces.NetDispatch);
code = FaultCode.CreateReceiverFaultCode(code);
MessageFault dispatchFault = MessageFault.CreateFault(code,
new FaultReason(new FaultReasonText(SR.InternalServerError, CultureInfo.CurrentCulture)));
return new FaultException(dispatchFault, FaultCodeConstants.Actions.NetDispatcher);
}
class WorkflowHostingContractBehavior : IContractBehavior
{
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
Fx.Assert(endpoint is WorkflowHostingEndpoint, "Must be hosting endpoint!");
foreach (OperationDescription operation in contractDescription.Operations)
{
if (operation.Behaviors.Find<WorkflowHostingOperationBehavior>() == null)
{
operation.Behaviors.Add(new WorkflowHostingOperationBehavior());
}
}
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
Fx.Assert(endpoint is WorkflowHostingEndpoint, "Must be hosting endpoint!");
}
class WorkflowHostingOperationBehavior : WorkflowOperationBehavior
{
public WorkflowHostingOperationBehavior()
: base(true)
{
}
protected internal override Bookmark OnResolveBookmark(WorkflowOperationContext context, out BookmarkScope bookmarkScope, out object value)
{
CorrelationMessageProperty correlationMessageProperty;
if (CorrelationMessageProperty.TryGet(context.OperationContext.IncomingMessageProperties, out correlationMessageProperty))
{
bookmarkScope = new BookmarkScope(correlationMessageProperty.CorrelationKey.Value);
}
else
{
bookmarkScope = null;
}
WorkflowHostingResponseContext responseContext = new WorkflowHostingResponseContext(context);
Fx.Assert(context.ServiceEndpoint is WorkflowHostingEndpoint, "serviceEnpoint must be of WorkflowHostingEndpoint type!");
Bookmark bookmark = ((WorkflowHostingEndpoint)context.ServiceEndpoint).OnResolveBookmark(context.Inputs, context.OperationContext, responseContext, out value);
if (bookmark == null)
{
throw FxTrace.Exception.AsError(CreateDispatchFaultException());
}
return bookmark;
}
}
}
}
}
|