我正在将我的网络应用程序中的所有图像移动到CDN,但我希望能够轻松地打开或关闭CDN,而无需硬编码图像的路径。
我的第一个想法是为图像扩展添加一个HttpHandler,这取决于web.config中的变量(类似的东西)是从服务器还是从CDN提供图像。但是稍微给出了这个之后我认为我基本上已经排除了这一点,因为它会导致ASP.NET处理每个图像的请求,从而增加了开销,它实际上可以完全减轻使用CDN的好处。 / p>
另一种方法是,由于我的所有页面都是从基页类继承的,因此我可以在基类中创建一个函数,该函数根据web.config变量确定从哪个文件路径提供服务。然后我会在标记中做这样的事情:
<img src='<%= GetImagePath()/image.png' />
我认为这可能是我最终要做的事情,但对我来说似乎有点笨拙。我还设想旧的.NET错误导致无法修改控件集合的问题,因为“&lt;%=”虽然“&lt;%#”解决方案可能会有效。
关于如何实现这一点的任何想法或想法?
答案 0 :(得分:2)
基于预优化假设,您已经驳回了编写HttpHandler
的问题。我会重新审视这个并且肯定写一个简单的HttpHandler
并测试它。您可能会发现您的Page方法解决方案可能会更慢,尤其是如果您涉及ASP预处理器。
HttpHandlers非常接近金属 - 这是IIS将请求交给ASP.Net的微不足道的开销。这将是一个比你提出的更优雅的解决方案,并且可能更具可扩展性,我愿意打赌 - 更快。
答案 1 :(得分:2)
您是否考虑过稍微简单的方法?
如果您的页面都是从基类继承的,那么您可以在包含CDN前置URL的属性上公开属性(或者,如果要关闭CDN,则向本地服务器公开)。然后,将前置URL存储在web.config中是一件小事:
public string PrependURLPath() {
get { return ConfigurationManager.AppSettings["ImagePrependURL"].ToString(); }
}
在<appSettings/>
元素中,您只需选择前置网址即可,例如:
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的基类也很简单,然后在你的解决方案中对所有剩余的页面进行查找/替换
希望这有帮助。
答案 2 :(得分:2)
在这里很晚才称重,但我一直在寻找类似的解决方案。搜索谷歌健全检查我做了什么。不考虑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; }
}
}
它很粗糙,准备就绪,但它确实有效:)显然它应该依赖于一些可配置的值而不是字符串文字,但这不是一个很大的改变
答案 3 :(得分: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>
答案 4 :(得分:0)
您可以循环所有控件并更改基类上的prerender事件中的图像URL ...
答案 5 :(得分:0)
HTTP Handler方法的好处在于它非常可重用和可配置:您可以根据位置识别要处理的img路径 - 假设它们所处的结构有助于此。
可能的缺点是图像文件扩展名(.jpg,.png等)不会自动传递到asp.net管道;您可以轻松配置IIS来执行此操作 - 但您需要在IIS上具有一定级别的contriol - 因此如果您在共享托管环境中,它可能不是一个选项。
答案 6 :(得分:0)
我将采用@Rhys方法进行图像控制。
大多数时候,我尝试使用背景图像css而不是使用图像控制。
之后,我将css和图像一起上传到云端,并在相对路径下正常工作。
答案 7 :(得分:0)
看起来还没有接受答案,所以这是我的建议。我有类似的问题处理透明地修改URL(到另一端,但我也想过将它用于CDN支持)。
这是一个旧的过滤器/模块,但它通过一些调整很好地满足了我的需求:http://www.paraesthesia.com/archive/2007/12/14/urlabsolutifiermodule---convert-urls-in-asp.net-output-to-absolute.aspx
你可以做的是做一个响应过滤器并用httpmodule挂钩(就像这个绝对模块那样)。如果您使用此模块+响应过滤器,您可以通过修改它的源来替换主机名/前缀所有URL以使用CDN,从而实现所需。
答案 8 :(得分: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));
}
}
}
有关更多信息,我写了一篇关于此的文章 How to use a CDN in production but not during development