MVC4自定义路由 - 验证个性化网址

时间:2016-08-03 14:22:20

标签: c# asp.net-mvc asp.net-mvc-4 asp.net-mvc-routing

我正在开发一个MVC4的网站,需要一些自定义路由。这是一个有几页的简单网站。例如:

/index
/plan
/investing
... etc.. a few others

通过管理面板,网站管理员可以创建"品牌"网站,基本上反映了上述内容,但交换了一些东西,如品牌公司名称,徽标等。一旦创建,URL将看起来像

/{personalizedurl}/index
/{personalizedurl}/plan
/{personalizedurl}/investing

......等......(与非品牌页面完全相同的页面。

我正在使用控制器方法上的操作过滤器属性验证个性化URL,如果在数据库中找不到则返回404。

以下是我的一个行动示例:

[ValidatePersonalizedUrl]
[ActionName("plan")]
public ActionResult Plan(string url)
{
    return View("Plan", GetSite(url));
}

到目前为止易于使用,并且可以通过以下路线运行良好:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        name: "Admin",
        url: "Admin/{action}/{id}",
        defaults: new { controller = "Admin", action = "Index", id = UrlParameter.Optional }
    );

    routes.MapRoute(
        name: "Default",
        url: "{action}",
        defaults: new { controller = "Default", action = "Index" }
    );

    routes.MapRoute(
        "Branded", // Route name
        "{url}/{action}", // URL with parameters
        new { controller = "Default", action = "Index" } // Parameter defaults
    );

/*
    routes.MapRoute(
        "BrandedHome", // Route name
         "{url}/", // URL with parameters
         new { controller = "Default", action = "Index" } // Parameter defaults
    );
*/
}

我目前遇到的问题是底部注释掉的路线。我希望能够转到/ {personalizedurl} /并让它找到正确的操作(默认控制器中的索引操作)。现在,底线被注释掉了,我得到了404因为它认为它是一个动作并且没有找到它。当我取消注释它时,索引页面,然而单个操作没有/计划,例如因为它认为它是一个pUrl并且无法在数据库中找到它。

无论如何,抱歉这个问题很长。如何设置它的任何帮助或建议将不胜感激。

詹姆斯

1 个答案:

答案 0 :(得分:0)

问题是MVC将使用第一个匹配的URL,因为第二个路径是:

routes.MapRoute(
  name: "Default",
  url: "{action}",
  defaults: new { controller = "Default", action = "Index" }
);

与您的 / {personalizedurl} / 匹配,它将路由到Default / {action}。

你想要的东西有点棘手!我认为个性化是动态的,而不是一些静态的品牌公司列表,而且每次添加/删除新的公司时,您都不想重新编译和部署。

我认为你需要在控制器中处理这个问题,它在路由方面不会很好用;除非它是个性化公司的静态列表。您需要能够检查第一部分是否是您的某个操作,并检查它是否是一个有效的公司,我将为您举例说明简单的字符串数组。我相信您将通过为您的个性化公司查询某种数据存储来构建阵列。我还创建了一个名为PersonalizedViewModel的快速视图模型,该模型采用名称字符串。

您的路由将会简化:

public static void RegisterRoutes(RouteCollection routes)
{
  routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

  routes.MapRoute(
    name: "Admin",
    url: "Admin/{action}/{id}",
    defaults: new { controller = "Admin", action = "Index", id = UrlParameter.Optional }
  );

  routes.MapRoute(
    name: "Default",
    url: "{url}/{action}",
    defaults: new { controller = "Default", action = "Index", url = UrlParameter.Optional }
  );
}

以下是我的示例使用的视图模型:

public class PersonalizedViewModel
{
  public string Name { get; private set; }
  public PersonalizedViewModel(string name)
  {
    Name = name;
  }
}

默认控制器:

public class DefaultController : Controller
{
  private static readonly IEnumerable<string> personalizedSites = new[] { "companyA", "companyB" };
  private static readonly IEnumerable<string> actions = new[] { "index", "plan", "investing", "etc" };

  public ActionResult Index(string url)
  {
    string view;
    PersonalizedViewModel viewModel;
    if (string.IsNullOrWhiteSpace(url) || actions.Any(a => a.Equals(url, StringComparison.CurrentCultureIgnoreCase)))
    {
      view = url;
      viewModel = new PersonalizedViewModel("Default");
    }
    else if (personalizedSites.Any(s => s.Equals(url, StringComparison.CurrentCultureIgnoreCase)))
    {
      view = "index";
      viewModel = new PersonalizedViewModel(url);
    }
    else
    {
      return View("Error404");
    }

    return View(view, viewModel);
  }

  public ActionResult Plan(string url)
  {
    PersonalizedViewModel viewModel;
    if (string.IsNullOrWhiteSpace(url))
    {
      viewModel = new PersonalizedViewModel("Default");
    }
    else if (personalizedSites.Any(s => s.Equals(url, StringComparison.CurrentCultureIgnoreCase)))
    {
      viewModel = new PersonalizedViewModel(url);
    }
    else
    {
      return View("Error404");
    }

    return View(viewModel);
  }
}