public void PipelineBuilder_BuildFromConfiguration_AssemblyServices_MultiAvailable()
        {
            var element = new ElementOptions()
            {
                BuilderName = "RequiredService"
            };

            // Create configuration object.
            PipelineOptions opts = new PipelineOptions();

            opts.Elements = new List <ElementOptions>
            {
                element
            };

            var service       = new RequiredServiceElementBuilder.EmptyService();
            var httpClient    = new Mock <HttpClient>();
            var updateService = new DataUpdateService(
                new Mock <ILogger <DataUpdateService> >().Object,
                httpClient.Object);
            var services = new FiftyOneServiceProvider();

            services.AddService(service);
            services.AddService(updateService);

            // Pass the configuration to the builder to create the pipeline.
            var pipeline = new PipelineBuilder(_loggerFactory, services)
                           .BuildFromConfiguration(opts);

            Assert.IsNotNull(pipeline.GetElement <RequiredServiceElement>().LoggerFactory);
            Assert.IsNotNull(pipeline.GetElement <RequiredServiceElement>().Service);
            Assert.AreEqual(service, pipeline.GetElement <RequiredServiceElement>().Service);
            Assert.IsNotNull(pipeline.GetElement <RequiredServiceElement>().UpdateService);
            Assert.AreEqual(updateService, pipeline.GetElement <RequiredServiceElement>().UpdateService);
        }
Example #2
0
        public void PipelineBuilder_BuildFromConfiguration_NotInServiceCollection()
        {
            var element = new ElementOptions()
            {
                BuilderName = "MultiplyByElementBuilder"
            };

            element.BuildParameters.Add("multiple", "3");

            // Create the configuration object.
            PipelineOptions opts = new PipelineOptions();

            opts.Elements = new List <ElementOptions>
            {
                element
            };

            _maxErrors = 1;

            Mock <IServiceProvider> services = new Mock <IServiceProvider>();

            services.Setup(s => s.GetService(typeof(MultiplyByElementBuilder)))
            .Returns(null);

            // Pass the configuration to the builder to create the pipeline.
            var pipeline = new PipelineBuilder(_loggerFactory, services.Object)
                           .BuildFromConfiguration(opts);
        }
