/// <inheritdoc /> public void Apply(ActionModel action) { var attribute = action.Attributes.OfType <WebHookAttribute>().FirstOrDefault(); if (attribute == null) { // Not a WebHook handler. return; } var template = ChooseTemplate(action.RouteValues); var selectors = action.Selectors; if (selectors.Count == 0) { var selector = new SelectorModel(); selectors.Add(selector); AddTemplate(attribute, template, selector); } else { for (var i = 0; i < selectors.Count; i++) { var selector = selectors[i]; AddTemplate(attribute, template, selector); } } AddConstraints(attribute, selectors); AddConstraints(action.Properties, selectors); if (action.Properties.TryGetValue(typeof(IWebHookBodyTypeMetadata), out var bodyTypeMetadata)) { action.Filters.Add(new WebHookVerifyBodyTypeFilter( (IWebHookBodyTypeMetadata)bodyTypeMetadata, _loggerFactory)); } }
public void AppliesToActionForPostActionWorksAsExpected(string actionName, string expected) { // Arrange ControllerModel controller = ControllerModelHelpers.BuildControllerModel <CustomersController>(actionName); ActionModel action = controller.Actions.First(); ODataControllerActionContext context = ODataControllerActionContextHelpers.BuildContext(string.Empty, EdmModel, controller); context.Action = controller.Actions.First(); EntitySetRoutingConvention entitySetConvention = ConventionHelpers.CreateConvention <EntitySetRoutingConvention>(); // Act bool returnValue = entitySetConvention.AppliesToAction(context); Assert.True(returnValue); // Assert SelectorModel selector = Assert.Single(action.Selectors); Assert.Equal(expected, selector.AttributeRouteModel.Template); }
// this method refers to the similar method in ASP.NET Core internal static SelectorModel CreateSelectorModel(IReadOnlyList <object> attributes) { var selectorModel = new SelectorModel(); AddRange(selectorModel.ActionConstraints, attributes.OfType <IActionConstraintMetadata>()); AddRange(selectorModel.EndpointMetadata, attributes); // Simple case, all HTTP method attributes apply var httpMethods = attributes .OfType <IActionHttpMethodProvider>() .SelectMany(a => a.HttpMethods) .Distinct(StringComparer.OrdinalIgnoreCase) .ToArray(); if (httpMethods.Length > 0) { selectorModel.ActionConstraints.Add(new HttpMethodActionConstraint(httpMethods)); selectorModel.EndpointMetadata.Add(new HttpMethodMetadata(httpMethods)); } return(selectorModel); }
public void AppliesToActionForEntityActionWithDerivedEntityTypeWorksAsExpected(string actionName) { // Arrange ControllerModel controller = ControllerModelHelpers.BuildControllerModel <CustomersController>(actionName); ActionModel action = controller.Actions.First(); ODataControllerActionContext context = ODataControllerActionContextHelpers.BuildContext(string.Empty, EdmModel, controller); context.Action = action; EntityRoutingConvention entityConvention = ConventionHelpers.CreateConvention <EntityRoutingConvention>(); // Act bool returnValue = entityConvention.AppliesToAction(context); Assert.True(returnValue); // Assert SelectorModel selector = Assert.Single(action.Selectors); Assert.Equal("Customers(FirstName={keyFirstName},LastName={keyLastName})/NS.VipCustomer", selector.AttributeRouteModel.Template); }
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 AppliesToActionDoesNothingForNotSupportedAction(string actionName) { // Arrange ControllerModel controller = ControllerModelHelpers.BuildControllerModel <AnotherCustomersController>(actionName); ActionModel action = controller.Actions.First(); ODataControllerActionContext context = ODataControllerActionContextHelpers.BuildContext(string.Empty, EdmModel, controller); context.Action = controller.Actions.First(); EntityRoutingConvention entityConvention = ConventionHelpers.CreateConvention <EntityRoutingConvention>(); // Act bool returnValue = entityConvention.AppliesToAction(context); Assert.False(returnValue); // Assert SelectorModel selector = Assert.Single(action.Selectors); Assert.Null(selector.AttributeRouteModel); }
protected virtual void TranslateActionRoute(ActionModel localizedActionModel, SelectorModel originalSelectorModel, string template, string culture) { Logger.LogDebug( $"Add translated selector for action {localizedActionModel.Controller.ControllerName}:{localizedActionModel.ActionName} with \"{template}\" ({culture})."); localizedActionModel.ThrowIfNotLocalizedModel(RouteTranslationConfiguration.Localizer); if (RouteTranslationConfiguration.ValidateUrl) { ValidateUrl(originalSelectorModel.AttributeRouteModel.Template, template); } // Don't add RoutePrefix twice if (RouteTranslationConfiguration.AddCultureAsRoutePrefix && !localizedActionModel.Controller .GetOriginalModel(RouteTranslationConfiguration.Localizer) .HasAttributeRoutes()) { template = RouteTranslationConfiguration.Localizer.ApplyRouteCulturePrefix(template, culture); } SelectorModel localizedSelectorModel = new SelectorModel(originalSelectorModel) { AttributeRouteModel = { Template = template, }, }; localizedActionModel.Selectors.Add(localizedSelectorModel); RouteTranslationConfiguration.OnActionRouteTranslated(this, new OnActionRouteTranslatedEventArgs() { OriginalActionModel = localizedActionModel.GetOriginalModel(RouteTranslationConfiguration.Localizer), LocalizedActionModel = localizedActionModel, OriginalSelectorModel = originalSelectorModel, LocalizedSelectorModel = localizedSelectorModel, }); }
/// <summary> /// /// </summary> /// <param name="action"></param> /// <param name="prefix"></param> /// <param name="model"></param> /// <param name="template"></param> public static void AddSelector(this ActionModel action, string prefix, IEdmModel model, ODataPathTemplate template) { if (action == null) { throw new ArgumentNullException(nameof(action)); } if (prefix == null) { throw new ArgumentNullException(nameof(prefix)); } if (model == null) { throw new ArgumentNullException(nameof(model)); } if (template == null) { throw new ArgumentNullException(nameof(template)); } SelectorModel selectorModel = action.Selectors.FirstOrDefault(s => s.AttributeRouteModel == null); if (selectorModel == null) { selectorModel = new SelectorModel(); action.Selectors.Add(selectorModel); } string templateStr = string.IsNullOrEmpty(prefix) ? template.Template : $"{prefix}/{template.Template}"; selectorModel.AttributeRouteModel = new AttributeRouteModel(new RouteAttribute(templateStr) { Name = templateStr }); selectorModel.EndpointMetadata.Add(new ODataEndpointMetadata(prefix, model, template)); }
public void AppliesToActionForSingletonDoesnotWorksAsExpected() { // Arrange ControllerModel controller = ControllerModelHelpers.BuildControllerModel <SingletonTestControllerWithPrefix>("GetVipCustomerAliasWithPrefix"); ActionModel action = controller.Actions.First(); ODataControllerActionContext context = new ODataControllerActionContext(string.Empty, _edmModel, controller); context.Action = action; context.Options = _options; // Act bool ok = _attributeConvention.AppliesToAction(context); Assert.False(ok); // Assert SelectorModel selector = Assert.Single(action.Selectors); Assert.NotNull(selector.AttributeRouteModel); Assert.Equal("Alias", selector.AttributeRouteModel.Template); Assert.DoesNotContain(selector.EndpointMetadata, a => a is ODataRoutingMetadata); }
public string Search(string regName, string key, string ds, int?pageSize, int?pageIndex) { var pagination = new Pagination(); pagination.PageSize = pageSize ?? 28; pagination.PageIndex = pageIndex ?? 0; SetPostDataSet(ds); key = key ?? ""; var dt = GetCodeTableInstance(regName); pagination.AppendToDataSet(PostDataSet, regName); var res = dt.Search(PostDataSet, key); //pagination.TotalCount = res.Count(); SelectorModel model = new SelectorModel(); model.List = res.ToList(); model.Index = pagination.PageIndex; model.Size = pagination.PageSize; model.Total = PostDataSet.Tables[regName + "_PAGER"].Rows[0]["TotalCount"].Value <int>(); //res = res.Skip((pagination.PageIndex - 1) * pagination.PageSize).Take(pagination.PageSize).ToList(); return(ReturnJson(model == null ? new SelectorModel() : model)); }
public void AppliesToAction_Works_ForPatchActionWorksAsExpected(Type controllerType, string actionName, string expected, bool ignoreCase) { // Arrange ControllerModel controller = ControllerModelHelpers.BuildControllerModel(controllerType, actionName); ActionModel action = controller.Actions.First(); ODataControllerActionContext context = ODataControllerActionContextHelpers.BuildContext(string.Empty, EdmModel, controller); context.Action = controller.Actions.First(); context.Options.RouteOptions.EnableActionNameCaseInsensitive = ignoreCase; EntitySetRoutingConvention entitySetConvention = ConventionHelpers.CreateConvention <EntitySetRoutingConvention>(); // Act bool returnValue = entitySetConvention.AppliesToAction(context); Assert.True(returnValue); // Assert SelectorModel selector = Assert.Single(action.Selectors); Assert.Equal(expected, selector.AttributeRouteModel.Template); }
public void Apply(ControllerModel controller) { if (!options.Controllers.TryGetValue(controller.ControllerType, out var metadata)) { return; } var model = new SelectorModel { AttributeRouteModel = metadata.Template == null ? null : new AttributeRouteModel( new RouteAttribute(metadata.Template) { Name = metadata.ActionName }) }; foreach (var constraint in metadata.ActionConstraints) { model.ActionConstraints.Add(constraint(provider)); } foreach (var filter in metadata.Filters) { controller.Filters.Add(filter(provider)); } var conventions = controller.Selectors.Where(s => s.AttributeRouteModel == null).ToList(); foreach (var convention in conventions) { controller.Selectors.Remove(convention); } controller.Selectors.Insert(0, model); }
private void AddVersion(ApplicationModel application, string version, IReadOnlyDictionary <string, TypeInfo> controllers, Dictionary <string, ControllerModel> versionedModels) { foreach (KeyValuePair <string, TypeInfo> controller in controllers) { string controllerTypeName = controller.Value.AssemblyQualifiedName; var controllerModel = new ControllerModel(versionedModels[controllerTypeName]) { ControllerName = $"{controller.Key}/{version}", RouteValues = { ["version"] = version, }, }; if (controllerModel.Selectors.Count > 1) { throw new InvalidOperationException("Versioned Controllers cannot have more than one route."); } RemoveApiRemovedActions(controllerModel); SelectorModel selector = controllerModel.Selectors.Count == 1 ? controllerModel.Selectors[0] : GetDefaultControllerSelector(controller); if (selector.AttributeRouteModel.IsAbsoluteTemplate) { throw new InvalidOperationException( "versioned api controllers are not allowed to have absolute routes."); } controllerModel.Selectors.Clear(); Options.VersioningScheme.Apply(selector, version); controllerModel.Selectors.Add(selector); application.Controllers.Add(controllerModel); controllerModel.Application = application; } }
public void Apply(ControllerModel controller) { var newSelectors = new List <SelectorModel>(); //Controller has Attribute Route var matchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel != null).ToList(); if (matchedSelectors.Any()) { foreach (var selectorModel in matchedSelectors) { var routeModel = AttributeRouteModel.CombineAttributeRouteModel(_culturePrefix, selectorModel.AttributeRouteModel); if (_optional) { var newSelector = new SelectorModel(); newSelector.AttributeRouteModel = routeModel; newSelector.AttributeRouteModel.Order = -1; newSelectors.Add(newSelector); } else { selectorModel.AttributeRouteModel = routeModel; } } } foreach (var action in controller.Actions) { Apply(action); } foreach (var newSelector in newSelectors) { controller.Selectors.Insert(0, newSelector); } }
public void Apply(PageRouteModel model) { var path = model.ViewEnginePath; var lastSeparator = path.LastIndexOf('/'); Debug.Assert(lastSeparator != -1); var lastDot = path.LastIndexOf('.', path.Length - 1, path.Length - lastSeparator); // /SomeFolder/MyPage.fr-FR -> fr-FR if (lastDot != -1) { var cultureName = path.Substring(lastDot + 1); var constraint = new CultureConstraint(new CultureInfo(cultureName)); for (var i = model.Selectors.Count - 1; i >= 0; i--) { var selector = model.Selectors[i]; selector.ActionConstraints.Add(constraint); var template = selector.AttributeRouteModel.Template; template = template.Substring(0, lastDot - 1); selector.AttributeRouteModel.Template = template; var fileName = template.Substring(lastSeparator); if (fileName == "Index") { selector.AttributeRouteModel.SuppressLinkGeneration = true; var indexSelector = new SelectorModel(selector); template = selector.AttributeRouteModel.Template.Substring(0, lastSeparator); indexSelector.AttributeRouteModel.Template = template; model.Selectors.Add(indexSelector); } } } }
public void AppliesToActionForSingletonWorksAsExpected(string actionName, string expectedTemplate) { // Arrange ControllerModel controller = ControllerModelHelpers.BuildControllerModel <SingletonTestControllerWithPrefix>(actionName); ActionModel action = controller.Actions.First(); ODataControllerActionContext context = new ODataControllerActionContext(string.Empty, _edmModel, controller); context.Action = action; context.Options = _options; AttributeRoutingConvention attributeConvention = CreateConvention(); // Act bool ok = _attributeConvention.AppliesToAction(context); Assert.False(ok); // Assert SelectorModel selector = Assert.Single(action.Selectors); Assert.NotNull(selector.AttributeRouteModel); Assert.Equal(expectedTemplate, selector.AttributeRouteModel.Template); Assert.Contains(selector.EndpointMetadata, a => a is ODataRoutingMetadata); }
private void Apply(ActionModel action) { var attribute = action.Attributes.OfType <WebHookAttribute>().FirstOrDefault(); if (attribute == null) { // Not a WebHook handler. return; } var template = ChooseTemplate(); var selectors = action.Selectors; if (selectors.Count == 0) { var selector = new SelectorModel(); selectors.Add(selector); AddTemplate(attribute, template, selector); } else { for (var i = 0; i < selectors.Count; i++) { var selector = selectors[i]; AddTemplate(attribute, template, selector); } } var properties = action.Properties; AddEventMapperConstraint(properties, selectors); AddEventNamesConstraint(properties, selectors); AddIdConstraint(attribute, selectors); AddReceiverExistsConstraint(properties, selectors); }
public static SelectorModel CreateSelectorModel(IRouteTemplateProvider route, IList <object> attributes) { var selectorModel = new SelectorModel(); if (route != null) { selectorModel.AttributeRouteModel = new AttributeRouteModel(route); } AddRange(selectorModel.ActionConstraints, attributes.OfType <IActionConstraintMetadata>()); var httpMethods = attributes .OfType <IActionHttpMethodProvider>() .SelectMany(a => a.HttpMethods) .Distinct(StringComparer.OrdinalIgnoreCase) .ToArray(); if (httpMethods.Length > 0) { selectorModel.ActionConstraints.Add(new HttpMethodActionConstraint(httpMethods)); } return(selectorModel); }
public static HudSelector FromModel(SelectorModel model, TextStyle textStyle) => model == null ? null : new HudSelector(model, textStyle);
private HudSelector(SelectorModel model, TextStyle textStyle) : this(model.Label, model.Tooltip, textStyle, model.Color, model.OnClick, model.OnHover) { }
private static bool IsEmptySelector(SelectorModel selector) { return(selector.AttributeRouteModel == null && selector.ActionConstraints.IsNullOrEmpty()); }
public void Apply(ApplicationModel application) { var controller = application.Controllers.FirstOrDefault( x => x.ControllerType == typeof(CompositeResourceController).GetTypeInfo()); // composites/v{compositeVersion}/{school year if year specific}/{organizationCode}/{compositeCategoryName (regex constraint}/{compositeName}/{id?} // the composite category is constrained by a regex expression // the id is optional // the attribute on the controller is composites if (controller != null) { var defaultRouteSuffix = new AttributeRouteModel { Template = CreateRouteTemplate() + "{compositeName}/{id?}" }; // the composite controller has only one selector and if more are added this should break var selector = controller.Selectors.SingleOrDefault(); if (selector.AttributeRouteModel != null) { // composites have children routes that need to be added to the controller. var routeMetadataGroupedByCompositeCategory = _compositesMetadataProvider.GetAllRoutes(); foreach (var routeGrouping in routeMetadataGroupedByCompositeCategory) { foreach (var routeElt in routeGrouping.Value) { string relativeRouteTemplate = routeElt.AttributeValue("relativeRouteTemplate") .TrimStart('/'); var routeSuffix = new AttributeRouteModel { Template = CreateRouteTemplate() + relativeRouteTemplate }; var childSelector = new SelectorModel { AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel( selector.AttributeRouteModel, routeSuffix) }; controller.Selectors.Add(childSelector); } } // set the base selector with the correct route selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel( selector.AttributeRouteModel, defaultRouteSuffix); } } string CreateRouteTemplate() { string template = $"v{ApiVersionConstants.Composite}/"; if (_apiSettings.GetApiMode() == ApiMode.YearSpecific) { template += RouteConstants.SchoolYearFromRoute; } if (_apiSettings.GetApiMode() == ApiMode.InstanceYearSpecific) { template += RouteConstants.InstanceIdFromRoute; template += RouteConstants.SchoolYearFromRoute; } var compositeCategoryNames = _compositesMetadataProvider .GetAllCategories() .Select(x => x.Name) .ToList <string>(); string allCompositeCategoriesConstraintExpression = $@"^(?i)({string.Join("|", compositeCategoryNames)})$"; string categoryName = "{organizationCode}/{compositeCategory}/"; template += categoryName; return(template); } }
public void Apply(SelectorModel model, string version) { AttributeRouteModel attributeRouteModel = model.AttributeRouteModel; attributeRouteModel.Template = $"api/{version}/{attributeRouteModel.Template}"; }
public void Apply(ActionModel action) { var attributeRoutes = action.Selectors.Where(x => x.AttributeRouteModel != null).ToList(); var newSelectors = new List <SelectorModel>(); //check if it's within an area var areaAttribute = action.Controller.Attributes.FirstOrDefault(x => x.GetType() == typeof(AreaAttribute)); var area = ""; if (areaAttribute != null) { area = "/" + ((AreaAttribute)areaAttribute).RouteValue; } foreach (var ar in attributeRoutes) { if (!action.Properties.ContainsKey("RouteName")) { action.Properties.Add("RouteName", ar.AttributeRouteModel.Name); } if (ar.AttributeRouteModel.Attribute is IDualRouteAttribute) { var dualRouteAttribute = (IDualRouteAttribute)ar.AttributeRouteModel.Attribute; if (dualRouteAttribute.OnlyApi) { var currentTemplate = ar.AttributeRouteModel.Template; if (currentTemplate.StartsWith("~/")) { ar.AttributeRouteModel.Template = area + "/" + ApplicationConfig.ApiEndpointName + "/" + currentTemplate.Replace("~/", ""); } else { ar.AttributeRouteModel.Template = area + "/" + ApplicationConfig.ApiEndpointName + "/[controller]/" + currentTemplate; } ar.AttributeRouteModel.Name = $"{ApplicationConfig.ApiEndpointName}_" + ar.AttributeRouteModel.Name; continue; //skip adding anything else } //add another route for api var selectorModel = new SelectorModel(ar); var newAm = selectorModel.AttributeRouteModel; if (newAm.Template.StartsWith("~/")) { newAm.Template = area + "/" + ApplicationConfig.ApiEndpointName + "/" + newAm.Template.Replace("~/", ""); } else { newAm.Template = area + "/" + ApplicationConfig.ApiEndpointName + "/[controller]/" + newAm.Template; } if (newAm.Name != null) { newAm.Name = $"{ApplicationConfig.ApiEndpointName}_" + newAm.Name; } newSelectors.Add(selectorModel); } else if (ar.AttributeRouteModel.Attribute is DynamicRouteAttribute) { #if DEBUGWS continue; #endif var dynamicRoute = (DynamicRouteAttribute)ar.AttributeRouteModel.Attribute; var template = dynamicRoute.DynamicTemplate; if (template.IsNullEmptyOrWhiteSpace()) { var settingService = DependencyResolver.Resolve <ISettingService>(); var settingName = dynamicRoute.SettingName; var setting = settingService.FirstOrDefault(x => x.GroupName == nameof(UrlSettings) && x.Key == settingName); if (setting == null) { continue; } template = dynamicRoute.TemplatePrefix + setting.Value + dynamicRoute.TemplateSuffix; } var dynamicRouteProvider = DependencyResolver.Resolve <IDynamicRouteProvider>(); dynamicRouteProvider.RegisterDynamicRoute(new RouteData() { Template = template, ActionName = action.ActionName, ControllerName = action.Controller.ControllerName, RouteName = dynamicRoute.Name, Order = dynamicRoute.Order, SeoEntityName = dynamicRoute.SeoEntityName, ParameterName = dynamicRoute.ParameterName }); } } foreach (var ns in newSelectors) { action.Selectors.Add(ns); } }
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); } } }
protected virtual bool IsEmptySelector(SelectorModel selector) { return(selector.AttributeRouteModel == null && selector.ActionConstraints.IsNullOrEmpty()); }
public void Apply(ActionModel action) { var newSelectors = new List <SelectorModel>(); //Action has Attribute Route var matchedSelectors = action.Selectors.Where(x => x.AttributeRouteModel != null).ToList(); if (matchedSelectors.Any()) { foreach (var selectorModel in matchedSelectors) { //https://andrewlock.net/applying-the-routedatarequest-cultureprovider-globally-with-middleware-as-filters/ if (selectorModel.AttributeRouteModel.Template != null && selectorModel.AttributeRouteModel.Template.StartsWith("~/")) { var path = selectorModel.AttributeRouteModel.Template.Length > 2 ? $"/{selectorModel.AttributeRouteModel.Template.Substring(2)}" : ""; var routeModel = new AttributeRouteModel(new RouteAttribute($"~/{_culturePrefix.Template}{path}")); if (_optional) { var newSelector = new SelectorModel(); newSelector.AttributeRouteModel = routeModel; newSelector.AttributeRouteModel.Order = -1; newSelectors.Add(newSelector); } else { selectorModel.AttributeRouteModel = routeModel; } } //https://andrewlock.net/applying-the-routedatarequest-cultureprovider-globally-with-middleware-as-filters/ else if (selectorModel.AttributeRouteModel.Template != null && selectorModel.AttributeRouteModel.Template.StartsWith("/")) { var path = selectorModel.AttributeRouteModel.Template.Length > 1 ? $"/{selectorModel.AttributeRouteModel.Template.Substring(1)}" : ""; var routeModel = new AttributeRouteModel(new RouteAttribute($"/{_culturePrefix.Template}{path}")); if (_optional) { var newSelector = new SelectorModel(); newSelector.AttributeRouteModel = routeModel; newSelector.AttributeRouteModel.Order = -1; newSelectors.Add(newSelector); } else { selectorModel.AttributeRouteModel = routeModel; } } //Controller doesn't have Attribute Route else if (action.Controller.Selectors.Where(x => x.AttributeRouteModel == null).ToList().Any()) { var routeModel = AttributeRouteModel.CombineAttributeRouteModel(_culturePrefix, selectorModel.AttributeRouteModel); if (_optional) { var newSelector = new SelectorModel(); newSelector.AttributeRouteModel = routeModel; newSelector.AttributeRouteModel.Order = -1; newSelectors.Add(newSelector); } else { selectorModel.AttributeRouteModel = routeModel; } } } } foreach (var newSelector in newSelectors) { action.Selectors.Insert(0, newSelector); } }
private void AddRoutePrefixToExistingRoute(SelectorModel selector) { selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_routePrefix, selector.AttributeRouteModel); }
/// <summary> /// /// </summary> /// <param name="application"></param> public void Apply(ApplicationModel application) { var controllerRegister = Env.Instance.ApplicationServices.GetService <IServiceRegister>(); if (controllerRegister == null) { return; } var controllers = controllerRegister.GetAll(); foreach (var controller in controllers) { var controllName = controller.Name; if (controllName.EndsWith("Controller")) { controllName = controllName.Substring(0, controllName.Length - "Controller".Length); } var controllAttrs = controller.GetCustomAttributes().ToList(); var routeAttr = (RouteAttribute)controllAttrs.Find(x => typeof(RouteAttribute).IsAssignableFrom(x.GetType())); var model = new ControllerModel(controller.GetTypeInfo(), controllAttrs); model.ControllerName = controllName; //model.ControllerName = controllName; string template = $"{controllName}"; if (routeAttr != null) { template = routeAttr.Template; } model.Selectors.Add(new SelectorModel() { AttributeRouteModel = new AttributeRouteModel() { Template = template } }); var methods = controller.GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); foreach (var method in methods) { var methodAttrs = method.GetCustomAttributes().ToList(); var httpAttr = (HttpMethodAttribute)methodAttrs.Find(x => typeof(HttpMethodAttribute).IsAssignableFrom(x.GetType())); string actionTemplate = method.Name; if (httpAttr != null && !string.IsNullOrWhiteSpace(httpAttr.Template)) { actionTemplate = httpAttr.Template; } //methodAttrs.Add(new SwaggerOperationAttribute(method.Name)); var actionModel = new ActionModel(method, methodAttrs); actionModel.ActionName = method.Name; actionModel.Controller = model; //actionModel.Selectors.Add(new SelectorModel()); var selectModel = new SelectorModel() { AttributeRouteModel = new AttributeRouteModel() { Template = actionTemplate } }; if (httpAttr != null) { selectModel.ActionConstraints.Add(new HttpMethodActionConstraint(httpAttr.HttpMethods) { }); } actionModel.Selectors.Add(selectModel); var paras = method.GetParameters(); foreach (var p in paras) { var paraAttrs = p.GetCustomAttributes().ToList(); ParameterModel pm = new ParameterModel(p, paraAttrs); pm.Action = actionModel; pm.ParameterName = p.Name; var fromBodyAttr = p.GetCustomAttribute <FromBodyAttribute>(); var fromFormAttr = p.GetCustomAttribute <FromFormAttribute>(); var fromQueryAttr = p.GetCustomAttribute <FromQueryAttribute>(); var fromHeaderAttr = p.GetCustomAttribute <FromHeaderAttribute>(); var fromRouteAttr = p.GetCustomAttribute <FromRouteAttribute>(); var fromServicesAttr = p.GetCustomAttribute <FromServicesAttribute>(); if (fromBodyAttr != null) { pm.BindingInfo = new Microsoft.AspNetCore.Mvc.ModelBinding.BindingInfo(); pm.BindingInfo.BindingSource = new Microsoft.AspNetCore.Mvc.ModelBinding.BindingSource("Body", "Body", true, true); } else if (fromFormAttr != null) { pm.BindingInfo = new Microsoft.AspNetCore.Mvc.ModelBinding.BindingInfo(); pm.BindingInfo.BindingSource = new Microsoft.AspNetCore.Mvc.ModelBinding.BindingSource("Form", "Form", true, true); } else if (fromQueryAttr != null) { pm.BindingInfo = new Microsoft.AspNetCore.Mvc.ModelBinding.BindingInfo(); pm.BindingInfo.BindingSource = new Microsoft.AspNetCore.Mvc.ModelBinding.BindingSource("Query", "Query", true, true); } else if (fromHeaderAttr != null) { pm.BindingInfo = new Microsoft.AspNetCore.Mvc.ModelBinding.BindingInfo(); pm.BindingInfo.BindingSource = new Microsoft.AspNetCore.Mvc.ModelBinding.BindingSource("Header", "Header", true, true); } else if (fromRouteAttr != null) { pm.BindingInfo = new Microsoft.AspNetCore.Mvc.ModelBinding.BindingInfo(); pm.BindingInfo.BindingSource = new Microsoft.AspNetCore.Mvc.ModelBinding.BindingSource("Route", "Route", true, true); } else if (fromServicesAttr != null) { pm.BindingInfo = new Microsoft.AspNetCore.Mvc.ModelBinding.BindingInfo(); pm.BindingInfo.BindingSource = new Microsoft.AspNetCore.Mvc.ModelBinding.BindingSource("Services", "Services", true, true); } actionModel.Parameters.Add(pm); } model.Actions.Add(actionModel); } application.Controllers.Add(model); } }
/// <summary> /// Adds the OData selector model to the action. /// </summary> /// <param name="action">The given action model.</param> /// <param name="httpMethods">The supported http methods, if multiple, using ',' to separate.</param> /// <param name="prefix">The prefix.</param> /// <param name="model">The Edm model.</param> /// <param name="path">The OData path template.</param> /// <param name="options">The route build options.</param> public static void AddSelector(this ActionModel action, string httpMethods, string prefix, IEdmModel model, ODataPathTemplate path, ODataRouteOptions options = null) { if (action == null) { throw Error.ArgumentNull(nameof(action)); } if (string.IsNullOrEmpty(httpMethods)) { throw Error.ArgumentNullOrEmpty(nameof(httpMethods)); } if (model == null) { throw Error.ArgumentNull(nameof(model)); } if (path == null) { throw Error.ArgumentNull(nameof(path)); } // if the controller has attribute route decorated, for example: // [Route("api/[controller]")] // public class CustomersController : Controller // {} // let's always create new selector model for action. // Since the new created selector model is absolute attribute route, the controller attribute route doesn't apply to this selector model. bool hasAttributeRouteOnController = action.Controller.Selectors.Any(s => s.AttributeRouteModel != null); // If the methods have different case sensitive, for example, "get", "Get", in the ASP.NET Core 3.1, // It will throw "An item with the same key has already been added. Key: GET", in // HttpMethodMatcherPolicy.BuildJumpTable(Int32 exitDestination, IReadOnlyList`1 edges) // Another root cause is that in attribute routing, we reuse the HttpMethodMetadata, the method name is always "upper" case. // Therefore, we upper the http method name always. string[] methods = httpMethods.ToUpperInvariant().Split(','); foreach (string template in path.GetTemplates(options)) { // Be noted: https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/ApplicationModels/ActionAttributeRouteModel.cs#L74-L75 // No matter whether the action selector model is absolute route template, the controller's attribute will apply automatically // So, let's only create/update the action selector model SelectorModel selectorModel = action.Selectors.FirstOrDefault(s => s.AttributeRouteModel == null); if (hasAttributeRouteOnController || selectorModel == null) { // Create a new selector model. selectorModel = CreateSelectorModel(action, methods); action.Selectors.Add(selectorModel); } else { // Update the existing non attribute routing selector model. selectorModel = UpdateSelectorModel(selectorModel, methods); } ODataRoutingMetadata odataMetadata = new ODataRoutingMetadata(prefix, model, path); selectorModel.EndpointMetadata.Add(odataMetadata); string templateStr = string.IsNullOrEmpty(prefix) ? template : $"{prefix}/{template}"; selectorModel.AttributeRouteModel = new AttributeRouteModel { // OData convention route template doesn't get combined with the route template applied to the controller. // Route templates applied to an action that begin with / or ~/ don't get combined with route templates applied to the controller. Template = $"/{templateStr}", Name = templateStr // do we need this? }; // Check with .NET Team whether the "Endpoint name metadata" needed? selectorModel.EndpointMetadata.Add(new EndpointNameMetadata(Guid.NewGuid().ToString())); // Do we need this? } }