5

我正在构建一个客户端/服务器解决方案,使用 AngularJS 单页应用程序作为客户端组件,使用 Self-Host ServiceStack RESTful API 作为服务器组件。单个 Visual Studio 控制台应用程序项目包含 AngularJS 组件的 HTML 和 JavaScript 文件,以及用于引导 ServiceStack AppHost 的 C# 类(我已将接口和服务职责转移到单独的 Visual Studio 项目中)。

我已将所有 HTML 和 JavaScript 文件设置为具有“无”的“构建操作”和“如果较新则复制”的“复制到输出目录”。

只要我准备好忍受在我的网站 URL 中使用“#”,一切都运行良好。我想通过使用 HTML5 pushstate URL 来消除这种情况。

实际上,这意味着每当请求不存在的路由时,我需要说服 ServiceStack 提供我的默认单页应用程序 HTML shell 页面。现在ServiceStack 中提供了一个FallbackRoute属性,似乎正是为此目的而添加的。

但是,我不确定如何使用它。我发现人们在这里这里这里提出了类似的问题。但是给出的答案都是在新的 FallbackRoute 属性到来之前。

本质上,我正在寻找一个简单但完整的示例,说明如何使用 FallbackRoute 属性确保对不存在的路由的任何请求都重定向到单个静态 HTML 页面。

4

2 回答 2

4

事实证明,使用 FallbackRoute 功能非常简单,只要您弄清楚如何正确使用它:

[FallbackRoute("/{Path*}")]
    public class Fallback
    {
        public string Path { get; set; }
    }

    public class FallBackService : Service
    {
        public object Any(Fallback request)
        {
            return new HttpResult(new FileInfo("index.html")) {ContentType = "text/html"};
        }
    }

一旦这到位,我发现每当我尝试访问不存在的路线时,'index.html' 确实会得到服务。

任何静态文件,例如 JavaScript 和 CSS 资源,都可以正常提供(当然,只要它们的“复制到输出目录”设置为“如果较新则复制”)。

这就像 AngularJS 中的 HTML5 推送状态功能的魅力一样。

于 2013-09-23T15:48:53.563 回答
4

RazorRockstars.Web一个实现。我将对其进行修改以使用通配符路径和默认视图:

[FallbackRoute("/{Path*}")]
public class Fallback
{
    public string Path { get; set; }
    public string PathInfo { get; set; }
}

public class RockstarsService : Service
{
    [DefaultView("Index")]
    public object Any(Fallback request)
    {
        request.PathInfo = base.Request.PathInfo;
        return request;
    }
    // ...
}

由于这是一项服务,因此它需要查看页面(此处为详细信息)而不是内容页面。

在 RockStars 示例中,我无法确定将为 FallBackResponse 呈现什么视图,但明确设置视图应该是您所需要的。

我添加到该方法的[DefaultView("Index")]属性Any将响应映射到 Views/Index.cshtml 文件。Index.cshtml 文件可以为空但用于模板声明,并且单页应用程序的完整标记可以在您的模板文件中(即 _Layout.cshtml)

没有剃须刀

将 html 读入字符串并返回,同时使用属性将内容类型设置为“text/html”,请参阅关于服务返回类型的 wiki 文档

public class RockstarsService : Service
{
    static string readContents;

    [AddHeader(ContentType = "text/html")]
    public string Any(Fallback request)
    {

        // check timestamp for changes for production use
        if (readContents == '') {
            using (StreamReader streamReader = new StreamReader(pathFromConfigFile, Encoding.UTF8))
            {
                 readContents = streamReader.ReadToEnd();
            }
        }
        return readContents;
    }
    // ...
}
于 2013-08-20T17:19:30.993 回答