Example #3
0
        /// <summary>
        /// Ensure the json and javascript elements are added to the configuration
        /// </summary>
        /// <param name="options"></param>
        private static void AddJsElements(PipelineOptions options)
        {
            var jsonConfig = options.Elements.Where(e =>
                                                    e.BuilderName.Contains(nameof(JsonBuilderElement),
                                                                           StringComparison.OrdinalIgnoreCase));
            var javascriptConfig = options.Elements.Where(e =>
                                                          e.BuilderName.Contains(nameof(JavaScriptBuilderElement),
                                                                                 StringComparison.OrdinalIgnoreCase));

            var jsIndex = javascriptConfig.Any() ?
                          options.Elements.IndexOf(javascriptConfig.First()) : -1;

            if (jsonConfig.Any() == false)
            {
                // The json builder is not included so add it.
                var newElementOptions = new ElementOptions()
                {
                    BuilderName = nameof(JsonBuilderElement)
                };
                if (jsIndex > -1)
                {
                    // There is already a javascript builder element
                    // so insert the json builder before it.
                    options.Elements.Insert(jsIndex, newElementOptions);
                }
                else
                {
                    options.Elements.Add(newElementOptions);
                }
            }

            if (jsIndex == -1)
            {
                // The builder is not included so add it.
                options.Elements.Add(new ElementOptions()
                {
                    BuilderName     = nameof(JavaScriptBuilderElement),
                    BuildParameters = new Dictionary <string, object>()
                    {
                        { "EndPoint", "/51dpipeline/json" }
                    }
                });
            }
            else
            {
                // There is already a JavaScript builder config so check if
                // the endpoint is specified. If not, add it.
                if (javascriptConfig.Single().BuildParameters.ContainsKey("EndPoint") == false)
                {
                    javascriptConfig.Single().BuildParameters.Add("EndPoint", "/51dpipeline/json");
                }
            }
        }
        public void PipelineBuilder_BuildFromConfiguration_ParallelElements()
        {
            var multiplyElement = new ElementOptions()
            {
                BuilderName = "MultiplyByElement"
            };

            multiplyElement.BuildParameters.Add("Multiple", "3");

            // Create the element that holds the elements that
            // will be run in parallel.
            var parentElement = new ElementOptions()
            {
            };

            parentElement.SubElements.Add(new ElementOptions()
            {
                BuilderName = "ListSplitterElement"
            });
            parentElement.SubElements.Add(multiplyElement);

            // Create the configuration object.
            PipelineOptions options = new PipelineOptions();

            options.Elements = new List <ElementOptions>
            {
                parentElement
            };

            // Pass the configuration to the builder to create the pipeline.
            var pipeline = _builder.BuildFromConfiguration(options);
            // Get the elements
            var splitterElement   = pipeline.GetElement <ListSplitterElement>();
            var multiplyByElement = pipeline.GetElement <MultiplyByElement>();

            // Create, populate and process flow data.
            using (var flowData = pipeline.CreateFlowData())
            {
                flowData
                .AddEvidence(splitterElement.EvidenceKeys[0], "1,2,abc")
                .AddEvidence(multiplyByElement.EvidenceKeys[0], 25)
                .Process();

                // Get the results and verify them.
                var splitterData   = flowData.GetFromElement(splitterElement);
                var multiplyByData = flowData.GetFromElement(multiplyByElement);

                Assert.AreEqual("1", splitterData.Result[0]);
                Assert.AreEqual("2", splitterData.Result[1]);
                Assert.AreEqual("abc", splitterData.Result[2]);
                Assert.AreEqual(75, multiplyByData.Result);
            }
        }
        /// <summary>
        /// Create a <see cref="ParallelElements"/> from the specified
        /// configuration and add it to the _flowElements list.
        /// </summary>
        /// <param name="elements">
        /// The list to add the new <see cref="ParallelElements"/> to.
        /// </param>
        /// <param name="elementOptions">
        /// The <see cref="ElementOptions"/> instance to use when creating
        /// the <see cref="ParallelElements"/>.
        /// </param>
        /// <param name="elementIndex">
        /// The index of the element within the <see cref="PipelineOptions"/>.
        /// </param>
        private void AddParallelElementsToList(
            List <IFlowElement> elements,
            ElementOptions elementOptions,
            int elementIndex)
        {
            // Element contains further sub elements, this is not allowed.
            if (string.IsNullOrEmpty(elementOptions.BuilderName) == false ||
                (elementOptions.BuildParameters != null &&
                 elementOptions.BuildParameters.Count > 0))
            {
                throw new PipelineConfigurationException(
                          $"ElementOptions {elementIndex} contains both " +
                          $"SubElements and other settings values. " +
                          $"This is invalid");
            }
            List <IFlowElement> parallelElements = new List <IFlowElement>();

            // Iterate through the sub elements, creating them and
            // adding them to the list.
            int subCounter = 0;

            foreach (var subElement in elementOptions.SubElements)
            {
                if (subElement.SubElements != null &&
                    subElement.SubElements.Count > 0)
                {
                    throw new PipelineConfigurationException(
                              $"ElementOptions {elementIndex} contains nested " +
                              $"sub elements. This is not supported.");
                }
                else
                {
                    AddElementToList(parallelElements, subElement,
                                     $"element {subCounter} in element {elementIndex}");
                }
                subCounter++;
            }
            // Now we've created all the elements, create the
            // ParallelElements instance and add it to the pipeline's
            // elements.
            var parallelInstance = new ParallelElements(
                LoggerFactory.CreateLogger <ParallelElements>(),
                parallelElements.ToArray());

            elements.Add(parallelInstance);
        }
Example #6
0
        public void PipelineBuilder_BuildFromConfiguration_ClassNameAlternate()
        {
            var element = new ElementOptions()
            {
                BuilderName = "Multiply"
            };

            element.BuildParameters.Add("multiple", "8");

            // Create the configuration object.
            PipelineOptions opts = new PipelineOptions();

            opts.Elements = new List <ElementOptions>
            {
                element
            };

            VerifyMultiplyByElementPipeline(opts);
        }
