Imported Upstream version 4.0.0~alpha1

Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
Jo Shields
2015-04-07 09:35:12 +01:00
parent 283343f570
commit 3c1f479b9d
22469 changed files with 2931443 additions and 869343 deletions

View File

@@ -0,0 +1,111 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
using System.Collections.ObjectModel;
using System.Runtime;
using System.ServiceModel.Activities.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Xml;
using SR = System.ServiceModel.Activities.SR;
public sealed class BufferedReceiveServiceBehavior : IServiceBehavior
{
internal const int DefaultMaxPendingMessagesPerChannel = 512;
int maxPendingMessagesPerChannel = DefaultMaxPendingMessagesPerChannel;
public int MaxPendingMessagesPerChannel
{
get
{
return this.maxPendingMessagesPerChannel;
}
set
{
if (value <= 0)
{
throw FxTrace.Exception.ArgumentOutOfRange("value", value, SR.MaxPendingMessagesPerChannelMustBeGreaterThanZero);
}
this.maxPendingMessagesPerChannel = value;
}
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
if (serviceHostBase is WorkflowServiceHost)
{
foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
if (channelDispatcher != null)
{
foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
{
if (WorkflowServiceBehavior.IsWorkflowEndpoint(endpointDispatcher))
{
// We need all incoming messages to be copyable
endpointDispatcher.DispatchRuntime.PreserveMessage = true;
// Enable BufferedReceive processing for each operation
foreach (DispatchOperation dispatchOperation in endpointDispatcher.DispatchRuntime.Operations)
{
dispatchOperation.BufferedReceiveEnabled = true;
}
}
}
}
}
serviceHostBase.Extensions.Add(new BufferedReceiveManager(this.MaxPendingMessagesPerChannel));
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
// Validate that ReceiveContext.ManualControl is set for each operation
foreach (ServiceEndpoint serviceEndpoint in serviceDescription.Endpoints)
{
if (BufferedReceiveServiceBehavior.IsWorkflowEndpoint(serviceEndpoint))
{
foreach (OperationDescription operation in serviceEndpoint.Contract.Operations)
{
ReceiveContextEnabledAttribute receiveContextEnabled = operation.Behaviors.Find<ReceiveContextEnabledAttribute>();
if (receiveContextEnabled == null || !receiveContextEnabled.ManualControl)
{
throw FxTrace.Exception.AsError(
new InvalidOperationException(SR.BufferedReceiveRequiresReceiveContext(operation.Name)));
}
}
}
}
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
// See WorkflowServiceBehavior.cs for another implementation of IsWorkflowEndpoint which
// operates against EndpointDispatchers instead of ServiceEndpoints
internal static bool IsWorkflowEndpoint(ServiceEndpoint serviceEndpoint)
{
if (serviceEndpoint.IsSystemEndpoint)
{
return false;
}
foreach (OperationDescription operation in serviceEndpoint.Contract.Operations)
{
if (operation.Behaviors.Find<WorkflowOperationBehavior>() == null)
{
return false;
}
}
return true;
}
}
}

View File

@@ -0,0 +1,91 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
using System.Runtime;
using System.ServiceModel.Activities.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
class ControlOperationBehavior : IOperationBehavior
{
bool isWrappedMode;
//There are two modes of operation.
// 1) IWorkflowControlServiceOperations :: Implemented completley by the ControlOperationInvoker.
// 2) Infrastructure endpoints(Delay/Compensation/OCS) where we wrap their invoker over ControlOperationInvoker.
public ControlOperationBehavior(bool isWrappedMode)
{
this.isWrappedMode = isWrappedMode;
}
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
ServiceHostBase serviceHost = dispatchOperation.Parent.ChannelDispatcher.Host;
if (!(serviceHost is WorkflowServiceHost))
{
throw FxTrace.Exception.AsError(
new InvalidOperationException(SR.WorkflowBehaviorWithNonWorkflowHost(typeof(ControlOperationBehavior).Name)));
}
ServiceEndpoint endpoint = null;
foreach (ServiceEndpoint endpointToMatch in serviceHost.Description.Endpoints)
{
if (endpointToMatch.Id == dispatchOperation.Parent.EndpointDispatcher.Id)
{
endpoint = endpointToMatch;
break;
}
}
if (this.isWrappedMode)
{
CorrelationKeyCalculator keyCalculator = null;
if (endpoint != null)
{
CorrelationQueryBehavior endpointQueryBehavior = endpoint.Behaviors.Find<CorrelationQueryBehavior>();
if (endpointQueryBehavior != null)
{
keyCalculator = endpointQueryBehavior.GetKeyCalculator();
}
}
//This will be the case for infrastructure endpoints like Compensation/Interop OCS endpoints.
dispatchOperation.Invoker = new ControlOperationInvoker(
operationDescription,
endpoint,
keyCalculator,
dispatchOperation.Invoker,
serviceHost);
}
else
{
//This will be for IWorkflowInstanceManagement endpoint operation.
dispatchOperation.Invoker = new ControlOperationInvoker(
operationDescription,
endpoint,
null,
serviceHost);
}
}
public void Validate(OperationDescription operationDescription)
{
}
}
}

View File

