我有一个Sitecore站点,在我的两个CD服务器上,Url.Action
返回一个空字符串。这适用于本地和其他9个服务器,从开发到产品,CD和CM。
部署自动化确保将完全相同的web.config
部署到所有环境中;同样适用于所有其他配置。
我的控制器正确地继承了SitecoreController
。这不会与某个控制器或操作隔离,所有控制器和操作都会发生这种情况。
什么会使Url.Action
在一个环境中返回一个空字符串而不是其他环境,使用相同的代码?
什么会使Url.Action有时会返回一个空字符串?
具体而言,路由从当前请求派生的值。
Url.Action
方法由UrlHelper
驱动,而Url.Action
又由路线驱动。它使用路由值来确定用于构建URL的路由。路由框架尝试按照它们注册的顺序将每个路由与路由值进行匹配,直到找到匹配为止。如果路由框架到达路由表的末尾并且仍然没有匹配,则返回一个空字符串(因为没有其他合理的默认行为)。
另一方面,如果您调用Url.Action
并传递路径名称,则会将可能的匹配范围缩小到仅1个特定路径(命名路径)。但是路由值仍然需要匹配该路由,否则您将获得默认的空字符串。
通常,所有路由值必须匹配,但有一些事情可能使行为古怪:
Url.Action
时未提供路由值,则可以在当前请求中存在时自动提供该路由值。第二个怪癖意味着如果将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" }
);
}
}
放在共享视图上,并且一个请求包含路由值以使其与路由匹配,而另一个请求不包含该路由值,则在后一种情况下,URL可能与另一个路由匹配可能是一个空字符串。
假设路由配置设置如下:
_Layout.cshtml
另外,假设<a href='@Url.Action("About", "Home")'>About</a>
页面上有一个链接:
/
如果您转到浏览器的主页(<a>About</a>
),结果链接URL将是:
foo
这是因为bar
和Url.Action
不存在于请求的路由值中,因此它与任何已注册的路由都不匹配。
实际上,
href=''
返回一个空字符串,但Razor优化了空的/test/home/contact/arg1/arg2
属性。
另一方面,如果您将此URL放在浏览器中:
<a href='/test/home/about/arg1/arg2'>About</a>
链接URL生成为:
{foo}
这是因为当前请求中都有arg1
(值{bar}
)和arg2
(值ContactWith4RouteValues
)。请注意,传入请求与AboutWith4RouteValues
路由匹配,但是当生成链接URL时,它使用foo
路由。由于bar
和/test/home/contact/arg1
都存在于请求中,因此它们会被转移到URL的生成中。
现在,如果浏览器中的URL更改为:
ContactWith4RouteValues
它仍然匹配<a>About</a>
路线,因为最后一个值是可选的。但是,生成的URL现在是:
foo
这是因为bar
在请求中有一个值,但是Url.Action
没有值,AboutWith4RouteValues
生成请求与bar
不匹配,因为Home
是一个必需的值,以使其匹配。由于它也与Url.Action
路由不匹配,我们已到达路由表的末尾,唯一合理的返回是空字符串。
避免当前请求的这些怪癖的最简单的解决方法是在调用UrlHelper
或其他基于ActionLink
的方法(例如RedirectToRoute
,<a href='@Url.Action("About", "Home", new { foo = Model.Foo, bar = Model.Bar })'>About</a>
等)时手动指定路由值。
Url.Action
这可确保在构建URL时始终存在这些值,即使它们不是当前请求的一部分。
我有这个完全相同的问题,对我来说,问题与我的路由中的Case-Sensitivity有关。
将同一站点部署到同一IIS Web服务器上的两个不同应用程序。
我使用了相同的web-config和相同的VS Web发布设置。
然而,我的WorkBench
在Prod中返回空白(空字符串),但在Dev中没有。
在查看代码后,有些东西引起了我的注意。
我有一个名为B
的区域(大写“Url.Action
”)。
在一些地方(Workbench
返回空白),我正在传递b
(小写“RouteConfig.cs
”)。
我的WorkBenchAreaRegistration.cs
和区域注册(即b
)有一些奇特的逻辑。
在这些文件中,我使用条件逻辑来确定应用程序运行的环境。
我使用相同的项目来共享代码,但只希望在不同的环境中可以访问某些区域。
即使Prod和Dev是不同的环境,要调试这个问题,
我改变了它们,所以它们会暂时显示出来。
一旦我将“B
”资本化为“qazxswpoi”,问题就解决了。
我仍然不知道为什么它可以在我的本地机器和Dev中工作,但不在Prod中。
它应该在两种环境中表现相同。
同样,相同的服务器,相同的发布,相同的web.config,相同的iis配置,相同的应用程序代码等...
对不起,我对此没有解释,但至少这是一个可能的解决方案,你可以尝试。
希望这有助于那里的人。
更新02/08/2019:我再次遇到这个问题有一个不同的链接,对于这一个我意识到我有一个选项设置为当我的一个Debug变量设置为true或在Prod中运行时访问区域内的所有操作。我在AreaRegistration.cs文件中删除了这个条件逻辑,它解决了在Staging环境中运行时的问题。
这里的经验教训是,无论何时你看到一个空白的Href,你都要检查那些路径配置。