public void TryParseOrchestration()
        {
            // Arrange
            var model  = Calculator.Semantic;
            var method = Calculator.MultiplyMethod;

            // Act
            var result = DurableFunction.TryParse(model, method, out DurableFunction function);

            // Assert
            Assert.True(result);
            Assert.Equal("WebJobs.Extensions.DurableTask.CodeGen.Example.Calculator.Multiply", function.FullTypeName);
            Assert.Equal(2, function.RequiredNamespaces.Count);
            var requiredNamespaceList = function.RequiredNamespaces.ToList();

            Assert.Equal("System.Threading.Tasks", requiredNamespaceList[0]);
            Assert.Equal("Microsoft.Azure.WebJobs.Extensions.DurableTask", requiredNamespaceList[1]);
            Assert.Equal("Multiply", function.Name);
            Assert.Equal(DurableFunctionKind.Orchestration, function.Kind);
            Assert.Equal(2, function.Parameters.Count);
            Assert.Equal("int", function.Parameters[0].Type.ToString());
            Assert.Equal("int", function.Parameters[1].Type.ToString());
            Assert.Equal("num1", function.Parameters[0].Name);
            Assert.Equal("num2", function.Parameters[1].Name);
            Assert.Equal("Task<int>", function.ReturnType);
            Assert.Equal("<int>", function.CallGenerics);
        }
        public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
        {
            try
            {
                // Only search on one visit, because we just need need to find the DurableTask types
                // once and then hold a reference of them to use later.
                if (!Searched)
                {
                    Searched    = true;
                    Initialized = true;

                    Initialized &= DurableFunctionUtility.TryFindDurableOrchestrationContextType(context.SemanticModel, out var durableOrchestrationContextTypeSymbol);
                    Initialized &= DurableFunctionUtility.TryFindDurableClientType(context.SemanticModel, out var durableClientTypeSymbol);

                    DurableOrchestrationContextTypeSymbol = durableOrchestrationContextTypeSymbol;
                    DurableClientTypeSymbol = durableClientTypeSymbol;
                }

                // Must have found DurableTask types in order to find DurableFunctions
                if (!Initialized)
                {
                    return;
                }

                // Looking for things that are methods
                if (!(context.Node is MethodDeclarationSyntax method))
                {
                    return;
                }

                if (!DurableFunction.TryParse(context.SemanticModel, method, out DurableFunction function))
                {
                    return;
                }

                Debug.WriteLine($"Adding function '{function.Name}'");

                DurableFunctions.Add(function);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }
예제 #3
0
        protected MethodDeclarationSyntax GenerateStartMethod(
            DurableFunction function
            )
        {
            const string instanceParameterName = "instance";

            var methodName = $"Start{function.Name}";

            var leadingTrivia = AsCrefSummary(function.FullTypeName);

            var parameterList = AsParameterList()
                                .AddParameters(function.Parameters.Select(p => AsParameter(p.Type.ToString(), p.Name)).ToArray())
                                .AddParameters(AsParameter("string", instanceParameterName).WithDefault(SyntaxFactory.EqualsValueClause(SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression))));

            return(SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("Task<string>"), methodName)
                   .WithLeadingTrivia(leadingTrivia)
                   .WithParameterList(parameterList)
                   .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)));
        }
        private MethodDeclarationSyntax GenerateCallerMethod(
            DurableFunction function,
            bool withRetry
            )
        {
            var parameters = function.Parameters;

            var methodName = $"{function.Name}{(withRetry ? "WithRetry" : string.Empty)}";

            var leadingTrivia = AsCrefSummary(function.FullTypeName);

            var parameterList = AsParameterList()
                                .AddParameters(withRetry ? AsParameter("RetryOptions", "options") : null)
                                .AddParameters(function.Parameters.Select(p => AsParameter(p.Type.ToString(), p.Name)).ToArray());

            return(SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName(function.ReturnType), methodName)
                   .WithLeadingTrivia(leadingTrivia)
                   .WithParameterList(parameterList)
                   .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)));
        }
        private MethodDeclarationSyntax GenerateCallerMethod(
            DurableFunction function,
            bool withRetry
            )
        {
            var parameters = function.Parameters;

            var methodName = $"{function.Name}{(withRetry ? "WithRetry" : string.Empty)}";

            var leadingTrivia = AsCrefSummary(function.FullTypeName);
            var modifiers     = AsModifierList(SyntaxKind.PublicKeyword);

            var parameterList = AsParameterList()
                                .AddParameters(withRetry ? AsParameter("RetryOptions", "options") : null)
                                .AddParameters(function.Parameters.Select(p => AsParameter(p.Type.ToString(), p.Name)).ToArray());

            var callMethodName = (function.Kind == DurableFunctionKind.Orchestration) ?
                                 $"CallSubOrchestrator{((withRetry) ? "WithRetry" : string.Empty)}Async" :
                                 $"CallActivity{((withRetry) ? "WithRetry" : string.Empty)}Async";
            var callGenerics          = function.CallGenerics;
            var functionNameParameter = $"\"{function.Name}\"";
            var callRetryParameter    = withRetry ? ", options" : string.Empty;
            var callContextParameters = (parameters.Count == 0) ?
                                        ", null" :
                                        (parameters.Count == 1) ?
                                        $", {parameters[0].Name}" :
                                        $", ({string.Join(",", parameters.Select(p => p.Name))})";
            var callParameters = $"{functionNameParameter}{callRetryParameter}{callContextParameters}";


            var bodyText        = $"return _context.{callMethodName}{callGenerics}({callParameters});";
            var returnStatement = SyntaxFactory.ParseStatement(bodyText);
            var bodyBlock       = SyntaxFactory.Block(returnStatement);

            return(SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName(function.ReturnType), methodName)
                   .WithModifiers(modifiers)
                   .WithLeadingTrivia(leadingTrivia)
                   .WithParameterList(parameterList)
                   .WithBody(bodyBlock));
        }
        protected MethodDeclarationSyntax GenerateStartMethod(
            DurableFunction function
            )
        {
            const string instanceParameterName = "instance";

            var parameters = function.Parameters;

            var methodName = $"Start{function.Name}";

            var modifiers = AsModifierList(SyntaxKind.PublicKeyword);

            var leadingTrivia = AsCrefSummary(function.FullTypeName);

            var parameterList = AsParameterList()
                                .AddParameters(function.Parameters.Select(p => AsParameter(p.Type.ToString(), p.Name)).ToArray())
                                .AddParameters(AsParameter("string", instanceParameterName).WithDefault(SyntaxFactory.EqualsValueClause(SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression))));

            // Add body
            var callMethodName        = "StartNewAsync";
            var functionNameParameter = $"\"{function.Name}\"";
            var callContextParameters = (parameters.Count == 0) ?
                                        $", {instanceParameterName}" :
                                        (parameters.Count == 1) ?
                                        $", {instanceParameterName}, {parameters[0].Name}" :
                                        $", {instanceParameterName}, ({string.Join(",", parameters.Select(p => p.Name))})";
            var callParameters = $"{functionNameParameter}{callContextParameters}";


            var bodyText        = $"return _client.{callMethodName}({callParameters});";
            var returnStatement = SyntaxFactory.ParseStatement(bodyText);
            var bodyBlock       = SyntaxFactory.Block(returnStatement);

            return(SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("Task<string>"), methodName)
                   .WithModifiers(modifiers)
                   .WithLeadingTrivia(leadingTrivia)
                   .WithParameterList(parameterList)
                   .WithBody(bodyBlock));
        }
 protected MethodDeclarationSyntax GenerateCallMethodWithoutRetry(DurableFunction function)
 {
     return(GenerateCallerMethod(function, withRetry: false));
 }