看一看ASP.NETCore3.0中的动态路由使用场景分析

译者注

今天在网上看到这篇关于ASP.NET Core动态路由的文章。这很有趣。让我为你翻译一下。文章中的例子虽然可能不会出现在日常编码中,但也为我们提供了一定的思路。

前言

与旧版ASP.NET MVC和ASP.NET Core MVC中的路由特性相比,在ASP.NET Core3.0中增加了一个很好的扩展点,即程序获取到路由后,可以动态指向给定的控制器/动作。

这个特性有很多使用场景。如果您从 ASP.NET Core 3.0 使用 Preview 7 及更高版本,则可以在 ASP.NET Core 3.0 中使用它。

PS:官方在Release Notes中并没有提到这一点。

我们来看看 ASP.NET Core 3.0 中的动态路由。

背景

我们在使用MVC路由的时候,最典型的用法就是我们使用路由属性(Route Attributes)来定义路由信息。使用这种方法,我们需要为每条路由做出明确的声明。

publicclassHomeController: Controller{[ Route( “”) ] [ Route( “Home”) ] [ Route( “Home/Index”) ] publicIActionResult Index( ) {returnView; }}

以下是使用新语法在 ASP.NET Core 3.0 中实现端点路由的方式。

app.UseEndpoints(endpoints=> {endpoints.MapControllerRoute(“default”, “{controller=Home}/{action=Index}/{id?}”); });

以上两种方式的共同点是,所有的路由信息​​都必须在应用启动时加载。

但是,如果您希望能够动态定义路由,并在应用程序运行时添加/删除它们呢?

下面我将列举几个动态定义路由的使用场景。

这个问题的处理应该很好理解。我们希望尽早拦截路由处理,检查已为其解析的当前路由值,并将它们“转换”为一组新的路由值,使用来自例如数据库的数据,指向一个控件实际存在的设备。

示例问题 – 多语言翻译路由问题

在旧版本的 ASP.NET Core MVC 中,我们通常通过自定义 IRouter 接口来解决这个问题。但是,在 ASP.NET Core 3.0 中,这种方式不再有效,因为路由已更改为由上述端点路由处理。幸运的是,在 ASP.NET Core 3.0 Preview 7 及后续版本中,我们可以通过新功能 MapDynamicControllRoute 和扩展点 DynamicRouteValueTransformer 来支持我们的需求。下面我们来看一个具体的例子。

想象一下,在您的项目中,您有一个 OrderController 控制器,并且您希望它支持多语言翻译路由。

publicclassOrdersController: Controller{publicIActionResult List {returnView; }}

我们可能希望请求的 URL 是这样的,例如

使用动态路由处理多语言翻译路由问题

那么我们现在如何解决这个问题呢?我们可以使用新特性 MapDynamicControllerRoute 来替换默认的 MVC 路由,并将其指向我们自定义的 DynamicRouteValueTransformer 类,该类实现了我们前面提到的路由值转换。

publicclassStartup{publicvoidConfigureServices(IServiceCollection 服务){services.AddMvc.SetCompatibilityVersion(CompatibilityVersion.Latest);

服务.AddSingleton;服务.AddSingleton;}

publicvoidConfigure(IApplicationBuilder app) {app.UseRouting;app.UseEndpoints(endpoints =>{endpoints.MapDynamicControllerRoute(“{language}/{controller}/{action}”); });}}

图片[1]-看一看ASP.NETCore3.0中的动态路由使用场景分析-老王博客

这里我们定义了一个 TranslationTransformer 类,它扩展了 DynamicRouteValueTransformer 类。这个新类将负责将特定于语言的路由值转换为路由值字典,该字典可以匹配到我们应用程序中的控制器/动作,通常不能直接匹配到我们应用程序中的任何控制器/动作。所以这里有一个简单的点,就是在德国场景中,控制器名称会从“Bestellungen”转换为“Orders”,动作名称“Liste”会转换为“List”。

