使用PushState的Backbone路由的ASP.NET路由配置

时间:2014-08-14 20:34:52

标签: asp.net asp.net-mvc backbone.js

我最近遇到了一个问题,我们被告知要从我们的Backbone应用程序中删除哈希符号。这提出了两个问题:(a)ASP.NET路由需要处理任何远程链接的URL(目前这对哈希符号没有问题),这样我们就不会遇到404错误而且(b)正确的路由需要保存并传递给客户端(Backbone)应用程序。我们目前正在为后端使用ASP.NET MVC5和Web API 2。

设置

对于一个示例(和测试项目),我使用Backbone创建了一个测试项目 - 一个简单的C#ASP.NET MVC5 Web应用程序。它非常简单(这里是index.cshtml文件的副本,请忽略注释掉的内容,因为它们将在下面解释):

<script type="text/javascript">
    $(document).ready(function(event) {
        Backbone.history.start({
            //pushState: true,
            //root: "/Home/Index/"
        });
        var Route = Backbone.Router.extend({
            routes: {
                "test/:id": function (event) {
                    $(".row").html("Hello, " + event);
                },
                "help": function () {
                    alert("help!");
                }
            }
        });
        var appRouter = new Route();
        //appRouter.navigate("/test/sometext", { trigger: true });
        //appRouter.navigate("/help", { trigger: true });
    });
</script>

<div class="jumbotron">
    <h3>Backbone PushState Test</h3>
</div>

<div class="row"></div>

现在,在没有启用pushState的情况下,我没有问题远程链接到此路由,即http://localhost/Home/Index#test/sometext

结果是div.row现在是"Hello, sometext"

问题

启用pushState将允许我们使用 / 替换网址中的那个讨厌的,即:http://localhost/Home/Index/test/sometext。我们可以使用router.navigate("url", true);的Backbone方法(以及其他方法)来手动调整URL。 然而,这并不能解决远程链接的问题。因此,在尝试访问http://localhost/Home/Index/test/sample时,您最终会遇到IIS提供的典型404.0错误。所以,我认为它是在 RouteConfig.cs 文件中处理的 - 在里面,我添加了一个“ CatchAll ”路线:

routes.MapRoute(
    name: "CatchAll",
    url: "{*clientRoute}",
   defaults: new { controller = "Home", action = "Index" }
);

我还取消注释Backbone.history.start()中的pushState和root属性;方法:

        Backbone.history.start({
            pushState: true,
            root: "/Home/Index/"
        });
        var Route = Backbone.Router.extend({
            routes: {
                "test/:id": function (event) {
                    $(".row").html("Hello, " + event);
                },
                "help": function () {
                    alert("help!");
                }
            }
        });
        var appRouter = new Route();
        //appRouter.navigate("/test/sometext", { trigger: true });
        //appRouter.navigate("/help", { trigger: true });

这使我至少可以在链接到这些路线时超过404.0页面 - 这很好。但是,当我去找他们时,没有一条路线真正“触发”。尝试在Chrome,Firefox和IE11中调试它们后,我注意到没有任何事件触发。但是,如果我使用appRouter.navigate("/help", { trigger: true });手动导航到它们,则会捕获路由并触发事件。

我现在不知道接下来应该从哪里开始进行故障排除。我已将我的Javascript放在$(document).ready()事件以及window.onload事件中(以及不在事件内部);这些都没有纠正这个问题。任何人都可以提供关于下一步的建议吗?

2 个答案:

答案 0 :(得分:1)

您只需在“新路线”行之后移动Backbone.history.start。

var Route = Backbone.Router.extend({
    routes: {
        "test/:id": function (event) {
            $(".row").html("Hello, " + event);
        },
        "help": function () {
            alert("help!");
        }
    }
});
var appRouter = new Route();
Backbone.history.start({
    pushState: true,
    root: "/Home/Index/"
});

请务必转到“... /主页/索引/帮助”。如果它不起作用,请尝试暂时删除root并转到“... / help”以查看根是否是问题。

如果仍有问题,请在“返回”行的Backbone.History.loadUrl中设置js断点。它从History.start的最后一行调用,以在页面加载时执行当前浏览器URL。 “this.matchRoot()”必须通过,“fragment”与“this.handlers”中的每个“route”或regexp字符串匹配。您可以看到浏览器URL与路由正则表达式匹配的原因或原因。

要设置为js断点,请在浏览器中按F12打开开发控制台,按Ctrl-O或Ctrl-P打开js文件,然后键入骨干js文件的名称。然后搜索“loadUrl:”。您还可以搜索“Router =”以查找路由器类定义的开头(与“View =”和“Model =”相同,以查找主干视图/模型实现代码)。当我遇到这样的问题时,我发现查看骨干代码非常有用。它具有令人惊讶的可读性以及获得答案的更好的地方?

如果你的js文件碰巧被缩小/压缩,最好关闭它。或者,您可以尝试使用浏览器unminify选项。在Chrome中,这是“{}”按钮或“漂亮的打印”。然后js代码不是全部在1行,你可以设置断点。但函数和变量名称可能仍会受到损坏。

答案 1 :(得分:0)

我通过以下方式使用感觉“hackish”解决了我自己的问题。如果有人能提交更好的回复,我们将不胜感激!

我的解决方案: 我全局覆盖默认的Backbone.Router.intilaize方法(它为空),其中包含以下内容:

$(document).ready(function (event) {
    var _root = "/Home/Index/";
    _.extend(Backbone.Router.prototype, {

        initialize: function () {
            /* check for route & navigate to it */
            var pathName = window.location.pathname;
            var route = pathName.split(_root)[1];
            if (route != undefined && route != "") {
                route = "/" + route;
                this.navigate("", { trigger: false });
                this.navigate(route, { trigger: true });
            }
        }

    });
});