Example #7
0
        public void PipelineBuilder_BuildFromConfiguration_ListFromStringSingleEntry()
        {
            var element = new ElementOptions()
            {
                BuilderName = "ListSplitterElement"
            };

            element.BuildParameters.Add("Delimiters", "|");

            // Create the configuration object.
            PipelineOptions opts = new PipelineOptions();

            opts.Elements = new List <ElementOptions>
            {
                element
            };

            VerifyListSplitterElementPipeline(opts, SplitOption.Pipe);
        }
Example #8
0
        public void PipelineBuilder_BuildFromConfiguration_MethodNameAlternate()
        {
            var element = new ElementOptions()
            {
                BuilderName = "ListSplitterElement"
            };

            element.BuildParameters.Add("delim", "|");

            // Create the configuration object.
            PipelineOptions opts = new PipelineOptions();

            opts.Elements = new List <ElementOptions>
            {
                element
            };

            VerifyListSplitterElementPipeline(opts, SplitOption.Pipe);
        }
Example #9
0
        public void PipelineBuilder_BuildFromConfiguration_OptionalMethodInteger()
        {
            var element = new ElementOptions()
            {
                BuilderName = "ListSplitterElement"
            };

            element.BuildParameters.Add("MaxLength", "3");

            // Create the configuration object.
            PipelineOptions opts = new PipelineOptions();

            opts.Elements = new List <ElementOptions>
            {
                element
            };

            VerifyListSplitterElementPipeline(opts, SplitOption.CommaMaxLengthThree);
        }
Example #10
0
        public void PipelineBuilder_BuildFromConfiguration_SingleMandatoryParameter()
        {
            // Create the configuration object.
            var element = new ElementOptions()
            {
                BuilderName = "MultiplyByElementBuilder"
            };

            element.BuildParameters.Add("multiple", "8");

            PipelineOptions opts = new PipelineOptions();

            opts.Elements = new List <ElementOptions>
            {
                element
            };

            VerifyMultiplyByElementPipeline(opts);
        }
Example #11
0
        public void PipelineBuilder_BuildFromConfiguration_NoBuilder()
        {
            var element = new ElementOptions()
            {
                BuilderName = "NoBuilder"
            };

            // Create the configuration object.
            PipelineOptions opts = new PipelineOptions();

            opts.Elements = new List <ElementOptions>
            {
                element
            };
            _maxErrors = 1;

            // Pass the configuration to the builder to create the pipeline.
            var pipeline = _builder.BuildFromConfiguration(opts);
        }
        public void PipelineBuilder_BuildFromConfiguration_ServiceCollection()
        {
            var element = new ElementOptions()
            {
                BuilderName = "MultiplyByElementBuilder"
            };

            element.BuildParameters.Add("multiple", "3");

            // Create the configuration object.
            PipelineOptions opts = new PipelineOptions();

            opts.Elements = new List <ElementOptions>
            {
                element
            };

            Mock <IServiceProvider> services = new Mock <IServiceProvider>();

            services.Setup(s => s.GetService(typeof(MultiplyByElementBuilder)))
            .Returns(new MultiplyByElementBuilder());

            // Pass the configuration to the builder to create the pipeline.
            var pipeline = new PipelineBuilder(_loggerFactory, services.Object)
                           .BuildFromConfiguration(opts);

            // Get the element
            var multiplyByElement = pipeline.GetElement <MultiplyByElement>();

            // Create, populate and process flow data.
            using (var flowData = pipeline.CreateFlowData())
            {
                flowData
                .AddEvidence(multiplyByElement.EvidenceKeys[0], 25)
                .Process();

                // Get the results and verify them.
                var multiplyByData = flowData.GetFromElement(multiplyByElement);

                Assert.AreEqual(75, multiplyByData.Result);
            }
        }
Example #13
0
        public void PipelineBuilder_BuildFromConfiguration_OptionalMethodWrongType()
        {
            var element = new ElementOptions()
            {
                BuilderName = "ListSplitterElement"
            };

            element.BuildParameters.Add("MaxLength", "WrongType");

            // Create the configuration object.
            PipelineOptions opts = new PipelineOptions();

            opts.Elements = new List <ElementOptions>
            {
                element
            };
            _maxErrors = 1;

            VerifyListSplitterElementPipeline(opts, SplitOption.Comma);
        }
