/// <summary> /// Registers a workflow implementation with Temporal. /// </summary> /// <typeparam name="TWorkflow">The <see cref="WorkflowBase"/> derived class implementing the workflow.</typeparam> /// <param name="disableDuplicateCheck">Disable checks for duplicate registrations.</param> /// <returns>The tracking <see cref="Task"/>.</returns> /// <exception cref="InvalidOperationException"> /// Thrown if the worker has already been started. You must register workflow /// and activity implementations before starting workers. /// </exception> /// <remarks> /// <note> /// Be sure to register all of your workflow implementations before starting a worker. /// </note> /// </remarks> public async Task RegisterWorkflowAsync <TWorkflow>(bool disableDuplicateCheck = false) where TWorkflow : WorkflowBase { await SyncContext.Clear; TemporalHelper.ValidateWorkflowImplementation(typeof(TWorkflow)); EnsureNotDisposed(); EnsureCanRegister(); var workflowType = typeof(TWorkflow); lock (registeredWorkflowTypes) { if (registeredWorkflowTypes.Contains(workflowType)) { if (disableDuplicateCheck) { return; } else { throw new RegistrationException($"Workflow implementation [{workflowType.FullName}] has already been registered."); } } registeredWorkflowTypes.Add(workflowType); } }
/// <summary> /// Registers a workflow implementation with temporal-proxy. /// </summary> /// <param name="workflowType">The workflow implementation type.</param> /// <exception cref="RegistrationException">Thrown when there's a problem with the registration.</exception> private async Task RegisterWorkflowImplementationAsync(Type workflowType) { await SyncContext.Clear; TemporalHelper.ValidateWorkflowImplementation(workflowType); var methodMap = WorkflowMethodMap.Create(workflowType); // We need to register each workflow method that implements a workflow interface method // with the same signature that that was tagged by [WorkflowMethod]. // // First, we'll create a dictionary that maps method signatures from any inherited // interfaces that are tagged by [WorkflowMethod] to the attribute. var methodSignatureToAttribute = new Dictionary <string, WorkflowMethodAttribute>(); foreach (var interfaceType in workflowType.GetInterfaces()) { foreach (var method in interfaceType.GetMethods(BindingFlags.Public | BindingFlags.Instance)) { var workflowMethodAttribute = method.GetCustomAttribute <WorkflowMethodAttribute>(); if (workflowMethodAttribute == null) { continue; } var signature = method.ToString(); if (methodSignatureToAttribute.ContainsKey(signature)) { throw new NotSupportedException($"Workflow type [{workflowType.FullName}] cannot implement the [{signature}] method from two different interfaces."); } methodSignatureToAttribute.Add(signature, workflowMethodAttribute); } } // Next, we need to register the workflow methods that implement the // workflow interface. foreach (var method in workflowType.GetMethods()) { if (!methodSignatureToAttribute.TryGetValue(method.ToString(), out var workflowMethodAttribute)) { continue; } var workflowTypeName = TemporalHelper.GetWorkflowTypeName(workflowType, workflowMethodAttribute); lock (nameToWorkflowRegistration) { if (nameToWorkflowRegistration.TryGetValue(workflowTypeName, out var existingRegistration)) { if (!object.ReferenceEquals(existingRegistration.WorkflowType, workflowType)) { throw new InvalidOperationException($"Conflicting workflow interface registration: Workflow interface [{workflowType.FullName}] is already registered for workflow type name [{workflowTypeName}]."); } } else { nameToWorkflowRegistration[workflowTypeName] = new WorkflowRegistration() { WorkflowType = workflowType, WorkflowMethod = method, WorkflowMethodParameterTypes = method.GetParameterTypes(), MethodMap = methodMap }; } } var reply = (WorkflowRegisterReply)await Client.CallProxyAsync( new WorkflowRegisterRequest() { WorkerId = WorkerId, Name = workflowTypeName, }); reply.ThrowOnError(); } }