【问题标题】:ResolveClientUrl works differently in ASP.Net 4 and 3.5ResolveClientUrl 在 ASP.Net 4 和 3.5 中的工作方式不同
【发布时间】:2011-08-24 21:29:46
【问题描述】:

[抱歉,如果我的问题标题不能准确描述我的问题 - 如果您能想到一个更好的标题并有权更改它,那么请随时更改它!]。

我认为我偶然发现了 ASP.Net 3.5 和 4.0 之间的一个小的突破性变化。

[编辑:我已经确认 twix 3.5 和 4.0 的行为发生了变化 - 请参阅我的回答]

这是场景:-

我有一个 ASP.Net 3.5 Web 应用程序。 我有一个简单的用户控件 {appRoot}/Controls/Widgets/MyPictureAndTextWidget.ascx,它基本上包含一些文本和另一个用户控件 ({appRoot}/Controls/Widgets/MyPicture.ascx)。

在大多数情况下,此控件以正常方式使用 - 即,将其包含在其他页面的标记中,但我有一个实例,我需要获取 HTML 以使用 Ajax 在客户端上呈现。

我实现这一点的方法是编写一个 asmx Web 服务,它以编程方式创建一个新页面并动态“LoadControl”用户控件,然后在字符串构建器中捕获页面呈现的输出 - 特别不雅,但它有效!来源见底部。

但是,在将项目升级到 Asp.Net 4.0 后,上面的代码不再像以前那样工作了;图像在渲染时具有src="../images/xxx.png(注意不需要的'../')。

如果您想自己运行它,我已经创建了一个小演示应用程序http://cid-916198839f3e806c.office.live.com/self.aspx/Public/TestingImageWTF.zip。当您使用 3.5 编译应用程序时,它可以工作(即您在测试页面上看到 2 张蜘蛛图片),但是当您在 4.0 下编译和运行时,您只能看到 1 张蜘蛛(另一张图片的 URL 错误)。

我能想到的唯一解释是ResolveClientUrl 方法(Image 控件将使用它来计算当前执行页面中图像的相对路径是什么)的行为不同。图片 url 以“../images/xxx.png”的形式出现的事实意味着 Image 控件“认为”它在运行时具有类似“{appRoot}/folder/handler”的路径的页面中执行在 4.0 以下,但它认为它在 3.5 以下的上下文“{appRoot}/handler”中运行。

我希望这对您有意义 - 抱歉,如果我没有非常清楚或简洁地描述问题。

谁能告诉我们怎么做:-

  • 恢复 3.5 的行为(显然不会恢复到 3.5 框架!)

  • 还是首先在 Web 服务中生成 HTML 的更好方法?

来源

可以从这里下载完整的测试应用程序http://cid-916198839f3e806c.office.live.com/self.aspx/Public/TestingImageWTF.zip

网络服务

    [WebMethod]
    [ScriptMethod]
    public string GetWidgetHtml(int number)
    {
        var pageHolder = new Page
                             {
                                         //AppRelativeVirtualPath = "~/" // I tried playing with this but it made no difference!
                             };
        for (int i = 0; i < number; i++)
        {
            var viewControl = (MyPictureAndTextWidget) pageHolder.LoadControl(@"~/Controls/Widgets/MyPictureAndTextWidget.ascx");
            pageHolder.Controls.Add(viewControl);
        }

        var output = new StringWriter();

        HttpContext.Current.Server.Execute(pageHolder, output, false);

        StringBuilder sb = output.GetStringBuilder();
        string fulloutput = sb.ToString();
        return fulloutput;
    }

这是我的用户控件的内容

控件/小部件/MyPictureAndTextWidget.ascx

    <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MyPictureAndTextWidget.ascx.cs" Inherits="TestingImageWTF.Controls.Widgets.MyPictureAndTextWidget" %>
    <%@ Register TagName="Picture" TagPrefix="widget" Src="~/Controls/Widgets/MyPictureWidget.ascx" %>

    <div style="background:#EEEEEE; border:1px dashed;">
        <h4>My control</h4>
        Some text from the widget ....: 
        <br /><widget:Picture runat="server" />
    </div>