Example #14
0
        public void PipelineBuilder_BuildFromConfiguration_MandatoryParameterWrongType()
        {
            var element = new ElementOptions()
            {
                BuilderName = "MultiplyByElementBuilder"
            };

            element.BuildParameters.Add("multiple", "WrongType");

            // Create the configuration object.
            PipelineOptions opts = new PipelineOptions();

            opts.Elements = new List <ElementOptions>
            {
                element
            };
            _maxErrors = 1;

            // Pass the configuration to the builder to create the pipeline.
            var pipeline = _builder.BuildFromConfiguration(opts);
        }
        public void PipelineBuilder_BuildFromConfiguration_AssemblyServices_NotAvailable()
        {
            var element = new ElementOptions()
            {
                BuilderName = "RequiredService"
            };

            // Create configuration object.
            PipelineOptions opts = new PipelineOptions();

            opts.Elements = new List <ElementOptions>
            {
                element
            };

            // Pass the configuration to the builder to create the pipeline.
            var pipeline = new PipelineBuilder(_loggerFactory, new FiftyOneServiceProvider())
                           .BuildFromConfiguration(opts);

            Assert.IsNotNull(pipeline.GetElement <RequiredServiceElement>().LoggerFactory);
            Assert.IsNull(pipeline.GetElement <RequiredServiceElement>().Service);
            Assert.IsNull(pipeline.GetElement <RequiredServiceElement>().UpdateService);
        }
Example #16
0
        private static bool WaitHandler(IWebElement e, int timeout, ElementOptions option, string text = "")
        {
            var watch  = new Stopwatch();
            var driver = WebDriverSupport.SupportDriver();
            var result = false;

            watch.Start();
            driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(0);
            while (watch.Elapsed.TotalMilliseconds <= timeout.ToMilliseconds() && !result)
            {
                try
                {
                    switch (option)
                    {
                    case ElementOptions.Displayed:
                        if (e.Displayed)
                        {
                            result = true;
                        }

                        break;

                    case ElementOptions.NotDisplayed:
                        if (e == null || !e.Displayed)
                        {
                            result = true;
                        }

                        break;

                    case ElementOptions.Enabled:
                        if (e.Enabled)
                        {
                            result = true;
                        }

                        break;

                    case ElementOptions.SelectOptionDisplayed:
                        if (e.FindElements(By.TagName("option")).Count(x => x.Text.Contains(text)) > 0)
                        {
                            result = true;
                        }

                        break;

                    default:
                        throw new ArgumentOutOfRangeException(nameof(option), option, null);
                    }
                }
                catch (NoSuchElementException)
                {
                    if (option == ElementOptions.NotDisplayed)
                    {
                        result = true;
                    }
                }
                catch (StaleElementReferenceException)
                {
                    if (option == ElementOptions.NotDisplayed)
                    {
                        result = true;
                    }
                }
                catch
                {
                    //Ignored
                }
            }

            // if (watch.Elapsed.Seconds > 1) Log.Info($"Waited for {watch.Elapsed.Seconds} seconds for the element state {option}");

            return(result);
        }
