Beispiel #1
0
        /// <summary>
        /// Ensures that the type passed is a valid activity interface.
        /// </summary>
        /// <param name="activityInterface">The type being tested.</param>
        /// <exception cref="ActivityTypeException">Thrown when the interface is not valid.</exception>
        internal static void ValidateActivityInterface(Type activityInterface)
        {
            Covenant.Requires <ArgumentNullException>(activityInterface != null, nameof(activityInterface));

            if (!activityInterface.IsInterface)
            {
                throw new ActivityTypeException($"[{activityInterface.FullName}] is not an interface.");
            }

            if (!activityInterface.Implements <IActivity>())
            {
                throw new ActivityTypeException($"[{activityInterface.FullName}] does not implement [{typeof(IActivity).FullName}].");
            }

            if (activityInterface.IsGenericType)
            {
                throw new ActivityTypeException($"[{activityInterface.FullName}] has generic type parameters.  Activity interfaces cannot be generic.");
            }

            if (!activityInterface.IsPublic && !activityInterface.IsNestedPublic)
            {
                throw new ActivityTypeException($"Activity interface [{activityInterface.FullName}] is not public.");
            }

            if (activityInterface.GetCustomAttribute <WorkflowInterfaceAttribute>() != null)
            {
                throw new WorkflowTypeException($"Workflow interface [{activityInterface.FullName}] cannot be tagged with [WorkflowInterface] because it doesn't define a workflow.");
            }

            if (activityInterface.GetCustomAttribute <ActivityAttribute>() != null)
            {
                throw new WorkflowTypeException($"Activity interface [{activityInterface.FullName}] cannot not be tagged with [Activity] because that is valid only for activity implementation classes.");
            }

            // Validate the activity methods.

            var activityNames = new HashSet <string>();

            foreach (var method in activityInterface.GetMethods())
            {
                var activityMethodAttribute = method.GetCustomAttribute <ActivityMethodAttribute>();

                if (activityMethodAttribute == null)
                {
                    continue;
                }

                if (!CadenceHelper.IsTask(method.ReturnType))
                {
                    throw new WorkflowTypeException($"Activity interface method [{activityInterface.FullName}.{method.Name}()] must return a Task.");
                }

                var name = activityMethodAttribute.Name ?? string.Empty;

                if (activityNames.Contains(name))
                {
                    throw new ActivityTypeException($"Multiple [{activityInterface.FullName}] activity methods are tagged by [ActivityMethod(Name = \"{name}\")].");
                }

                activityNames.Add(name);
            }

            if (activityNames.Count == 0)
            {
                throw new ActivityTypeException($"Activity interface [{activityInterface.FullName}] does not define any methods tagged with [ActivityMethod].");
            }
        }
Beispiel #2
0
        /// <summary>
        /// Ensures that the type passed is a valid workflow interface.
        /// </summary>
        /// <param name="workflowInterface">The type being tested.</param>
        /// <exception cref="ActivityTypeException">Thrown when the interface is not valid.</exception>
        internal static void ValidateWorkflowInterface(Type workflowInterface)
        {
            Covenant.Requires <ArgumentNullException>(workflowInterface != null, nameof(workflowInterface));

            if (!workflowInterface.IsInterface)
            {
                throw new WorkflowTypeException($"[{workflowInterface.FullName}] is not an interface.");
            }

            if (!workflowInterface.Implements <IWorkflow>())
            {
                throw new WorkflowTypeException($"[{workflowInterface.FullName}] does not implement [{typeof(IWorkflow).FullName}].");
            }

            if (workflowInterface.IsGenericType)
            {
                throw new WorkflowTypeException($"[{workflowInterface.FullName}] has generic type parameters.  Workflow interfaces cannot be generic.");
            }

            if (!workflowInterface.IsPublic && !workflowInterface.IsNestedPublic)
            {
                throw new WorkflowTypeException($"Workflow interface [{workflowInterface.FullName}] is not public.");
            }

            if (workflowInterface.GetCustomAttribute <ActivityInterfaceAttribute>() != null)
            {
                throw new WorkflowTypeException($"Workflow interface [{workflowInterface.FullName}] cannot be tagged with [ActivityInterface] because it doesn't define an activity.");
            }

            if (workflowInterface.GetCustomAttribute <WorkflowAttribute>() != null)
            {
                throw new WorkflowTypeException($"Workflow interface [{workflowInterface.FullName}] cannot not be tagged with [Workflow] because that is valid only for activity implementation classes.");
            }

            // Validate the entrypoint method names and result types.

            var workflowNames = new HashSet <string>();

            foreach (var method in workflowInterface.GetMethods())
            {
                var workflowMethodAttribute = method.GetCustomAttribute <WorkflowMethodAttribute>();

                if (workflowMethodAttribute == null)
                {
                    continue;
                }

                if (!CadenceHelper.IsTask(method.ReturnType))
                {
                    throw new WorkflowTypeException($"Workflow interface method [{workflowInterface.FullName}.{method.Name}()] must return a Task.");
                }

                var name = workflowMethodAttribute.Name ?? string.Empty;

                if (workflowNames.Contains(name))
                {
                    throw new WorkflowTypeException($"Multiple workflow methods are tagged by [WorkflowMethod(Name = \"{name}\")].");
                }

                workflowNames.Add(name);
            }

            if (workflowNames.Count == 0)
            {
                throw new ActivityTypeException($"Workflow interface [{workflowInterface.FullName}] does not define any methods tagged with [WorkflowMethod].");
            }

            // Validate the signal method names and return types.

            var signalNames = new HashSet <string>();

            foreach (var method in workflowInterface.GetMethods())
            {
                var signalMethodAttribute = method.GetCustomAttribute <SignalMethodAttribute>();

                if (signalMethodAttribute == null)
                {
                    continue;
                }

                if (!CadenceHelper.IsTask(method.ReturnType))
                {
                    throw new WorkflowTypeException($"Workflow interface method [{workflowInterface.FullName}.{method.Name}()] must return a Task.");
                }

                var name = signalMethodAttribute.Name ?? string.Empty;

                if (signalNames.Contains(name))
                {
                    throw new WorkflowTypeException($"Multiple signal methods are tagged by [SignalMethod(name:\"{name}\")].");
                }

                signalNames.Add(name);
            }

            // Validate the signal method names and return types.

            var queryNames = new HashSet <string>();

            foreach (var method in workflowInterface.GetMethods())
            {
                var queryMethodAttribute = method.GetCustomAttribute <QueryMethodAttribute>();

                if (queryMethodAttribute == null)
                {
                    continue;
                }

                if (!CadenceHelper.IsTask(method.ReturnType))
                {
                    throw new WorkflowTypeException($"Workflow interface method [{workflowInterface.FullName}.{method.Name}()] must return a Task.");
                }

                var name = queryMethodAttribute.Name ?? string.Empty;

                if (queryNames.Contains(name))
                {
                    throw new WorkflowTypeException($"Multiple query methods are tagged by [QueryMethod(name:\"{name}\")].");
                }

                queryNames.Add(name);
            }
        }