@@ -0,0 +1,421 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime;
using System.ServiceModel;
using System.ServiceModel.Activities.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Xml.Linq;
class CorrelationQueryBehavior : IEndpointBehavior, IChannelInitializer, IExtension<IContextChannel>
{
const string defaultQueryFormat = "sm:correlation-data('{0}')";
const string contextCorrelationName = "wsc-instanceId";
const string cookieCorrelationName = "http-cookie";
static string xPathForCookie = string.Format(CultureInfo.InvariantCulture, defaultQueryFormat, cookieCorrelationName);
CorrelationKeyCalculator correlationKeyCalculator;
ICollection<CorrelationQuery> queries;
ReadOnlyCollection<string> sendNames;
ReadOnlyCollection<string> receiveNames;
bool shouldPreserveMessage;
public CorrelationQueryBehavior(ICollection<CorrelationQuery> queries)
{
Fx.AssertAndThrow(queries != null, "queries must not be null");
foreach (CorrelationQuery query in queries)
{
Fx.AssertAndThrow(query.Where != null, "CorrelationQuery.Where must not be null");
}
this.queries = queries;
this.shouldPreserveMessage = true;
}
public ICollection<CorrelationQuery> CorrelationQueries
{
get { return this.queries; }
}
[SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode,
Justification = "We will use this")]
public ICollection<string> ReceiveNames
{
get { return this.receiveNames; }
}
public ICollection<string> SendNames
{
get { return this.sendNames; }
}
internal XName ScopeName
{
set;
get;
}
public XName ServiceContractName
{
get;
set;
}
internal bool IsCookieBasedQueryPresent()
{
if (this.queries.Count > 0)
{
foreach (CorrelationQuery query in this.queries)
{
// we only need to look at queries for selectAdditional since this query should be always initializing
foreach (MessageQuerySet messageQueryset in query.SelectAdditional)
{
foreach (KeyValuePair<string, MessageQuery> item in messageQueryset)
{
XPathMessageQuery xPathQuery = item.Value as XPathMessageQuery;
if (xPathQuery != null && xPathQuery.Expression.Equals(xPathForCookie))
{
return true;
}
}
}
}
}
return false;
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
ICorrelationDataSource source = endpoint.Binding.GetProperty<ICorrelationDataSource>(new BindingParameterCollection());
if (source != null)
{
this.ConfigureBindingDataNames(source);
this.ConfigureBindingDefaultQueries(endpoint, source, false);
}
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
ICorrelationDataSource source = endpoint.Binding.GetProperty<ICorrelationDataSource>(new BindingParameterCollection());
if (source != null)
{
this.ConfigureBindingDataNames(source);
this.ConfigureBindingDefaultQueries(endpoint, source, true);
}
ServiceDescription description = endpointDispatcher.ChannelDispatcher.Host.Description;
WorkflowServiceHost host = endpointDispatcher.ChannelDispatcher.Host as WorkflowServiceHost;
if (host == null)
{
// setup the scope name to be the Namespace + Name of the ServiceDescription. This will be
// either have been explicitly set by WorkflowService.Name or defaulted through the infrastructure
this.ScopeName = XNamespace.Get(description.Namespace).GetName(description.Name);
}
else
{
this.ScopeName = host.DurableInstancingOptions.ScopeName;
}
endpointDispatcher.ChannelDispatcher.ChannelInitializers.Add(this);
if (this.shouldPreserveMessage)
{
// there could be a query that might be read from the message body
// let us buffer the message at the dispatcher
endpointDispatcher.DispatchRuntime.PreserveMessage = true;
}
}
public static bool BindingHasDefaultQueries(Binding binding)
{
ICorrelationDataSource source = binding.GetProperty<ICorrelationDataSource>(new BindingParameterCollection());
bool hasDefaults = false;
if (source != null)
{
foreach (CorrelationDataDescription data in source.DataSources)
{
if (data.IsDefault)
{
hasDefaults = true;
break;
}
}
}
return hasDefaults;
}
void ConfigureBindingDataNames(ICorrelationDataSource source)
{
List<string> receiveNames = new List<string>();
List<string> sendNames = new List<string>();
foreach (CorrelationDataDescription data in source.DataSources)
{
if (data.ReceiveValue)
{
receiveNames.Add(data.Name);
}
// we want to optimize the correlation path for Send/SendReply cases,
// when using httpbinding, we always have 'http-cookie' added by transport, so we
// add data.name even when we don't have a query. This results in postponing the correlation key calculation
// till the channel calls us back.
if (data.SendValue)
{
// if the data.Name is for cookie, but there is no user added query for the cookie, we will not
// add this to sendNames.
// Note that we only look at user added queries. This is because http-cookie does not have a default query
//
if (data.Name == cookieCorrelationName && !this.IsCookieBasedQueryPresent())
{
continue;
}
else
{
sendNames.Add(data.Name);
}
}
}
this.receiveNames = new ReadOnlyCollection<string>(receiveNames);
this.sendNames = new ReadOnlyCollection<string>(sendNames);
}
void ConfigureBindingDefaultQueries(ServiceEndpoint endpoint, ICorrelationDataSource source, bool dispatch)
{
if (!CorrelationQuery.IsQueryCollectionSearchable(this.queries))
{
return;
}
// we should preserve the message if there are any existing queries added by the user
if (this.queries.Count <= 0)
{
this.shouldPreserveMessage = false;
}
foreach (OperationDescription operation in endpoint.Contract.Operations)
{
string inAction;
CorrelationQuery inQuery;
string outAction = null;
CorrelationQuery outQuery = null;
CorrelationQuery noActionReplyQuery = null;
inAction = operation.Messages[0].Action;
inQuery = CorrelationQuery.FindCorrelationQueryForAction(this.queries, inAction);
if (!operation.IsOneWay)
{
outAction = operation.Messages[1].Action;
outQuery = CorrelationQuery.FindCorrelationQueryForAction(this.queries, outAction);
if (!dispatch)
{
noActionReplyQuery = CorrelationQuery.FindCorrelationQueryForAction(this.queries, String.Empty);
}
}
// we will not add default query if a query already exists for the action
bool canDefaultIn = inQuery == null;
bool canDefaultOut = !operation.IsOneWay && outQuery == null;
// if there are no user added queries for receiveReply, we add a NoActionQuery
bool addNoActionQueryForReply = !operation.IsOneWay && !dispatch && noActionReplyQuery == null;
// On the client side we add special filters, SendFilter and ReceiveFilter
// But on dispatch side, we use ActionFilter and therefore need to verify that for wildcardaction, we
// only add a single defaultquery
if (canDefaultIn && canDefaultOut)
{
//verify if any of them is a wildcardaction, in that case let's just add a single query with a MatchAllFilter
if (inAction == MessageHeaders.WildcardAction)
{
canDefaultOut = false;
}
else if (outAction == MessageHeaders.WildcardAction)
{
canDefaultIn = false;
}
else if (inAction == outAction)
{
// in this case we will be adding the same query twice, let's just add once
// a possible scenario is when we add a contractDescription with wildcardaction for request & reply
canDefaultOut = false;
}
}
if (!canDefaultIn && !canDefaultOut)
{
continue;
}
foreach (CorrelationDataDescription data in source.DataSources)
{
if (!data.IsDefault)
{
continue;
}
if (canDefaultIn &&
(dispatch && data.ReceiveValue || data.SendValue))
{
inQuery = CreateDefaultCorrelationQuery(inQuery, inAction, data, ref shouldPreserveMessage);
}
if (canDefaultOut &&
(dispatch && data.SendValue || data.ReceiveValue))
{
outQuery = CreateDefaultCorrelationQuery(outQuery, outAction, data, ref shouldPreserveMessage);
}
if (addNoActionQueryForReply)
{
noActionReplyQuery = CreateDefaultCorrelationQuery(noActionReplyQuery, String.Empty, data, ref shouldPreserveMessage);
}
}
if (canDefaultIn && inQuery != null)
{
this.queries.Add(inQuery);
}
if (canDefaultOut && outQuery != null )
{
this.queries.Add(outQuery);
}
if (addNoActionQueryForReply && noActionReplyQuery != null)
{
this.queries.Add(noActionReplyQuery);
}
}
}
static CorrelationQuery CreateDefaultCorrelationQuery(CorrelationQuery query, string action, CorrelationDataDescription data, ref bool shouldPreserveMessage)
{
MessageQuery messageQuery = new XPathMessageQuery
{
Expression = string.Format(CultureInfo.InvariantCulture, defaultQueryFormat, data.Name),
Namespaces = new XPathMessageContext()
};
if (data.IsOptional)
{
messageQuery = new OptionalMessageQuery
{
Query = messageQuery
};
}
if (query == null)
{
MessageFilter filter;
// verify if the data name is added by the context channel
bool isContextQuery = (data.Name == contextCorrelationName);
// if there is a query that is not a context query set it to true since we might read from
// the message body
if (!shouldPreserveMessage && !isContextQuery)
{
shouldPreserveMessage = true;
}
// this is a server side query, we use an action filter
if (action == MessageHeaders.WildcardAction)
{
filter = new MatchAllMessageFilter();
}
else
{
filter = new ActionMessageFilter(action);
}
return new CorrelationQuery
{
Where = filter,
IsDefaultContextQuery = isContextQuery,
Select = new MessageQuerySet
{
{ data.Name, messageQuery }
}
};
}
else
{
query.Select[data.Name] = messageQuery;
return query;
}
}
public void Validate(ServiceEndpoint endpoint)
{
}
void IChannelInitializer.Initialize(IClientChannel channel)
{
channel.Extensions.Add(this);
}
void IExtension<IContextChannel>.Attach(IContextChannel owner)
{
}
void IExtension<IContextChannel>.Detach(IContextChannel owner)
{
}
public CorrelationKeyCalculator GetKeyCalculator()
{
if (this.correlationKeyCalculator == null)
{
CorrelationKeyCalculator localKeyCalculator = new CorrelationKeyCalculator(this.ScopeName);
foreach (CorrelationQuery query in this.queries)
{
IDictionary<string, MessageQueryTable<string>> dictionary =
new Dictionary<string, MessageQueryTable<string>>();
// consider changing Dictionary to Collection
int count = 0;
foreach (MessageQuerySet querySet in query.SelectAdditional)
{
dictionary.Add("SelectAdditional_item_" + count, querySet.GetMessageQueryTable());
count++;
}
localKeyCalculator.AddQuery(
query.Where,
query.Select != null ? query.Select.GetMessageQueryTable() : new MessageQueryTable<string>(),
dictionary,
query.IsDefaultContextQuery);
}
this.correlationKeyCalculator = localKeyCalculator;
}
return this.correlationKeyCalculator;
}
}
}

