public void Apply(ControllerModel controller) { var routes = routeBuilder.GetTypedRoutes(); if (routes.ContainsKey(controller.ControllerType)) { var typedRoutes = routes[controller.ControllerType]; foreach (var route in typedRoutes) { var selectorModel = new SelectorModel { AttributeRouteModel = route }; var selectors = controller.Selectors; var action = controller.Actions.FirstOrDefault(x => x.ActionMethod == route.ActionMember); if (action != null) { foreach (var constraint in route.Constraints) { selectorModel.ActionConstraints.Add(constraint); } selectors = action.Selectors; } selectors.Clear(); selectors.Add(selectorModel); } } }
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); } }
private static void AddActionConstraints( ControllerActionDescriptor actionDescriptor, SelectorModel selectorModel, IEnumerable <IActionConstraintMetadata> controllerConstraints) { var constraints = new List <IActionConstraintMetadata>(); if (selectorModel.ActionConstraints != null) { constraints.AddRange(selectorModel.ActionConstraints); } if (controllerConstraints != null) { constraints.AddRange(controllerConstraints); } if (constraints.Count > 0) { actionDescriptor.ActionConstraints = constraints; } }
public void CopyConstructor_CopiesAllProperties() { // Arrange var controller = new ControllerModel( typeof(TestController).GetTypeInfo(), new List <object>() { new HttpGetAttribute(), new MyFilterAttribute(), }); var selectorModel = new SelectorModel(); selectorModel.ActionConstraints.Add(new HttpMethodActionConstraint(new string[] { "GET" })); controller.Selectors.Add(selectorModel); controller.Application = new ApplicationModel(); controller.ControllerName = "cool"; controller.Filters.Add(new MyFilterAttribute()); controller.RouteValues.Add("key", "value"); controller.Properties.Add(new KeyValuePair <object, object>("test key", "test value")); controller.ControllerProperties.Add( new PropertyModel(typeof(TestController).GetProperty("TestProperty"), new List <object>())); // Act var controller2 = new ControllerModel(controller); // Assert foreach (var property in typeof(ControllerModel).GetProperties()) { if (property.Name.Equals("Actions") || property.Name.Equals("Selectors") || property.Name.Equals("ApiExplorer") || property.Name.Equals("ControllerProperties")) { // This test excludes other ApplicationModel objects on purpose because we deep copy them. continue; } var value1 = property.GetValue(controller); var value2 = property.GetValue(controller2); 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 (typeof(IDictionary <string, string>).IsAssignableFrom(property.PropertyType)) { Assert.Equal(value1, value2); // Ensure non-default value Assert.NotEmpty((IDictionary <string, string>)value1); } else if (typeof(IDictionary <object, object>).IsAssignableFrom(property.PropertyType)) { Assert.Equal(value1, value2); // Ensure non-default value Assert.NotEmpty((IDictionary <object, 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 if (property.Name.Equals(nameof(ControllerModel.DisplayName))) { // DisplayName is re-calculated, hence reference equality wouldn't work. Assert.Equal(value1, value2); } else { Assert.Same(value1, value2); // Ensure non-default value Assert.NotNull(value1); } } }
private static bool IsEmptySelector(SelectorModel selector) { return selector.AttributeRouteModel == null && selector.ActionConstraints.IsNullOrEmpty(); }
private void AddAbpServiceSelector(string moduleName, string controllerName, ActionModel action, [CanBeNull] AbpServiceControllerSetting configuration) { var abpServiceSelectorModel = new SelectorModel { AttributeRouteModel = CreateAbpServiceAttributeRouteModel(moduleName, controllerName, action) }; var verb = configuration?.UseConventionalHttpVerbs == true ? ProxyScriptingHelper.GetConventionalVerbForMethodName(action.ActionName) : ProxyScriptingHelper.DefaultHttpVerb; abpServiceSelectorModel.ActionConstraints.Add(new HttpMethodActionConstraint(new[] { verb })); action.Selectors.Add(abpServiceSelectorModel); }
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 void CopyConstructor_CopiesAllProperties() { // Arrange var action = new ActionModel( typeof(TestController).GetMethod("Edit"), new List<object>() { new HttpGetAttribute(), new MyFilterAttribute(), }); var selectorModel = new SelectorModel(); selectorModel.ActionConstraints.Add(new HttpMethodActionConstraint(new string[] { "GET" })); action.Selectors.Add(selectorModel); action.ActionName = "Edit"; action.Controller = new ControllerModel(typeof(TestController).GetTypeInfo(), new List<object>()); action.Filters.Add(new MyFilterAttribute()); action.RouteConstraints.Add(new MyRouteConstraintAttribute()); action.Properties.Add(new KeyValuePair<object, object>("test key", "test value")); // Act var action2 = new ActionModel(action); // Assert foreach (var property in typeof(ActionModel).GetProperties()) { // Reflection is used to make sure the test fails when a new property is added. if (property.Name.Equals("ApiExplorer") || property.Name.Equals("Selectors") || property.Name.Equals("Parameters")) { // This test excludes other ApplicationModel objects on purpose because we deep copy them. continue; } var value1 = property.GetValue(action); var value2 = property.GetValue(action2); 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 (typeof(IDictionary<object, object>).IsAssignableFrom(property.PropertyType)) { Assert.Equal(value1, value2); // Ensure non-default value Assert.NotEmpty((IDictionary<object, 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); } } }
public void CopyConstructor_CopiesAllProperties() { // Arrange var action = new ActionModel( typeof(TestController).GetMethod("Edit"), new List <object>() { new HttpGetAttribute(), new MyFilterAttribute(), }); var selectorModel = new SelectorModel(); selectorModel.ActionConstraints.Add(new HttpMethodActionConstraint(new string[] { "GET" })); action.Selectors.Add(selectorModel); action.ActionName = "Edit"; action.Controller = new ControllerModel(typeof(TestController).GetTypeInfo(), new List <object>()); action.Filters.Add(new MyFilterAttribute()); action.RouteConstraints.Add(new MyRouteConstraintAttribute()); action.Properties.Add(new KeyValuePair <object, object>("test key", "test value")); // Act var action2 = new ActionModel(action); // Assert foreach (var property in typeof(ActionModel).GetProperties()) { // Reflection is used to make sure the test fails when a new property is added. if (property.Name.Equals("ApiExplorer") || property.Name.Equals("Selectors") || property.Name.Equals("Parameters")) { // This test excludes other ApplicationModel objects on purpose because we deep copy them. continue; } var value1 = property.GetValue(action); var value2 = property.GetValue(action2); 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 (typeof(IDictionary <object, object>).IsAssignableFrom(property.PropertyType)) { Assert.Equal(value1, value2); // Ensure non-default value Assert.NotEmpty((IDictionary <object, 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); } } }
private static void AddAttributeRoute(ControllerActionDescriptor actionDescriptor, SelectorModel selectorModel) { if (selectorModel.AttributeRouteModel != null) { actionDescriptor.AttributeRouteInfo = new AttributeRouteInfo { Template = selectorModel.AttributeRouteModel.Template, Order = selectorModel.AttributeRouteModel.Order ?? 0, Name = selectorModel.AttributeRouteModel.Name, SuppressLinkGeneration = selectorModel.AttributeRouteModel.SuppressLinkGeneration, SuppressPathMatching = selectorModel.AttributeRouteModel.SuppressPathMatching, }; } }
private static void AddEndpointMetadata(ControllerActionDescriptor actionDescriptor, SelectorModel selectorModel) { if (selectorModel.EndpointMetadata?.Count > 0) { actionDescriptor.EndpointMetadata = new List <object>(selectorModel.EndpointMetadata); } }
private static void AddActionConstraints(ControllerActionDescriptor actionDescriptor, SelectorModel selectorModel) { if (selectorModel.ActionConstraints?.Count > 0) { actionDescriptor.ActionConstraints = new List <IActionConstraintMetadata>(selectorModel.ActionConstraints); } }