【问题标题】:Reload routes on runtime in dotnetcore在 dotnetcore 运行时重新加载路由
【发布时间】:2020-08-24 16:52:43
【问题描述】:

我有一个自定义路由,它从非 SQL 数据库 (MongoDB) 读取 URL,并在应用程序启动时将它们添加到路由管道,这是“非常标准的”

类似这样的东西(在我的 startup.cs 文件中):

app.UseMvc(routes =>
{
    routes.MapRoute(
        "default",
        "{controller=Home}/{action=Index}/{id?}");
    routes.Routes.Add(
        new LandingPageRouter(routes, webrequest, memoryCache, Configuration)); 
    // this custom routes adds URLs from database
}

问题是,如果我在应用程序启动后向数据库添加另一条路由,我基本上会得到 404,因为路由系统不知道这条新路由,我认为我需要在运行时或(不太方便)从另一个 Web 应用程序(已在框架 4.5 上开发,显然它运行在不同的池上)重新启动应用程序池

对此还有其他想法吗? 谢谢。

【问题讨论】:

  • 配置的来源是什么?您提到数据库,是 SQL 吗?你能从 JSON 文件中获取路由吗?
  • 其实是一个带有路由元数据的mongoDB集合

标签: c# asp.net-core asp.net-core-mvc


【解决方案1】:

第一个问题是database 是什么意思,当您说:I add another route to the database 时,您是否可以将路由保存在 JSON、XML 或 INI 文件中。

例如,如果您可以将路由保存在 JSON 文件中,那么路由可能会在运行时动态可用 (as you can read in the ASP.NET Core Documentation)

You can find a full blog post about this here.

假设routes.json是一个类似下面结构的JSON文件,并且和Startup在同一个文件夹下:

{
    "route": "This is a route",
    "another-route": "This is another route",
    "default": "This is default!"
}

您可以通过以下方式配置Startup类:

请注意,此示例不使用 MVC,而是使用单独的路由包,尽管我假设您可以将其转置为使用 MVC。

public class Startup
{
    public IConfiguration Configuration {get;set;}
    public Startup(IHostingEnvironment env)
    {
        var configurationBuilder = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("routes.json", optional: false, reloadOnChange: true);
        
        Configuration = configurationBuilder.Build();
    }
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRouting();
    }
    public void Configure(IApplicationBuilder app)
    {
        var routeBuilder = new RouteBuilder(app);

        routeBuilder.MapGet("{route}", context => 
        {
            var routeMessage = Configuration.AsEnumerable()
                .FirstOrDefault(r => r.Key == context.GetRouteValue("route")
                .ToString())
                .Value;
            
            var defaultMessage = Configuration.AsEnumerable()
                .FirstOrDefault(r => r.Key == "default")
                .Value;

            var response = (routeMessage != null) ? routeMessage : defaultMessage;

            return context.Response.WriteAsync(response);
        });

        app.UseRouter(routeBuilder.Build());
    }
}

此时,当应用程序运行时,您可以修改 JSON 文件,将其保存,然后由于 reloadOnChange: true 参数,框架会将新配置重新注入到 Configuration 属性中。

重载的实现是基于文件观察器的,所以如果你想为此使用数据库——SQL Server,那么我认为你必须自己实现。

一个(一点也不漂亮,在这里提醒只是为了完整性)解决方案可能是创建一个控制台应用程序,在文件中添加数据库更改,然后在应用程序配置中使用该文件。

最好的问候!

【讨论】:

  • 嗨@radu-matei,reloadOnChange 让事情变得很有趣,让我看看这个,感谢你指出正确的方向,如果这种方法对我有用,我会告诉你。
  • 当然。如果您有任何其他问题,我很乐意提供帮助。
【解决方案2】:

在 ASP.NET Core 3 中,您可以使用动态路由。在 Startup.cs 添加:

app.UseEndpoints(endpoints =>
{
     endpoints.MapDynamicControllerRoute<SearchValueTransformer>("{**url}");
});

并创建新类 SearchValueTransformer

class SearchValueTransformer : DynamicRouteValueTransformer
{

    public override async ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values)
    {
        
        var url = values["url"] as string;

        if (String.IsNullOrEmpty(url))
            return values;

        values["controller"] = "Controller";
        values["action"] = "Action";
        values["name"] = url;

        return values;
    }
}

同样在 TransformAsync 方法中,您可以在 MongoDB 中搜索正确的 Controller、Action 和 Name 值。更多信息:https://weblogs.asp.net/ricardoperes/dynamic-routing-in-asp-net-core-3

【讨论】:

    猜你喜欢
    • 2019-01-18
    • 1970-01-01
    • 1970-01-01
    • 2019-08-26
    • 1970-01-01
    • 2010-10-19
    • 2017-04-15
    • 2013-01-03
    • 2021-12-16
    相关资源
    最近更新 更多