View File

@@ -0,0 +1,14 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
enum DurableConsistencyScope
{
Global = 0,
InstanceGlobalKeyLocal,
Local,
}
}

View File

@@ -0,0 +1,76 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
using System.Activities.Tracking;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Runtime;
using System.ServiceModel.Activation;
using System.ServiceModel.Activities.Tracking;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
[Fx.Tag.XamlVisible(false)]
public class EtwTrackingBehavior : IServiceBehavior
{
public EtwTrackingBehavior()
{
}
public string ProfileName
{
get;
set;
}
public virtual void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public virtual void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
WorkflowServiceHost workflowServiceHost = serviceHostBase as WorkflowServiceHost;
if (null != workflowServiceHost)
{
string workflowDisplayName = workflowServiceHost.Activity.DisplayName;
string hostReference = string.Empty;
if (AspNetEnvironment.Enabled)
{
VirtualPathExtension virtualPathExtension = serviceHostBase.Extensions.Find<VirtualPathExtension>();
if (virtualPathExtension != null && virtualPathExtension.VirtualPath != null)
{
//Format Website name\Application Virtual Path|\relative service virtual path|serviceName
string name = serviceDescription != null ? serviceDescription.Name : string.Empty;
string application = virtualPathExtension.ApplicationVirtualPath;
//If the application is the root, do not include it in servicePath
string servicePath = virtualPathExtension.VirtualPath.Replace("~", application + "|");
hostReference = string.Format(CultureInfo.InvariantCulture, "{0}{1}|{2}", virtualPathExtension.SiteName, servicePath, name);
}
}
TrackingProfile trackingProfile = this.GetProfile(this.ProfileName, workflowDisplayName);
workflowServiceHost.WorkflowExtensions.Add(
() => new EtwTrackingParticipant
{
ApplicationReference = hostReference,
TrackingProfile = trackingProfile
});
}
}
public virtual void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
TrackingProfile GetProfile(string profileName, string displayName)
{
DefaultProfileManager profileManager = new DefaultProfileManager();
return profileManager.GetProfile(profileName, displayName);
}
}
}

View File

