public void CopyConstructor_DoesDeepCopyOfOtherModels() { // Arrange var action = new ActionModel(typeof(TestController).GetMethod(nameof(TestController.Edit)), new List<object>()); var parameter = new ParameterModel(action.ActionMethod.GetParameters()[0], new List<object>()); parameter.Action = action; action.Parameters.Add(parameter); var route = new AttributeRouteModel(new HttpGetAttribute("api/Products")); action.Selectors.Add(new SelectorModel() { AttributeRouteModel = route }); var apiExplorer = action.ApiExplorer; apiExplorer.IsVisible = false; apiExplorer.GroupName = "group1"; // Act var action2 = new ActionModel(action); // Assert Assert.NotSame(action, action2.Parameters[0]); Assert.NotSame(apiExplorer, action2.ApiExplorer); Assert.NotSame(action.Selectors, action2.Selectors); Assert.NotNull(action2.Selectors); Assert.Single(action2.Selectors); Assert.NotSame(route, action2.Selectors[0].AttributeRouteModel); }
public AttributeRouteModel(AttributeRouteModel other) { if (other == null) { throw new ArgumentNullException(nameof(other)); } Attribute = other.Attribute; Name = other.Name; Order = other.Order; Template = other.Template; }
public SelectorModel(SelectorModel other) { if (other == null) { throw new ArgumentNullException(nameof(other)); } ActionConstraints = new List<IActionConstraintMetadata>(other.ActionConstraints); if (other.AttributeRouteModel != null) { AttributeRouteModel = new AttributeRouteModel(other.AttributeRouteModel); } }
public SelectorModel(SelectorModel other) { if (other == null) { throw new ArgumentNullException(nameof(other)); } ActionConstraints = new List <IActionConstraintMetadata>(other.ActionConstraints); if (other.AttributeRouteModel != null) { AttributeRouteModel = new AttributeRouteModel(other.AttributeRouteModel); } }
/// <summary> /// Copy constructor for <see cref="AttributeRoute"/>. /// </summary> /// <param name="other">The <see cref="AttributeRouteModel"/> to copy.</param> public AttributeRouteModel(AttributeRouteModel other) { if (other == null) { throw new ArgumentNullException(nameof(other)); } Attribute = other.Attribute; Name = other.Name; Order = other.Order; Template = other.Template; SuppressLinkGeneration = other.SuppressLinkGeneration; SuppressPathMatching = other.SuppressPathMatching; }
public void ReplaceTokens_InvalidFormat(string template, Dictionary <string, string> values, string reason) { // Arrange var expected = string.Format( "The route template '{0}' has invalid syntax. {1}", template, reason); // Act var ex = Assert.Throws <InvalidOperationException>( () => { AttributeRouteModel.ReplaceTokens(template, values); }); // Assert Assert.Equal(expected, ex.Message); }
public void Combine_RightOverridesReflectedAttributeRouteModel( AttributeRouteModel left, AttributeRouteModel right) { // Arrange var expectedTemplate = AttributeRouteModel.CombineTemplates(null, right.Template); // Act var combined = AttributeRouteModel.CombineAttributeRouteModel(left, right); // Assert Assert.NotNull(combined); Assert.Equal(expectedTemplate, combined.Template); Assert.Equal(combined.Order, right.Order); }
public void ReplaceTokens_ValidValues(string template, object values, string expected) { // Arrange var valuesDictionary = values as IDictionary <string, object>; if (valuesDictionary == null) { valuesDictionary = new RouteValueDictionary(values); } // Act var result = AttributeRouteModel.ReplaceTokens(template, valuesDictionary); // Assert Assert.Equal(expected, result); }
private static AttributeRouteInfo CreateAttributeRouteInfo(AttributeRouteModel routeModel) { if (routeModel == null) { return(null); } return(new AttributeRouteInfo { Template = routeModel.Template, Order = routeModel.Order ?? DefaultAttributeRouteOrder, Name = routeModel.Name, SuppressLinkGeneration = routeModel.SuppressLinkGeneration, SuppressPathMatching = routeModel.SuppressPathMatching, }); }
public static IEnumerable <(AttributeRouteModel?route, SelectorModel actionSelector, SelectorModel?controllerSelector)> GetAttributeRoutes(ActionModel actionModel) { var controllerAttributeRoutes = actionModel.Controller.Selectors .Where(sm => sm.AttributeRouteModel != null) .Select(sm => sm.AttributeRouteModel) .ToList(); foreach (var actionSelectorModel in actionModel.Selectors) { var actionRouteModel = actionSelectorModel.AttributeRouteModel; // We check the action to see if the template allows combination behavior // (It doesn't start with / or ~/) so that in the case where we have multiple // [Route] attributes on the controller we don't end up creating multiple if (actionRouteModel != null && actionRouteModel.IsAbsoluteTemplate) { var route = AttributeRouteModel.CombineAttributeRouteModel( left: null, right: actionRouteModel); yield return(route, actionSelectorModel, null); } else if (controllerAttributeRoutes.Count > 0) { for (var i = 0; i < actionModel.Controller.Selectors.Count; i++) { // We're using the attribute routes from the controller var controllerSelector = actionModel.Controller.Selectors[i]; var route = AttributeRouteModel.CombineAttributeRouteModel( controllerSelector.AttributeRouteModel, actionRouteModel); yield return(route, actionSelectorModel, controllerSelector); } } else { var route = AttributeRouteModel.CombineAttributeRouteModel( left: null, right: actionRouteModel); yield return(route, actionSelectorModel, null); } } }
public void Combine_SetsSuppressPathGenerationToTrue_IfEitherIsTrue(bool leftSuppress, bool rightSuppress) { // Arrange var left = new AttributeRouteModel { Template = "Template", SuppressPathMatching = leftSuppress, }; var right = new AttributeRouteModel { SuppressPathMatching = rightSuppress, }; var combined = AttributeRouteModel.CombineAttributeRouteModel(left, right); // Assert Assert.True(combined.SuppressPathMatching); }
internal static PageConventionCollection AddAreaFolderRouteInternal(this PageConventionCollection conventions, string areaName, string folderPath, string folderRoute, bool isAdmin) { conventions.AddAreaFolderRouteModelConvention(areaName, folderPath, model => { if (isAdmin != (model.ViewEnginePath.Contains("/Admin/") || model.Properties.ContainsKey("Admin"))) { return; } var areaFolder = areaName + folderPath; foreach (var selector in model.Selectors.ToArray()) { var route = selector.AttributeRouteModel; if (route.Template.StartsWith(areaFolder, StringComparison.Ordinal) || (route.Template == areaName && folderPath == "/")) { route.SuppressLinkGeneration = true; string template; if (route.Template == areaName && folderPath == "/") { template = folderRoute; } else { var cleanSubTemplate = route.Template.Substring(areaFolder.Length).TrimStart('/'); template = AttributeRouteModel.CombineTemplates(folderRoute, cleanSubTemplate); } model.Selectors.Add(new SelectorModel { AttributeRouteModel = new AttributeRouteModel { Template = template } }); } } }); return(conventions); }
public void CopyConstructor_CopiesAllProperties() { // Arrange var route = new AttributeRouteModel(new HttpGetAttribute("/api/Products")) { Name = "products", Order = 5, SuppressLinkGeneration = true, SuppressPathMatching = true, }; // Act var route2 = new AttributeRouteModel(route); // Assert foreach (var property in typeof(AttributeRouteModel).GetProperties()) { var value1 = property.GetValue(route); var value2 = property.GetValue(route2); if (typeof(IEnumerable <object>).IsAssignableFrom(property.PropertyType)) { Assert.Equal <object>((IEnumerable <object>)value1, (IEnumerable <object>)value2); // Ensure non-default value Assert.NotEmpty((IEnumerable <object>)value1); } else if (property.PropertyType.IsValueType || Nullable.GetUnderlyingType(property.PropertyType) != null) { Assert.Equal(value1, value2); // Ensure non-default value Assert.NotEqual(value1, Activator.CreateInstance(property.PropertyType)); } else { Assert.Same(value1, value2); // Ensure non-default value Assert.NotNull(value1); } } }
public void CopyConstructor_DoesDeepCopyOfOtherModels() { // Arrange var action = new ActionModel(typeof(TestController).GetMethod(nameof(TestController.Edit)), new List <object>()); var parameter = new ParameterModel(action.ActionMethod.GetParameters()[0], new List <object>()); parameter.Action = action; action.Parameters.Add(parameter); var route = new AttributeRouteModel(new HttpGetAttribute("api/Products")); action.Selectors.Add(new SelectorModel() { AttributeRouteModel = route }); var apiExplorer = action.ApiExplorer; apiExplorer.IsVisible = false; apiExplorer.GroupName = "group1"; // Act var action2 = new ActionModel(action); // Assert Assert.NotSame(action.Parameters, action2.Parameters); Assert.NotNull(action2.Parameters); Assert.Single(action2.Parameters); Assert.NotSame(parameter, action2.Parameters[0]); Assert.NotSame(apiExplorer, action2.ApiExplorer); Assert.NotSame(action.Selectors, action2.Selectors); Assert.NotNull(action2.Selectors); Assert.Single(action2.Selectors); Assert.NotSame(action.Selectors[0], action2.Selectors[0]); Assert.NotSame(route, action2.Selectors[0].AttributeRouteModel); Assert.NotSame(action, action2.Parameters[0].Action); Assert.Same(action2, action2.Parameters[0].Action); }
public void CopyConstructor_DoesDeepCopyOfOtherModels() { // Arrange var controller = new ControllerModel(typeof(TestController).GetTypeInfo(), new List <object>()); var action = new ActionModel(typeof(TestController).GetMethod("Edit"), new List <object>()); controller.Actions.Add(action); action.Controller = controller; var route = new AttributeRouteModel(new HttpGetAttribute("api/Products")); controller.Selectors.Add(new SelectorModel() { AttributeRouteModel = route }); var apiExplorer = controller.ApiExplorer; controller.ApiExplorer.GroupName = "group"; controller.ApiExplorer.IsVisible = true; // Act var controller2 = new ControllerModel(controller); // Assert Assert.NotSame(action, controller2.Actions[0]); Assert.NotNull(controller2.Selectors); Assert.Single(controller2.Selectors); Assert.NotSame(route, controller2.Selectors[0].AttributeRouteModel); Assert.NotSame(apiExplorer, controller2.ApiExplorer); Assert.NotSame(controller.Selectors[0].ActionConstraints, controller2.Selectors[0].ActionConstraints); Assert.NotSame(controller.Actions, controller2.Actions); Assert.NotSame(controller.Attributes, controller2.Attributes); Assert.NotSame(controller.Filters, controller2.Filters); Assert.NotSame(controller.RouteValues, controller2.RouteValues); }
private static void PopulateRouteModel(PageRouteModel model, string pageRoute, string? routeTemplate) { model.RouteValues.Add("page", model.ViewEnginePath); var selectorModel = CreateSelectorModel(pageRoute, routeTemplate); model.Selectors.Add(selectorModel); var fileName = Path.GetFileName(model.RelativePath); if (!AttributeRouteModel.IsOverridePattern(routeTemplate) && string.Equals(IndexFileName, fileName, StringComparison.OrdinalIgnoreCase)) { // For pages without an override route, and ending in /Index.cshtml, we want to allow // incoming routing, but force outgoing routes to match to the path sans /Index. selectorModel.AttributeRouteModel!.SuppressLinkGeneration = true; var index = pageRoute.LastIndexOf('/'); var parentDirectoryPath = index == -1 ? string.Empty : pageRoute.Substring(0, index); model.Selectors.Add(CreateSelectorModel(parentDirectoryPath, routeTemplate)); } }
public void ReplaceTokens_UnknownValue(string template, string token) { // Arrange var values = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase) { { "area", "Help" }, { "controller", "Admin" }, { "action", "SeeUsers" }, }; var expected = $"While processing template '{template}', " + $"a replacement value for the token '{token}' could not be found. " + "Available tokens: 'action, area, controller'. To use a '[' or ']' as a literal string in a " + "route or within a constraint, use '[[' or ']]' instead."; // Act var ex = Assert.Throws <InvalidOperationException>( () => { AttributeRouteModel.ReplaceTokens(template, values); }); // Assert Assert.Equal(expected, ex.Message); }
public void Apply(ApplicationModel application) { var centralPrefix = new AttributeRouteModel(new RouteAttribute($"{routingModel.Prefix}/{routingModel.Controller}")); foreach (var controller in application.Controllers) { if (controller.ControllerType.UnderlyingSystemType == typeof(AppConfigurationController)) { var hasRouteAttributes = controller.Selectors.Any(selector => selector.AttributeRouteModel != null); if (hasRouteAttributes) { // This controller manually defined some routes, so treat this // as an override and not apply the convention here. continue; } foreach (var selector in controller.Selectors) { selector.AttributeRouteModel = centralPrefix; } } } }
public void ReplaceTokens_UnknownValue() { // Arrange var template = "[area]/[controller]/[action2]"; var values = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase) { { "area", "Help" }, { "controller", "Admin" }, { "action", "SeeUsers" }, }; var expected = "While processing template '[area]/[controller]/[action2]', " + "a replacement value for the token 'action2' could not be found. " + "Available tokens: 'action, area, controller'."; // Act var ex = Assert.Throws <InvalidOperationException>( () => { AttributeRouteModel.ReplaceTokens(template, values); }); // Assert Assert.Equal(expected, ex.Message); }
public void Combine_Names( AttributeRouteModel left, AttributeRouteModel right, string expectedName) { // Arrange & Act var combined = AttributeRouteModel.CombineAttributeRouteModel(left, right); // Assert Assert.NotNull(combined); Assert.Equal(expectedName, combined.Name); }
private static string ChooseName( AttributeRouteModel left, AttributeRouteModel right) { if (right.Name == null && string.IsNullOrEmpty(right.Template)) { return left.Name; } else { return right.Name; } }
public void Combine_NullOrNullTemplateReflectedAttributeRouteModels( AttributeRouteModel left, AttributeRouteModel right) { // Arrange & Act var combined = AttributeRouteModel.CombineAttributeRouteModel(left, right); // Assert Assert.Null(combined); }
public static IEnumerable <SelectorModel> FlattenSelectors(ActionModel actionModel) { // Loop through all attribute routes defined on the controller. // These perform a cross-product with all of the action-level attribute routes. var controllerSelectors = actionModel.Controller.Selectors .Where(sm => sm.AttributeRouteModel != null) .ToList(); // We also include metadata and action constraints from the controller // even when there are no routes, or when an action overrides the route template. SelectorModel?additionalSelector = null; if (actionModel.Controller.Selectors.Count > 0) { // This logic seems arbitrary but there's a good reason for it. // // When we build the controller level selectors, any metadata or action constraints // that aren't IRouteTemplateProvider will be included in all selectors. So we // pick any selector and then grab all of the stuff that isn't IRouteTemplateProvider // then we've found all of the items that aren't routes. // // This is fragile wrt application model customizing the data - but no one has // run into an issue with this and its pretty esoteric. additionalSelector = new SelectorModel(actionModel.Controller.Selectors.First()); additionalSelector.AttributeRouteModel = null; for (var i = additionalSelector.ActionConstraints.Count - 1; i >= 0; i--) { if (additionalSelector.ActionConstraints[i] is IRouteTemplateProvider) { additionalSelector.ActionConstraints.RemoveAt(i); } } for (var i = additionalSelector.EndpointMetadata.Count - 1; i >= 0; i--) { if (additionalSelector.EndpointMetadata[i] is IRouteTemplateProvider) { additionalSelector.EndpointMetadata.RemoveAt(i); } } } var actionConstraints = new List <IActionConstraintMetadata>(); foreach (var actionSelector in actionModel.Selectors) { var actionRouteModel = actionSelector.AttributeRouteModel; // We check the action to see if the template allows combination behavior // (It doesn't start with / or ~/) so that in the case where we have multiple // [Route] attributes on the controller we don't end up creating multiple if (actionRouteModel != null && actionRouteModel.IsAbsoluteTemplate) { // We're overriding the routes from the controller, but any *unbound* constraints // still apply. var selector = new SelectorModel(actionSelector); selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel( left: null, right: actionRouteModel); AddActionConstraints(selector, additionalSelector?.ActionConstraints); AddEndpointMetadata(selector, additionalSelector?.EndpointMetadata); yield return(selector); } else if (controllerSelectors.Count > 0) { for (var i = 0; i < controllerSelectors.Count; i++) { var controllerSelector = controllerSelectors[i]; // We're using the attribute routes from the controller var selector = new SelectorModel(actionSelector); selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel( controllerSelector.AttributeRouteModel, actionRouteModel); AddActionConstraints(selector, controllerSelector.ActionConstraints); AddEndpointMetadata(selector, controllerSelector.EndpointMetadata); // No need to include the additional selector here because it would duplicate // data in controllerSelector. yield return(selector); } } else { // There are no routes on the controller, but any *unbound* constraints // still apply. var selector = new SelectorModel(actionSelector); selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel( left: null, right: actionRouteModel); AddActionConstraints(selector, additionalSelector?.ActionConstraints); AddEndpointMetadata(selector, additionalSelector?.EndpointMetadata); yield return(selector); } } }
public GlobalRoutePrefixConvention(IRouteTemplateProvider routeTemplateProvider) { _centralPrefix = new AttributeRouteModel(routeTemplateProvider); }
public void Combine_Orders( AttributeRouteModel left, AttributeRouteModel right, int? expected) { // Arrange & Act var combined = AttributeRouteModel.CombineAttributeRouteModel(left, right); // Assert Assert.NotNull(combined); Assert.Equal(expected, combined.Order); }
/// <summary> /// Combines two <see cref="AttributeRouteModel"/> instances and returns /// a new <see cref="AttributeRouteModel"/> instance with the result. /// </summary> /// <param name="left">The left <see cref="AttributeRouteModel"/>.</param> /// <param name="right">The right <see cref="AttributeRouteModel"/>.</param> /// <returns>A new instance of <see cref="AttributeRouteModel"/> that represents the /// combination of the two <see cref="AttributeRouteModel"/> instances or <c>null</c> if both /// parameters are <c>null</c>.</returns> public static AttributeRouteModel CombineAttributeRouteModel( AttributeRouteModel left, AttributeRouteModel right) { right = right ?? _default; // If the right template is an override template (starts with / or ~/) // we ignore the values from left. if (left == null || IsOverridePattern(right.Template)) { left = _default; } var combinedTemplate = CombineTemplates(left.Template, right.Template); // The action is not attribute routed. if (combinedTemplate == null) { return null; } return new AttributeRouteModel() { Template = combinedTemplate, Order = right.Order ?? left.Order, Name = ChooseName(left, right), }; }
public void Combine_ValidReflectedAttributeRouteModels( AttributeRouteModel left, AttributeRouteModel right, AttributeRouteModel expectedResult) { // Arrange & Act var combined = AttributeRouteModel.CombineAttributeRouteModel(left, right); // Assert Assert.NotNull(combined); Assert.Equal(expectedResult.Template, combined.Template); }
private static ControllerActionDescriptor CreateActionDescriptor(ActionModel action, AttributeRouteModel routeModel) { var parameterDescriptors = new List <ParameterDescriptor>(); foreach (var parameter in action.Parameters) { var parameterDescriptor = CreateParameterDescriptor(parameter); parameterDescriptors.Add(parameterDescriptor); } var actionDescriptor = new ControllerActionDescriptor { ActionName = action.ActionName, MethodInfo = action.ActionMethod, Parameters = parameterDescriptors, AttributeRouteInfo = CreateAttributeRouteInfo(routeModel), }; return(actionDescriptor); }
public void CopyConstructor_CopiesAllProperties() { // Arrange var route = new AttributeRouteModel(new HttpGetAttribute("/api/Products")); route.Name = "products"; route.Order = 5; // Act var route2 = new AttributeRouteModel(route); // Assert foreach (var property in typeof(AttributeRouteModel).GetProperties()) { var value1 = property.GetValue(route); var value2 = property.GetValue(route2); if (typeof(IEnumerable<object>).GetTypeInfo().IsAssignableFrom(property.PropertyType.GetTypeInfo())) { Assert.Equal<object>((IEnumerable<object>)value1, (IEnumerable<object>)value2); // Ensure non-default value Assert.NotEmpty((IEnumerable<object>)value1); } else if (property.PropertyType.GetTypeInfo().IsValueType || Nullable.GetUnderlyingType(property.PropertyType) != null) { Assert.Equal(value1, value2); // Ensure non-default value Assert.NotEqual(value1, Activator.CreateInstance(property.PropertyType)); } else { Assert.Same(value1, value2); // Ensure non-default value Assert.NotNull(value1); } } }