C# ASP.NET中图像的CDN
我正在将web应用程序中的所有图像移动到CDN,但我希望能够轻松地打开或关闭CDN,而无需硬编码图像路径 我的第一个想法是为映像扩展添加一个HttpHandler,该扩展取决于web.config(类似)中的变量是从服务器还是从CDN为映像提供服务。但在给出一点之后,我认为我基本上已经排除了这一点,因为这将导致ASP.NET处理每个映像的请求,从而增加开销,并且实际上可能完全减轻使用CDN的好处 另一种方法是,由于我的所有页面都继承自一个基类,因此我可以在基类中创建一个函数,该函数根据web.config变量确定从哪个路径为文件提供服务。然后我会在标记中执行类似的操作:C# ASP.NET中图像的CDN,c#,asp.net,httphandler,cdn,static-content,C#,Asp.net,Httphandler,Cdn,Static Content,我正在将web应用程序中的所有图像移动到CDN,但我希望能够轻松地打开或关闭CDN,而无需硬编码图像路径 我的第一个想法是为映像扩展添加一个HttpHandler,该扩展取决于web.config(类似)中的变量是从服务器还是从CDN为映像提供服务。但在给出一点之后,我认为我基本上已经排除了这一点,因为这将导致ASP.NET处理每个映像的请求,从而增加开销,并且实际上可能完全减轻使用CDN的好处 另一种方法是,由于我的所有页面都继承自一个基类,因此我可以在基类中创建一个函数,该函数根据web.c
<img src='<%= GetImagePath()/image.png' />
我想这可能是我最后不得不做的,但对我来说似乎有点笨重。我还设想了旧的.NET错误的问题,即由于“您可以循环所有控件,并在基类上的prerender事件中更改图像url…基于预优化的假设,您已放弃编写
HttpHandler
。我会重新考虑这一点,肯定会编写一个简单的HttpHandler
,并对其进行测试。您可能会发现您的页面方法解决方案可能会更慢,尤其是当您使用ASP预处理器时
HttpHandler非常接近于金属——IIS将请求传递给ASP.Net的开销很小。这将是一个比您所建议的更优雅的解决方案,而且可能更具可扩展性,我愿意打赌它会更快。HTTP处理程序方法的优点是它非常可重用和可配置:您可以根据位置识别要处理的img路径——假设它们所在的结构有助于实现这一点
可能的缺点是图像文件扩展名(.jpg、.png等)不会自动传递到asp.net管道;您可以很容易地配置IIS来实现这一点,但您需要对IIS进行一定程度的控制,因此,如果您在共享主机环境中,这可能不是一个选项。您是否考虑过稍微简单一点的方法 如果您的页面都从基类继承,则可以将包含前置URL的属性公开到您的CDN(或者,如果要关闭CDN,则公开到您的本地服务器)。然后,在web.config中存储前置URL是一件小事:
public string PrependURLPath() {
get { return ConfigurationManager.AppSettings["ImagePrependURL"].ToString(); }
}
在
元素中,您只需选择前置URL,例如:
http://my.cdn.com/user/
或:
很简单
然后,您可以按照示例对图像引用进行编码,但需要调用您的基本页属性以公开所需的路径:
<img src='<%= this.BasePage.PrependURLPath() + [YourImagePath.png] %>'/>
”/>
我同意通过内联调用设置图像源很麻烦,但是您可以按照其他人的建议执行,然后迭代页面上的图像控件,在执行时更改前置URL
即使您的页面当前仅继承自System.Web.UI.Page,创建您自己的基类继承System.Web.Page也是一件简单的事情,然后在解决方案中对所有剩余页面执行查找/替换
希望这会有所帮助。如果您使用标记显示图像,您可以创建一个控件适配器,这些标记允许您更改.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>
我将采用@Rhys方法进行图像控制 大多数时候,我尝试使用背景图像css,而不是使用图像控件
之后,我将css和图像一起上传到云端,并在相对路径上运行良好。在这里已经很晚了,但我自己一直在寻找类似的解决方案。搜索谷歌来检查我做了什么。没有考虑<代码> HttpHandler <代码>方法,我所做的只是扩展ASP.NET <代码>图像<代码>控件:
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; }
}
}
这是一个粗糙的、现成的,但它是有效的:)显然,它应该依赖于一些可配置的值,而不是字符串文字,但这不是一个大的变化看起来还没有一个被接受的答案,所以这里是我的建议。我在透明地修改URL时遇到了类似的问题(为了不同的目的,但我也考虑将其用于CDN支持) 这是一个旧的过滤器/模块,但只需稍加调整即可满足我的需要:
您可以做的是创建一个响应过滤器,并将其与一个httpmodule挂钩(就像这个绝对化器所做的那样)。如果您使用此模块+响应过滤器,您可能会通过修改其源代码来替换主机名/前缀所有URL以使用CDN来实现所需的功能。我必须解决您的问题和另一个问题,也就是说,我不想在开发过程中从CDN获取资源,而只是在网站部署到生产服务器上时。 为了解决这个问题,我开发了一个ExpressionBuilder,它只在生产环境中预先添加CDN URL
<asp:Image ImageUrl="<%$ CdnUrl:/images/myimage.png %>" runat="server" />
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));
}
}
}
为了获得更多信息,我写了一篇关于这方面的文章
是的,我不知道为什么我没有意识到第二种方法会涉及ASP.net进程。我这方面真是太粗心了。我想我最担心的是,每个映像请求都会从CDN请求映像,并且可能会减少从CDN的响应头执行的客户端缓存?我对引擎盖下发生的事情了解得不够,无法做出这样的决定。如果您的HttpHandler服务器提供图像数据,那么使用CDN不会节省任何带宽。另一种选择是让您的HttpHandler向CDN版本发送302
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));
}
}
}