@@ -0,0 +1,52 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
using System.Collections.ObjectModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
class SendMessageChannelCacheBehavior : IServiceBehavior
{
public SendMessageChannelCacheBehavior()
{
}
public bool AllowUnsafeCaching
{
get;
set;
}
public ChannelCacheSettings FactorySettings
{
get;
set;
}
public ChannelCacheSettings ChannelSettings
{
get;
set;
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
WorkflowServiceHost workflowServiceHost = serviceHostBase as WorkflowServiceHost;
if (workflowServiceHost != null)
{
workflowServiceHost.WorkflowExtensions.Add(new SendMessageChannelCache(this.FactorySettings, this.ChannelSettings, this.AllowUnsafeCaching));
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
}

View File

@@ -0,0 +1,28 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
using System;
class ServiceDescriptionData
{
public ServiceDescriptionData() { }
public bool IsInsideTransactedReceiveScope
{
get;
set;
}
//This is the first receive of the transacted receive scope tree
//i.e. in a nested TRS scenario, this tells if the receive is one associated with the
//Request property of the outermost TRS or not
public bool IsFirstReceiveOfTransactedReceiveScopeTree
{
get;
set;
}
}
}

View File

@@ -0,0 +1,181 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
using System.Activities.DurableInstancing;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Linq;
using System.Runtime;
using System.Runtime.DurableInstancing;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Xml.Linq;
using System.Globalization;
[Fx.Tag.XamlVisible(false)]
public class SqlWorkflowInstanceStoreBehavior : IServiceBehavior
{
internal const int defaultMaximumRetries = 4;
internal const string defaultHostRenewalString = "00:00:30.0";
static TimeSpan defaultHostRenewalPeriod = TimeSpan.Parse(defaultHostRenewalString, CultureInfo.InvariantCulture);
internal const string defaultRunnableInstancesDetectionPeriodString = "00:00:05.0";
static TimeSpan defaultRunnableInstancesDetectionPeriod = TimeSpan.Parse(defaultRunnableInstancesDetectionPeriodString, CultureInfo.InvariantCulture);
internal const InstanceEncodingOption defaultEncodingOption = InstanceEncodingOption.GZip;
internal const InstanceCompletionAction defaultInstanceCompletionAction = InstanceCompletionAction.DeleteAll;
internal const InstanceLockedExceptionAction defaultInstanceLockedExceptionAction = InstanceLockedExceptionAction.NoRetry;
public SqlWorkflowInstanceStoreBehavior() :
this(null)
{
}
public SqlWorkflowInstanceStoreBehavior(string connectionString)
{
this.SqlWorkflowInstanceStore = new SqlWorkflowInstanceStore(connectionString)
{
InstanceEncodingOption = defaultEncodingOption,
InstanceCompletionAction = defaultInstanceCompletionAction,
InstanceLockedExceptionAction = defaultInstanceLockedExceptionAction,
HostLockRenewalPeriod = defaultHostRenewalPeriod,
RunnableInstancesDetectionPeriod = defaultRunnableInstancesDetectionPeriod,
EnqueueRunCommands = true
};
}
public InstanceEncodingOption InstanceEncodingOption
{
get
{
return this.SqlWorkflowInstanceStore.InstanceEncodingOption;
}
set
{
this.SqlWorkflowInstanceStore.InstanceEncodingOption = value;
}
}
public InstanceCompletionAction InstanceCompletionAction
{
get
{
return this.SqlWorkflowInstanceStore.InstanceCompletionAction;
}
set
{
this.SqlWorkflowInstanceStore.InstanceCompletionAction = value;
}
}
public InstanceLockedExceptionAction InstanceLockedExceptionAction
{
get
{
return this.SqlWorkflowInstanceStore.InstanceLockedExceptionAction;
}
set
{
this.SqlWorkflowInstanceStore.InstanceLockedExceptionAction = value;
}
}
public string ConnectionString
{
get
{
return this.SqlWorkflowInstanceStore.ConnectionString;
}
set
{
this.SqlWorkflowInstanceStore.ConnectionString = value;
}
}
public TimeSpan HostLockRenewalPeriod
{
get
{
return this.SqlWorkflowInstanceStore.HostLockRenewalPeriod;
}
set
{
TimeoutHelper.ThrowIfNonPositiveArgument(value);
this.SqlWorkflowInstanceStore.HostLockRenewalPeriod = value;
}
}
public TimeSpan RunnableInstancesDetectionPeriod
{
get
{
return this.SqlWorkflowInstanceStore.RunnableInstancesDetectionPeriod;
}
set
{
TimeoutHelper.ThrowIfNonPositiveArgument(value);
this.SqlWorkflowInstanceStore.RunnableInstancesDetectionPeriod = value;
}
}
public int MaxConnectionRetries
{
get
{
if (this.SqlWorkflowInstanceStore != null)
{
return this.SqlWorkflowInstanceStore.MaxConnectionRetries;
}
else
{
return defaultMaximumRetries;
}
}
set
{
Fx.Assert(this.SqlWorkflowInstanceStore != null, "The SqlWorkflowInstanceStore should never be null");
if (this.SqlWorkflowInstanceStore != null)
{
this.SqlWorkflowInstanceStore.MaxConnectionRetries = value;
}
}
}
SqlWorkflowInstanceStore SqlWorkflowInstanceStore
{
get;
set;
}
public void Promote(string name, IEnumerable<XName> promoteAsSqlVariant, IEnumerable<XName> promoteAsBinary)
{
this.SqlWorkflowInstanceStore.Promote(name, promoteAsSqlVariant, promoteAsBinary);
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
if (serviceHostBase == null)
{
throw FxTrace.Exception.ArgumentNull("serviceHostBase");
}
WorkflowServiceHost workflowServiceHost = serviceHostBase as WorkflowServiceHost;
if (workflowServiceHost != null)
{
workflowServiceHost.DurableInstancingOptions.InstanceStore = this.SqlWorkflowInstanceStore;
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
}

View File

@@ -0,0 +1,47 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
using System.ServiceModel.Activities.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
//Marker Attribute for StandardEndpoint contract to opt-in for Durable setup.
[AttributeUsage(AttributeTargets.Interface, AllowMultiple = false)]
public sealed class WorkflowContractBehaviorAttribute : Attribute, 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)
{
//Only when DurableServiceBehavior is present ensure this endpoint operates in wrapped mode.
if (dispatchRuntime.ChannelDispatcher.Host.Description.Behaviors.Contains(typeof(WorkflowServiceBehavior)))
{
foreach (OperationDescription operation in contractDescription.Operations)
{
if (operation.Behaviors.Find<ControlOperationBehavior>() == null)
{
operation.Behaviors.Add(new ControlOperationBehavior(true));
}
}
}
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
}
}
}

View File

