这是将 Web Api 作为单独项目托管的最佳实践吗

Is that a best practice to host WebApi as a seperate project

我正在使用 Web Api 和 Angular JS 开发单页应用程序。我想获取出色 SPA 应用程序的所有最佳实践。

我想知道最好的做法是将 Web Api 项目作为一个单独的项目托管,或者只是将其与您的水疗中心一起包含在同一个项目中。

谢谢

我相信你最好的选择是将 SPA 放入一个单独的项目中,甚至更好地放在一个不同的存储库中,因为这样更灵活并且支持许多不同的 development/deployment 场景,尤其是当你的项目变得更大时。

我个人从混合文件方法开始,并在项目超出 Todos 示例的大小几天后转向单独的 Repos 方法。

单独 projects/repos 的一些优点是:

  • search/replace 或转到 file/class 的更好搜索上下文。
  • 每个 project/solution 的文件较少,因此 visual studio 没有抓取到 它的膝盖。
  • 如果你在 SPA 项目中获得比 VS(例如 webstorm)更好的 javascript/typescript 支持,你可以更轻松地使用不同的编辑器。
  • 文件结构在小型解决方案资源管理器中更具可读性window,因为嵌套较少
  • 不同的人可以在 frontend/backend
  • 上独立工作
  • 您的 SPA 可以有自己的版本控制,您可以根据需要混合和匹配 FE/BE 个版本
  • 更简单的持续集成,因为您不混合 frontend/backend 构建步骤
  • 您可以在部署时决定它们是否要托管在
    同一台主机,或不同的机器(启用 CORS 支持后)
  • 最终,它使您的 SPA 成为第一个 class 公民,而不仅仅是您网站的子文件夹 api。

另一方面,我想不出将 SPA 作为 WebApi 的子文件夹有什么好处,除非您希望将复杂性降至最低的非常小的项目。

一个主机SPA应该独立于API吗?

如果您需要独立于后端扩展前端,那么请使用 内容分发网络 (CDN),它允许您使用自己的域名,具有可配置的缓存策略和所有其他现代属性,如 100% SLA 等

您的顾虑可能是

  • 单个解决方案的两个重要部分的非同步部署。
  • 维护分布式基础架构(另一个故障点)的额外资源(工时);
  • 向前端传递基本参数的权衡。任何一个
    • 您使前端包在暂存环境之间可变并包含参数或
    • 你保持它不可变并且在启动时需要额外的时间来获取它们。

我会消除对 CORS 的额外 OPTIONS 请求的担忧,因为 HTTP/2 将延迟降至 0。

Hosting SPA from WebAPI wouldn't have those concerns (but doesn't allow independent scaling).

如何从 .NET Web 托管 SPAAPI?

从 .NET API 托管 SPA 时,可以使用三种扩展方法来完成所有繁重的工作(从 .NET Core 2.x 开始,现在仍然如此.NET 5):

  • UseSpa 提供默认页面 (index.html) 并将所有请求重定向到那里。
  • UseStaticFiles 服务于 Web 根文件夹下的 index.html 静态文件(默认情况下 wwwroot)。如果没有此方法,Kestrel 将 return index.html 响应所有静态内容请求。
  • UseSpaStaticFiles does a similar thing but it requires ISpaStaticFileProvider 待注册以解析静态文件的位置。如果静态文件不在默认的 Web 根文件夹 wwwroot.
  • 下,则需要它

要从 wwwroot 托管 SPA,您只需要 UseSpaUseStaticFiles 方法。

不要忘记两件重要的事情:

  • 静态资产的缓存策略;
  • 正在为前端服务注入环境变量。

所以你在Startup.cs中的Configure方法可能有以下补充:

// Serves other than 'index.html' files from wwwroot folder with a cache policy
app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        var headers = ctx.Context.Response.GetTypedHeaders();
        headers.CacheControl = new CacheControlHeaderValue { MaxAge = TimeSpan.FromDays(12*30) };
    }
});
// Serves 'index.html' with no-cache policy and passing variables in a cookie
app.UseSpa(c => c.Options.DefaultPageStaticFileOptions = new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        var response = ctx.Context.Response; 
        response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue
        {
            NoCache = true,
            NoStore = true,
            MustRevalidate = true,
            MaxAge = TimeSpan.Zero
        };
        // Passing a variable to SPA in a short-lived cookie
        response.Cookies.Append("importantVariable", "Value", new CookieOptions { MaxAge = TimeSpan.FromSeconds(30) });
    }
})

this blog post 中查看更多内容,其中还考虑了其​​他选项。如果您不喜欢 cookie,修改 index.html 和注入变量的静态文件没有问题。

另请查看 this open source project at GitHub that does the trick with hosting SPA and passing parameters in cookies (direct link to Startup configuration and reading cookies in Angular)。