ResolveClientUrl在ASP.Net 4和3.5中的工作方式有所不同 [英] ResolveClientUrl works differently in ASP.Net 4 and 3.5

查看:75
本文介绍了ResolveClientUrl在ASP.Net 4和3.5中的工作方式有所不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[很抱歉,如果我的问题标题不能准确描述我的问题,如果您能想到一个更好的标题并有权更改此标题,请随时进行更改!]

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

这是场景:-

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

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

我实现这一目标的方法是编写一个asmx Web服务,该服务以编程方式创建一个新的Page并动态地"LoadControl"用户控制,然后在字符串生成器中捕获页面呈现的输出-特别是不雅致,但它可以正常工作!请参阅底部的来源.

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

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

我能提出的唯一解释是 ResolveClientUrl 方法(Image控件将使用该方法来确定从当前正在执行的页面到图像的相对路径是什么)表现不同.图片网址显示为"../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

Web服务

  [WebMethod][ScriptMethod]公共字符串GetWidgetHtml(int number){var pageHolder =新页面{//AppRelativeVirtualPath =〜/"//我尝试使用此方法,但没有区别!};为(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,输出,false);StringBuilder sb = output.GetStringBuilder();字符串fulloutput = sb.ToString();返回全输出;} 

这是我的用户控件的内容

Controls/Widgets/MyPictureAndTextWidget.ascx

 <%@控制语言="C#" AutoEventWireup ="true" CodeBehind ="MyPictureAndTextWidget.ascx.cs" Inherits ="TestingImageWTF.Controls.Widgets.MyPictureAndTextWidget"%><%@注册TagName ="Picture" TagPrefix ="widget" Src =〜/Controls/Widgets/MyPictureWidget.ascx"%>< div style ="background:#EEEEEE; border:1px dashed;";>< h4>我的控件</h4>小部件中的一些文本....:< br/><小部件:图片runat ="server"/></div> 

Controls/Widgets/MyPictureWidget.ascx

 <%@控制语言="C#" AutoEventWireup ="true" CodeBehind ="MyPictureWidget.ascx.cs" Inherits ="TestingImageWTF.Controls.Widgets.MyWidget"%>< script runat ="server">受保护的void Page_Load(对象发送者,EventArgs e){image.ImageUrl =〜/images/spider.png";}</script>< asp:图片ID =图片" runat =服务器"/> 

解决方案

o因此,至少有一部分是答案.

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

答案:.

(我知道)行为的变化是它对PathInfo的区别对待.

为演示,请制作以下页面.

 <%@页面语言="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"><身体>< form id ="form1" runat ="server">DateTime.Now.Ticks:<%= DateTime.Now.Ticks%>< br/>< asp:HyperLink runat ="server" NavigateUrl =〜/PathInfoLinkTest.aspx">这链接到〜/PathInfoLinkTest.aspx</asp:HyperLink>< br/>< asp:HyperLink ID ="HyperLink1" runat ="server" NavigateUrl =〜/PathInfoLinkTest.aspx/foo/bar">这链接到〜/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")='酒吧'

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

实质上,3.5中的错误是,如果您当前正在浏览URL http://host/app/page.aspx/foo/bar ,并且您想要链接到http://host/app/page2.aspx ,则客户端呈现的URL应该为 ../../page2.aspx .

Asp.Net 4能够正确解决此问题!
Asp.Net 3.5不能-将链接的网址输出为" page2.aspx "(因此,单击该按钮时,浏览器将要求页面' http://host/app/page.aspx/foo/bar/page2.aspx '.如果您在.Net 3.5和更高版本中运行以上页面,则可以看到此错误的体现.单击第二个超链接几次-然后在浏览器的地址栏中查看!

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

[Apologies if my question title does not accurately describe my problem- if you can think of a better title and have the permissions to change this then please feel free to change it!].

I think that I have stumbled upon a minor breaking change between ASP.Net 3.5 and 4.0.

[Edit: I have confirmed that there is a change in behaviour twix 3.5 and 4.0 - see my answer]

Here is the scenario: -

I have a ASP.Net 3.5 web application. I have a trivial user control {appRoot}/Controls/Widgets/MyPictureAndTextWidget.ascx that essentially contains some text and another user control ({appRoot}/Controls/Widgets/MyPicture.ascx).

For the most part, this control is used in the normal fashion - i.e. including it in the mark up of other pages but I have one instance where I need to obtain the HTML to render on the client using Ajax.

The way I achieved this was to write an asmx web service that programmatically created a new Page and dynamically `LoadControl' the user controls and then captured the output from the rendering of the page in a string builder - particulary inelegant but it worked! See bottom for the source.

However, after upgrading the project to Asp.Net 4.0, the above code no longer works as it used to; the image, when rendered has src="../images/xxx.png (note the '../' which is not wanted).

I have created a little demo app http://cid-916198839f3e806c.office.live.com/self.aspx/Public/TestingImageWTF.zip if you want to run it for yourselves. When you compile the app using 3.5, it works (i.e. you see 2 pictures of a spider on the test page) but when you compile and run under 4.0, you only see 1 spider (the other image has the wrong URL).

The only explanation that I can come up with is that the ResolveClientUrl method (which the Image control will use in order to work out what is the relative path to the image from the currently executing page) is behaving differently. The fact that the image url is coming out as "../images/xxx.png" means that the Image control 'thinks' it is executing in a page that has a path like '{appRoot}/folder/handler' when running under 4.0 but it thinks it is running in a context '{appRoot}/handler' under 3.5.

I hope this is making sense to you - sorry if I am not describing the problem very clearly or concisely.

Can anyone either tell us how: -

  • to restore the 3.5 behaviour (without reverting to the 3.5 framework obviously!)

  • or a better way of generating the HTML in the web service in the first place?

The source

A full test application can be downloaded from here http://cid-916198839f3e806c.office.live.com/self.aspx/Public/TestingImageWTF.zip

Web Service

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

Here are the contents of my user controls

Controls/Widgets/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>

Controls/Widgets/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" />

解决方案

oSo here is at least part if the answer.

Question: Does ResolveClientUrl working differently in ASP.Net 4 and 3.5?

Answer: Yes.

And the change in behaviour (that I know of) is that it treats PathInfo differently.

To demonstrate, make the following page.

<%@ 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>

And run under .Net4 and .Net 3.5.

You will see that under 3.5:
ResolveClientUrl("~/PathInfoLinkTest.aspx/foo/bar") = 'PathInfoLinkTest.aspx/foo/bar'

whereas under 4.0 you get
ResolveClientUrl("~/PathInfoLinkTest.aspx/foo/bar") = 'bar'

The change seems to be a bug fix in response to the problems that these folk were having.

In essence, the bug in 3.5 is that if you are currently browsing the url http://host/app/page.aspx/foo/bar and you want to link to http://host/app/page2.aspx, then the URL as rendered on the client should be ../../page2.aspx.

Asp.Net 4 gets this correct!
Asp.Net 3.5 doesn't - it outputs the link's url as 'page2.aspx' (so when clicked, the browser will request the page 'http://host/app/page.aspx/foo/bar/page2.aspx'. You can see a manifestation of this bug if you run the above page in .Net 3.5 and click on the 2nd hyperlink several times - then have a look in your browser's address bar!

Unfortunately the bug fix broke my code - because my code was relying on the (incorrect) behaviour of .Net 3.5: The web service request always has Pathinfo (the web service method name) and so when the controls render themselves, calls to ResolveClientUrl("~/xxx") (correctly) puts returns "../xxx".

这篇关于ResolveClientUrl在ASP.Net 4和3.5中的工作方式有所不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