@@ -0,0 +1,71 @@
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
using System.Collections.ObjectModel;
using System.Runtime;
using System.ServiceModel.Activities;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
class WorkflowFormatterBehavior : IOperationBehavior
{
IDispatchMessageFormatter formatter;
IDispatchFaultFormatter faultFormatter;
Collection<Receive> receives;
public Collection<Receive> Receives
{
get
{
if (this.receives == null)
{
this.receives = new Collection<Receive>();
}
return this.receives;
}
}
public void ApplyClientBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.ClientOperation clientOperation)
{
throw FxTrace.Exception.AsError(new NotImplementedException());
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
Fx.Assert(operationDescription != null, "OperationDescription cannot be null!");
Fx.Assert(dispatchOperation != null, "DispatchOperation cannot be null!");
if (dispatchOperation.Formatter == null)
{
return;
}
this.formatter = dispatchOperation.Formatter;
this.faultFormatter = dispatchOperation.FaultFormatter;
if (this.receives != null)
{
foreach (Receive receive in this.receives)
{
receive.SetFormatter(this.formatter, this.faultFormatter, dispatchOperation.IncludeExceptionDetailInFaults);
}
}
// Remove operation formatter from dispatch runtime
dispatchOperation.Formatter = null;
dispatchOperation.DeserializeRequest = false;
dispatchOperation.SerializeReply = false;
}
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}
public void Validate(OperationDescription operationDescription)
{
}
}
}

View File

@@ -0,0 +1,83 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
using System.Collections.ObjectModel;
using System.Globalization;
using System.Runtime;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
[Fx.Tag.XamlVisible(false)]
public class WorkflowIdleBehavior : IServiceBehavior
{
internal const string defaultTimeToPersistString = "Infinite";
internal static TimeSpan defaultTimeToPersist = TimeSpan.MaxValue;
internal const string defaultTimeToUnloadString = "00:01:00";
internal static TimeSpan defaultTimeToUnload = TimeSpan.Parse(defaultTimeToUnloadString, CultureInfo.InvariantCulture);
TimeSpan timeToPersist;
TimeSpan timeToUnload;
public WorkflowIdleBehavior()
{
this.timeToPersist = defaultTimeToPersist;
this.timeToUnload = defaultTimeToUnload;
}
public TimeSpan TimeToPersist
{
get { return this.timeToPersist; }
set
{
if (value < TimeSpan.Zero)
{
throw FxTrace.Exception.ArgumentOutOfRange("value", value, SR.ErrorTimeToPersistLessThanZero);
}
this.timeToPersist = value;
}
}
public TimeSpan TimeToUnload
{
get { return this.timeToUnload; }
set
{
if (value < TimeSpan.Zero)
{
throw FxTrace.Exception.ArgumentOutOfRange("value", value, SR.ErrorTimeToUnloadLessThanZero);
}
this.timeToUnload = value;
}
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
WorkflowServiceHost workflowServiceHost = serviceHostBase as WorkflowServiceHost;
if (workflowServiceHost != null)
{
workflowServiceHost.IdleTimeToPersist = this.TimeToPersist;
workflowServiceHost.IdleTimeToUnload = this.TimeToUnload;
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
if (serviceDescription == null)
{
throw FxTrace.Exception.ArgumentNull("serviceDescription");
}
if (serviceHostBase == null)
{
throw FxTrace.Exception.ArgumentNull("serviceHostBase");
}
}
}
}

View File

