ResolveClientUrl在ASP.Net 4和3.5中的工作方式不同

时间:2011-05-23 15:25:40

标签: asp.net

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

我认为我偶然发现了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)。

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

我实现这一目标的方法是编写一个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”这一事实意味着图像控件“认为”它正在一个页面中执行,该页面在运行时具有类似“{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" />

3 个答案:

答案 0 :(得分:5)

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中的错误是如果您当前正在浏览网址http://host/app/page.aspx/foo/bar并且想要链接到http://host/app/page2.aspx,那么客户端上呈现的网址应为{{1} }。

Asp.Net 4是正确的!
Asp.Net 3.5没有 - 它将链接的URL输出为“../../page2.aspx”(因此,点击后,浏览器将请求页面'{{ 1}}'。如果您在.Net 3.5中运行上述页面并多次点击第二个超链接,您可以看到此错误的表现形式 - 然后查看浏览器的地址栏!

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

答案 1 :(得分: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

此外,您可以尝试在Web服务中使用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(可能有点过时了......)

希望这有帮助!

答案 2 :(得分:0)

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