public static bool TryGetResolver(string value, out BindingParameterResolver resolver) { if (string.IsNullOrEmpty(value)) { throw new ArgumentNullException("value"); } resolver = _resolvers.FirstOrDefault(p => value.StartsWith(p.Name, StringComparison.OrdinalIgnoreCase)); return(resolver != null); }
public static bool IsSystemParameter(string value) { if (string.IsNullOrEmpty(value)) { throw new ArgumentNullException("value"); } BindingParameterResolver resolver = null; return(TryGetResolver(value, out resolver)); }
internal static bool IsValidIdentifier(string identifier) { // built-in sysetem identifiers are valid if (BindingParameterResolver.IsSystemParameter(identifier)) { return(true); } // match against our identifier regex // note that system identifiers include a '-' character so wouldn't // pass this test return(Regex.IsMatch(identifier, IdentifierPattern)); }
public static BindingTemplateToken NewExpression(string expression) { // BindingData takes precedence over builtins. BindingParameterResolver builtin; BindingParameterResolver.TryGetResolver(expression, out builtin); // check for formatter, which is applied to finale results. string format = null; if (builtin == null) { int indexColon = expression.IndexOf(':'); if (indexColon > 0) { format = expression.Substring(indexColon + 1); expression = expression.Substring(0, indexColon); } } if (!BindingTemplateParser.IsValidIdentifier(expression)) { throw new FormatException($"Invalid template expression '{expression}"); } // Expression is just a series of dot operators like: a.b.c var parts = expression.Split('.'); // For backwards compat, first part can't have a '-' if (builtin == null) { if (parts[0].IndexOf('-') >= 0) { throw new FormatException($"The parameter name '{parts[0]}' is invalid."); } } foreach (var part in parts) { if (string.IsNullOrWhiteSpace(part)) { throw new InvalidOperationException($"Illegal expression: {parts}"); } } return(new ExpressionToken(parts, format, builtin)); }
/// <summary> /// Resolves original parameterized template into a string by replacing parameters with values provided as /// a dictionary. /// </summary> /// <param name="parameters">Dictionary providing parameter values.</param> /// <returns>Resolved string if succeeded.</returns> /// <exception cref="InvalidOperationException">Thrown when required parameter value is not available. /// </exception> public string Bind(IReadOnlyDictionary <string, string> parameters) { StringBuilder builder = new StringBuilder(); if (_ignoreCase && parameters != null) { // convert to a case insensitive dictionary var caseInsensitive = new Dictionary <string, string>(parameters.Count, StringComparer.OrdinalIgnoreCase); foreach (var pair in parameters) { caseInsensitive.Add(pair.Key, pair.Value); } parameters = caseInsensitive; } foreach (BindingTemplateToken token in Tokens) { if (token.IsParameter) { string value; BindingParameterResolver resolver = null; if (parameters != null && parameters.TryGetValue(token.Value, out value)) { // parameter is resolved from binding data builder.Append(value); } else if (BindingParameterResolver.TryGetResolver(token.Value, out resolver)) { // parameter maps to one of the built-in system binding // parameters (e.g. rand-guid, datetime, etc.) value = resolver.Resolve(token.Value); builder.Append(value); } else { throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "No value for named parameter '{0}'.", token.Value)); } } else { builder.Append(token.Value); } } return(builder.ToString()); }
public ExpressionToken(string[] expressionParts, string format, BindingParameterResolver builtin) { _expressionParts = expressionParts; _builtin = builtin; _format = format; }