public void Apply(ApplicationModel application) { var matchedSelectors = application.Controllers.FirstOrDefault(c => c.ControllerType == typeof(T))?.Selectors; if (matchedSelectors != null && matchedSelectors.Any()) { var centralPrefix = new AttributeRouteModel(_routeTemplateProvider); foreach (var selectorModel in matchedSelectors) { selectorModel.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(centralPrefix, selectorModel.AttributeRouteModel); } } }
public void ConfigureServices(IServiceCollection services) { // Register the db context, but do not specify a provider/connection // string since these vary by tenant. services.AddDbContext <ApplicationDbContext>(); services.AddIdentity <ApplicationUser, ApplicationRole>() .AddEntityFrameworkStores <ApplicationDbContext>() .AddDefaultTokenProviders(); services.Configure <DataProtectionTokenProviderOptions>(options => { options.TokenLifespan = TimeSpan.FromDays(1.0); }); services.Configure <IdentityOptions>(options => { // Default Password settings. options.Password.RequireDigit = false; options.Password.RequireLowercase = false; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = false; options.Password.RequiredLength = 6; options.Password.RequiredUniqueChars = 1; }); //services.AddControllersWithViews().AddRazorRuntimeCompilation(); services.AddRazorPages(options => { // Since we are using the route multitenant strategy we must add the // route parameter to the Pages conventions used by Identity. options.Conventions.AddAreaFolderRouteModelConvention("Identity", "/Account", model => { foreach (var selector in model.Selectors) { selector.AttributeRouteModel.Template = AttributeRouteModel.CombineTemplates("{__tenant__}", selector.AttributeRouteModel.Template); } }); }); services.DecorateService <LinkGenerator, AmbientValueLinkGenerator>(new List <string> { "__tenant__" }); services.AddMultiTenant <ApplicationTenantInfo>() .WithRouteStrategy() .WithConfigurationStore() .WithPerTenantAuthentication(); }
public ApiPrefixConvention() { //These are meant to be combined with existing route attributes _apiPrefix = new AttributeRouteModel( new RouteAttribute("api/")); _apiCulturePrefix = new AttributeRouteModel( new RouteAttribute("api/{language:regex(^[[a-z]]{{2}}(?:-[[A-Z]]{{2}})?$)}/")); //These are meant to be added as routes for api controllers that do not specify any route attribute _apiRouteWithController = new AttributeRouteModel( new RouteAttribute("api/[controller]")); _apiCultureRouteWithController = new AttributeRouteModel( new RouteAttribute("api/{language:regex(^[[a-z]]{{2}}(?:-[[A-Z]]{{2}})?$)}/[controller]")); }
/// <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 Apply(ControllerModel controller) { foreach (var selector in controller.Selectors) { if (selector.AttributeRouteModel != null) { selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_routePrefix, selector.AttributeRouteModel); } else { selector.AttributeRouteModel = _routePrefix; } } }
public void Apply(ApplicationModel application) { foreach (var selector in application.Controllers.Where(c => c.Filters.Any(f => f is IApiBehaviorMetadata)).SelectMany(c => c.Selectors)) { if (selector.AttributeRouteModel != null) { selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_routePrefix, selector.AttributeRouteModel); } else { selector.AttributeRouteModel = _routePrefix; } } }
public void Apply(ApplicationModel applicationModel) { foreach (var controller in applicationModel.Controllers.SelectMany(x => x.Selectors)) { if (controller.AttributeRouteModel != null) { controller.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_attributeRouteModel, controller.AttributeRouteModel); } else { controller.AttributeRouteModel = _attributeRouteModel; } } }
/// <summary> /// Called to apply the convention to the <see cref="T:Microsoft.AspNetCore.Mvc.ApplicationModels.ApplicationModel" />. /// </summary> /// <param name="application">The <see cref="T:Microsoft.AspNetCore.Mvc.ApplicationModels.ApplicationModel" />.</param> public void Apply(ApplicationModel application) { foreach (var selector in application.Controllers.SelectMany(c => c.Selectors)) { if (selector.AttributeRouteModel != null) { selector.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_routePrefix, selector.AttributeRouteModel); } else { selector.AttributeRouteModel = _routePrefix; } } }
public void ConfigureServices(IServiceCollection services) { // Register the db context, but do not specify a provider/connection // string since these vary by tenant. services.AddDbContext <ApplicationDbContext>(); services.AddIdentity <IdentityUser, IdentityRole>() .AddDefaultTokenProviders() .AddDefaultUI(UIFramework.Bootstrap4) .AddEntityFrameworkStores <ApplicationDbContext>(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .AddMvcOptions(options => options.EnableEndpointRouting = false) .AddRazorPagesOptions(options => { // Since we are using the route multitenant strategy we must add the // route parameter to the Pages conventions used by Identity. options.Conventions.AddAreaFolderRouteModelConvention("Identity", "/Account", model => { foreach (var selector in model.Selectors) { selector.AttributeRouteModel.Template = AttributeRouteModel.CombineTemplates("{__tenant__}", selector.AttributeRouteModel.Template); } }); }); services.AddMultiTenant() .WithRouteStrategy(ConfigRoutes) .WithInMemoryStore(Configuration.GetSection("Finbuckle:MultiTenant:InMemoryStore")) .WithPerTenantOptions <CookieAuthenticationOptions>((options, tenantInfo) => { // Since we are using the route strategy configure each tenant // to have a different cookie name and adjust the paths. options.Cookie.Name = $"{tenantInfo.Id}_{options.Cookie.Name}"; // See below for why this is commented out. //options.LoginPath = $"/{tenantInfo.Identifier}/Home/Login"; //options.LogoutPath = $"/{tenantInfo.Identifier}"; options.Cookie.Path = $"/{tenantInfo.Identifier}"; }); // Required due to a bug in ASP.NET Core Identity (https://github.com/aspnet/Identity/issues/2019) services.PostConfigure <CookieAuthenticationOptions>(IdentityConstants.ApplicationScheme, options => { // This will result in a path of /_tenant_/Identity/Account/Login options.LoginPath = $"{options.Cookie.Path}{options.LoginPath}"; options.LogoutPath = $"{options.Cookie.Path}{options.LogoutPath}"; }); }
private void ApplyControllerModel(ControllerModel controllerModel) { if (typeof(IRemoteService).IsAssignableFrom(controllerModel.ControllerType)) { if (controllerModel.ApiExplorer.IsVisible == null) { controllerModel.ApiExplorer.IsVisible = true; } controllerModel.ControllerName = ApplyControllerName(controllerModel.ControllerName); foreach (var item in controllerModel.Selectors) { if (!controllerModel.Attributes.Any(a => a.GetType() == typeof(ApiControllerAttribute))) { item.EndpointMetadata.Add(new ApiControllerAttribute()); } if (!controllerModel.Attributes.Any(a => a.GetType() == typeof(ControllerAttribute))) { item.EndpointMetadata.Add(new ControllerAttribute()); } if (!controllerModel.Attributes.Any(a => a.GetType() == typeof(ControllerAttribute))) { item.EndpointMetadata.Add(new RouteAttribute("[controller]")); } if (item.AttributeRouteModel == null) { item.AttributeRouteModel = new AttributeRouteModel(new RouteAttribute("[controller]")); } if (!string.IsNullOrEmpty(_options.ServiceNamePrefix)) { var prefixRoute = new AttributeRouteModel(new RouteAttribute(_options.ServiceNamePrefix)); item.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(prefixRoute, item.AttributeRouteModel); } } } else if (!string.IsNullOrEmpty(_options.ControllerNamePrefix)) { foreach (var item in controllerModel.Selectors) { if (item.AttributeRouteModel == null) { item.AttributeRouteModel = new AttributeRouteModel(new RouteAttribute(_options.ControllerNamePrefix)); } else { item.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(new AttributeRouteModel(new RouteAttribute(_options.ControllerNamePrefix)), item.AttributeRouteModel); } } } }
//接口的Apply方法 public void Apply(ApplicationModel application) { //遍历所有的 Controller foreach (var controller in application.Controllers) { // 1、已经标记了 RouteAttribute 的 Controller //这一块需要注意,如果在控制器中已经标注有路由了,则会在路由的前面再添加指定的路由内容。 var matchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel != null).ToList(); if (matchedSelectors.Any()) { foreach (var selectorModel in matchedSelectors) { // 在 当前路由上 再 添加一个 路由前缀 selectorModel.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_centralPrefix, selectorModel.AttributeRouteModel); } } //2、 没有标记 RouteAttribute 的 Controller var unmatchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel == null).ToList(); if (unmatchedSelectors.Any()) { foreach (var selectorModel in unmatchedSelectors) { // 添加一个 路由前缀 selectorModel.AttributeRouteModel = _centralPrefix; } } } }
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 Apply(ApplicationModel application) { foreach (var controller in application.Controllers) { var matchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel != null).ToList(); if (matchedSelectors.Any()) { foreach (var selectorModel in matchedSelectors) { selectorModel.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_routingPrefix, selectorModel.AttributeRouteModel); } } } }
/// <summary> /// Add an AttributeRouteModel to a SelectorModel list. /// It also tries to set the first entry of the list if the AttributeRouteModel is null there. /// </summary> /// <param name="selectorModels"></param> /// <param name="attributeRouteModel"></param> public void AddAttributeRouteModel(IList <SelectorModel> selectorModels, AttributeRouteModel attributeRouteModel) { // Override what seems to be default SelectorModel if (selectorModels.Count == 1 && selectorModels[0].AttributeRouteModel == null) { selectorModels[0].AttributeRouteModel = attributeRouteModel; } else { selectorModels.Add(new SelectorModel { AttributeRouteModel = attributeRouteModel }); } }
public void Apply(ApplicationModel application) { var globalPrefix = new AttributeRouteModel(new RouteAttribute("api/")); application.Controllers?.ToList().ForEach(controller => { var routeSelectors = controller.Selectors.Where(x => x.AttributeRouteModel != null); //routeSelectors?.ToList().ForEach( sel => Console.WriteLine("sel "+ sel.AttributeRouteModel.Name)); //Console.WriteLine("---------"); routeSelectors?.ToList().ForEach(sel => sel.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(globalPrefix, sel.AttributeRouteModel) ); }); }
public void Apply(PageRouteModel model) { (from SelectorModel in model.Selectors select new SelectorModel { AttributeRouteModel = new AttributeRouteModel { Order = -1, Template = AttributeRouteModel.CombineTemplates("/{culture:required}", SelectorModel.AttributeRouteModel.Template) } }) .ToList() .ForEach(s => model.Selectors.Add(s)); }
/// <summary> /// Intializes a new <see cref="SelectorModel"/>. /// </summary> /// <param name="other">The <see cref="SelectorModel"/> to copy from.</param> public SelectorModel(SelectorModel other) { if (other == null) { throw new ArgumentNullException(nameof(other)); } ActionConstraints = new List <IActionConstraintMetadata>(other.ActionConstraints); EndpointMetadata = new List <object>(other.EndpointMetadata); if (other.AttributeRouteModel != null) { AttributeRouteModel = new AttributeRouteModel(other.AttributeRouteModel); } }
private ThrottleRoute CreateRoute(AttributeRouteModel controllerTemplate) { string routeTemplate; if (controllerTemplate == null) { routeTemplate = _actionTemplate.Template; } else { routeTemplate = AttributeRouteModel.CombineAttributeRouteModel(controllerTemplate, _actionTemplate).Template; } return(new NamedThrottleRoute(_httpMethods, routeTemplate, _policyName)); }
public void Apply(PageRouteModel model) { var selectorCount = model.Selectors.Count; for (var i = 0; i < selectorCount; i++) { var selector = model.Selectors[i]; model.Selectors.Add(new SelectorModel { AttributeRouteModel = new AttributeRouteModel { Order = -1, Template = AttributeRouteModel.CombineTemplates("{culture?}", selector.AttributeRouteModel.Template), } }); } }
public void ReplaceTokens_InvalidFormat(string template, Dictionary <string, string> values, string reason) { // Arrange var expected = string.Format( CultureInfo.InvariantCulture, "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); }
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 void Apply(ApplicationModel application) { foreach (var item in application.Controllers) { var matchedSelectors = item.Selectors.Where(p => p.AttributeRouteModel != null).ToList(); matchedSelectors.ForEach(p => { p.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_centralPrefix, p.AttributeRouteModel); }); var unmatchedSeletors = item.Selectors.Where(p => p.AttributeRouteModel == null).ToList(); unmatchedSeletors.ForEach(p => { p.AttributeRouteModel = _centralPrefix; }); } }
public static IPageRouteModelConvention AddFolderRouteParameter( this PageConventionCollection conventions, string folder, string routeParameter) { return(conventions.AddFolderRouteModelConvention(folder, model => { foreach (var s in model.Selectors) { var templateWithId = AttributeRouteModel .CombineTemplates(s.AttributeRouteModel.Template, routeParameter); s.AttributeRouteModel.Template = templateWithId; } })); }
private static void AppendTenantPageRoute(PageRouteModel model) { var selectorCount = model.Selectors.Count; for (var i = 0; i < selectorCount; i++) { var selector = model.Selectors[i]; var appended = new SelectorModel(selector); var template = appended.AttributeRouteModel.Template; var tenantTemplates = AttributeRouteModel.CombineTemplates("{tenant}", template); appended.AttributeRouteModel.Template = tenantTemplates; model.Selectors.Add(appended); } }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); // Register the ToDo db context, but do not specify a provider/connection string since // these vary by tenant. services.AddDbContext <ToDoDbContext>(); // Configure Identity services.AddRazorPages(options => { // Since we are using the route multitenant strategy we must add the // route parameter to the Pages conventions used by Identity. options.Conventions.AddAreaFolderRouteModelConvention("Identity", "/Account", model => { foreach (var selector in model.Selectors) { selector.AttributeRouteModel.Template = AttributeRouteModel.CombineTemplates("{__tenant__}", selector.AttributeRouteModel.Template); } }); }); // Preserve the tenant route param when new links are generated. services.DecorateService <LinkGenerator, AmbientValueLinkGenerator>(new List <string> { "__tenant__" }); services.AddDbContext <FinbuckleSqlServerToDoIdentityDbContext>(options => options.UseSqlite(Configuration.GetConnectionString("FinbuckleSqlServerToDoIdentityDbContextConnection"))); services.AddDefaultIdentity <IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddEntityFrameworkStores <FinbuckleSqlServerToDoIdentityDbContext>(); // Register the tenant store db context. services.AddDbContext <TenantStoreDbContext>(options => { options.UseSqlServer(Configuration.GetConnectionString("TenantStoreConnectionString")); }); // Configure Finbuckle, the store db context does not need to be // added separately. // Also note this must come after Identity configuration. services.AddMultiTenant <TenantInfo>() .WithEFCoreStore <TenantStoreDbContext, TenantInfo>() .WithRouteStrategy() .WithPerTenantAuthentication(); }
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 Apply(ApplicationModel application) { foreach (var controller in application.Controllers) { var matchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel != null).ToList(); foreach (var selectorModel in matchedSelectors) { selectorModel.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(_centralPrefix, selectorModel.AttributeRouteModel); } var unmatchedSelectors = controller.Selectors.Where(x => x.AttributeRouteModel == null).ToList(); foreach (var selectorModel in unmatchedSelectors) { selectorModel.AttributeRouteModel = _centralPrefix; } } }
public void ConfigureServices(IServiceCollection services) { // Register the db context, but do not specify a provider/connection // string since these vary by tenant. services.AddDbContext <ApplicationDbContext>(); services.AddDefaultIdentity <MultiTenantIdentityUser>() .AddEntityFrameworkStores <ApplicationDbContext>(); services.AddAuthentication() .AddGoogle("Google", options => { // These configuration settings should be set via user-secrets or environment variables! options.ClientId = Configuration.GetValue <string>("GoogleClientId"); options.ClientSecret = Configuration.GetValue <string>("GoogleClientSecret"); options.AuthorizationEndpoint = string.Concat(options.AuthorizationEndpoint, "?prompt=consent"); }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1) .AddRazorPagesOptions(options => { // Since we are using the route multitenant strategy we must add the // route parameter to the Pages conventions used by Identity. options.Conventions.AddAreaFolderRouteModelConvention("Identity", "/Account", model => { foreach (var selector in model.Selectors) { selector.AttributeRouteModel.Template = AttributeRouteModel.CombineTemplates("{__tenant__}", selector.AttributeRouteModel.Template); } }); }); services.AddMultiTenant() .WithRouteStrategy(ConfigRoutes) .WithInMemoryStore(Configuration.GetSection("Finbuckle:MultiTenant:InMemoryStore")) .WithPerTenantOptions <CookieAuthenticationOptions>((options, tenantInfo) => { // Since we are using the route strategy configure each tenant // to have a different cookie name and adjust the paths. options.Cookie.Name = $"{tenantInfo.Id}_{options.Cookie.Name}"; options.LoginPath = $"/{tenantInfo.Identifier}/Home/Login"; options.LogoutPath = $"/{tenantInfo.Identifier}"; options.Cookie.Path = $"/{tenantInfo.Identifier}"; }); }
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); }
/// <inheritdoc /> public void Apply(ApplicationModel application) { foreach (var controller in application.Controllers) { var matched = controller.Selectors.Where(x => x.AttributeRouteModel != null); foreach (var model in matched) { model.AttributeRouteModel = AttributeRouteModel.CombineAttributeRouteModel(prefix, model.AttributeRouteModel); } var unmatched = controller.Selectors.Where(x => x.AttributeRouteModel == null); foreach (var model in unmatched) { model.AttributeRouteModel = prefix; } } }