Url.Action在某些环境中返回空字符串

时间:2018-01-30 18:44:56

标签: asp.net-mvc asp.net-mvc-routing sitecore8 sitecore-mvc

我有一个Sitecore站点,在我的两个CD服务器上,Url.Action返回一个空字符串。这适用于本地和其他9个服务器,从开发到产品,CD和CM。

部署自动化可确保将完全相同的web.config部署到所有环境中;所有其他配置都同样如此。

我的控制器正确地从SitecoreController继承。这不会与某个控制器或操作隔离,所有控制器和操作都会发生这种情况。

什么会使Url.Action在一个环境中返回空字符串而不是其他环境中的相同代码?

2 个答案:

答案 0 :(得分:6)

  

什么会让Url.Action有时会返回一个空字符串?

具体而言,路由从当前请求派生的值。

说明

Url.Action方法由UrlHelper驱动,后者又由路由驱动。它使用路由值来确定用于构建URL的路由。路由框架尝试按照它们注册的顺序将每个路由与路由值进行匹配,直到找到匹配为止。如果路由框架到达路由表的末尾并且仍然没有匹配,则返回一个空字符串(因为没有其他合理的默认行为)。

另一方面,如果您呼叫Url.Action并传递路由名称,则会将可能的匹配范围缩小到仅1个特定路由(命名路由)。但是路由值仍然需要匹配该路由,否则您将获得默认的空字符串。

通常,所有路线值必须匹配,但有一些事情可能会使行为古怪:

  1. 路线值可以是可选的。这意味着路线值不需要存在,以便路线匹配。
  2. 如果在Url.Action的来电中未提供路线值,则可能会自动提供如果当前请求中存在
  3. 第二个怪癖意味着如果Url.Action放在共享视图上,并且一个请求包含路由值以使其与路由匹配,而另一个请求不包含该路由值,则后者如果URL可能与另一条路线匹配,或者它可能是一个空字符串。

    实施例

    假设路由配置设置如下:

    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
            routes.MapRoute(
                name: "AboutWith4RouteValues",
                url: "test/home/about/{foo}/{bar}",
                defaults: new { controller = "Home", action = "About" });
    
            routes.MapRoute(
                name: "ContactWith4RouteValues",
                url: "test/home/contact/{foo}/{bar}",
                defaults: new { controller = "Home", action = "Contact", bar = UrlParameter.Optional });
    
            routes.MapRoute(
                name: "Home",
                url: "",
                defaults: new { controller = "Home", action = "Index" }
            );
        }
    }
    

    另外,我们假设_Layout.cshtml页面上有一个链接:

    <a href='@Url.Action("About", "Home")'>About</a>
    

    如果您转到浏览器中的主页(/),则生成的链接网址将为:

    <a>About</a>
    

    这是因为foobar不存在于请求的路由值中,因此它不匹配任何已注册的路由。

      

    实际上,Url.Action会返回一个空字符串,但Razor会优化空的href=''属性。

    另一方面,如果您将此URL放在浏览器中:

    /test/home/contact/arg1/arg2
    

    链接网址生成为:

    <a href='/test/home/about/arg1/arg2'>About</a>
    

    这是因为当前请求中都有{foo}(值arg1)和{bar}(值arg2)。请注意,传入请求与ContactWith4RouteValues路由匹配,但在生成链接URL时,它使用AboutWith4RouteValues路由。由于请求中都包含foobar,因此会将其转移到URL的生成位置。

    现在,如果浏览器中的URL更改为:

    /test/home/contact/arg1
    

    它仍匹配ContactWith4RouteValues路由,因为最后一个值是可选的。但是,生成的URL现在是:

    <a>About</a>
    

    这是因为foo在请求中有值,但bar没有值,Url.Action生成请求与AboutWith4RouteValues不匹配,因为bar是一个必需的值,以使其匹配。由于它也不匹配Home路由,因此我们已经到达路由表的末尾,并且返回的唯一逻辑是空字符串。

    解决方法

    避免当前请求的这些怪癖的最简单的解决方法是在调用Url.Action或其他基于UrlHelper的方法(例如{{1}时手动指定路由值 },ActionLink等。)

    RedirectToRoute

    这可以确保在构建URL时始终存在这些值,即使它们不是当前请求的一部分。

答案 1 :(得分:0)

我遇到了完全相同的问题,对我来说,这个问题与我的路由中的区分大小写有关。
将同一站点部署到同一IIS Web服务器上的两个不同的应用程序。
我使用了相同的Web配置和VS Web发布设置。
但是,我的Url.Action在Prod中返回了空白(空字符串),而在Dev中却没有。
在查看了代码之后,有什么引起了我的注意。

我有一个名为WorkBench的区域(大写的“ B”)。
在某些地方(Url.Action返回空白),我传入了Workbench(小写的“ b”)。
我在RouteConfig.cs和区域注册(即WorkBenchAreaRegistration.cs)中有一些幻想。
在这些文件中,我使用条件逻辑来确定应用程序在哪个环境中运行。
我使用同一项目共享代码,但只希望在不同环境中访问某些区域。
即使Prod和Dev是不同的环境,也要调试此问题,
我更改了它们,以便它们暂时显示为相同。

在所有地方将大写字母“ b大写为“ B”后,该问题已解决。
我仍然不知道为什么它不能在我的本地计算机和Dev中工作,但是在Prod中不是
在两个环境中,它应该具有相同的行为。
同样,相同的服务器,相同的发布,相同的web.config,相同的iis配置,相同的应用程序代码等...
抱歉,我对此没有任何解释,但是至少这是您可以尝试的解决方法。

希望这可以帮助某个人。

更新02/08/2019:我通过另一个链接再次遇到此问题,为此我意识到当我的一个Debug变量设置为true时,或者当我将一个Debug变量设置为true时,我已经设置了一个选项来访问区域内的所有操作在产品中运行。我在AreaRegistration.cs文件中删除了此条件逻辑,并解决了在暂存环境中运行时的问题。

这里的经验教训是,只要您看到空白的Href,就必须检查那些路由配置。