Example #17
0
        /// <summary>
        /// Private constructor used to construct the only instance which will
        /// exist of this class.
        /// </summary>
        private WebPipeline()
        {
            IConfiguration config = new ConfigurationBuilder()
                .AddPipelineConfig()
                .Build();
            _options = new PipelineWebIntegrationOptions();
            config.Bind("PipelineOptions", _options);
            
            if (_options == null ||
                _options.Elements == null)
            {
                throw new PipelineConfigurationException(
                   Messages.ExceptionNoConfiguration);
            }

            // Add the sequence element.
            var sequenceConfig = _options.Elements.Where(e =>
                e.BuilderName.IndexOf(nameof(SequenceElement),
                    StringComparison.OrdinalIgnoreCase) >= 0);
            if (sequenceConfig.Any() == false)
            {
                // The sequence element is not included so add it.
                // Make sure it's added as the first element.
                _options.Elements.Insert(0, new ElementOptions()
                {
                    BuilderName = nameof(SequenceElement)
                });
            }

            if (ClientSideEvidenceEnabled)
            {
                // Client-side evidence is enabled so make sure the 
                // JsonBuilderElement and JavaScriptBundlerElement has been 
                // included.
                var jsonConfig = _options.Elements.Where(e =>
                    e.BuilderName.StartsWith(nameof(JsonBuilderElement),
                        StringComparison.OrdinalIgnoreCase));
                var javascriptConfig = _options.Elements.Where(e =>
                    e.BuilderName.StartsWith(nameof(JavaScriptBuilderElement),
                        StringComparison.OrdinalIgnoreCase));

                var jsIndex = javascriptConfig.Any() ?
                    _options.Elements.IndexOf(javascriptConfig.First()) : -1;

                if (jsonConfig.Any() == false)
                {
                    // The json builder is not included so add it.
                    var newElementOptions = new ElementOptions()
                    {
                        BuilderName = nameof(JsonBuilderElement)
                    };
                    if (jsIndex > -1)
                    {
                        // There is already a javascript builder element
                        // so insert the json builder before it.
                        _options.Elements.Insert(jsIndex, newElementOptions);
                    }
                    else
                    {
                        _options.Elements.Add(newElementOptions);
                    }
                }

                if (jsIndex == -1)
                {
                    // The javascript builder is not included so add it.
                    _options.Elements.Add(new ElementOptions()
                    {
                        BuilderName = nameof(JavaScriptBuilderElement),
                        BuildParameters = new Dictionary<string, object>()
                        {
                            { "EndPoint", "/51dpipeline/json" }
                        }
                    });
                }
                else
                {
                    // There is already a JavaScript builder config so check if 
                    // the endpoint is specified. If not, add it.
                    if (javascriptConfig.Single().BuildParameters.ContainsKey("EndPoint") == false)
                    {
                        javascriptConfig.Single().BuildParameters.Add("EndPoint", "/51dpipeline/json");
                    }
                }
            }

            // Add the set headers
            var setHeadersConfig = _options.Elements.Where(e =>
                e.BuilderName.IndexOf(nameof(SetHeadersElement),
                    StringComparison.OrdinalIgnoreCase) >= 0);
            if (setHeadersConfig.Any() == false)
            {
                // The set headers element is not included, so add it.
                // Make sure it's added as the last element.
                _options.Elements.Add(new ElementOptions()
                {
                    BuilderName = nameof(SetHeadersElement)
                });
            }

            // Set up common services.
            var loggerFactory = new LoggerFactory();
            var updateService = new DataUpdateService(
                loggerFactory.CreateLogger<DataUpdateService>(),
                new System.Net.Http.HttpClient());
            var services = new FiftyOneServiceProvider();
            // Add data update and missing property services.
            services.AddService(updateService);
            services.AddService(MissingPropertyService.Instance);

            Pipeline = new PipelineBuilder(
                loggerFactory,
                services)
                .BuildFromConfiguration(_options);
        }
        /// <summary>
        /// The default <see cref="IPipeline"/> factory function.
        /// This looks for a 'PipelineOptions' configuration item and uses
        /// that to build the pipeline.
        /// </summary>
        /// <param name="config">
        /// The application configuration object
        /// </param>
        /// <param name="pipelineBuilder">
        /// a pipeline builder instance to use when constructing the
        /// <see cref="IPipeline"/>.
        /// </param>
        /// <returns>
        /// A new <see cref="IPipeline"/> instance
        /// </returns>
        private static IPipeline CreatePipelineFromConfig(
            IConfiguration config,
            IPipelineBuilderFromConfiguration pipelineBuilder)
        {
            // Get Pipeline options to check that it is present
            PipelineOptions options = new PipelineOptions();

            config.Bind("PipelineOptions", options);

            if (options == null ||
                options.Elements == null ||
                options.Elements.Count == 0)
            {
                throw new PipelineConfigurationException(
                          Messages.ExceptionNoConfiguration);
            }

            PipelineWebIntegrationOptions webOptions = new PipelineWebIntegrationOptions();

            config.Bind("PipelineWebIntegrationOptions", webOptions);

            // Add the sequence element.
            var sequenceConfig = options.Elements.Where(e =>
                                                        e.BuilderName.Contains(nameof(SequenceElement),
                                                                               StringComparison.OrdinalIgnoreCase));

            if (sequenceConfig.Any() == false)
            {
                // The sequence element is not included so add it.
                // Make sure it's added as the first element.
                options.Elements.Insert(0, new ElementOptions()
                {
                    BuilderName = nameof(SequenceElement)
                });
            }

            if (webOptions.ClientSideEvidenceEnabled)
            {
                // Client-side evidence is enabled so make sure the
                // JsonBuilderElement and JavaScriptBundlerElement has been
                // included.
                var jsonConfig = options.Elements.Where(e =>
                                                        e.BuilderName.Contains(nameof(JsonBuilderElement),
                                                                               StringComparison.OrdinalIgnoreCase));
                var javascriptConfig = options.Elements.Where(e =>
                                                              e.BuilderName.Contains(nameof(JavaScriptBuilderElement),
                                                                                     StringComparison.OrdinalIgnoreCase));

                var jsIndex = javascriptConfig.Any() ?
                              options.Elements.IndexOf(javascriptConfig.First()) : -1;

                if (jsonConfig.Any() == false)
                {
                    // The json builder is not included so add it.
                    var newElementOptions = new ElementOptions()
                    {
                        BuilderName = nameof(JsonBuilderElement)
                    };
                    if (jsIndex > -1)
                    {
                        // There is already a javascript builder element
                        // so insert the json builder before it.
                        options.Elements.Insert(jsIndex, newElementOptions);
                    }
                    else
                    {
                        options.Elements.Add(newElementOptions);
                    }
                }

                if (jsIndex == -1)
                {
                    // The builder is not included so add it.
                    options.Elements.Add(new ElementOptions()
                    {
                        BuilderName     = nameof(JavaScriptBuilderElement),
                        BuildParameters = new Dictionary <string, object>()
                        {
                            { "EnableCookies", true }
                        }
                    });
                }
            }

            return(pipelineBuilder.BuildFromConfiguration(options));
        }
        /// <summary>
        /// Create a new <see cref="IFlowElement"/> using the specified
        /// <see cref="ElementOptions"/> and add it to the supplied list
        /// of elements.
        /// </summary>
        /// <param name="elements">
        /// The list to add the new <see cref="IFlowElement"/> to.
        /// </param>
        /// <param name="elementOptions">
        /// The <see cref="ElementOptions"/> instance to use when creating
        /// the <see cref="IFlowElement"/>.
        /// </param>
        /// <param name="elementLocation">
        /// The string description of the element's location within the
        /// <see cref="PipelineOptions"/> instance.
        /// </param>
        private void AddElementToList(
            List <IFlowElement> elements,
            ElementOptions elementOptions,
            string elementLocation)
        {
            // Check that a builder name is set
            if (string.IsNullOrEmpty(elementOptions.BuilderName))
            {
                throw new PipelineConfigurationException(
                          $"A BuilderName must be specified for " +
                          $"{elementLocation}.");
            }

            // Try to get the builder to use
            var builderType = GetBuilderType(elementOptions.BuilderName);

            if (builderType == null)
            {
                throw new PipelineConfigurationException(
                          $"Could not find builder matching " +
                          $"'{elementOptions.BuilderName}' for " +
                          $"{elementLocation}. Available builders are: " +
                          $"{string.Join(",", _elementBuilders.Select(t => t.Name))}");
            }

            // Get the methods on the builder
            var buildMethods = builderType.GetRuntimeMethods()
                               .Where(m => m.Name == "Build");

            // If there are no 'Build' methods or if there is no default
            // constructor then throw an error.
            if (buildMethods.Any() == false)
            {
                throw new PipelineConfigurationException(
                          $"Builder '{builderType.FullName}' for " +
                          $"{elementLocation} has no 'Build' methods.");
            }

            object builderInstance = null;

            if (_services != null)
            {
                // Try to get a a builder instance from the service collection.
                builderInstance = _services.GetRequiredService(builderType);
            }
            else
            {
                // A service collection does not exist in the builder, so try
                // to construct a builder instance from the assemblies
                // currently loaded.
                builderInstance = GetBuilderFromAssemlies(builderType);
                if (builderInstance == null)
                {
                    throw new PipelineConfigurationException(
                              $"Builder '{builderType.FullName}' for " +
                              $"{elementLocation} does not have a default constructor. " +
                              $"i.e. One that takes no parameters. Or a constructor " +
                              $"which takes an ILoggerFactory parameter.");
                }
            }
            // Holds a list of the names of parameters to pass to the
            // build method when we're ready.
            List <string> buildParameterList = new List <string>();

            if (elementOptions.BuildParameters != null)
            {
                // Call any non-build methods on the builder to set optional
                // parameters.
                buildParameterList = ProcessBuildParameters(
                    elementOptions.BuildParameters,
                    builderType,
                    builderInstance,
                    elementLocation);
            }

            // At this point, all the optional methods on the builder
            // have been called and we're ready to call the Build method.
            // If there are no matching build methods or multiple possible
            // build methods based on our parameters then throw an exception.
            var possibleBuildMethods = buildMethods.Where(m =>
                                                          m.GetParameters().Length == buildParameterList.Count &&
                                                          m.GetParameters().All(p => buildParameterList.Contains(p.Name.ToUpperInvariant())));

            StringBuilder buildSignatures = new StringBuilder();

            buildSignatures.AppendLine();
            foreach (var method in buildMethods)
            {
                buildSignatures.AppendLine(string.Join(",",
                                                       method.GetParameters().Select(p =>
                                                                                     $"{p.Name} ({p.ParameterType.Name})")));
            }

            if (possibleBuildMethods.Any() == false)
            {
                StringBuilder methodSignatures = new StringBuilder();
                methodSignatures.AppendLine();
                // Build a list of the 'set' methods on this builder
                // along with their parameter.
                foreach (var method in builderType.GetRuntimeMethods()
                         // Include any methods that are:
                         // 1. public
                         // 2. have a single parameter
                         .Where(m => m.IsPublic && m.GetParameters().Length == 1 &&
                                m.DeclaringType.Name.ToUpperInvariant().Contains("BUILDER")))
                {
                    methodSignatures.AppendLine($"{method.Name} ({method.GetParameters()[0].GetType().Name})");
                }
                throw new PipelineConfigurationException(
                          $"Builder '{builderType.FullName}' for " +
                          $"{elementLocation} has no " +
                          $"'Set' methods or 'Build' methods that match " +
                          $"(case-insensitively) the following parameters: " +
                          $"{string.Join(",", buildParameterList)}. " +
                          $"The available configuration methods on this builder are: " +
                          $"{methodSignatures.ToString()}" +
                          $"The available 'Build' methods have the following signatures: " +
                          $"{buildSignatures.ToString()}");
            }
            else if (possibleBuildMethods.Count() > 1)
            {
                throw new PipelineConfigurationException(
                          $"Builder '{builderType.FullName}' for " +
                          $"{elementLocation} has multiple " +
                          $"'Build' methods that match the following parameters: " +
                          $"{string.Join(",", buildParameterList)}. " +
                          $"Matching method signatures are: {buildSignatures.ToString()}");
            }

            // Get the build method parameters and add the configured
            // values to the parameter list.
            List <object> parameters  = new List <object>();
            var           buildMethod = possibleBuildMethods.Single();
            var           caseInsensitiveParameters = elementOptions.BuildParameters
                                                      .ToDictionary(d => d.Key.ToUpperInvariant(), d => d.Value);

            foreach (var parameterInfo in buildMethod.GetParameters())
            {
                var    paramType  = parameterInfo.ParameterType;
                object paramValue = caseInsensitiveParameters[parameterInfo.Name.ToUpperInvariant()];
                if (paramType != typeof(string))
                {
                    paramValue = ParseToType(paramType,
                                             (string)paramValue,
                                             $"Method 'Build' on builder " +
                                             $"'{builderType.FullName}' for " +
                                             $"{elementLocation} expects a parameter of type " +
                                             $"'{paramType.Name}'");
                }
                parameters.Add(paramValue);
            }
            // Call the build method with the parameters we set up above.
            object result = buildMethod.Invoke(builderInstance, parameters.ToArray());

            if (result == null)
            {
                throw new PipelineConfigurationException(
                          $"Failed to build {elementLocation} using " +
                          $"'{builderType.FullName}', reason unknown.");
            }
            IFlowElement element = result as IFlowElement;

            if (element == null)
            {
                throw new PipelineConfigurationException(
                          $"Failed to cast '{result.GetType().FullName}' to " +
                          $"'IFlowElement' for {elementLocation}");
            }

            // Add the element to the list.
            elements.Add(element);
        }
Example #20
0
 public void AddElement(NoteOption child)
 {
     child.Parent = this;
     ElementOptions.Add(child);
 }