【问题标题】:Override ASP.NET tilde (~) resolution just for images仅针对图像覆盖 ASP.NET 波浪号 (~) 分辨率
【发布时间】:2012-05-10 13:51:10
【问题描述】:

我有一个大型遗留应用程序,我想将我们所有的图像移动到 CDN。

目前,我们所有的图像都位于应用程序根目录下,因此路径都类似于"~/Images/MyImage.jpg." 由于我们系统的要求,如果要生存,我必须在运行时确定给定图像的完整 URL在 CDN 中。这使我们可以严格控制版本控制、缓存等。逐个图像地更改代码将是一个非常漫长、乏味且容易出错的过程。

我想做的是能够连接到 ASP.NET 中的某些机制,我可以在其中决定如何解析图像的波浪号。这将允许我们所有现有代码保持原样,并且图像将在运行时定向到 CDN。

我发现了一些关于 VirtualPathProviders 的提及,这听起来像是我正在寻找的东西,但是当我测试它时,唯一的路径被传递到 CombineVirtualPaths 函数是以.ASPX, .ASCX, and .MASTER 结尾的路径。

谁能帮我找到一个干净、低风险的选择?

基本上,我需要在我的应用程序中将“~/images/myimage.jpg”作为“http://mycdnhost.com/myimage.jpg”呈现给浏览器的任何地方。这将完全避免浏览器向我们的服务器发送图像请求。

【问题讨论】:

标签: asp.net cdn virtualpathprovider resolveurl


【解决方案1】:

使用 IIS 路由

提供来自不同站点或服务器的静态内容。 您的 Web 应用程序部署在多台服务器上,动态 Web 内容位于一个站点或服务器上,而所有静态内容位于不同的站点或服务器上。您可以将 URL 重写模块与 IIS 应用程序请求路由模块一起使用,将所有对静态文件的请求转发到不同的服务器,同时为来自当前服务器的所有动态网页请求提供服务。这样,ASP.NET 路由仅用于动态 Web 内容,而不评估静态内容的任何 URL。

以下示例显示了可用于此场景的 URL 重写规则:

<rewrite>
    <rules>
        <rule name="Forward to static file server">
            <match url="^.+\.(?:jpg|bmp|gif)$" />
            <action type="Rewrite" url="http://static_file_server/{R:0}" />
        </rule>
    </rules>
</rewrite>

更多信息请访问:http://learn.iis.net/page.aspx/496/iis-url-rewriting-and-aspnet-routing/

使用 HttpModule

  1. 您应该尝试创建拦截图像请求的 HttpModule 并尝试将它们重定向到您的 CDN 路径。首先,您需要将图像文件的文件扩展名映射到 IIS 中的 aspnet_isapi。 然后,添加一个为这些文件扩展名执行 url 重定向的 httpmodule。 例如,在模块的 beginrequest 方法中:

    void context_BeginRequest(object sender, EventArgs e) { 如果(request.url.endwith .jpg/.png ...) 重定向到相对于根文件夹的路径。 }

  2. 使用 httpmodule 的另一个选项是拦截呈现的 html 并使用正则表达式替换图像 url 以指向 CDN。在这里你可以看到它是如何工作的http://shoaibsheikh.blogspot.com/2012/05/change-image-url-in-aspnet-using.html

此方法将增加 asp.net 生命周期的开销,因为我们必须在将整个页面发送到客户端之前拦截整个页面。

使用控制适配器

如果您只想处理图像控件以劫持图像控件渲染方法并有选择地更改 cdn url 的路径,您应该尝试使用 ASP.Net 控件适配器。这种方法风险较小,可拆卸。

 public class CDNImageControlAdapter : ControlAdapter
    {
        protected override void Render(HtmlTextWriter writer)
        {
            Image img = this.Control as Image;
            if (img == null)
            {
                base.Render(writer);
                return;
            }

            if (img.ImageUrl.Length > 0)
            {
                // Let the HyperLink render its begin tag
                img.RenderBeginTag(writer);

                Image image = new Image();

                if (img.ImageUrl.IndexOf("~") == 0)
                {
                    img.ImageUrl = (img.ImageUrl.Replace("~", "http://mycdn.com/images/"));

                }

                img.RenderControl(writer);
            }
            else
            {
                // HyperLink.RenderContents handles a couple of other
                // cases if its ImageUrl property hasn't been set. We
                // delegate to that behavior here.
                base.Render(writer);
            }
        }
    }

并将 All.broswer 文件添加到应用程序的 App_Browsers 文件夹中

<!--
    You can find existing browser definitions at
    <windir>\Microsoft.NET\Framework\<ver>\CONFIG\Browsers
-->
<browsers>
  <browser id="Default">
    <controlAdapters>
      <adapter controlType="System.Web.UI.WebControls.Image" adapterType="CDNImageControlAdapter, MyWebApplication" />
    </controlAdapters>
  </browser>
</browsers>

问候。

【讨论】:

  • 这个解决方案对我来说并不理想,因为这只会解决 Image 控件。我想在任何地方使用波浪号指定图像路径。这可以是任意数量的 WebControls、HtmlControls 或 3rd 方控件上的任意数量的属性。我需要一个通用的解决方案。
  • 好吧,我以为你只关心图像控件。在您的情况下,您应该尝试使用 httpmodule 但为此您必须映射要通过托管 isapi 模块传递的图像扩展名,这可能会给服务器上的 asp.net 进程带来开销,但这是一个选项。
  • 感谢您的更新,但它仍然不能满足我的确切要求。我更新了我的问题,希望能增加清晰度。您的建议要求图像请​​求首先到达我们的服务器,然后重定向到其他地方。我们需要最初呈现给服务器的标记使图像路径指向完全不同的主机。
  • 如果你可以应用的话,我已经添加了另一个使用 IIS 路由的选项。检查
  • 再次,问题是您建议的每个解决方案都会在服务器接收到图像请求时重写路径。我需要在将路径发送到浏览器之前操作图像的路径。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-20
  • 1970-01-01
  • 1970-01-01
  • 2017-08-23
相关资源
最近更新 更多