控件/小部件/MyPictureWidget.ascx

    <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MyPictureWidget.ascx.cs" Inherits="TestingImageWTF.Controls.Widgets.MyWidget" %>

    <script runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
            image.ImageUrl = "~/images/spider.png";
        }
    </script>
    <asp:Image ID="image" runat="server" />

【问题讨论】:

    标签: asp.net


    【解决方案1】:

    o所以这里至少是部分答案。

    问题:ResolveClientUrl 在 ASP.Net 4 和 3.5 中的工作方式是否不同?

    回答:是的

    并且行为的变化(据我所知)是它以不同的方式对待 PathInfo。

    为了演示,制作以下页面。

    <%@ Page Language="C#" AutoEventWireup="true"  %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <body>
        <form id="form1" runat="server">
            DateTime.Now.Ticks: <%= DateTime.Now.Ticks %>
            <br />
            <asp:HyperLink runat="server" NavigateUrl="~/PathInfoLinkTest.aspx">This links to ~/PathInfoLinkTest.aspx</asp:HyperLink>
            <br />
            <asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/PathInfoLinkTest.aspx/foo/bar">This links to ~/PathInfoLinkTest.aspx/foo/bar</asp:HyperLink>
            <br />
            ResolveClientUrl("~/PathInfoLinkTest.aspx/foo/bar") = <%= ResolveClientUrl("~/PathInfoLinkTest.aspx/foo/bar") %>
        </form>
    </body>
    </html>
    

    并在 .Net4 和 .Net 3.5 下运行。

    你会在 3.5 下看到:
    ResolveClientUrl("~/PathInfoLinkTest.aspx/foo/bar") = 'PathInfoLinkTest.aspx/foo/bar'

    而在 4.0 下你会得到
    ResolveClientUrl("~/PathInfoLinkTest.aspx/foo/bar") = 'bar'

    此更改似乎是针对这些人遇到的问题进行的错误修复。

    本质上,3.5 中的 bug 是,如果您当前正在浏览 url http://host/app/page.aspx/foo/bar 并且您想链接到 http://host/app/page2.aspx,那么客户端上呈现的 URL 应该是 ../../page2.aspx

    Asp.Net 4 正确!
    Asp.Net 3.5 没有 - 它将链接的 url 输出为“page2.aspx”(因此当点击时,浏览器将请求页面“http://host/app/page.aspx/foo/bar/page2.aspx”。如果您在 .Net 3.5 中运行上述页面并多次单击第二个超链接,则可以看到此错误的表现 - 然后查看浏览器的地址栏!

    不幸的是,错误修复破坏了我的代码 - 因为我的代码依赖于 .Net 3.5 的(不正确)行为:Web 服务请求始终具有 Pathinfo(Web 服务方法名称),因此当控件呈现自身时,调用to ResolveClientUrl("~/xxx") (正确) puts 返回 "../xxx"。

    【讨论】:

      【解决方案2】:

      我不确定 ResolveClientUrl 方法的更新,但我知道他们更新了 .NET 4.0 和 3.5 之间的控件呈现方式。您可能想尝试更新您的 web.config 以包括:

      <pages controlRenderingCompatibilityVersion="3.5" />
      

      查看:http://www.asp.net/learn/whitepapers/aspnet4/breaking-changes#0.1__Toc256770141

      另外,您可以尝试在您的网络服务中使用 RenderControl,如下所示:

      StringBuilder sb = new StringBuilder();
      StringWriter tw = new StringWriter(sb);
      HtmlTextWriter hw = new HtmlTextWriter(tw);
      
      control.RenderControl(hw);
      return sb.ToString();
      

      Rick Strahl 有一篇可能有用的文章:http://www.west-wind.com/weblog/posts/2004/Jun/08/Capturing-Output-from-ASPNet-Pages(不过可能有些过时...)

      希望这会有所帮助!

      【讨论】:

      • 感谢您的回复。我已经指定 controlRenderingCompatibilityVersion=3.5。我将尝试获取文本的替代方法,看看是否有所作为。
      【解决方案3】:

      尝试从 ImageUrl 值中删除前导波浪号。

      【讨论】:

      • 我 95% 确定删除 ~ 将意味着呈现的 URL 将是“/images/spider.png”
      猜你喜欢
      • 2011-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-08
      • 2013-02-13
      • 1970-01-01
      相关资源
      最近更新 更多