protected override void ProcessInternal(IFlowData data) { // Create a new IStarSignData, and cast to StarSignData so the 'setter' is available. StarSignData starSignData = (StarSignData)data.GetOrAdd(ElementDataKey, CreateElementData); if (data.TryGetEvidence("date-of-birth", out DateTime dateOfBirth)) { // "date-of-birth" is there, so set the star sign. var monthAndDay = new DateTime(1, dateOfBirth.Month, dateOfBirth.Day); foreach (var starSign in _starSigns) { if (monthAndDay > starSign.Start && monthAndDay < starSign.End) { // The star sign has been found, so set it in the // results. starSignData.StarSign = starSign.Name; break; } } } else { // "date-of-birth" is not there, so set the star sign to unknown. starSignData.StarSign = "Unknown"; } }
protected override void ProcessEngine(IFlowData data, IStarSignData aspectData) { // Cast aspectData to AgeData so the 'setter' is available. StarSignData starSignData = (StarSignData)aspectData; if (data.TryGetEvidence("date-of-birth", out DateTime dateOfBirth)) { // "date-of-birth" is there, so set the star sign. var monthAndDay = new DateTime(1, dateOfBirth.Month, dateOfBirth.Day); foreach (var starSign in _starSigns) { if (monthAndDay > starSign.Start && monthAndDay < starSign.End) { // The star sign has been found, so set it in the // results. starSignData.StarSign = starSign.Name; break; } } } else { // "date-of-birth" is not there, so set the star sign to unknown. starSignData.StarSign = "Unknown"; } }
protected override void ProcessInternal(IFlowData data) { var monthAndDay = new DateTime(1, 1, 1); // Create a new IStarSignData, and cast to StarSignData so the 'setter' is available. StarSignData starSignData = (StarSignData)data.GetOrAdd(ElementDataKey, CreateElementData); bool validDateOfBirth = false; if (data.TryGetEvidence("cookie.date-of-birth", out string dateString)) { // "date-of-birth" is there, so parse it. string[] dateSections = dateString.Split('/'); try { monthAndDay = new DateTime( 1, int.Parse(dateSections[1]), int.Parse(dateSections[0])); validDateOfBirth = true; } catch (Exception) { } } if (validDateOfBirth) { // "date-of-birth" is valid, so set the star sign. foreach (var starSign in _starSigns) { if (monthAndDay > starSign.Start && monthAndDay < starSign.End) { // The star sign has been found, so set it in the // results. starSignData.StarSign = starSign.Name; break; } } // No need to run the client side code again. starSignData.DobJavaScript = new JavaScript(""); } else { // "date-of-birth" is not there, so set the star sign to unknown. starSignData.StarSign = "Unknown"; // Set the client side JavaScript to get the date of birth. starSignData.DobJavaScript = new JavaScript( "var dob = window.prompt('Enter your date of birth.','dd/mm/yyyy');" + "if (dob != null) {" + "document.cookie='date-of-birth='+dob;" + "location.reload();" + "}"); } }
/// <summary> /// Get the sequence number from the evidence. /// </summary> /// <param name="data"></param> /// <returns></returns> /// <exception cref="ArgumentNullException"> /// Thrown if the supplied flow data is null. /// </exception> /// <exception cref="PipelineException"> /// Thrown if sequence number is not present in the evidence. /// </exception> protected static int GetSequenceNumber(IFlowData data) { if (data == null) { throw new ArgumentNullException(nameof(data)); } if (data.TryGetEvidence(Engines.FiftyOne.Constants.EVIDENCE_SEQUENCE, out int sequence) == false) { throw new PipelineException(Messages.ExceptionSequenceNumberNotPresent); } return(sequence); }
/// <summary> /// Get the session-id evidence if it exists. /// </summary> /// <param name="data"></param> /// <returns></returns> protected virtual string GetSessionId(IFlowData data) { if (data == null) { throw new ArgumentException(Messages.ExceptionFlowDataIsNull); } string sessionId = string.Empty; // Get the session-id evidence if it exists. if (data.TryGetEvidence(Engines.FiftyOne.Constants.EVIDENCE_SESSIONID, out object objSessionId)) { sessionId = objSessionId?.ToString() ?? string.Empty; } return(sessionId); }
/// <summary> /// Called for this engine to perform its processing. /// </summary> /// <param name="data"> /// The <see cref="IFlowData"/> that contains the input and output data. /// </param> /// <param name="aspectData"> /// The data instance to use to output results. /// </param> protected override void ProcessEngine(IFlowData data, IPrimeCheckerData aspectData) { int value; // Try to get the evidence this engine requires. if (data.TryGetEvidence(Constants.PRIMECHECKER_EVIDENCE_KEY, out value)) { // Determine if the number is prime and set the output // data accordingly. aspectData.IsPrime = IsPrime(value); // Wait for a short time. // This is done to help illustrate the impact of // features such as caching and lazy loading. Task.Delay(Constants.PRIMECHECKER_ENGINE_DELAY).Wait(); } else { // If the evidence is not present then throw an exception. throw new Exception($"No evidence for key '{Constants.PRIMECHECKER_EVIDENCE_KEY}'"); } }
/// <summary> /// Get the sequence evidence if it exists. /// </summary> /// <param name="data"></param> /// <returns></returns> protected virtual int GetSequence(IFlowData data) { if (data == null) { throw new ArgumentException(Messages.ExceptionFlowDataIsNull); } // Get the sequence evidence if it exists. int sequence = 1; if (data.TryGetEvidence(Engines.FiftyOne.Constants.EVIDENCE_SEQUENCE, out object sequenceObject)) { if (sequenceObject is int sequenceValue || (sequenceObject is string seq && int.TryParse(seq, out sequenceValue))) { sequence = sequenceValue; } } return(sequence); }
/// <summary> /// Build the JavaScript content and add it to the supplied /// <see cref="IFlowData"/> instance. /// </summary> /// <param name="data"> /// The <see cref="IFlowData"/> instance to populate with the /// resulting <see cref="JavaScriptBuilderElementData"/> /// </param> /// <param name="jsonObject"> /// The JSON data object to include in the JavaScript. /// </param> /// <param name="supportsPromises"> /// True to build JavaScript that uses promises. False to /// build JavaScript that does not use promises. /// </param> /// <param name="url"> /// The callback URL for the JavaScript to send a request to /// when it has new evidence values to supply. /// </param> /// <exception cref="ArgumentNullException"> /// Thrown if the supplied flow data is null. /// </exception> protected void BuildJavaScript(IFlowData data, string jsonObject, bool supportsPromises, Uri url) { if (data == null) { throw new ArgumentNullException(nameof(data)); } JavaScriptBuilderElementData elementData = (JavaScriptBuilderElementData) data.GetOrAdd( ElementDataKeyTyped, CreateElementData); // Try and get the requested object name from evidence. if (data.TryGetEvidence(Constants.EVIDENCE_OBJECT_NAME, out string objectName) == false || string.IsNullOrWhiteSpace(objectName)) { objectName = ObjName; } var ubdateEnabled = url != null && url.AbsoluteUri.Length > 0; JavaScriptResource javaScriptObj = new JavaScriptResource( objectName, jsonObject, supportsPromises, url, EnableCookies, ubdateEnabled); string content = _stubble.Render(_template, javaScriptObj.AsDictionary() /*, _renderSettings*/); string minifiedContent = content; if (_minify) { // Minimize the script. var ugly = Uglify.Js(content); if (ugly.HasErrors) { // If there were are errors then log them and // return the non-minified response. minifiedContent = content; if (_lastRequestWasError == false) { StringBuilder errorText = new StringBuilder(); errorText.AppendLine("Errors occurred when minifying JavaScript."); foreach (var error in ugly.Errors) { errorText.AppendLine($"{error.ErrorCode}: {error.Message}. " + $"Line(s) {error.StartLine}-{error.EndLine}. " + $"Column(s) {error.StartColumn}-{error.EndColumn}"); } errorText.AppendLine(content); Logger.LogError(errorText.ToString()); _lastRequestWasError = true; #pragma warning disable CS0618 // Type or member is obsolete // This usage should be replaced with the // CancellationToken implementation once it // is available. data.Stop = true; #pragma warning restore CS0618 // Type or member is obsolete } } else { minifiedContent = ugly.Code; } } elementData.JavaScript = minifiedContent; }
private void SetUp(IFlowData data) { var host = Host; var protocol = Protocol; bool supportsPromises; if (string.IsNullOrEmpty(host)) { // Try and get the request host name so it can be used to request // the Json refresh in the JavaScript code. data.TryGetEvidence(Constants.EVIDENCE_HOST_KEY, out host); } if (string.IsNullOrEmpty(protocol)) { // Try and get the request protocol so it can be used to request // the JSON refresh in the JavaScript code. data.TryGetEvidence(Constants.EVIDENCE_PROTOCOL, out protocol); } // Couldn't get protocol from anywhere if (string.IsNullOrEmpty(protocol)) { protocol = Constants.DEFAULT_PROTOCOL; } // If device detection is in the Pipeline then we can check // if the client's browser supports promises. // This can be used to customize the JavaScript response. try { var promise = data.GetAs <IAspectPropertyValue <string> >("Promise"); supportsPromises = promise != null && promise.HasValue && promise.Value == "Full"; } catch (PipelineDataException) { supportsPromises = false; } catch (InvalidCastException) { supportsPromises = false; } catch (KeyNotFoundException) { supportsPromises = false; } // Get the JSON include to embed into the JavaScript include. string jsonObject = string.Empty; try { jsonObject = data.Get <IJsonBuilderElementData>().Json; } catch (KeyNotFoundException ex) { throw new PipelineConfigurationException( Messages.ExceptionJsonBuilderNotRun, ex); } // Generate any required parameters for the JSON request. List <string> parameters = new List <string>(); // Any query parameters from this request that were ingested by // the Pipeline are added to the request URL that will appear // in the JavaScript. var queryEvidence = data .GetEvidence() .AsDictionary() .Where(e => e.Key.StartsWith(Core.Constants.EVIDENCE_QUERY_PREFIX, StringComparison.OrdinalIgnoreCase)) .Select(k => { var dotPos = k.Key.IndexOf(Core.Constants.EVIDENCE_SEPERATOR, StringComparison.OrdinalIgnoreCase); return($"{WebUtility.UrlEncode(k.Key.Remove(0, dotPos + 1))}" + $"={WebUtility.UrlEncode(k.Value.ToString())}"); }); parameters.AddRange(queryEvidence); string queryParams = string.Join("&", parameters); string endpoint = Endpoint; Uri url = null; if (string.IsNullOrWhiteSpace(protocol) == false && string.IsNullOrWhiteSpace(host) == false && string.IsNullOrWhiteSpace(endpoint) == false) { var endpointHasSlash = endpoint[0] == '/'; var hostHasSlash = host[host.Length - 1] == '/'; // if there is no slash between host and endpoint then add one. if (endpointHasSlash == false && hostHasSlash == false) { endpoint = $"/{endpoint}"; } // if there are two slashes between host and endpoint then remove one. else if (endpointHasSlash == true && hostHasSlash == true) { endpoint = endpoint.Substring(1); } url = new Uri($"{protocol}://{host}{endpoint}" + (String.IsNullOrEmpty(queryParams) ? "" : $"?{queryParams}")); } // With the gathered resources, build a new JavaScriptResource. BuildJavaScript(data, jsonObject, supportsPromises, url); }
private bool EvidenceContainsUserAgent(IFlowData data) { return(data.TryGetEvidence("header.user-agent", out object _)); }
/// <summary> /// Build the JavaScript content and add it to the supplied /// <see cref="IFlowData"/> instance. /// </summary> /// <param name="data"> /// The <see cref="IFlowData"/> instance to populate with the /// resulting <see cref="JavaScriptBuilderElementData"/> /// </param> /// <param name="jsonObject"> /// The JSON data object to include in the JavaScript. /// </param> /// <param name="sessionId"> /// The session Id to use in the JavaScript response. /// </param> /// <param name="sequence"> /// The sequence value to use in the JavaScript response. /// </param> /// <param name="supportsPromises"> /// True to build JavaScript that uses promises. False to /// build JavaScript that does not use promises. /// </param> /// <param name="supportsFetch"> /// True to build JavaScript that makes use of the /// fetch API. Otherwise, the template will fall back to using /// XMLHttpRequest. /// </param> /// <param name="url"> /// The callback URL for the JavaScript to send a request to /// when it has new evidence values to supply. /// </param> /// <param name="parameters">The parameters to append to the URL</param> /// <exception cref="ArgumentNullException"> /// Thrown if the supplied flow data is null. /// </exception> protected void BuildJavaScript( IFlowData data, string jsonObject, string sessionId, int sequence, bool supportsPromises, bool supportsFetch, Uri url, string parameters) { if (data == null) { throw new ArgumentNullException(nameof(data)); } JavaScriptBuilderElementData elementData = (JavaScriptBuilderElementData) data.GetOrAdd( ElementDataKeyTyped, CreateElementData); string objectName = ObjName; // Try and get the requested object name from evidence. if (data.TryGetEvidence(Constants.EVIDENCE_OBJECT_NAME, out object objObjectName)) { objectName = objObjectName?.ToString() ?? ObjName; } var ubdateEnabled = url != null && url.AbsoluteUri.Length > 0; // This check won't be 100% fool-proof but it only needs to be // reasonably accurate and not take too long. var hasDelayedProperties = jsonObject != null && jsonObject.Contains("delayexecution"); JavaScriptResource javaScriptObj = new JavaScriptResource( objectName, jsonObject, sessionId, sequence, supportsPromises, supportsFetch, url, parameters, EnableCookies, ubdateEnabled, hasDelayedProperties); string content = _stubble.Render(_template, javaScriptObj.AsDictionary()); string minifiedContent = content; if (_minify) { // Minimize the script. var ugly = Uglify.Js(content); if (ugly.HasErrors) { // If there were are errors then log them and // return the non-minified response. minifiedContent = content; if (_lastRequestWasError == false) { StringBuilder errorText = new StringBuilder(); errorText.AppendLine("Errors occurred when minifying JavaScript."); foreach (var error in ugly.Errors) { errorText.AppendLine($"{error.ErrorCode}: {error.Message}. " + $"Line(s) {error.StartLine}-{error.EndLine}. " + $"Column(s) {error.StartColumn}-{error.EndColumn}"); } errorText.AppendLine(content); Logger.LogError(errorText.ToString()); _lastRequestWasError = true; #pragma warning disable CS0618 // Type or member is obsolete // This usage should be replaced with the // CancellationToken implementation once it // is available. data.Stop = true; #pragma warning restore CS0618 // Type or member is obsolete } } else { minifiedContent = ugly.Code; } } elementData.JavaScript = minifiedContent; }
private void SetUp(IFlowData data) { var host = Host; var protocol = Protocol; bool supportsPromises = false; bool supportsFetch = false; if (string.IsNullOrEmpty(host) && // Try and get the request host name so it can be used to request // the Json refresh in the JavaScript code. data.TryGetEvidence(Constants.EVIDENCE_HOST_KEY, out object hostObj)) { host = hostObj?.ToString() ?? String.Empty; } if (string.IsNullOrEmpty(protocol) && // Try and get the request protocol so it can be used to request // the JSON refresh in the JavaScript code. data.TryGetEvidence(Core.Constants.EVIDENCE_PROTOCOL, out object protocolObj)) { protocol = protocolObj?.ToString() ?? String.Empty; } // Couldn't get protocol from anywhere if (string.IsNullOrEmpty(protocol)) { protocol = Constants.DEFAULT_PROTOCOL; } // If device detection is in the Pipeline then we can check // if the client's browser supports promises. // This can be used to customize the JavaScript response. if (_promisePropertyAvailable) { // Execute this action if one of our expected // exceptions occurs. Action promisesNotAvailable = () => { // Short-circuit future calls, so we don't keep checking // for this property. _promisePropertyAvailable = false; supportsPromises = false; }; try { var promise = data.GetAs <IAspectPropertyValue <string> >("Promise"); supportsPromises = promise != null && promise.HasValue && promise.Value == "Full"; } catch (PropertyMissingException) { promisesNotAvailable(); } catch (PipelineDataException) { promisesNotAvailable(); } catch (InvalidCastException) { promisesNotAvailable(); } catch (KeyNotFoundException) { promisesNotAvailable(); } } // If device detection is in the Pipeline then we can check // if the client's browser supports fetch. // This can be used to customize the JavaScript response. if (_fetchPropertyAvailable) { // Execute this action if one of our expected // exceptions occurs. Action fetchNotAvailable = () => { // Short-circuit future calls, so we don't keep checking // for this property. _fetchPropertyAvailable = false; supportsFetch = false; }; try { var fetch = data.GetAs <IAspectPropertyValue <bool> >("Fetch"); supportsFetch = fetch != null && fetch.HasValue && fetch.Value; } catch (PropertyMissingException) { fetchNotAvailable(); } catch (PipelineDataException) { fetchNotAvailable(); } catch (InvalidCastException) { fetchNotAvailable(); } catch (KeyNotFoundException) { fetchNotAvailable(); } } // Get the JSON include to embed into the JavaScript include. string jsonObject = string.Empty; try { jsonObject = data.Get <IJsonBuilderElementData>().Json; } catch (KeyNotFoundException ex) { throw new PipelineConfigurationException( Messages.ExceptionJsonBuilderNotRun, ex); } var parameters = GetParameters(data); var paramsObject = JsonConvert.SerializeObject(parameters); var sessionId = GetSessionId(data); var sequence = GetSequence(data); string endpoint = Endpoint; Uri url = null; // Check the call-back URL is formatted correctly. if (string.IsNullOrWhiteSpace(protocol) == false && string.IsNullOrWhiteSpace(host) == false && string.IsNullOrWhiteSpace(endpoint) == false) { var endpointHasSlash = endpoint[0] == '/'; var hostHasSlash = host[host.Length - 1] == '/'; // if there is no slash between host and endpoint then add one. if (endpointHasSlash == false && hostHasSlash == false) { endpoint = $"/{endpoint}"; } // if there are two slashes between host and endpoint then remove one. else if (endpointHasSlash == true && hostHasSlash == true) { endpoint = endpoint.Substring(1); } url = new Uri($"{protocol}://{host}{endpoint}"); } // With the gathered resources, build a new JavaScriptResource. BuildJavaScript(data, jsonObject, sessionId, sequence, supportsPromises, supportsFetch, url, paramsObject); }