【问题标题】:CDN for Images in ASP.NETASP.NET 中图像的 CDN
【发布时间】:2015-12-20 02:38:40
【问题描述】:

我正在将我的 Web 应用程序中的所有图像移动到 CDN,但我希望能够轻松地打开或关闭 CDN,而无需硬编码图像的路径。

我的第一个想法是为图像扩展添加一个 HttpHandler,这取决于 web.config 中的变量(类似 )是从服务器还是从 CDN 提供图像。但是在稍微考虑一下之后,我认为我基本上已经排除了这一点,因为它会导致 ASP.NET 处理每个图像的请求,从而增加开销,它实际上可能会完全降低使用 CDN 的好处。

另一种方法是,由于我的所有页面都继承自一个基页面类,因此我可以在基类中创建一个函数,该函数根据 web.config 变量确定从哪个路径提供文件。然后我会在标记中做这样的事情:

<img src='<%= GetImagePath()/image.png' />

我认为这可能是我最终必须要做的事情,但对我来说似乎有点笨拙。我还设想由于“

关于如何实现这一点的任何想法或想法?

【问题讨论】:

    标签: c# asp.net httphandler cdn static-content


    【解决方案1】:

    您基于预先优化的假设拒绝编写HttpHandler。我会重新审视这个,肯定会写一个简单的HttpHandler 并测试它。您可能会发现您的 Page 方法解决方案甚至可能会更慢,尤其是在涉及 ASP 预处理器的情况下。

    HttpHandlers 非常接近金属 - IIS 将请求交给 ASP.Net 的开销微乎其微。这将是一个比您提出的更优雅的解决方案,并且可能更具可扩展性,我愿意打赌 - 更快。

    【讨论】:

    • 是的,我不知道为什么我什至没有意识到第二种方法会涉及到 ASP.net 进程。 . .就我而言,相当轻率。我想我最大的担心是每个图像请求都会从 CDN 请求图像,并可能减轻从 CDN 的响应标头完成的客户端缓存?我对幕后发生的事情了解得不够多,无法做出这个决定。
    • 如果您的 HttpHandler 为图像数据提供服务器,那么使用 CDN 不会节省任何带宽。另一种选择是让您的 HttpHandler 向同一 url 的 CDN 版本发送 302。
    【解决方案2】:

    您考虑过稍微简单一点的方法吗?

    如果您的页面都继承自一个基类,您可以将包含前置 URL 的属性公开给您的 CDN(或者,如果您想关闭 CDN,则公开给您的本地服务器)。然后将前置 URL 存储在 web.config 中是一件小事:

    public string PrependURLPath() {
     get { return ConfigurationManager.AppSettings["ImagePrependURL"].ToString(); }
    }
    

    在您的&lt;appSettings/&gt; 元素中,您可以简单地选择前置网址,例如:

    http://my.cdn.com/user/

    或:

    http://my.own.server.com/images/
    

    很简单!

    然后,您就可以按照您的示例对图像引用进行编码,但调用您的基本页面属性以公开所需的路径:

    <img src='<%= this.BasePage.PrependURLPath() + [YourImagePath.png] %>'/>
    

    我同意通过内联调用设置图像源很麻烦,但您可以按照其他人的建议进行操作,然后遍历页面上的图像控件,随时更改前置 URL。

    即使您的页面当前仅从 System.Web.UI.Page 继承,创建您自己的继承 System.Web.Page 的基类也是一件简单的事情,然后在您的解决方案中对所有剩余页面执行查找/替换.

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      在这里称重很晚,但我自己一直在寻找类似的解决方案。搜索谷歌以健全检查我做了什么。没有考虑HttpHandler 方法,我所做的只是扩展ASP.net Image 控件:

      public class Img : Image
      {
          public Img()
          {
              RelativePath = false;
          }
      
          public bool RelativePath { get; set; }
      
          public override string ImageUrl
          {
              get
              {
                  if (RelativePath)
                      return base.ImageUrl;
      
                  return "http://some.configurable-value.com" + base.ImageUrl;
              } 
              set { base.ImageUrl = value; }
          }
      }
      

      它很粗糙而且准备好了,但它可以工作:) 显然它应该依赖于一些可配置的值而不是字符串文字,但这并不是一个大的变化

      【讨论】:

        【解决方案4】:

        如果您使用标签显示图像,您可以创建一个控件适配器,这些允许您更改 .net 控件的呈现方式或普遍更改它们,这样的事情应该可以解决问题:

        using System.Web.UI.WebControls.Adapters;
        using System.Web.UI;
        using System.Web.UI.WebControls;
        
        namespace ExampleCode
        {
            public class ImageAdapter : WebControlAdapter
            {
                private bool UseCdn
                {
                    get { return true; } // Get value from config or anywhere else
                }
        
                protected override void OnPreRender(EventArgs e)
                {
                    base.OnPreRender(e);
        
                    Image image = (Image)Control;
        
                    if (UseCdn)
                    {
                        // If using relative urls for images may need to handle ~
                        image.ImageUrl = String.Format("{0}/{1}", "CDN URL", image.ImageUrl);
                    }
                 }
              }
         }
        

        然后将浏览器文件添加到您的 Web 项目中的 App_Browsers 文件夹,如下所示:

        <browsers>
            <browser refID="Default">
              <controlAdapters>
                <adapter
                  controlType="System.Web.UI.WebControls.Image"
                  adapterType="ExampleCode.ImageAdapter"
                  />
              </controlAdapters>
            </browser>
        </browsers>
        

        【讨论】:

          【解决方案5】:

          您可以循环所有控件并在基类的 prerender 事件中更改图像 url...

          【讨论】:

            【解决方案6】:

            HTTP 处理程序方法的好处是它非常可重用和可配置:您可以根据位置识别要处理的 img 路径 - 假设它们所在的结构对此有所帮助。

            可能的缺点是图像文件扩展名(.jpg、.png 等)不会自动传递到 asp.net 管道;您可以轻松配置 IIS 来执行此操作 - 但您需要对 IIS 有一定程度的控制 - 因此,如果您在共享托管环境中,这可能不是一个选项。

            【讨论】:

              【解决方案7】:

              我将采用@Rhys 方法进行图像控制。

              大多数时候,我尝试使用背景图像 css 而不是使用图像控件。

              之后,我将 css 和图像一起上传到云端,并在相对路径下正常工作。

              【讨论】:

                【解决方案8】:

                似乎还没有公认的答案,所以这是我的建议。我在处理透明地修改 URL 时遇到了类似的问题(为了不同的目的,但我也考虑过使用它来支持 CDN)。

                这是一个旧的过滤器/模块,但它通过一点调整就可以很好地满足我的需求:http://www.paraesthesia.com/archive/2007/12/14/urlabsolutifiermodule---convert-urls-in-asp.net-output-to-absolute.aspx

                您可以做一个响应过滤器并将其与 httpmodule 挂钩(就像这个绝对值一样)。如果您使用此模块 + 响应过滤器,您可能可以通过修改其源以替换主机名/前缀所有 url 以使用 CDN 来实现您所需要的。

                【讨论】:

                  【解决方案9】:

                  我必须解决您的问题和另一个问题,即我不想在开发过程中从 CDN 中获取资源,但仅在网站部署在生产服务器上时才需要。 为了解决这个问题,我开发了一个 ExpressionBuilder,它只在生产环境中添加 CDN URL。

                  <asp:Image ImageUrl="<%$ CdnUrl:/images/myimage.png %>" runat="server" />
                  

                  在之前的代码中,CDN URL 只会在生产环境中添加。

                  namespace IdeaR.Web.Compilation
                  {
                  [ExpressionPrefix("CdnUrl")]
                  public class CdnUrlExpressionBuilder : ExpressionBuilder
                  {
                      public static object GetCdnUrl(string expression, Type target, string entry)
                      {
                          var retvalue = expression;
                          var productionUri = new Uri("http://www.myproductionurl.com",
                              UriKind.Absolute);
                          var currentUri = HttpContext.Current.Request.Url;
                          var cdnUrl = "http://cdn.mycdn.com";
                  
                          // If this is a production website URL
                          if (currentUri.Scheme == productionUri.Scheme &&
                              currentUri.Host == productionUri.Host)
                              retvalue = cdnUrl + expression;
                  
                          return retvalue;
                      }
                  
                      public override CodeExpression GetCodeExpression(BoundPropertyEntry entry,
                          object parsedData, ExpressionBuilderContext context)
                      {
                          var componentType = entry.DeclaringType;
                          var expressionArray = new CodeExpression[3]
                          {
                              new CodePrimitiveExpression(entry.Expression.Trim()),
                              new CodeTypeOfExpression(componentType),
                              new CodePrimitiveExpression(entry.Name)
                          };
                  
                          var descriptor = TypeDescriptor.GetProperties(componentType)
                              [entry.PropertyInfo.Name];
                          return new CodeCastExpression(descriptor.PropertyType,
                              new CodeMethodInvokeExpression(
                                  new CodeTypeReferenceExpression(GetType()),
                                  "GetCdnUrl", expressionArray));
                      }       
                  }
                  }
                  

                  有关更多信息,我写了一篇关于此的文章 How to use a CDN in production but not during development

                  【讨论】:

                    猜你喜欢
                    • 2012-02-28
                    • 1970-01-01
                    • 2011-04-21
                    • 2016-08-20
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-07-21
                    • 2011-04-20
                    相关资源
                    最近更新 更多