e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
902 lines
42 KiB
C#
902 lines
42 KiB
C#
using System;
|
|
using System.Reflection;
|
|
using System.Drawing;
|
|
using System.Drawing.Design;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Specialized;
|
|
using System.ComponentModel;
|
|
using System.ComponentModel.Design;
|
|
using System.Workflow.ComponentModel;
|
|
using System.Workflow.ComponentModel.Design;
|
|
using System.Workflow.ComponentModel.Compiler;
|
|
using System.Workflow.Runtime;
|
|
using System.CodeDom;
|
|
using System.ComponentModel.Design.Serialization;
|
|
using System.Diagnostics;
|
|
using System.Workflow.Runtime.Hosting;
|
|
using System.Runtime.Remoting.Messaging;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Workflow.Activities.Common;
|
|
|
|
namespace System.Workflow.Activities
|
|
{
|
|
[SRDescription(SR.WebServiceReceiveActivityDescription)]
|
|
[SRCategory(SR.Standard)]
|
|
[ToolboxBitmap(typeof(WebServiceInputActivity), "Resources.WebServiceIn.png")]
|
|
[Designer(typeof(WebServiceReceiveDesigner), typeof(IDesigner))]
|
|
[ActivityValidator(typeof(WebServiceReceiveValidator))]
|
|
[ActivityCodeGeneratorAttribute(typeof(WebServiceCodeGenerator))]
|
|
[DefaultEvent("InputReceived")]
|
|
[Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")]
|
|
public sealed class WebServiceInputActivity : Activity, IEventActivity, IPropertyValueProvider, IActivityEventListener<QueueEventArgs>, IDynamicPropertyTypeProvider
|
|
{
|
|
//metadata properties
|
|
public static readonly DependencyProperty IsActivatingProperty = DependencyProperty.Register("IsActivating", typeof(bool), typeof(WebServiceInputActivity), new PropertyMetadata(false, DependencyPropertyOptions.Metadata));
|
|
public static readonly DependencyProperty InterfaceTypeProperty = DependencyProperty.Register("InterfaceType", typeof(Type), typeof(WebServiceInputActivity), new PropertyMetadata(null, DependencyPropertyOptions.Metadata));
|
|
public static readonly DependencyProperty MethodNameProperty = DependencyProperty.Register("MethodName", typeof(string), typeof(WebServiceInputActivity), new PropertyMetadata("", DependencyPropertyOptions.Metadata));
|
|
public static readonly DependencyProperty RolesProperty = DependencyProperty.Register("Roles", typeof(WorkflowRoleCollection), typeof(WebServiceInputActivity));
|
|
|
|
//instance properties
|
|
public static readonly DependencyProperty ParameterBindingsProperty = DependencyProperty.Register("ParameterBindings", typeof(WorkflowParameterBindingCollection), typeof(WebServiceInputActivity), new PropertyMetadata(DependencyPropertyOptions.Metadata | DependencyPropertyOptions.ReadOnly, new Attribute[] { new BrowsableAttribute(false), new DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content) }));
|
|
public static readonly DependencyProperty ActivitySubscribedProperty = DependencyProperty.Register("ActivitySubscribed", typeof(bool), typeof(WebServiceInputActivity), new PropertyMetadata(false));
|
|
private static readonly DependencyProperty QueueNameProperty = DependencyProperty.Register("QueueName", typeof(IComparable), typeof(WebServiceInputActivity));
|
|
|
|
//event
|
|
public static readonly DependencyProperty InputReceivedEvent = DependencyProperty.Register("InputReceived", typeof(EventHandler), typeof(WebServiceInputActivity));
|
|
|
|
#region Constructors
|
|
|
|
public WebServiceInputActivity()
|
|
{
|
|
//
|
|
base.SetReadOnlyPropertyValue(ParameterBindingsProperty, new WorkflowParameterBindingCollection(this));
|
|
}
|
|
|
|
public WebServiceInputActivity(string name)
|
|
: base(name)
|
|
{
|
|
//
|
|
base.SetReadOnlyPropertyValue(ParameterBindingsProperty, new WorkflowParameterBindingCollection(this));
|
|
}
|
|
|
|
#endregion
|
|
|
|
[SRCategory(SR.Activity)]
|
|
[SRDescription(SR.InterfaceTypeDescription)]
|
|
[RefreshProperties(RefreshProperties.All)]
|
|
[Editor(typeof(TypeBrowserEditor), typeof(UITypeEditor))]
|
|
[TypeFilterProviderAttribute(typeof(InterfaceTypeFilterProvider))]
|
|
[DefaultValue(null)]
|
|
public Type InterfaceType
|
|
{
|
|
get
|
|
{
|
|
return base.GetValue(InterfaceTypeProperty) as Type;
|
|
}
|
|
|
|
set
|
|
{
|
|
base.SetValue(InterfaceTypeProperty, value);
|
|
}
|
|
}
|
|
|
|
[SRCategory(SR.Activity)]
|
|
[SRDescription(SR.WebServiceMethodDescription)]
|
|
[TypeConverter(typeof(PropertyValueProviderTypeConverter))]
|
|
[RefreshProperties(RefreshProperties.All)]
|
|
[MergablePropertyAttribute(false)]
|
|
[DefaultValue("")]
|
|
public string MethodName
|
|
{
|
|
get
|
|
{
|
|
return (string)base.GetValue(MethodNameProperty);
|
|
}
|
|
|
|
set
|
|
{
|
|
base.SetValue(MethodNameProperty, value);
|
|
}
|
|
}
|
|
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
[Browsable(false)]
|
|
public WorkflowParameterBindingCollection ParameterBindings
|
|
{
|
|
get
|
|
{
|
|
return base.GetValue(ParameterBindingsProperty) as WorkflowParameterBindingCollection;
|
|
}
|
|
}
|
|
|
|
[SRCategory(SR.Activity)]
|
|
[SRDescription(SR.RoleDescr)]
|
|
[Editor(typeof(BindUITypeEditor), typeof(UITypeEditor))]
|
|
[DefaultValue(null)]
|
|
public WorkflowRoleCollection Roles
|
|
{
|
|
get
|
|
{
|
|
return base.GetValue(RolesProperty) as WorkflowRoleCollection;
|
|
}
|
|
set
|
|
{
|
|
base.SetValue(RolesProperty, value);
|
|
}
|
|
}
|
|
|
|
[SRCategory(SR.Activity)]
|
|
[SRDescription(SR.ActivationDescr)]
|
|
[DefaultValue(false)]
|
|
[MergableProperty(false)]
|
|
public bool IsActivating
|
|
{
|
|
get
|
|
{
|
|
return (bool)base.GetValue(IsActivatingProperty);
|
|
}
|
|
|
|
set
|
|
{
|
|
base.SetValue(IsActivatingProperty, value);
|
|
}
|
|
}
|
|
|
|
[SRDescription(SR.OnAfterReceiveDescr)]
|
|
[SRCategory(SR.Handlers)]
|
|
[MergableProperty(false)]
|
|
public event EventHandler InputReceived
|
|
{
|
|
add
|
|
{
|
|
base.AddHandler(InputReceivedEvent, value);
|
|
}
|
|
remove
|
|
{
|
|
base.RemoveHandler(InputReceivedEvent, value);
|
|
}
|
|
}
|
|
|
|
internal bool ActivitySubscribed
|
|
{
|
|
get
|
|
{
|
|
return (bool)base.GetValue(ActivitySubscribedProperty);
|
|
}
|
|
set
|
|
{
|
|
base.SetValue(ActivitySubscribedProperty, value);
|
|
}
|
|
}
|
|
|
|
ICollection IPropertyValueProvider.GetPropertyValues(ITypeDescriptorContext context)
|
|
{
|
|
ITypeProvider typeProvider = (ITypeProvider)context.GetService(typeof(ITypeProvider));
|
|
if (typeProvider == null)
|
|
throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(ITypeProvider).FullName));
|
|
|
|
StringCollection names = new StringCollection();
|
|
if (context.PropertyDescriptor.Name == "MethodName")
|
|
{
|
|
if (this.InterfaceType != null)
|
|
{
|
|
Type type = typeProvider.GetType(this.InterfaceType.AssemblyQualifiedName);
|
|
if (type != null)
|
|
{
|
|
foreach (MethodInfo method in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))
|
|
{
|
|
if (!method.IsSpecialName)
|
|
names.Add(method.Name);
|
|
}
|
|
|
|
foreach (Type interfaceType in type.GetInterfaces())
|
|
{
|
|
foreach (MethodInfo method in interfaceType.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))
|
|
{
|
|
names.Add(interfaceType.FullName + "." + method.Name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return names;
|
|
}
|
|
|
|
protected sealed override void Initialize(IServiceProvider provider)
|
|
{
|
|
if (provider == null)
|
|
throw new ArgumentNullException("provider");
|
|
|
|
if (this.Parent == null)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_MustHaveParent));
|
|
|
|
WorkflowQueuingService queueService = (WorkflowQueuingService)provider.GetService(typeof(WorkflowQueuingService));
|
|
|
|
//create a static q entry
|
|
EventQueueName key = new EventQueueName(this.InterfaceType, this.MethodName);
|
|
this.SetValue(QueueNameProperty, key);
|
|
|
|
if (!queueService.Exists(key))
|
|
queueService.CreateWorkflowQueue(key, true);
|
|
}
|
|
|
|
#region Execute/Cancel
|
|
|
|
protected sealed override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
|
|
{
|
|
if (executionContext == null)
|
|
throw new ArgumentNullException("executionContext");
|
|
|
|
ActivityExecutionStatus status = ExecuteForActivity(executionContext, this.InterfaceType, this.MethodName);
|
|
if (status == ActivityExecutionStatus.Closed)
|
|
{
|
|
UnsubscribeForActivity(executionContext);
|
|
executionContext.CloseActivity();
|
|
return status;
|
|
}
|
|
|
|
// cannot resolve queue name or message not available
|
|
// hence subscribe for message arrival
|
|
if (!this.ActivitySubscribed)
|
|
{
|
|
this.ActivitySubscribed = CorrelationService.Subscribe(executionContext, this, this.InterfaceType, this.MethodName, this, this.WorkflowInstanceId);
|
|
}
|
|
|
|
return ActivityExecutionStatus.Executing;
|
|
}
|
|
|
|
private ActivityExecutionStatus ExecuteForActivity(ActivityExecutionContext context, Type interfaceType, string operation)
|
|
{
|
|
WorkflowQueuingService queueSvcs = (WorkflowQueuingService)context.GetService(typeof(WorkflowQueuingService));
|
|
|
|
IComparable queueName = new EventQueueName(interfaceType, operation);
|
|
if (queueName != null)
|
|
{
|
|
WorkflowQueue queue;
|
|
object message = InboundActivityHelper.DequeueMessage(queueName, queueSvcs, this, out queue);
|
|
if (message != null)
|
|
{
|
|
ProcessMessage(context, message, interfaceType, operation);
|
|
return ActivityExecutionStatus.Closed;
|
|
}
|
|
}
|
|
|
|
return ActivityExecutionStatus.Executing;
|
|
}
|
|
|
|
private void ProcessMessage(ActivityExecutionContext context, object msg, Type interfaceType, string operation)
|
|
{
|
|
IMethodMessage message = msg as IMethodMessage;
|
|
if (message == null)
|
|
{
|
|
Exception excp = msg as Exception;
|
|
if (excp != null)
|
|
throw excp;
|
|
throw new ArgumentNullException("msg");
|
|
}
|
|
|
|
CorrelationService.InvalidateCorrelationToken(this, interfaceType, operation, message.Args);
|
|
|
|
IdentityContextData identityData =
|
|
(IdentityContextData)message.LogicalCallContext.GetData(IdentityContextData.IdentityContext);
|
|
InboundActivityHelper.ValidateRoles(this, identityData.Identity);
|
|
|
|
ProcessParameters(context, message, interfaceType, operation);
|
|
RaiseEvent(WebServiceInputActivity.InputReceivedEvent, this, EventArgs.Empty);
|
|
}
|
|
|
|
private void ProcessParameters(ActivityExecutionContext context, IMethodMessage message, Type interfaceType, string operation)
|
|
{
|
|
WorkflowParameterBindingCollection parameters = ParameterBindings;
|
|
if (parameters == null)
|
|
return;
|
|
|
|
//cache mInfo todo
|
|
MethodInfo mInfo = interfaceType.GetMethod(operation);
|
|
if (mInfo == null)
|
|
return;
|
|
|
|
int index = 0;
|
|
bool responseRequired = false;
|
|
foreach (ParameterInfo formalParameter in mInfo.GetParameters())
|
|
{
|
|
// populate in params, checking on IsIn alone is not sufficient
|
|
if (!(formalParameter.ParameterType.IsByRef || (formalParameter.IsIn && formalParameter.IsOut)))
|
|
{
|
|
if (parameters.Contains(formalParameter.Name))
|
|
{
|
|
WorkflowParameterBinding binding = parameters[formalParameter.Name];
|
|
binding.Value = message.Args[index++];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
responseRequired = true;
|
|
}
|
|
}
|
|
|
|
if (mInfo.ReturnType != typeof(void) || responseRequired)
|
|
{
|
|
// create queue entry {interface, operation and receive activity Id}
|
|
IComparable queueId = new EventQueueName(interfaceType, operation, QualifiedName);
|
|
// enqueue the message for sendresponse reply context
|
|
WorkflowQueuingService queuingService = (WorkflowQueuingService)context.GetService(typeof(WorkflowQueuingService));
|
|
if (!queuingService.Exists(queueId))
|
|
queuingService.CreateWorkflowQueue(queueId, true);
|
|
|
|
queuingService.GetWorkflowQueue(queueId).Enqueue(message);
|
|
}
|
|
}
|
|
|
|
protected sealed override ActivityExecutionStatus HandleFault(ActivityExecutionContext executionContext, Exception exception)
|
|
{
|
|
if (executionContext == null)
|
|
throw new ArgumentNullException("executionContext");
|
|
|
|
if (exception == null)
|
|
throw new ArgumentNullException("exception");
|
|
|
|
ActivityExecutionStatus newStatus = this.Cancel(executionContext);
|
|
if (newStatus == ActivityExecutionStatus.Canceling)
|
|
return ActivityExecutionStatus.Faulting;
|
|
|
|
return newStatus;
|
|
}
|
|
|
|
protected sealed override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext)
|
|
{
|
|
if (executionContext == null)
|
|
throw new ArgumentNullException("executionContext");
|
|
|
|
UnsubscribeForActivity(executionContext);
|
|
|
|
return ActivityExecutionStatus.Closed;
|
|
}
|
|
|
|
private void UnsubscribeForActivity(ActivityExecutionContext context)
|
|
{
|
|
if (this.ActivitySubscribed)
|
|
{
|
|
CorrelationService.Unsubscribe(context, this, this.InterfaceType, this.MethodName, this);
|
|
this.ActivitySubscribed = false;
|
|
}
|
|
}
|
|
|
|
void IActivityEventListener<QueueEventArgs>.OnEvent(object sender, QueueEventArgs e)
|
|
{
|
|
ActivityExecutionContext context = (ActivityExecutionContext)sender;
|
|
WebServiceInputActivity activity = context.Activity as WebServiceInputActivity;
|
|
|
|
// if activity is not scheduled for execution do not dequeue the message
|
|
if (activity.ExecutionStatus != ActivityExecutionStatus.Executing) return;
|
|
|
|
ActivityExecutionStatus status = ExecuteForActivity(context, activity.InterfaceType, activity.MethodName);
|
|
if (status == ActivityExecutionStatus.Closed)
|
|
{
|
|
UnsubscribeForActivity(context);
|
|
context.CloseActivity();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region IEventActivity members
|
|
void IEventActivity.Subscribe(ActivityExecutionContext parentContext, IActivityEventListener<QueueEventArgs> parentEventHandler)
|
|
{
|
|
if (parentContext == null)
|
|
throw new ArgumentNullException("parentContext");
|
|
if (parentEventHandler == null)
|
|
throw new ArgumentNullException("parentEventHandler");
|
|
|
|
CorrelationService.Subscribe(parentContext, this, this.InterfaceType, this.MethodName, parentEventHandler, this.WorkflowInstanceId);
|
|
}
|
|
|
|
void IEventActivity.Unsubscribe(ActivityExecutionContext parentContext, IActivityEventListener<QueueEventArgs> parentEventHandler)
|
|
{
|
|
if (parentContext == null)
|
|
throw new ArgumentNullException("parentContext");
|
|
if (parentEventHandler == null)
|
|
throw new ArgumentNullException("parentEventHandler");
|
|
|
|
CorrelationService.Unsubscribe(parentContext, this, this.InterfaceType, this.MethodName, parentEventHandler);
|
|
}
|
|
|
|
IComparable IEventActivity.QueueName
|
|
{
|
|
get
|
|
{
|
|
return (IComparable)this.GetValue(QueueNameProperty);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IDynamicPropertyTypeProvider
|
|
|
|
Type IDynamicPropertyTypeProvider.GetPropertyType(IServiceProvider serviceProvider, string propertyName)
|
|
{
|
|
if (propertyName == null)
|
|
throw new ArgumentNullException("propertyName");
|
|
|
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|
this.GetParameterPropertyDescriptors(parameters);
|
|
if (parameters.ContainsKey(propertyName))
|
|
{
|
|
ParameterInfoBasedPropertyDescriptor descriptor = parameters[propertyName] as ParameterInfoBasedPropertyDescriptor;
|
|
if (descriptor != null)
|
|
return descriptor.ParameterType;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
AccessTypes IDynamicPropertyTypeProvider.GetAccessType(IServiceProvider serviceProvider, string propertyName)
|
|
{
|
|
if (propertyName == null)
|
|
throw new ArgumentNullException("propertyName");
|
|
|
|
return AccessTypes.Read;
|
|
}
|
|
|
|
internal void GetParameterPropertyDescriptors(IDictionary properties)
|
|
{
|
|
if (((IComponent)this).Site == null)
|
|
return;
|
|
|
|
ITypeProvider typeProvider = (ITypeProvider)((IComponent)this).Site.GetService(typeof(ITypeProvider));
|
|
if (typeProvider == null)
|
|
throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(ITypeProvider).FullName));
|
|
|
|
Type type = null;
|
|
if (this.InterfaceType != null)
|
|
type = typeProvider.GetType(this.InterfaceType.AssemblyQualifiedName);
|
|
|
|
if (type != null && type.IsInterface)
|
|
{
|
|
MethodInfo method = Helpers.GetInterfaceMethod(type, this.MethodName);
|
|
if (method != null && WebServiceActivityHelpers.ValidateParameterTypes(method).Count == 0)
|
|
{
|
|
List<ParameterInfo> inputParameters, outParameters;
|
|
WebServiceActivityHelpers.GetParameterInfo(method, out inputParameters, out outParameters);
|
|
|
|
foreach (ParameterInfo paramInfo in inputParameters)
|
|
{
|
|
PropertyDescriptor prop = new ParameterInfoBasedPropertyDescriptor(typeof(WebServiceInputActivity), paramInfo, true, DesignOnlyAttribute.Yes);
|
|
properties[prop.Name] = prop;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
internal sealed class WebServiceReceiveValidator : ActivityValidator
|
|
{
|
|
public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
|
|
{
|
|
ValidationErrorCollection validationErrors = base.Validate(manager, obj);
|
|
|
|
WebServiceInputActivity webServiceReceive = obj as WebServiceInputActivity;
|
|
if (webServiceReceive == null)
|
|
throw new ArgumentException(SR.GetString(SR.Error_UnexpectedArgumentType, typeof(WebServiceInputActivity).FullName), "obj");
|
|
|
|
if (Helpers.IsActivityLocked(webServiceReceive))
|
|
{
|
|
return validationErrors;
|
|
}
|
|
|
|
if (webServiceReceive.IsActivating)
|
|
{
|
|
if (WebServiceActivityHelpers.GetPreceedingActivities(webServiceReceive).GetEnumerator().MoveNext() == true)
|
|
{
|
|
ValidationError error = new ValidationError(SR.GetString(SR.Error_ActivationActivityNotFirst), ErrorNumbers.Error_ActivationActivityNotFirst);
|
|
error.PropertyName = "IsActivating";
|
|
validationErrors.Add(error);
|
|
return validationErrors;
|
|
}
|
|
|
|
if (WebServiceActivityHelpers.IsInsideLoop(webServiceReceive, null))
|
|
{
|
|
ValidationError error = new ValidationError(SR.GetString(SR.Error_ActivationActivityInsideLoop), ErrorNumbers.Error_ActivationActivityInsideLoop);
|
|
error.PropertyName = "IsActivating";
|
|
validationErrors.Add(error);
|
|
return validationErrors;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (WebServiceActivityHelpers.GetPreceedingActivities(webServiceReceive, true).GetEnumerator().MoveNext() == false)
|
|
{
|
|
ValidationError error = new ValidationError(SR.GetString(SR.Error_WebServiceReceiveNotMarkedActivate), ErrorNumbers.Error_WebServiceReceiveNotMarkedActivate);
|
|
error.PropertyName = "IsActivating";
|
|
validationErrors.Add(error);
|
|
return validationErrors;
|
|
}
|
|
}
|
|
|
|
ITypeProvider typeProvider = (ITypeProvider)manager.GetService(typeof(ITypeProvider));
|
|
if (typeProvider == null)
|
|
throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(ITypeProvider).FullName));
|
|
|
|
Type interfaceType = null;
|
|
if (webServiceReceive.InterfaceType != null)
|
|
interfaceType = typeProvider.GetType(webServiceReceive.InterfaceType.AssemblyQualifiedName);
|
|
|
|
if (interfaceType == null)
|
|
{
|
|
ValidationError error = new ValidationError(SR.GetString(SR.Error_TypePropertyInvalid, "InterfaceType"), ErrorNumbers.Error_PropertyNotSet);
|
|
error.PropertyName = "InterfaceType";
|
|
validationErrors.Add(error);
|
|
}
|
|
else if (!interfaceType.IsInterface)
|
|
{
|
|
ValidationError error = new ValidationError(SR.GetString(SR.Error_InterfaceTypeNotInterface, "InterfaceType"), ErrorNumbers.Error_InterfaceTypeNotInterface);
|
|
error.PropertyName = "InterfaceType";
|
|
validationErrors.Add(error);
|
|
}
|
|
else
|
|
{
|
|
// Validate method
|
|
if (String.IsNullOrEmpty(webServiceReceive.MethodName))
|
|
validationErrors.Add(ValidationError.GetNotSetValidationError("MethodName"));
|
|
else
|
|
{
|
|
MethodInfo methodInfo = Helpers.GetInterfaceMethod(interfaceType, webServiceReceive.MethodName);
|
|
|
|
if (methodInfo == null)
|
|
{
|
|
ValidationError error = new ValidationError(SR.GetString(SR.Error_MethodNotExists, "MethodName", webServiceReceive.MethodName), ErrorNumbers.Error_MethodNotExists);
|
|
error.PropertyName = "MethodName";
|
|
validationErrors.Add(error);
|
|
}
|
|
else
|
|
{
|
|
ValidationErrorCollection parameterTypeErrors = WebServiceActivityHelpers.ValidateParameterTypes(methodInfo);
|
|
if (parameterTypeErrors.Count > 0)
|
|
{
|
|
foreach (ValidationError parameterTypeError in parameterTypeErrors)
|
|
{
|
|
parameterTypeError.PropertyName = "MethodName";
|
|
}
|
|
validationErrors.AddRange(parameterTypeErrors);
|
|
}
|
|
else
|
|
{
|
|
List<ParameterInfo> inputParameters, outParameters;
|
|
WebServiceActivityHelpers.GetParameterInfo(methodInfo, out inputParameters, out outParameters);
|
|
|
|
// Check to see if all input parameters have a valid binding.
|
|
foreach (ParameterInfo paramInfo in inputParameters)
|
|
{
|
|
string paramName = paramInfo.Name;
|
|
string parameterPropertyName = ParameterInfoBasedPropertyDescriptor.GetParameterPropertyName(webServiceReceive.GetType(), paramName);
|
|
|
|
Type paramType = paramInfo.ParameterType.IsByRef ? paramInfo.ParameterType.GetElementType() : paramInfo.ParameterType;
|
|
object paramValue = null;
|
|
if (webServiceReceive.ParameterBindings.Contains(paramName))
|
|
{
|
|
if (webServiceReceive.ParameterBindings[paramName].IsBindingSet(WorkflowParameterBinding.ValueProperty))
|
|
paramValue = webServiceReceive.ParameterBindings[paramName].GetBinding(WorkflowParameterBinding.ValueProperty);
|
|
else
|
|
paramValue = webServiceReceive.ParameterBindings[paramName].GetValue(WorkflowParameterBinding.ValueProperty);
|
|
}
|
|
|
|
if (!paramType.IsPublic || !paramType.IsSerializable)
|
|
{
|
|
ValidationError validationError = new ValidationError(SR.GetString(SR.Error_TypeNotPublicSerializable, paramName, paramType.FullName), ErrorNumbers.Error_TypeNotPublicSerializable);
|
|
validationError.PropertyName = parameterPropertyName;
|
|
validationErrors.Add(validationError);
|
|
}
|
|
else if (!webServiceReceive.ParameterBindings.Contains(paramName) || paramValue == null)
|
|
{
|
|
ValidationError validationError = ValidationError.GetNotSetValidationError(paramName);
|
|
validationError.PropertyName = parameterPropertyName;
|
|
validationErrors.Add(validationError);
|
|
}
|
|
else
|
|
{
|
|
AccessTypes access = AccessTypes.Read;
|
|
if (paramInfo.ParameterType.IsByRef)
|
|
access |= AccessTypes.Write;
|
|
|
|
ValidationErrorCollection variableErrors = ValidationHelpers.ValidateProperty(manager, webServiceReceive, paramValue,
|
|
new PropertyValidationContext(webServiceReceive.ParameterBindings[paramName], null, paramName), new BindValidationContext(paramInfo.ParameterType.IsByRef ? paramInfo.ParameterType.GetElementType() : paramInfo.ParameterType, access));
|
|
foreach (ValidationError validationError in variableErrors)
|
|
validationError.PropertyName = parameterPropertyName;
|
|
validationErrors.AddRange(variableErrors);
|
|
}
|
|
}
|
|
|
|
if (webServiceReceive.ParameterBindings.Count > inputParameters.Count)
|
|
validationErrors.Add(new ValidationError(SR.GetString(SR.Warning_AdditionalBindingsFound), ErrorNumbers.Warning_AdditionalBindingsFound, true));
|
|
|
|
bool foundMatchingResponse = false;
|
|
foreach (Activity succeedingActivity in WebServiceActivityHelpers.GetSucceedingActivities(webServiceReceive))
|
|
{
|
|
if ((succeedingActivity is WebServiceOutputActivity && ((WebServiceOutputActivity)succeedingActivity).InputActivityName == webServiceReceive.Name) ||
|
|
(succeedingActivity is WebServiceFaultActivity && ((WebServiceFaultActivity)succeedingActivity).InputActivityName == webServiceReceive.Name))
|
|
{
|
|
foundMatchingResponse = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If the method has out parameters or is the method has a return value,
|
|
// check to see if there are any corresponding WebServiceResponse activities.
|
|
if ((outParameters.Count > 0 || methodInfo.ReturnType != typeof(void)) && !foundMatchingResponse)
|
|
{
|
|
validationErrors.Add(new ValidationError(SR.GetString(SR.Error_WebServiceResponseNotFound), ErrorNumbers.Error_WebServiceResponseNotFound));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return validationErrors;
|
|
}
|
|
}
|
|
|
|
internal sealed class WebServiceCodeGenerator : ActivityCodeGenerator
|
|
{
|
|
public override void GenerateCode(CodeGenerationManager manager, object obj)
|
|
{
|
|
WebServiceInputActivity webserviceInput = obj as WebServiceInputActivity;
|
|
|
|
if (manager == null)
|
|
throw new ArgumentNullException("manager");
|
|
|
|
if (obj == null)
|
|
throw new ArgumentNullException("obj");
|
|
|
|
if (webserviceInput == null)
|
|
return;
|
|
|
|
ITypeProvider typeProvider = manager.GetService(typeof(ITypeProvider)) as ITypeProvider;
|
|
|
|
if (typeProvider == null)
|
|
throw new InvalidOperationException(SR.GetString(SR.General_MissingService, typeof(ITypeProvider).FullName));
|
|
|
|
CodeNamespaceCollection codeNamespaces = manager.Context[typeof(CodeNamespaceCollection)] as CodeNamespaceCollection;
|
|
|
|
if (codeNamespaces == null)
|
|
throw new InvalidOperationException(SR.GetString(SR.Error_ContextStackItemMissing, typeof(CodeNamespaceCollection).Name));
|
|
|
|
CodeTypeDeclaration webServiceClass = CreateOrGetServiceDeclaration(Helpers.GetRootActivity(webserviceInput), codeNamespaces);
|
|
|
|
Debug.Assert(webserviceInput.InterfaceType != null, "Interface type should not be null");
|
|
|
|
if (webserviceInput.InterfaceType != null)
|
|
{
|
|
bool memberExists = false;
|
|
MethodInfo methodInfo = Helpers.GetInterfaceMethod(webserviceInput.InterfaceType, webserviceInput.MethodName);
|
|
|
|
//Check to see if a method with the same name already exists (the same activity may be used
|
|
// in multiple places).
|
|
SupportedLanguages language = CompilerHelpers.GetSupportedLanguage(manager);
|
|
foreach (CodeTypeMember member in webServiceClass.Members)
|
|
{
|
|
//
|
|
if (member is CodeMemberMethod && String.Compare(member.Name, methodInfo.Name, language == SupportedLanguages.CSharp ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase) == 0)
|
|
memberExists = true;
|
|
}
|
|
|
|
if (!memberExists)
|
|
webServiceClass.Members.Add(this.GetWebServiceMethodDeclaraion(methodInfo, webserviceInput.IsActivating, language));
|
|
}
|
|
base.GenerateCode(manager, obj);
|
|
return;
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Globalization", "CA1307:SpecifyStringComparison", Justification = "IndexOf(\".\") not a security issue.")]
|
|
private CodeTypeDeclaration CreateOrGetServiceDeclaration(Activity rootActivity, CodeNamespaceCollection codeNamespaceCollection)
|
|
{
|
|
String namespaceName = "";
|
|
CodeNamespace webServiceCodeNamespace = null;
|
|
string className = rootActivity.GetType().FullName;
|
|
CodeTypeDeclaration webServiceClass = null;
|
|
|
|
if (rootActivity.GetType().FullName.IndexOf(".") != -1)
|
|
namespaceName = rootActivity.GetType().FullName.Substring(0, rootActivity.GetType().FullName.LastIndexOf('.'));
|
|
|
|
|
|
foreach (CodeNamespace codeNamespace in codeNamespaceCollection)
|
|
{
|
|
if (codeNamespace.Name == namespaceName)
|
|
{
|
|
webServiceCodeNamespace = codeNamespace;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (webServiceCodeNamespace == null)
|
|
{
|
|
webServiceCodeNamespace = this.GetWebServiceCodeNamespace(namespaceName);
|
|
codeNamespaceCollection.Add(webServiceCodeNamespace);
|
|
}
|
|
String webServiceTypeName = className.Substring(className.LastIndexOf('.') + 1) + "_WebService";
|
|
|
|
foreach (CodeTypeDeclaration codeTypeDeclaration in webServiceCodeNamespace.Types)
|
|
{
|
|
if (codeTypeDeclaration.Name == webServiceTypeName)
|
|
{
|
|
webServiceClass = codeTypeDeclaration;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (webServiceClass == null)
|
|
{
|
|
webServiceClass = this.GetWebserviceCodeTypeDeclaration(className.Substring(className.LastIndexOf('.') + 1));
|
|
webServiceCodeNamespace.Types.Add(webServiceClass);
|
|
//Ensure namespaces are imported.
|
|
webServiceCodeNamespace.Imports.Add(new CodeNamespaceImport("System"));
|
|
webServiceCodeNamespace.Imports.Add(new CodeNamespaceImport("System.Web"));
|
|
webServiceCodeNamespace.Imports.Add(new CodeNamespaceImport("System.Web.Services"));
|
|
webServiceCodeNamespace.Imports.Add(new CodeNamespaceImport("System.Web.Services.Protocols"));
|
|
webServiceCodeNamespace.Imports.Add(new CodeNamespaceImport("System.Workflow.Runtime.Hosting"));
|
|
webServiceCodeNamespace.Imports.Add(new CodeNamespaceImport("System.Workflow.Activities"));
|
|
}
|
|
|
|
return webServiceClass;
|
|
}
|
|
|
|
|
|
private CodeNamespace GetWebServiceCodeNamespace(string namespaceName)
|
|
{
|
|
CodeNamespace nameSpace = new CodeNamespace(namespaceName);
|
|
return nameSpace;
|
|
}
|
|
|
|
//[WebServiceBinding(ConformsTo=WsiClaims.BP10,EmitConformanceClaims = true)]
|
|
//public class <WorkflowTypeName>_WebService : System.Workflow.Runtime.Hosting.WorkflowWebService
|
|
//{
|
|
// public <WorkflowTypeName>_WebService():base(typeof(<WorkflowTypeName>)) {}
|
|
//}
|
|
private CodeTypeDeclaration GetWebserviceCodeTypeDeclaration(string workflowTypeName)
|
|
{
|
|
CodeTypeDeclaration typeDeclaration = new CodeTypeDeclaration(workflowTypeName + "_WebService");
|
|
typeDeclaration.BaseTypes.Add(new CodeTypeReference("WorkflowWebService"));
|
|
|
|
CodeAttributeDeclaration attributeDeclaration = new CodeAttributeDeclaration("WebServiceBinding", new CodeAttributeArgument("ConformsTo", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression("WsiProfiles"), "BasicProfile1_1")), new CodeAttributeArgument("EmitConformanceClaims", new CodePrimitiveExpression(true)));
|
|
typeDeclaration.CustomAttributes.Add(attributeDeclaration);
|
|
|
|
//Emit Constructor
|
|
CodeConstructor constructor = new CodeConstructor();
|
|
constructor.Attributes = MemberAttributes.Public;
|
|
constructor.BaseConstructorArgs.Add(new CodeTypeOfExpression(workflowTypeName));
|
|
typeDeclaration.Members.Add(constructor);
|
|
|
|
return typeDeclaration;
|
|
}
|
|
|
|
//[WebMethod(Description=<OperationName>, EnableSession=true)]
|
|
//public virtual <ReturnType> <OperationName>(<Arguments>)
|
|
//{
|
|
// For No out ref case.
|
|
// return (<ReturnType>)base.Invoke(<InterfaceType>, <MethodName>, true | false(based on activation), arguments)[0];
|
|
//
|
|
// For out & ref case.
|
|
// Object[] results = base.Invoke(<InterfaceType>, <MethodName>, true | false(based on activation), arguments);
|
|
// refParam1 = (RPType)results[1];
|
|
// refParam2 = (RPType)results[2];
|
|
// outParam3 = (RPType)results[3];
|
|
// return (<ReturnType>)results[0];
|
|
//}
|
|
private CodeMemberMethod GetWebServiceMethodDeclaraion(MethodInfo methodInfo, bool isActivation, SupportedLanguages language)
|
|
{
|
|
CodeMemberMethod webMethod = new CodeMemberMethod();
|
|
webMethod.Attributes = MemberAttributes.Public;
|
|
webMethod.ReturnType = new CodeTypeReference(methodInfo.ReturnType);
|
|
webMethod.Name = methodInfo.Name;
|
|
|
|
CodeAttributeDeclaration attrDecl = new CodeAttributeDeclaration("WebMethodAttribute");
|
|
attrDecl.Arguments.Add(new CodeAttributeArgument("Description", new CodePrimitiveExpression(methodInfo.Name)));
|
|
attrDecl.Arguments.Add(new CodeAttributeArgument("EnableSession", new CodePrimitiveExpression(false)));
|
|
|
|
webMethod.CustomAttributes.Add(attrDecl);
|
|
|
|
List<ParameterInfo> outRefParams = new List<ParameterInfo>();
|
|
|
|
CodeArrayCreateExpression paramArrayCreationExpression = new CodeArrayCreateExpression();
|
|
paramArrayCreationExpression.CreateType = new CodeTypeReference(typeof(Object));
|
|
|
|
foreach (ParameterInfo paramInfo in methodInfo.GetParameters())
|
|
{
|
|
CodeParameterDeclarationExpression paramDecl = new CodeParameterDeclarationExpression();
|
|
|
|
if (paramInfo.IsOut || paramInfo.ParameterType.IsByRef)
|
|
{
|
|
paramDecl.Type = new CodeTypeReference(paramInfo.ParameterType.GetElementType().FullName);
|
|
paramDecl.Direction = paramInfo.IsOut ? FieldDirection.Out : FieldDirection.Ref;
|
|
|
|
if (paramDecl.Direction == FieldDirection.Out && language == SupportedLanguages.VB)
|
|
paramDecl.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(System.Runtime.InteropServices.OutAttribute))));
|
|
|
|
|
|
outRefParams.Add(paramInfo);
|
|
}
|
|
else
|
|
{
|
|
paramDecl.Type = new CodeTypeReference(paramInfo.ParameterType.FullName);
|
|
}
|
|
paramDecl.Name = paramInfo.Name;
|
|
webMethod.Parameters.Add(paramDecl);
|
|
|
|
if (!paramInfo.IsOut)
|
|
paramArrayCreationExpression.Initializers.Add(new CodeArgumentReferenceExpression(paramInfo.Name));
|
|
}
|
|
|
|
//Emit method body
|
|
CodeMethodInvokeExpression baseInvokeExpression = new CodeMethodInvokeExpression();
|
|
baseInvokeExpression.Method = new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), "Invoke");
|
|
|
|
baseInvokeExpression.Parameters.Add(new CodeTypeOfExpression(methodInfo.DeclaringType));
|
|
baseInvokeExpression.Parameters.Add(new CodePrimitiveExpression(methodInfo.Name));
|
|
baseInvokeExpression.Parameters.Add(new CodePrimitiveExpression(isActivation));
|
|
baseInvokeExpression.Parameters.Add(paramArrayCreationExpression);
|
|
|
|
int iStartIndex = (methodInfo.ReturnType == typeof(void)) ? 0 : 1;
|
|
if (outRefParams.Count != 0)
|
|
{
|
|
//Results variable declaration
|
|
CodeVariableDeclarationStatement resultsDeclaration = new CodeVariableDeclarationStatement(new CodeTypeReference(new CodeTypeReference(typeof(Object)), 1), "results");
|
|
resultsDeclaration.InitExpression = baseInvokeExpression;
|
|
webMethod.Statements.Add(resultsDeclaration);
|
|
|
|
for (int i = 0; i < outRefParams.Count; ++i)
|
|
{
|
|
ParameterInfo pinfo = outRefParams[i];
|
|
CodeAssignStatement assignStatement = new CodeAssignStatement();
|
|
CodeExpression leftExpression = new CodeArgumentReferenceExpression(pinfo.Name);
|
|
CodeExpression rightExpression = new CodeCastExpression(new CodeTypeReference(pinfo.ParameterType.GetElementType().FullName), new CodeIndexerExpression(new CodeVariableReferenceExpression("results"), new CodePrimitiveExpression(i + iStartIndex)));
|
|
assignStatement.Left = leftExpression;
|
|
assignStatement.Right = rightExpression;
|
|
webMethod.Statements.Add(assignStatement);
|
|
}
|
|
}
|
|
if (methodInfo.ReturnType != typeof(void))
|
|
{
|
|
CodeExpression returnTargetExpression;
|
|
|
|
if (outRefParams.Count != 0)
|
|
returnTargetExpression = new CodeVariableReferenceExpression("results");
|
|
else
|
|
returnTargetExpression = baseInvokeExpression;
|
|
|
|
CodeMethodReturnStatement methodReturnStatement = new CodeMethodReturnStatement(new CodeCastExpression(methodInfo.ReturnType, new CodeIndexerExpression(returnTargetExpression, new CodePrimitiveExpression(0))));
|
|
webMethod.Statements.Add(methodReturnStatement);
|
|
}
|
|
else if (outRefParams.Count == 0 && methodInfo.ReturnType == typeof(void))
|
|
{
|
|
webMethod.Statements.Add(baseInvokeExpression);
|
|
}
|
|
|
|
return webMethod;
|
|
}
|
|
}
|
|
|
|
internal sealed class InterfaceTypeFilterProvider : ITypeFilterProvider
|
|
{
|
|
private IServiceProvider serviceProvider;
|
|
public InterfaceTypeFilterProvider(IServiceProvider serviceProvider)
|
|
{
|
|
this.serviceProvider = serviceProvider;
|
|
}
|
|
|
|
public bool CanFilterType(Type type, bool throwOnError)
|
|
{
|
|
if (throwOnError && !type.IsInterface)
|
|
throw new Exception(SR.GetString(SR.Error_InterfaceTypeNotInterface, "InterfaceType"));
|
|
|
|
return type.IsInterface;
|
|
}
|
|
public string FilterDescription
|
|
{
|
|
get
|
|
{
|
|
return SR.GetString(SR.InterfaceTypeFilterDescription);
|
|
}
|
|
}
|
|
}
|
|
}
|