Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/31.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ASP.NET中图像的CDN_C#_Asp.net_Httphandler_Cdn_Static Content - Fatal编程技术网

C# ASP.NET中图像的CDN

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

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

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

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

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