我正在寻找一种基于Id返回视图的方法,但在返回时添加友好的url部分。
我知道当我有这些数据时,我可以传递id和名称,例如使用:
app
上面这段代码不是问题。当我提交表单(下拉列表)时,我只有Id可用,就会出现问题。
Url.Action("Index", "Cat", new { id = model.ID, seoname = model.SEO });
[AllowAnonymous]
[Route("Cat/{id?}/{seoname?}")]
public ActionResult Index(int? id = null, string seoname = null) {
// do something with id and create viewmodel
// in case I get redirect from the SelCat actionresult:
if (id.HasValue and string.IsNullOrEmpty(seoname)) {
// look in the database for title by the given id
string seofriendlyTitle = ...;
RouteData.Values.AddOrSet("seoname", seofriendlyTitle);
}
return View(viewmodel);
}
如果我从SelCat操作重定向到只有ID的Index操作,我想搜索友好名称并返回视图。我希望网址有友好的网址部分。
[HttpPost]
[AllowAnonymous]
[Route("Cat/SelCat/{form?}")]
public ActionResult SelCat(FormCollection form)
{
string selectedValues = form["SelectedCat"];
// ...
int id = selectedCatID;
return RedirectToAction("Index", new { id = id });
}
如果仅提供ID,如何在我的控制器操作中返回视图时,如何使我的网址友好? 设置RouteData.Values。似乎没有将该部分添加到网址。
答案 0 :(得分:2)
你必须在数据库中查看SEO友好的slu <之前重定向并将其包含在网址中,否则为时已晚:
Index
一旦你到达<div class="innerDiv" id="Scorecards">
<br>Scorecards<br>
<a href="https://google.com"><img class="imgCustom" id="menuImages" src="http://image.flaticon.com/icons/svg/44/44357.svg"><div>Google</div></a>
</div>
<div class="innerDiv" id="Dashboards">
<br>Dashboards<br>
<a href="https://abc.aspx"><img class="imgCustom" id="menuImages" src="http://icons.iconarchive.com/icons/aha-soft/3d-social/64/Online-writing-icon.png"><div>Microsoft</div></a>
<a href="https://cde.aspx"><img class="imgCustom" id="menuImages" src="http://icons.iconarchive.com/icons/babasse/old-school/64/old-videos-icon.png"><div>Amazon</div></a>
</div>
行动,现在已经太晚了,无法改变客户端上显示的网址,除非你进行额外的重定向(当然这会是疯狂的)。
答案 1 :(得分:1)
您可以创建自定义RouteBase
子类并将所有网址加载到缓存中。然后,您只需要id
(可能基于主键)来查找URL。请注意,您可以id
Guid
(如图所示)或int
。
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 }
);
通过上述注册,您可以使用@Html.ActionLink("A link to a page", "Details", "CustomPage", new { id = "9a19078b-2d7e-4fc6-ae1d-3e76f8be46e5" }, null)
生成基于ID的网址。这将带您到名为Details
的控制器上的CustomPageController
操作(然后可以返回视图)。
BTW - 路由是“返回视图”的另一个问题,所以你的问题有点令人困惑。