TranslationTransformer 类作为泛型类型参数传递给 MapDynamicControllerRoute 方法,并且必须在依赖注入容器中注册。这里,我们还需要注册一个 TranslationDatabase 类,不过这个类只是为了帮助演示,后面会用到。

publicclassTranslationTransformer: DynamicRouteValueTransformer{privatereadonlyTranslationDatabase _translationDatabase;

publicTranslationTransformer(TranslationDatabase translationDatabase) {_translationDatabase = translationDatabase;}

publicoverrideasyncValueTask TransformAsync( HttpContext httpContext, RouteValueDictionary values) {if(!values.ContainsKey( “language”) || !values.ContainsKey( “controller”) || !values.ContainsKey( “action”)) returnvalues;

varlanguage =(字符串)值[“语言”];varcontroller = await_translationDatabase.Resolve(语言,(字符串)值[“控制器”]);如果(控制器 == null)返回值;值[“控制器”] =控制器;

varaction = await_translationDatabase.Resolve(语言, (string)values[ “action”]); if(action == null) 返回值;价值观[“行动”] =行动;

返回值;}}

在这个转换器中,我们需要尝试提取 3 个路由参数, language , controller , action ,然后我们需要在用于模拟的数据库类中找到对应的翻译。正如我们之前提到的,您通常会希望从数据库中查找相应的内容,因为这样,我们可以在应用程序生命周期的任何时间点动态影响路由。为了说明这一点,我们将使用 TranslationDatabase 类来模拟数据库操作,在这里您可以将其想象为一个真正的数据库存储库服务。

publicclassTranslationDatabase{privatestaticDictionary< string, Dictionary< string, string>> Translations = newDictionary< string, Dictionary< string, string>> {{“en”, newDictionary< string, string> {{ “orders”, “orders”}, { “list”, “list”} }},{“de”, newDictionary< string, string> {{ “bestellungen”, “orders”}, { “liste”, “list”} }},{“pl”, newDictionary<string, string> {{ “zamowienia”, “order”}, { “lista”, “list”} }},};

publicasyncTask<string> Resolve(stringlang, stringvalue) {varnormalizedLang = lang.ToLowerInvariant; varnormalizedValue = value.ToLowerInvariant; if(Translations.ContainsKey(normalizedLang) && Translations[normalizedLang].ContainsKey(normalizedValue)){returnTranslations[normalizedLang][normalizedValue] ; }

返回空;}}

到目前为止只能进入index控制器,我们已经很好地解决了这个问题。通过在 MVC 应用程序中启用此设置,我们可以将请求发送到我们之前定义的 3 个路由。

每个请求都会命中 OrderController 控制器和 List 方法。目前,您可以将此方法进一步扩展到其他控制器。但最重要的是,如果您添加新语言或新的路由别名映射到现有语言的控制器/操作,则无需进行任何代码更改甚至重新启动项目。

请注意,在本文中,我们只关注路由转换,这里只是为了演示 ASP.NET Core 3.0 中的动态路由功能。如果您希望在应用程序中实现本地化,您可能还需要阅读 ASP.NET Core 3.0 的本地化指南,因为您可能需要根据语言的路由值设置正确的 CurrentCulture。

最后,我想补充一点,在我们之前的示例中,我们在路由模板中明确使用了 {controller} 和 {action} 占位符。这不是必需的,在其他情况下,您还可以使用“catch-all”路由通配符并将其转换为控制器/动作路由值。

“catch-all”路由通配符是CMS系统中的典型解决方案,您可以使用它来处理不同的动态“页面”路由。

它可能看起来像:

endpoints.MapDynamicControllerRoute

(“pages/{**slug}”);

然后,您需要将页面后的整个 URL 参数转换为现有可执行控制器的内容 – 通常 URL/路由映射保存在数据库中。

希望你会发现这篇文章很有用——所有的演示源代码都可以在 Github 上找到。

支持小微:

299元买5000+.NET架构课程,还送初中级课程!

腾讯云热门2核2G云服务器首年40元只能进入index控制器,2G4核云服务器298元/3年

右下角,你点击查看图片

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论