@@ -0,0 +1,272 @@
namespace System.ServiceModel.Activities.Description
{
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime;
using System.Security.Principal;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Activities.Dispatcher;
using System.Xml;
using System.ServiceModel.Security;
using System.Net.Security;
[Fx.Tag.XamlVisible(false)]
public sealed class WorkflowInstanceManagementBehavior : IServiceBehavior
{
public const string ControlEndpointAddress = "System.ServiceModel.Activities_IWorkflowInstanceManagement";
static Binding httpBinding;
static Binding namedPipeBinding;
string windowsGroup;
public WorkflowInstanceManagementBehavior()
{
this.windowsGroup = GetDefaultBuiltinAdministratorsGroup();
}
public string WindowsGroup
{
get
{
return this.windowsGroup;
}
set
{
if (string.IsNullOrEmpty(value))
{
throw FxTrace.Exception.ArgumentNullOrEmpty("WindowsGroup");
}
this.windowsGroup = value;
}
}
public static Binding HttpControlEndpointBinding
{
get
{
if (httpBinding == null)
{
httpBinding = new WSHttpBinding
{
TransactionFlow = true,
Security = new WSHttpSecurity
{
Mode = SecurityMode.Message,
Message = new NonDualMessageSecurityOverHttp
{
ClientCredentialType = MessageCredentialType.Windows
}
}
};
}
return httpBinding;
}
}
public static Binding NamedPipeControlEndpointBinding
{
get
{
if (namedPipeBinding == null)
{
namedPipeBinding = new NetNamedPipeBinding
{
TransactionFlow = true,
Security = new NetNamedPipeSecurity
{
Mode = NetNamedPipeSecurityMode.Transport,
Transport = new NamedPipeTransportSecurity
{
ProtectionLevel = ProtectionLevel.Sign
}
}
};
}
return namedPipeBinding;
}
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
if (serviceHostBase == null)
{
throw FxTrace.Exception.ArgumentNull("serviceHostBase");
}
WorkflowServiceHost workflowServiceHost = serviceHostBase as WorkflowServiceHost;
if (workflowServiceHost != null)
{
CreateWorkflowManagementEndpoint(workflowServiceHost);
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
internal static string GetDefaultBuiltinAdministratorsGroup()
{
SecurityIdentifier identifier = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
NTAccount account = (NTAccount)identifier.Translate(typeof(NTAccount));
return account.Value;
}
void CreateWorkflowManagementEndpoint(WorkflowServiceHost workflowServiceHost)
{
Binding controlEndpointBinding;
if (workflowServiceHost.InternalBaseAddresses.Contains(Uri.UriSchemeNetPipe))
{
controlEndpointBinding = NamedPipeControlEndpointBinding;
}
else if (workflowServiceHost.InternalBaseAddresses.Contains(Uri.UriSchemeHttp))
{
controlEndpointBinding = HttpControlEndpointBinding;
}
else
{
return;
}
Uri controlEndpointAddress = ServiceHost.GetVia(controlEndpointBinding.Scheme, new Uri(ControlEndpointAddress, UriKind.Relative), workflowServiceHost.InternalBaseAddresses);
XmlQualifiedName contractName = new XmlQualifiedName(XD2.WorkflowInstanceManagementService.ContractName, XD2.WorkflowServices.Namespace);
//Create the Endpoint Dispatcher
EndpointAddress address = new EndpointAddress(controlEndpointAddress.AbsoluteUri);
EndpointDispatcher endpointDispatcher = new EndpointDispatcher(address,
XD2.WorkflowInstanceManagementService.ContractName,
XD2.WorkflowServices.Namespace, true)
{
ContractFilter = new ActionMessageFilter(
NamingHelper.GetMessageAction(contractName, XD2.WorkflowInstanceManagementService.Abandon, null, false),
NamingHelper.GetMessageAction(contractName, XD2.WorkflowInstanceManagementService.Cancel, null, false),
NamingHelper.GetMessageAction(contractName, XD2.WorkflowInstanceManagementService.Run, null, false),
NamingHelper.GetMessageAction(contractName, XD2.WorkflowInstanceManagementService.Suspend, null, false),
NamingHelper.GetMessageAction(contractName, XD2.WorkflowInstanceManagementService.Terminate, null, false),
NamingHelper.GetMessageAction(contractName, XD2.WorkflowInstanceManagementService.TransactedCancel, null, false),
NamingHelper.GetMessageAction(contractName, XD2.WorkflowInstanceManagementService.TransactedRun, null, false),
NamingHelper.GetMessageAction(contractName, XD2.WorkflowInstanceManagementService.TransactedSuspend, null, false),
NamingHelper.GetMessageAction(contractName, XD2.WorkflowInstanceManagementService.TransactedTerminate, null, false),
NamingHelper.GetMessageAction(contractName, XD2.WorkflowInstanceManagementService.TransactedUnsuspend, null, false),
NamingHelper.GetMessageAction(contractName, XD2.WorkflowInstanceManagementService.TransactedUpdate, null, false),
NamingHelper.GetMessageAction(contractName, XD2.WorkflowInstanceManagementService.Unsuspend, null, false),
NamingHelper.GetMessageAction(contractName, XD2.WorkflowInstanceManagementService.Update, null, false)),
};
//Create Listener
ServiceEndpoint endpoint = new ServiceEndpoint(WorkflowControlEndpoint.WorkflowControlServiceContract, controlEndpointBinding, address);
BindingParameterCollection parameters = workflowServiceHost.GetBindingParameters(endpoint);
IChannelListener listener;
if (controlEndpointBinding.CanBuildChannelListener<IDuplexSessionChannel>(controlEndpointAddress, parameters))
{
listener = controlEndpointBinding.BuildChannelListener<IDuplexSessionChannel>(controlEndpointAddress, parameters);
}
else if (controlEndpointBinding.CanBuildChannelListener<IReplySessionChannel>(controlEndpointAddress, parameters))
{
listener = controlEndpointBinding.BuildChannelListener<IReplySessionChannel>(controlEndpointAddress, parameters);
}
else
{
listener = controlEndpointBinding.BuildChannelListener<IReplyChannel>(controlEndpointAddress, parameters);
}
//Add the operations
bool formatRequest;
bool formatReply;
foreach (OperationDescription operation in WorkflowControlEndpoint.WorkflowControlServiceContract.Operations)
{
DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior = new DataContractSerializerOperationBehavior(operation);
DispatchOperation operationDispatcher = new DispatchOperation(endpointDispatcher.DispatchRuntime, operation.Name,
NamingHelper.GetMessageAction(operation, false), NamingHelper.GetMessageAction(operation, true))
{
Formatter = (IDispatchMessageFormatter)dataContractSerializerOperationBehavior.GetFormatter(operation, out formatRequest, out formatReply, false),
Invoker = new ControlOperationInvoker(
operation,
new WorkflowControlEndpoint(controlEndpointBinding, address),
null,
workflowServiceHost),
};
endpointDispatcher.DispatchRuntime.Operations.Add(operationDispatcher);
OperationBehaviorAttribute operationAttribute = operation.Behaviors.Find<OperationBehaviorAttribute>();
((IOperationBehavior)operationAttribute).ApplyDispatchBehavior(operation, operationDispatcher);
}
DispatchRuntime dispatchRuntime = endpointDispatcher.DispatchRuntime;
dispatchRuntime.ConcurrencyMode = ConcurrencyMode.Multiple;
dispatchRuntime.InstanceContextProvider = new DurableInstanceContextProvider(workflowServiceHost);
dispatchRuntime.InstanceProvider = new DurableInstanceProvider(workflowServiceHost);
dispatchRuntime.ServiceAuthorizationManager = new WindowsAuthorizationManager(this.WindowsGroup);
//Create the Channel Dispatcher
ServiceDebugBehavior serviceDebugBehavior = workflowServiceHost.Description.Behaviors.Find<ServiceDebugBehavior>();
ServiceBehaviorAttribute serviceBehaviorAttribute = workflowServiceHost.Description.Behaviors.Find<ServiceBehaviorAttribute>();
bool includeDebugInfo = false;
if (serviceDebugBehavior != null)
{
includeDebugInfo |= serviceDebugBehavior.IncludeExceptionDetailInFaults;
}
if (serviceBehaviorAttribute != null)
{
includeDebugInfo |= serviceBehaviorAttribute.IncludeExceptionDetailInFaults;
}
ChannelDispatcher channelDispatcher = new ChannelDispatcher(listener, controlEndpointBinding.Name, controlEndpointBinding)
{
MessageVersion = controlEndpointBinding.MessageVersion,
Endpoints = { endpointDispatcher },
ServiceThrottle = workflowServiceHost.ServiceThrottle
};
workflowServiceHost.ChannelDispatchers.Add(channelDispatcher);
}
sealed class WindowsAuthorizationManager : ServiceAuthorizationManager
{
SecurityIdentifier sid;
public WindowsAuthorizationManager(string windowsGroup)
{
NTAccount identity = new NTAccount(windowsGroup);
try
{
this.sid = identity.Translate(typeof(SecurityIdentifier)) as SecurityIdentifier;
}
catch (IdentityNotMappedException)
{
throw FxTrace.Exception.Argument(windowsGroup, SR.WindowsGroupNotFound(windowsGroup));
}
}
protected override bool CheckAccessCore(OperationContext operationContext)
{
WindowsPrincipal principal = new WindowsPrincipal(operationContext.ServiceSecurityContext.WindowsIdentity);
bool isAuthorized = false;
if (!operationContext.ServiceSecurityContext.IsAnonymous)
{
isAuthorized = principal.IsInRole(sid);
}
return isAuthorized;
}
}
}
}

View File

@@ -0,0 +1,204 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
using System.Collections;
using System.Collections.Generic;
using System.Activities;
using System.Runtime;
using System.Runtime.Diagnostics;
using System.Runtime.DurableInstancing;
using System.ServiceModel.Activities.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Diagnostics;
using System.ServiceModel.Dispatcher;
using System.Transactions;
class WorkflowOperationBehavior : IOperationBehavior
{
Bookmark bookmark;
public WorkflowOperationBehavior(Bookmark bookmark, bool canCreateInstance)
: this(canCreateInstance)
{
Fx.Assert(bookmark != null, "bookmark must not be null!");
this.bookmark = bookmark;
}
protected WorkflowOperationBehavior(bool canCreateInstance)
{
this.CanCreateInstance = canCreateInstance;
}
internal bool CanCreateInstance
{
get;
set;
}
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
if (operationDescription == null)
{
throw FxTrace.Exception.ArgumentNull("operationDescription");
}
if (dispatchOperation == null)
{
throw FxTrace.Exception.ArgumentNull("dispatchOperation");
}
if (dispatchOperation.Parent == null
|| dispatchOperation.Parent.ChannelDispatcher == null
|| dispatchOperation.Parent.ChannelDispatcher.Host == null
|| dispatchOperation.Parent.ChannelDispatcher.Host.Description == null
|| dispatchOperation.Parent.ChannelDispatcher.Host.Description.Behaviors == null)
{
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.DispatchOperationInInvalidState));
}
ServiceHostBase serviceHost = dispatchOperation.Parent.ChannelDispatcher.Host;
if (!(serviceHost is WorkflowServiceHost))
{
throw FxTrace.Exception.AsError(
new InvalidOperationException(SR.WorkflowBehaviorWithNonWorkflowHost(typeof(WorkflowOperationBehavior).Name)));
}
CorrelationKeyCalculator correlationKeyCalculator = null;
ServiceEndpoint endpoint = null;
foreach (ServiceEndpoint endpointToMatch in serviceHost.Description.Endpoints)
{
if (endpointToMatch.Id == dispatchOperation.Parent.EndpointDispatcher.Id)
{
endpoint = endpointToMatch;
break;
}
}
if (endpoint != null)
{
CorrelationQueryBehavior queryBehavior = endpoint.Behaviors.Find<CorrelationQueryBehavior>();
if (queryBehavior != null)
{
correlationKeyCalculator = queryBehavior.GetKeyCalculator();
}
}
dispatchOperation.Invoker = new WorkflowOperationInvoker(operationDescription,
endpoint, correlationKeyCalculator, this, serviceHost, dispatchOperation.Invoker);
}
public void Validate(OperationDescription operationDescription)
{
}
protected internal virtual Bookmark OnResolveBookmark(WorkflowOperationContext context, out BookmarkScope bookmarkScope, out object value)
{
Fx.Assert(this.bookmark != null, "bookmark must not be null!");
CorrelationMessageProperty correlationMessageProperty;
if (CorrelationMessageProperty.TryGet(context.OperationContext.IncomingMessageProperties, out correlationMessageProperty))
{
bookmarkScope = new BookmarkScope(correlationMessageProperty.CorrelationKey.Value);
}
else
{
bookmarkScope = BookmarkScope.Default;
}
value = context;
return this.bookmark;
}
//Invoker for workflowbased application endpoint operation
class WorkflowOperationInvoker : ControlOperationInvoker, IInstanceTransaction
{
bool performanceCountersEnabled;
bool propagateActivity;
bool isHostingEndpoint;
IOperationInvoker innerInvoker;
WorkflowOperationBehavior behavior;
bool isFirstReceiveOfTransactedReceiveScopeTree;
public WorkflowOperationInvoker(OperationDescription operationDescription, ServiceEndpoint endpoint,
CorrelationKeyCalculator keyCalculator, WorkflowOperationBehavior behavior, ServiceHostBase host, IOperationInvoker innerInvoker)
: base(operationDescription, endpoint, keyCalculator, host)
{
Fx.Assert(operationDescription != null, "Null OperationDescription");
Fx.Assert(behavior != null, "Null WorkflowOperationBehavior");
this.StaticBookmarkName = behavior.bookmark == null ? null : behavior.bookmark.Name;
this.behavior = behavior;
this.CanCreateInstance = behavior.CanCreateInstance;
this.performanceCountersEnabled = PerformanceCounters.PerformanceCountersEnabled;
this.propagateActivity = TraceUtility.ShouldPropagateActivity;
this.isHostingEndpoint = endpoint is WorkflowHostingEndpoint;
this.innerInvoker = innerInvoker;
this.isFirstReceiveOfTransactedReceiveScopeTree = operationDescription.IsFirstReceiveOfTransactedReceiveScopeTree;
}
public override object[] AllocateInputs()
{
if (this.isHostingEndpoint)
{
return this.innerInvoker.AllocateInputs();
}
// InternalReceiveMessage & InternalSendMessage is always MessageIn - MessageOut.
// Therefore we always need an array of size 1.
// DispatchOperationRuntime saves the request into this array in this case ( i.e., when DeserializeRequest is false)
return new object[1];
}
protected override IAsyncResult OnBeginServiceOperation(WorkflowServiceInstance workflowInstance, OperationContext operationContext,
object[] inputs, Transaction currentTransaction, IInvokeReceivedNotification notification, TimeSpan timeout, AsyncCallback callback, object state)
{
Fx.Assert(workflowInstance != null, "caller must verify");
Fx.Assert(inputs != null, "caller must verify");
return WorkflowOperationContext.BeginProcessRequest(workflowInstance, operationContext, this.OperationName, inputs,
this.performanceCountersEnabled, this.propagateActivity, currentTransaction, notification, this.behavior, this.endpoint, timeout, callback, state);
}
protected override object OnEndServiceOperation(WorkflowServiceInstance durableInstance, out object[] outputs, IAsyncResult result)
{
// InternalSendMessage always redirects the replyMessage into the returnValue
object returnValue = WorkflowOperationContext.EndProcessRequest(result, out outputs);
//we will just assert that outputs is always an empty array
Fx.Assert(this.isHostingEndpoint || outputs == null || outputs.Length == 0, "Workflow returned a non-empty out-arg");
return returnValue;
}
public Transaction GetTransactionForInstance(OperationContext operationContext)
{
Transaction tx = null;
// We are only going to go ask the PPD for the transaction if we are NOT the first
// Receive in a TransactedReceiveScope;
if (!this.isFirstReceiveOfTransactedReceiveScopeTree)
{
// We need to get the InstanceKey.
InstanceKey instanceKey;
ICollection<InstanceKey> additionalKeys;
this.GetInstanceKeys(operationContext, out instanceKey, out additionalKeys);
Fx.Assert((instanceKey != null) && (instanceKey.IsValid), "InstanceKey is null or invalid in GetInstanceTransaction");
tx = this.InstanceManager.PersistenceProviderDirectory.GetTransactionForInstance(instanceKey);
}
return tx;
}
}
}
}

