public VisualStudio2015SolutionTemplate(IApplication application, VisualStudioSolutionModel model, IEnumerable <IVisualStudioProject> projects) { Application = application; Model = model; BindingContext = new TemplateBindingContext(new VisualStudio2015SolutionTemplateModel(Application)); Projects = projects; }
private bool AllRequiredParametersHaveValue(TemplateBindingContext context) { for (var i = 0; i < _template.Parameters.Count; i++) { var parameter = _template.Parameters[i]; if (parameter.IsOptional || parameter.IsCatchAll) { continue; } if (!context.AcceptedValues.ContainsKey(parameter.Name)) { // We don't have a value for this parameter, so we can't generate a url. return(false); } } return(true); }
private void CopyParameterDefaultValues(TemplateBindingContext context) { for (var i = 0; i < _template.Parameters.Count; i++) { var parameter = _template.Parameters[i]; if (parameter.IsOptional || parameter.IsCatchAll) { continue; } if (context.NeedsValue(parameter.Name)) { // Add the default value only if there isn't already a new value for it and // only if it actually has a default value, which we determine based on whether // the parameter value is required. context.AcceptDefault(parameter.Name); } } }
private void CopyNonParameterAmbientValues( RouteValueDictionary ambientValues, RouteValueDictionary combinedValues, TemplateBindingContext context) { if (ambientValues == null) { return; } foreach (var kvp in ambientValues) { if (IsRoutePartNonEmpty(kvp.Value)) { var parameter = GetParameter(kvp.Key); if (parameter == null && !context.AcceptedValues.ContainsKey(kvp.Key)) { combinedValues.Add(kvp.Key, kvp.Value); } } } }
internal TemplateValuesResult GetValues( RouteValueDictionary ambientValues, RouteValueDictionary explicitValues, IEnumerable <string> requiredKeys) { var context = new TemplateBindingContext(_defaults); var canCopyParameterAmbientValues = true; // In case a route template is not parameterized, we do not know what the required parameters are, so look // at required values of an endpoint to get the key names and then use them to decide if ambient values // should be used. // For example, in case of MVC it flattens out a route template like below // {controller}/{action}/{id?} // to // Products/Index/{id?}, // defaults: new { controller = "Products", action = "Index" }, // requiredValues: new { controller = "Products", action = "Index" } // In the above example, "controller" and "action" are no longer parameters. if (requiredKeys != null) { canCopyParameterAmbientValues = CanCopyParameterAmbientValues( ambientValues: ambientValues, explicitValues: explicitValues, requiredKeys); } if (canCopyParameterAmbientValues) { // Copy ambient values when no explicit values are provided CopyParameterAmbientValues( ambientValues: ambientValues, explicitValues: explicitValues, context); } // Add all remaining new values to the list of values we will use for URI generation CopyNonParamaterExplicitValues(explicitValues, context); // Accept all remaining default values if they match a required parameter CopyParameterDefaultValues(context); if (!AllRequiredParametersHaveValue(context)) { return(null); } // Any default values that don't appear as parameters are treated like filters. Any new values // provided must match these defaults. if (!FiltersMatch(explicitValues)) { return(null); } // Add any ambient values that don't match parameters - they need to be visible to constraints // but they will ignored by link generation. var combinedValues = new RouteValueDictionary(context.AcceptedValues); CopyNonParameterAmbientValues( ambientValues: ambientValues, combinedValues: combinedValues, context); return(new TemplateValuesResult() { AcceptedValues = context.AcceptedValues, CombinedValues = combinedValues, }); }
private void CopyNonParamaterExplicitValues(RouteValueDictionary explicitValues, TemplateBindingContext context) { foreach (var kvp in explicitValues) { if (IsRoutePartNonEmpty(kvp.Value)) { context.Accept(kvp.Key, kvp.Value); } } }
private void CopyParameterAmbientValues( RouteValueDictionary ambientValues, RouteValueDictionary explicitValues, TemplateBindingContext context) { // Find out which entries in the URI are valid for the URI we want to generate. // If the URI had ordered parameters a="1", b="2", c="3" and the new values // specified that b="9", then we need to invalidate everything after it. The new // values should then be a="1", b="9", c=<no value>. // // We also handle the case where a parameter is optional but has no value - we shouldn't // accept additional parameters that appear *after* that parameter. for (var i = 0; i < _template.Parameters.Count; i++) { var parameter = _template.Parameters[i]; // If it's a parameter subsegment, examine the current value to see if it matches the new value var parameterName = parameter.Name; var hasExplicitValue = explicitValues.TryGetValue(parameterName, out var explicitValue); object ambientValue = null; var hasAmbientValue = ambientValues != null && ambientValues.TryGetValue(parameterName, out ambientValue); if (hasExplicitValue && hasAmbientValue && !RoutePartsEqual(ambientValue, explicitValue)) { // Stop copying current values when we find one that doesn't match break; } if (!hasExplicitValue && !hasAmbientValue && _defaults?.ContainsKey(parameter.Name) != true) { // This is an unsatisfied parameter value and there are no defaults. We might still // be able to generate a URL but we should stop 'accepting' ambient values. // // This might be a case like: // template: a/{b?}/{c?} // ambient: { c = 17 } // values: { } // // We can still generate a URL from this ("/a") but we shouldn't accept 'c' because // we can't use it. // // In the example above we should fall into this block for 'b'. break; } // If the parameter is a match, add it to the list of values we will use for URI generation if (hasExplicitValue) { if (IsRoutePartNonEmpty(explicitValue)) { context.Accept(parameterName, explicitValue); } } else if (hasAmbientValue) { context.Accept(parameterName, ambientValue); } } }
// Step 1: Get the list of values we're going to try to use to match and generate this URI public TemplateValuesResult GetValues(IDictionary <string, object> ambientValues, IDictionary <string, object> values) { var context = new TemplateBindingContext(_defaults, values); // Find out which entries in the URI are valid for the URI we want to generate. // If the URI had ordered parameters a="1", b="2", c="3" and the new values // specified that b="9", then we need to invalidate everything after it. The new // values should then be a="1", b="9", c=<no value>. for (var i = 0; i < _template.Parameters.Count; i++) { var parameter = _template.Parameters[i]; // If it's a parameter subsegment, examine the current value to see if it matches the new value var parameterName = parameter.Name; object newParameterValue; var hasNewParameterValue = values.TryGetValue(parameterName, out newParameterValue); object currentParameterValue = null; var hasCurrentParameterValue = ambientValues != null && ambientValues.TryGetValue(parameterName, out currentParameterValue); if (hasNewParameterValue && hasCurrentParameterValue) { if (!RoutePartsEqual(currentParameterValue, newParameterValue)) { // Stop copying current values when we find one that doesn't match break; } } // If the parameter is a match, add it to the list of values we will use for URI generation if (hasNewParameterValue) { if (IsRoutePartNonEmpty(newParameterValue)) { context.Accept(parameterName, newParameterValue); } } else { if (hasCurrentParameterValue) { context.Accept(parameterName, currentParameterValue); } } } // Add all remaining new values to the list of values we will use for URI generation foreach (var kvp in values) { if (IsRoutePartNonEmpty(kvp.Value)) { context.Accept(kvp.Key, kvp.Value); } } // Accept all remaining default values if they match a required parameter for (var i = 0; i < _template.Parameters.Count; i++) { var parameter = _template.Parameters[i]; if (parameter.IsOptional || parameter.IsCatchAll) { continue; } if (context.NeedsValue(parameter.Name)) { // Add the default value only if there isn't already a new value for it and // only if it actually has a default value, which we determine based on whether // the parameter value is required. context.AcceptDefault(parameter.Name); } } // Validate that all required parameters have a value. for (var i = 0; i < _template.Parameters.Count; i++) { var parameter = _template.Parameters[i]; if (parameter.IsOptional || parameter.IsCatchAll) { continue; } if (!context.AcceptedValues.ContainsKey(parameter.Name)) { // We don't have a value for this parameter, so we can't generate a url. return(null); } } // Any default values that don't appear as parameters are treated like filters. Any new values // provided must match these defaults. if (context.Filters != null) { foreach (var filter in context.Filters) { var parameter = GetParameter(filter.Key); if (parameter != null) { continue; } object value; if (values.TryGetValue(filter.Key, out value)) { if (!RoutePartsEqual(value, filter.Value)) { // If there is a non-parameterized value in the route and there is a // new value for it and it doesn't match, this route won't match. return(null); } } } } // Add any ambient values that don't match parameters - they need to be visible to constraints // but they will ignored by link generation. var combinedValues = new RouteValueDictionary(context.AcceptedValues); if (ambientValues != null) { foreach (var kvp in ambientValues) { if (IsRoutePartNonEmpty(kvp.Value)) { var parameter = GetParameter(kvp.Key); if (parameter == null && !context.AcceptedValues.ContainsKey(kvp.Key)) { combinedValues.Add(kvp.Key, kvp.Value); } } } } return(new TemplateValuesResult() { AcceptedValues = context.AcceptedValues, CombinedValues = combinedValues, }); }
// Step 1: Get the list of values we're going to try to use to match and generate this URI public TemplateValuesResult GetValues(RouteValueDictionary ambientValues, RouteValueDictionary values) { var context = new TemplateBindingContext(_defaults); // Find out which entries in the URI are valid for the URI we want to generate. // If the URI had ordered parameters a="1", b="2", c="3" and the new values // specified that b="9", then we need to invalidate everything after it. The new // values should then be a="1", b="9", c=<no value>. for (var i = 0; i < _template.Parameters.Count; i++) { var parameter = _template.Parameters[i]; // If it's a parameter subsegment, examine the current value to see if it matches the new value var parameterName = parameter.Name; object newParameterValue; var hasNewParameterValue = values.TryGetValue(parameterName, out newParameterValue); object currentParameterValue = null; var hasCurrentParameterValue = ambientValues != null && ambientValues.TryGetValue(parameterName, out currentParameterValue); if (hasNewParameterValue && hasCurrentParameterValue) { if (!RoutePartsEqual(currentParameterValue, newParameterValue)) { // Stop copying current values when we find one that doesn't match break; } } // If the parameter is a match, add it to the list of values we will use for URI generation if (hasNewParameterValue) { if (IsRoutePartNonEmpty(newParameterValue)) { context.Accept(parameterName, newParameterValue); } } else { if (hasCurrentParameterValue) { context.Accept(parameterName, currentParameterValue); } } } // Add all remaining new values to the list of values we will use for URI generation foreach (var kvp in values) { if (IsRoutePartNonEmpty(kvp.Value)) { context.Accept(kvp.Key, kvp.Value); } } // Accept all remaining default values if they match a required parameter for (var i = 0; i < _template.Parameters.Count; i++) { var parameter = _template.Parameters[i]; if (parameter.IsOptional || parameter.IsCatchAll) { continue; } if (context.NeedsValue(parameter.Name)) { // Add the default value only if there isn't already a new value for it and // only if it actually has a default value, which we determine based on whether // the parameter value is required. context.AcceptDefault(parameter.Name); } } // Validate that all required parameters have a value. for (var i = 0; i < _template.Parameters.Count; i++) { var parameter = _template.Parameters[i]; if (parameter.IsOptional || parameter.IsCatchAll) { continue; } if (!context.AcceptedValues.ContainsKey(parameter.Name)) { // We don't have a value for this parameter, so we can't generate a url. return null; } } // Any default values that don't appear as parameters are treated like filters. Any new values // provided must match these defaults. foreach (var filter in _filters) { var parameter = GetParameter(filter.Key); if (parameter != null) { continue; } object value; if (values.TryGetValue(filter.Key, out value)) { if (!RoutePartsEqual(value, filter.Value)) { // If there is a non-parameterized value in the route and there is a // new value for it and it doesn't match, this route won't match. return null; } } } // Add any ambient values that don't match parameters - they need to be visible to constraints // but they will ignored by link generation. var combinedValues = new RouteValueDictionary(context.AcceptedValues); if (ambientValues != null) { foreach (var kvp in ambientValues) { if (IsRoutePartNonEmpty(kvp.Value)) { var parameter = GetParameter(kvp.Key); if (parameter == null && !context.AcceptedValues.ContainsKey(kvp.Key)) { combinedValues.Add(kvp.Key, kvp.Value); } } } } return new TemplateValuesResult() { AcceptedValues = context.AcceptedValues, CombinedValues = combinedValues, }; }
// Step 1: Get the list of values we're going to try to use to match and generate this URI public (DispatcherValueCollection acceptedValues, DispatcherValueCollection combinedValues) GetValues(DispatcherValueCollection ambientValues, DispatcherValueCollection values) { var context = new TemplateBindingContext(_defaults); // Find out which entries in the URI are valid for the URI we want to generate. // If the URI had ordered parameters a="1", b="2", c="3" and the new values // specified that b="9", then we need to invalidate everything after it. The new // values should then be a="1", b="9", c=<no value>. // // We also handle the case where a parameter is optional but has no value - we shouldn't // accept additional parameters that appear *after* that parameter. for (var i = 0; i < _pattern.Parameters.Count; i++) { var parameter = _pattern.Parameters[i]; // If it's a parameter subsegment, examine the current value to see if it matches the new value var parameterName = parameter.Name; var hasNewParameterValue = values.TryGetValue(parameterName, out var newParameterValue); object currentParameterValue = null; var hasCurrentParameterValue = ambientValues != null && ambientValues.TryGetValue(parameterName, out currentParameterValue); if (hasNewParameterValue && hasCurrentParameterValue) { if (!RoutePartsEqual(currentParameterValue, newParameterValue)) { // Stop copying current values when we find one that doesn't match break; } } if (!hasNewParameterValue && !hasCurrentParameterValue && _defaults?.ContainsKey(parameter.Name) != true) { // This is an unsatisfied parameter value and there are no defaults. We might still // be able to generate a URL but we should stop 'accepting' ambient values. // // This might be a case like: // template: a/{b?}/{c?} // ambient: { c = 17 } // values: { } // // We can still generate a URL from this ("/a") but we shouldn't accept 'c' because // we can't use it. // // In the example above we should fall into this block for 'b'. break; } // If the parameter is a match, add it to the list of values we will use for URI generation if (hasNewParameterValue) { if (IsRoutePartNonEmpty(newParameterValue)) { context.Accept(parameterName, newParameterValue); } } else { if (hasCurrentParameterValue) { context.Accept(parameterName, currentParameterValue); } } } // Add all remaining new values to the list of values we will use for URI generation foreach (var kvp in values) { if (IsRoutePartNonEmpty(kvp.Value)) { context.Accept(kvp.Key, kvp.Value); } } // Accept all remaining default values if they match a required parameter for (var i = 0; i < _pattern.Parameters.Count; i++) { var parameter = _pattern.Parameters[i]; if (parameter.IsOptional || parameter.IsCatchAll) { continue; } if (context.NeedsValue(parameter.Name)) { // Add the default value only if there isn't already a new value for it and // only if it actually has a default value, which we determine based on whether // the parameter value is required. context.AcceptDefault(parameter.Name); } } // Validate that all required parameters have a value. for (var i = 0; i < _pattern.Parameters.Count; i++) { var parameter = _pattern.Parameters[i]; if (parameter.IsOptional || parameter.IsCatchAll) { continue; } if (!context.AcceptedValues.ContainsKey(parameter.Name)) { // We don't have a value for this parameter, so we can't generate a url. return(null, null); } } // Any default values that don't appear as parameters are treated like filters. Any new values // provided must match these defaults. foreach (var filter in _filters) { var parameter = _pattern.GetParameter(filter.Key); if (parameter != null) { continue; } if (values.TryGetValue(filter.Key, out var value)) { if (!RoutePartsEqual(value, filter.Value)) { // If there is a non-parameterized value in the route and there is a // new value for it and it doesn't match, this route won't match. return(null, null); } } } // Add any ambient values that don't match parameters - they need to be visible to constraints // but they will ignored by link generation. var combinedValues = new DispatcherValueCollection(context.AcceptedValues); if (ambientValues != null) { foreach (var kvp in ambientValues) { if (IsRoutePartNonEmpty(kvp.Value)) { var parameter = _pattern.GetParameter(kvp.Key); if (parameter == null && !context.AcceptedValues.ContainsKey(kvp.Key)) { combinedValues.Add(kvp.Key, kvp.Value); } } } } return(context.AcceptedValues, combinedValues); }