ASP.Net Core中的动态路由

时间:2016-07-11 02:25:16

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

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

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

2 个答案:

答案 0 :(得分:3)

我不确定以下方式是否正确。它适用于我,但你应该为你的场景测试它。

首先创建用户服务以检查用户名:

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()
    {
        //
    }
}

答案 1 :(得分:1)

.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;
        }
    }