View File

@@ -0,0 +1,119 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
using System.Activities;
using System.ServiceModel;
using System.ServiceModel.Activities.Dispatcher;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
class WorkflowServiceBehavior : IServiceBehavior
{
public WorkflowServiceBehavior(WorkflowDefinitionProvider workflowDefinitionProvider)
{
this.WorkflowDefinitionProvider = workflowDefinitionProvider;
}
public WorkflowDefinitionProvider WorkflowDefinitionProvider
{
get;
private set;
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
if (serviceDescription == null)
{
throw FxTrace.Exception.ArgumentNull("serviceDescription");
}
if (serviceHostBase == null)
{
throw FxTrace.Exception.ArgumentNull("serviceHostBase");
}
DurableInstanceContextProvider instanceContextProvider = new DurableInstanceContextProvider(serviceHostBase);
DurableInstanceProvider instanceProvider = new DurableInstanceProvider(serviceHostBase);
ServiceDebugBehavior serviceDebugBehavior = serviceDescription.Behaviors.Find<ServiceDebugBehavior>();
bool includeExceptionDetailInFaults = serviceDebugBehavior != null ?
serviceDebugBehavior.IncludeExceptionDetailInFaults
: false;
foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
if (channelDispatcher != null)
{
foreach (EndpointDispatcher endPointDispatcher in channelDispatcher.Endpoints)
{
if (IsWorkflowEndpoint(endPointDispatcher))
{
DispatchRuntime dispatchRuntime = endPointDispatcher.DispatchRuntime;
dispatchRuntime.AutomaticInputSessionShutdown = true;
dispatchRuntime.ConcurrencyMode = ConcurrencyMode.Multiple;
//
dispatchRuntime.InstanceContextProvider = instanceContextProvider;
dispatchRuntime.InstanceProvider = instanceProvider;
if (includeExceptionDetailInFaults)
{
dispatchRuntime.SetDebugFlagInDispatchOperations(includeExceptionDetailInFaults);
}
}
}
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
if (serviceDescription == null)
{
throw FxTrace.Exception.ArgumentNull("serviceDescription");
}
if (serviceHostBase == null)
{
throw FxTrace.Exception.ArgumentNull("serviceHostBase");
}
}
internal static bool IsWorkflowEndpoint(EndpointDispatcher endpointDispatcher)
{
if (endpointDispatcher.IsSystemEndpoint)
{
//Check whether the System Endpoint Opted in for WorkflowDispatch
ServiceHostBase serviceHost = endpointDispatcher.ChannelDispatcher.Host;
ServiceEndpoint serviceEndpoint = null;
foreach (ServiceEndpoint endpointToMatch in serviceHost.Description.Endpoints)
{
if (endpointToMatch.Id == endpointDispatcher.Id)
{
serviceEndpoint = endpointToMatch;
break;
}
}
if (serviceEndpoint != null)
{
//User defined Std Endpoint with WorkflowContractBehaviorAttribute.
return serviceEndpoint is WorkflowHostingEndpoint || serviceEndpoint.Contract.Behaviors.Contains(typeof(WorkflowContractBehaviorAttribute));
}
return false; //Some Einstein scenario where EndpointDispatcher is added explicitly without associated ServiceEndpoint.
}
return true; //Application Endpoint
}
}
}

