2

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

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

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

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

我认为这可能是我最终必须要做的,但对我来说似乎有点笨拙。我还设想由于“<%=”而无法修改控件集合的旧 .NET 错误的问题,尽管“<%#”解决方案可能会起作用。

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

4

9 回答 9

2

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

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

于 2010-03-27T19:59:53.903 回答
2

您是否考虑过一种稍微简单的方法?

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

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

在您的<appSettings/>元素中,您可以简单地选择前置 URL,例如:

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 的基类也是一件简单的事情,然后在您的解决方案中对所有剩余页面执行查找/替换。

希望这可以帮助。

于 2010-03-29T16:04:05.980 回答
2

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

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; }
    }
}

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

于 2011-03-07T12:52:23.873 回答
1

如果您使用标签显示图像,您可以创建一个控件适配器,这些允许您更改 .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>
于 2010-03-30T22:42:14.310 回答
0

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

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

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

于 2011-12-02T14:38:13.400 回答
0

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

于 2010-03-27T19:59:34.067 回答
0

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

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

于 2010-03-29T00:13:21.447 回答
0

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

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

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

于 2011-01-14T03:37:25.747 回答
0

我必须解决你的问题和另一个问题,即我不想在开发过程中从 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));
    }       
}
}

有关更多信息,我写了一篇关于 如何在生产中使用 CDN 而不是在开发期间使用 CDN的文章

于 2015-12-19T18:38:40.883 回答