【问题标题】:Dynamic routing in ASP.Net CoreASP.Net Core 中的动态路由
【发布时间】:2016-11-12 21:23:19
【问题描述】:

我需要提供一种路由机制,其中路由是在运行时从用户帐户创建中生成的。如http://mysite/username/home

我认为这可以通过路由来完成,但我不确定从哪里开始使用 ASP.Net Core。我在网上看到了一些 MVC 5 的示例,但 ASP.Net Core 处理路由的方式似乎有点不同。如何确保网站不会混淆 http://mysite/username/news 是用户自定义登录页面和 http://mysite/news 是网站新闻页面?

【问题讨论】:

  • 你可以通过路由权来解决这个问题。例如,您的控制器中有一个 [Route("{username}/news")] 的路由,它与另一个 Route["news"] 不同。这是有道理还是我误解了。
  • 我没有意识到你可以使用{username}。 asp.net core 是否通过查看身份来处理这个问题?如果http://mysite/johndoe/news 是一个面向公众的 url,那么任何未经身份验证的人都可以点击它会发生什么?
  • 对不起,我的意思是您将其作为路由参数并根据需要进行重定向。这有意义吗?

标签: asp.net-mvc asp.net-core asp.net-mvc-routing


【解决方案1】:

我不确定以下方法是否正确。它对我有用,但您应该针对您的场景进行测试。

首先创建一个用户服务来检查用户名:

public interface IUserService
{
    bool IsExists(string value);
}

public class UserService : IUserService
{
    public bool IsExists(string value)
    {
        // your implementation
    }
}
// register it
services.AddScoped<IUserService, UserService>();

然后为用户名创建路由约束:

public class UserNameRouteConstraint : IRouteConstraint
{
    public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
    {
        // check nulls
        object value;
        if (values.TryGetValue(routeKey, out value) && value != null)
        {
            var userService = httpContext.RequestServices.GetService<IUserService>();
            return userService.IsExists(Convert.ToString(value));
        }

        return false;
    }
}

// service configuration
services.Configure<RouteOptions>(options =>
            options.ConstraintMap.Add("username", typeof(UserNameRouteConstraint)));

最后写路由和控制器:

app.UseMvc(routes =>
{
    routes.MapRoute("default",
        "{controller}/{action}/{id?}",
        new { controller = "Home", action = "Index" },
        new { controller = @"^(?!User).*$" }// exclude user controller
    );

    routes.MapRoute("user",
        "{username:username}/{action=Index}",
        new { controller = "User" },
        new { controller = @"User" }// only work user controller 
     );
});

public class UserController : Controller
{
    public IActionResult Index()
    {
        //
    }
    public IActionResult News()
    {
        //
    }
}

public class NewsController : Controller
{
    public IActionResult Index()
    {
        //
    }
}

【讨论】:

  • 我知道放置路由的顺序很重要,所以我现在想知道如果有一个名为“news”的用户名会与我的“News”控制器操作路由冲突会发生什么。通过首先放置默认路由内容,“新闻”用户将被忽略,因为存在“新闻”控制器操作。在达到默认值之前,我是否应该先尝试路由到用户“域”?
  • 如果你改变路由的顺序,在这种情况下News控制器路由将被忽略,UserService.Exists方法将被所有请求调用(即使它不是必需的)。我认为无论如何你都应该处理冲突。使用“保留用户名”似乎是合理的。
  • 也可以使用 .net core 3.0 中引入的端点路由来做到这一点,例如 app.UseEndpoints(endpoints => { endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index }/{id?}"); });
【解决方案2】:

.net Core 中的路由是一个相当广泛的话题,但我对动态路由的偏好如下!

   public class Router : IRouter
    {
        private readonly IRouter _innerRouter;
        IApplicationBuilder b;

        public Router(IRouter innerRouter, IApplicationBuilder bb)
        {
            if (innerRouter == null)
                throw new ArgumentNullException("innerRouter");
            this._innerRouter = innerRouter;

            b = bb;
        }

        public async Task RouteAsync(RouteContext context)
        {
            var requestPath = context.HttpContext.Request.Path.Value;

            if (!string.IsNullOrEmpty(requestPath) && requestPath[0] == '/')
            {
                // Trim the leading slash
                requestPath = requestPath.Substring(1);
            }

            if (requestPath.Trim() == String.Empty)
                return;

            using (var serviceScope = b.ApplicationServices.CreateScope())
            {
                DomainDbContext dbContext = serviceScope.ServiceProvider.GetRequiredService<DomainDbContext>();

                int type = 0;
                int id = 0;
                Page page = dbContext.Page.Where(_ => _.Url.ToLower().Contains(requestPath.ToLower()) || requestPath.ToLower().Contains(_.Url.ToLower())).FirstOrDefault();
                if (page != null)
                {
                    type = 1; //page
                    id = page.Id;
                }

                Blog blog = dbContext.Blog.Where(_ => _.Url.ToLower().Contains(requestPath.ToLower()) || requestPath.ToLower().Contains(_.Url.ToLower())).FirstOrDefault();
                if (blog != null)
                {
                    type = 2; //blog
                    id = blog.Id;
                }

                if (type == 0)
                    return;

                //Invoke MVC controller/action
                var oldRouteData = context.RouteData;
                var newRouteData = new RouteData(oldRouteData);
                newRouteData.Routers.Add(this._innerRouter);

                newRouteData.Values["controller"] = "Dynamic";
                newRouteData.Values["action"] = "Index";
                newRouteData.Values["id"] = type + "," + id;

                try
                {
                    context.RouteData = newRouteData;
                    await this._innerRouter.RouteAsync(context);
                }
                finally
                {
                    // Restore the original values to prevent polluting the route data.
                    //if (!context.IsHandled)
                    //{
                    //    context.RouteData = oldRouteData;
                    //}
                }
            }

        }

        public VirtualPathData GetVirtualPath(VirtualPathContext context)
        {
            VirtualPathData result = null;

            var values = context.Values;
            var controller = Convert.ToString(values["controller"]);
            var action = Convert.ToString(values["action"]);
            var id = Convert.ToString(values["id"]);

            if ("Item".Equals(controller) && "View".Equals(action))
            {
                result = new VirtualPathData(this, "abcd?id=" + id);
                //context.IsBound = true;
            }

            // IMPORTANT: Always return null if there is no match.
            // This tells .NET routing to check the next route that is registered.
            return result;
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-29
    • 2017-04-13
    • 2020-05-01
    相关资源
    最近更新 更多