ASP.Net MVC/Web API自定义动态bundle在生产中工作,但在开发中不工作



在我的开发环境中,当我尝试加载动态生成的捆绑包时,我会收到404个响应。奇怪的是,这并没有发生在我们的生产环境中,所以这并不是真正的灾难,但它让开发有点令人沮丧。

应该发生的是:

  1. 在应用程序预启动(WebActivatorPreStart)时,设置DependencyResolver、Webneneneba API和MVC配置
  2. 在应用程序后启动(WebActivatorPostStart)时,通过依赖解析程序(比如IMyService)加载服务
  3. 实例化自定义IBundleTransformJsonBundleTransform-请参阅下面的代码)
  4. 致电IEnumerable<string> IMyService.ListSupportedGroups()
  5. 循环使用支持的组并构建自定义捆绑包(CustomBundle-请参阅下文…)
  6. 将自定义捆绑包添加到BundleTable.Bundles
  7. 将静态JS/CSS文件添加到BundleTable.Bundles
  8. 在页面中引用各种捆绑包,并在浏览器中查看内容

对于自定义捆绑包,它在步骤8失败,出现404个错误。调试时,永远不会调用自定义bundle transformer。然而,正如我上面提到的,在生产中一切都很好——尽管我已经比较了配置文件,但在我的开发配置中没有发现任何遗漏,这应该会有任何效果。此外,在生产中,无论web.config中的compilation->debug值如何,捆绑内容都会正确呈现。

其他注意事项:

  • 我在生产中使用IIS 7.5,在开发中使用IIS 8
  • 当我在dev中设置debug="false"时,我在所有捆绑包上都会得到404
  • 这是有效的,但在某个时候停止了,我无法确定何时或为什么会发生这种情况

我使用的代码如下(删除多余的代码,更改名称以保护无辜者,等等):

转换

public class JsonBundleTransform: IBundleTransform
{
    public void Process( BundleContext context, BundleResponse response )
    {
        var bundle = context.BundleCollection.FirstOrDefault(b => b.Path == context.BundleVirtualPath) as CustomBundle;
        response.Content = string.Format( ";var obj = {0};", JsonConvert.SerializeObject( bundle.KeyValues ) );
        response.ContentType = "application/javascript";
        response.Cacheability = HttpCacheability.Server;
    }
}

自定义捆绑包

public class CustomBundle: Bundle
{
    public CustomBundle( string virtualPath, IBundleTransform transform, IMyService myService, string groupId ) : base( virtualPath, transform )
    {
        keyValues = myService.GetKeyValuesByGroupId( groupId );
    }
    public IDictionary<string, string> KeyValues { get; private set; }
}

配置

public class BundleConfig
{
    public static void RegisterBundles( BundleCollection bundles, IMyService myService )
    {
        var transform = new JsonBundleTransform();
        var jsonBundles = myService
            .ListSupportedGroups()
            .Select( groupId => 
                new CustomBundle( 
                    string.Format( "~/resource/script/keyValues-{0}.js", groupId ), 
                    transform, 
                    myService, 
                    groupId
                )
            );
        foreach ( var jsonBundle in jsonBundles ) {
            bundles.Add( jsonBundle );
        }
        // Static bundles added here...
    }
}

渲染脚本

@Scripts.Render( Url.Content( string.Format( "~/resource/script/keyValues-{0}.js", Model.GroupId ) ) ) )

知道我在这里错过了什么吗?

提前感谢您提供的任何帮助或建议。

编辑

考虑到它正在生产中,我强烈倾向于认为这个问题是环境问题,而不是代码问题——尽管,就我而言,我还不知道它是什么。我认为最有可能的候选者是与配置或引用有关的东西(老实说,IIS版本似乎是不太可能的原因)。

如果将".js"附加到捆绑包的虚拟路径,IIS将把对这些捆绑包的任何请求解释为对静态文件的请求,除非:

  • 您已指示IIS为所有请求运行所有托管模块
  • 您已明确配置IIS以使用路由处理程序处理捆绑包URL

如果您比较生产和开发配置,我怀疑您会发现生产环境的"runAllManagedModulesForAllRequests"设置为"true"。

解决这个问题最简单的方法就是从捆绑包的虚拟路径中删除".js"扩展名。如果您希望保留扩展,可以配置IIS将请求传递给路由处理程序:

  <system.webServer>
    <handlers>      
      <add name="UrlRoutingHandler" 
           type="System.Web.Routing.UrlRoutingHandler, 
                 System.Web, Version=4.0.0.0, 
                 Culture=neutral, 
                 PublicKeyToken=b03f5f7f11d50a3a" 
           path="/resource/script/*" 
           verb="GET"/>      
    </handlers>
  </system.webServer>

您也可以启用"runAllManagedModulesForAllRequests",但这会带来性能问题,因为没有理由在整个托管管道中运行静态文件。

相关内容

最新更新