View File

@@ -0,0 +1,25 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
public enum WorkflowUnhandledExceptionAction
{
Abandon,
Cancel,
Terminate,
AbandonAndSuspend,
}
static class WorkflowUnhandledExceptionActionHelper
{
internal static bool IsDefined(WorkflowUnhandledExceptionAction value)
{
return (value == WorkflowUnhandledExceptionAction.Abandon ||
value == WorkflowUnhandledExceptionAction.Cancel ||
value == WorkflowUnhandledExceptionAction.Terminate ||
value == WorkflowUnhandledExceptionAction.AbandonAndSuspend);
}
}
}

View File

@@ -0,0 +1,63 @@
//----------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------
namespace System.ServiceModel.Activities.Description
{
using System.Collections.ObjectModel;
using System.Runtime;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
[Fx.Tag.XamlVisible(false)]
public class WorkflowUnhandledExceptionBehavior : IServiceBehavior
{
internal const WorkflowUnhandledExceptionAction defaultAction = WorkflowUnhandledExceptionAction.AbandonAndSuspend;
WorkflowUnhandledExceptionAction action;
public WorkflowUnhandledExceptionBehavior()
{
this.action = defaultAction;
}
public WorkflowUnhandledExceptionAction Action
{
get { return this.action; }
set
{
if (!WorkflowUnhandledExceptionActionHelper.IsDefined(value))
{
throw FxTrace.Exception.AsError(new ArgumentOutOfRangeException("value"));
}
this.action = value;
}
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
WorkflowServiceHost workflowServiceHost = serviceHostBase as WorkflowServiceHost;
if (workflowServiceHost != null)
{
workflowServiceHost.UnhandledExceptionAction = this.Action;
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
if (serviceDescription == null)
{
throw FxTrace.Exception.ArgumentNull("serviceDescription");
}
if (serviceHostBase == null)
{
throw FxTrace.Exception.ArgumentNull("serviceHostBase");
}
}
}
}