/// <summary> /// Returns the Cadence workflow type name to be used for a workflow interface or /// implementation class. /// </summary> /// <param name="workflowType">The workflow interface or implementation type.</param> /// <param name="workflowAttribute">Specifies the <see cref="WorkflowAttribute"/>.</param> /// <returns>The type name.</returns> /// <remarks> /// <para> /// If <paramref name="workflowAttribute"/> is passed and <see cref="WorkflowAttribute.Name"/> /// is not <c>null</c> or empty, then the name specified in the attribute is returned. /// </para> /// <para> /// Otherwise, we'll return the fully qualified name of the workflow interface /// with the leadting "I" removed. /// </para> /// </remarks> internal static string GetWorkflowTypeName(Type workflowType, WorkflowAttribute workflowAttribute) { Covenant.Requires <ArgumentNullException>(workflowType != null, nameof(workflowType)); if (workflowAttribute != null && !string.IsNullOrEmpty(workflowAttribute.Name)) { return(workflowAttribute.Name); } if (workflowType.IsClass) { CadenceHelper.ValidateWorkflowImplementation(workflowType); workflowType = CadenceHelper.GetWorkflowInterface(workflowType); } else { CadenceHelper.ValidateWorkflowInterface(workflowType); } var fullName = workflowType.FullName; var name = workflowType.Name; if (name.StartsWith("I") && name != "I") { // We're going to strip the leading "I" from the unqualified // type name (unless that's the only character). fullName = fullName.Substring(0, fullName.Length - name.Length); fullName += name.Substring(1); } // We need to replace the "+" characters .NET uses for nested types into // "." so the result will be a valid C# type identifier. return(fullName.Replace('+', '.')); }
/// <summary> /// Returns the workflow type and method information for a workflow interface and /// an optional target method name. /// </summary> /// <param name="workflowInterface">The target workflow interface.</param> /// <param name="methodName"> /// Optionally specifies the target method name (as specified in the <c>[WorkflowMethod]</c> /// attribiute tagging the workflow method within the interface. /// </param> /// <returns>The workflow type name for the workflow interface as well as the method information and attribute.</returns> /// <exception cref="ArgumentException">Thrown if target method does not exist.</exception> /// <remarks> /// <paramref name="methodName"/> is optional. When this is passed as <c>null</c> /// or empty, the default workflow method will be targeted (if any). /// </remarks> internal static (string WorkflowTypeName, MethodInfo TargetMethod, WorkflowMethodAttribute MethodAttribute) GetWorkflowTarget(Type workflowInterface, string methodName = null) { Covenant.Requires <ArgumentNullException>(workflowInterface != null); CadenceHelper.ValidateWorkflowInterface(workflowInterface); var workflowAttribute = workflowInterface.GetCustomAttribute <WorkflowAttribute>(); var methodAttribute = (WorkflowMethodAttribute)null; var targetMethod = (MethodInfo)null; if (string.IsNullOrEmpty(methodName)) { // Look for the entrypoint method with a null or empty method name. foreach (var method in workflowInterface.GetMethods()) { methodAttribute = method.GetCustomAttribute <WorkflowMethodAttribute>(); if (methodAttribute != null) { if (string.IsNullOrEmpty(methodAttribute.Name)) { targetMethod = method; break; } } } } else { // Look for the entrypoint method with the matching method name. foreach (var method in workflowInterface.GetMethods()) { methodAttribute = method.GetCustomAttribute <WorkflowMethodAttribute>(); if (methodAttribute != null) { if (methodName == methodAttribute.Name) { targetMethod = method; break; } } } } if (targetMethod == null) { throw new ArgumentException($"Workflow interface [{workflowInterface.FullName}] does not have a method tagged by [WorkflowMethod(Name = {methodName})].", nameof(workflowInterface)); } var workflowTypeName = CadenceHelper.GetWorkflowTypeName(workflowInterface, workflowAttribute); if (!string.IsNullOrEmpty(methodAttribute.Name)) { workflowTypeName += $"::{methodAttribute.Name}"; } return(workflowTypeName, targetMethod, methodAttribute); }