MVC自定义路由中的多个级别

我正在尝试建立自己的小cms。我创建了一个抽象的pageBase类,该类由“静态”,“评论”,“文章”,“新闻”继承。每个都有自己的控制器方法。

我的问题是我需要允许管理员定义自己的自定义路径级别。例如news\local\mynewdogArticles\events\conventions\mycon。所以我想要一种传递字符串数组并设置自定义路由的方法。

回答:

您可以使用自定义RouteBase子类无缝进行CMS样式的路由。

public class PageInfo

{

// VirtualPath should not have a leading slash

// example: events/conventions/mycon

public string VirtualPath { get; set; }

public Guid Id { get; set; }

}

public class CustomPageRoute

: RouteBase

{

private object synclock = new object();

public override RouteData GetRouteData(HttpContextBase httpContext)

{

RouteData result = null;

// Trim the leading slash

var path = httpContext.Request.Path.Substring(1);

// Get the page that matches.

var page = GetPageList(httpContext)

.Where(x => x.VirtualPath.Equals(path))

.FirstOrDefault();

if (page != null)

{

result = new RouteData(this, new MvcRouteHandler());

// Optional - make query string values into route values.

this.AddQueryStringParametersToRouteData(result, httpContext);

// TODO: You might want to use the page object (from the database) to

// get both the controller and action, and possibly even an area.

// Alternatively, you could create a route for each table and hard-code

// this information.

result.Values["controller"] = "CustomPage";

result.Values["action"] = "Details";

// This will be the primary key of the database row.

// It might be an integer or a GUID.

result.Values["id"] = page.Id;

}

// IMPORTANT: Always return null if there is no match.

// This tells .NET routing to check the next route that is registered.

return result;

}

public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)

{

VirtualPathData result = null;

PageInfo page = null;

// Get all of the pages from the cache.

var pages = GetPageList(requestContext.HttpContext);

if (TryFindMatch(pages, values, out page))

{

if (!string.IsNullOrEmpty(page.VirtualPath))

{

result = new VirtualPathData(this, page.VirtualPath);

}

}

// IMPORTANT: Always return null if there is no match.

// This tells .NET routing to check the next route that is registered.

return result;

}

private bool TryFindMatch(IEnumerable<PageInfo> pages, RouteValueDictionary values, out PageInfo page)

{

page = null;

Guid id = Guid.Empty;

// This example uses a GUID for an id. If it cannot be parsed,

// we just skip it.

if (!Guid.TryParse(Convert.ToString(values["id"]), out id))

{

return false;

}

var controller = Convert.ToString(values["controller"]);

var action = Convert.ToString(values["action"]);

// The logic here should be the inverse of the logic in

// GetRouteData(). So, we match the same controller, action, and id.

// If we had additional route values there, we would take them all

// into consideration during this step.

if (action == "Details" && controller == "CustomPage")

{

page = pages

.Where(x => x.Id.Equals(id))

.FirstOrDefault();

if (page != null)

{

return true;

}

}

return false;

}

private void AddQueryStringParametersToRouteData(RouteData routeData, HttpContextBase httpContext)

{

var queryString = httpContext.Request.QueryString;

if (queryString.Keys.Count > 0)

{

foreach (var key in queryString.AllKeys)

{

routeData.Values[key] = queryString[key];

}

}

}

private IEnumerable<PageInfo> GetPageList(HttpContextBase httpContext)

{

string key = "__CustomPageList";

var pages = httpContext.Cache[key];

if (pages == null)

{

lock(synclock)

{

pages = httpContext.Cache[key];

if (pages == null)

{

// TODO: Retrieve the list of PageInfo objects from the database here.

pages = new List<PageInfo>()

{

new PageInfo()

{

Id = new Guid("cfea37e8-657a-43ff-b73c-5df191bad7c9"),

VirtualPath = "somecategory/somesubcategory/content1"

},

new PageInfo()

{

Id = new Guid("9a19078b-2d7e-4fc6-ae1d-3e76f8be46e5"),

VirtualPath = "somecategory/somesubcategory/content2"

},

new PageInfo()

{

Id = new Guid("31d4ea88-aff3-452d-b1c0-fa5e139dcce5"),

VirtualPath = "somecategory/somesubcategory/content3"

}

};

httpContext.Cache.Insert(

key: key,

value: pages,

dependencies: null,

absoluteExpiration: System.Web.Caching.Cache.NoAbsoluteExpiration,

slidingExpiration: TimeSpan.FromMinutes(15),

priority: System.Web.Caching.CacheItemPriority.NotRemovable,

onRemoveCallback: null);

}

}

}

return (IEnumerable<PageInfo>)pages;

}

}

您可以这样向MVC注册路由。

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

// Case sensitive lowercase URLs are faster.

// If you want to use case insensitive URLs, you need to

// adjust the matching code in the `Equals` method of the CustomPageRoute.

routes.LowercaseUrls = true;

routes.Add(

name: "CustomPage",

item: new CustomPageRoute());

routes.MapRoute(

name: "Default",

url: "{controller}/{action}/{id}",

defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

);

上面假设您有CustomPageController一个Details带动作的方法。

public class CustomPageController : Controller

{

public ActionResult Details(Guid id)

{

// Do something with id

return View();

}

}

如果希望路由转到其他控制器操作(甚至使它们成为构造函数参数),则可以更改路由。

以上是 MVC自定义路由中的多个级别 的全部内容, 来源链接: utcz.com/qa/402797.html

回到顶部