Asp。用于AJAX调用的Net单控件呈现。

时间:2022-12-30 02:01:46

I'm trying to implement something similar to this or this.

我正在尝试实现类似的东西。

I've created a user control, a web service and a web method to return the rendered html of the control, executing the ajax calls via jQuery.

我创建了一个用户控件、一个web服务和一个web方法来返回控件的呈现的html,并通过jQuery执行ajax调用。

All works fine, but if I put something in the user control that uses a relative path (in my case an HyperLink with NavigateUrl="~/mypage.aspx") the resolution of relative path fails in my developing server.

所有的工作都很好,但是如果我在用户控件中使用了相对路径(在我的例子中是与NavigateUrl=“~/mypage.aspx”的超链接),那么在我的开发服务器中相对路径的解析就失败了。

I'm expecting: http://localhost:999/MyApp/mypage.aspx

我希望:http://localhost:999 / MyApp / mypage.aspx

But I get: http://localhost:999/mypage.aspx

但我得到:http://localhost:999 / mypage.aspx

Missing 'MyApp'...

缺少“MyApp”……

I think the problem is on the creation of the Page used to load the control:

我认为问题在于创建用于加载控件的页面:

Page page = new Page();
Control control = page.LoadControl(userControlVirtualPath);
page.Controls.Add(control);
...

But I can't figure out why....

但是我不明白为什么....

EDIT Just for clarity

编辑只是为了清晰

My user control is located at ~/ascx/mycontrol.ascx and contains a really simple structure: by now just an hyperlink with NavigateUrl like "~/mypage.aspx". And "mypage.aspx" really resides on the root.

我的用户控件位于~/ascx/mycontrol。ascx和包含一个非常简单的结构:现在只是一个与NavigateUrl的超链接,比如“~/mypage.aspx”。和“mypage。aspx真的存在于根中。

Then I've made up a web service to return to ajax the partial rendered control:

然后我创建了一个web服务,将部分呈现控件返回给ajax:

[ScriptService]
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class wsAsynch : System.Web.Services.WebService
{
    [WebMethod(EnableSession = true)]
    public string GetControl(int parma1, int param2)
    {
        /* ...do some stuff with params... */
        Page pageHolder = new Page();

        UserControl viewControl = (UserControl)pageHolder.LoadControl("~/ascx/mycontrol.ascx");
        Type viewControlType = viewControl.GetType();

        /* ...set control properties with reflection... */

        pageHolder.Controls.Add(viewControl);
        StringWriter output = new StringWriter();
        HttpContext.Current.Server.Execute(pageHolder, output, false);

        return output.ToString();
    }
}

The html is correctly rendered, but the relative path in the NavigateUrl of hyperlink is incorrectly resolved, because when I execute the project from developing server of VS2008, the root of my application is

html得到了正确的呈现,但是hyperlink的NavigateUrl中的相关路径被错误地解析,因为当我在VS2008开发服务器上执行项目时,我的应用程序的根是

http://localhost:999/MyApp/

http://localhost:999 / MyApp /

and it's fine, but the NavigateUrl is resolved as

这很好,但通航符被解析为

http://localhost:999/mypage.aspx

http://localhost:999 / mypage.aspx

losing /MyApp/ . Of Course if I put my ascx in a real page, instead of the pageHolder instance used in the ws, all works fine.

失去/ MyApp /。当然,如果我把我的ascx放到一个真实的页面中,而不是在ws中使用的pageHolder实例,那么一切都可以正常工作。

Another strange thing is that if I set the hl.NavigateUrl = Page.ResolveUrl("~/mypage.aspx") I get the correct url of the page: http://localhost:999/MyApp/mypage.aspx

另一件奇怪的事情是如果我设置hl。NavigateUrl = Page.ResolveUrl(“~/mypage.aspx”)我得到了页面的正确url: http://localhost:999/MyApp/mypage.aspx

And by now I'll do that, but I would understand WHY it doesn't work in the normal way. Any idea?

现在我要这么做,但我能理解为什么它不能正常工作。任何想法?

6 个解决方案

#1


4  

The problem is that the Page-class is not intented for instantiating just like that. If we fire up Reflector we'll quickly see that the Asp.Net internals sets an important property after instantiating a Page class an returning it as a IHttpHandler. You would have to set AppRelativeTemplateSourceDirectory. This is a property that exists on the Control class and internally it sets the TemplateControlVirtualDirectory property which is used by for instance HyperLink to resolve the correct url for "~" in a link.

问题是,页面类并没有像这样进行实例化。如果我们启动反射器,我们将很快看到Asp。Net internals在将一个页面类实例化为IHttpHandler后设置一个重要属性。你需要设置一个外贸目录。这是一个存在于控件类上的属性,它在内部设置TemplateControlVirtualDirectory属性,例如,HyperLink使用该属性来解析链接中“~”的正确url。

Its important that you set this value before calling the LoadControl method, since the value of AppRelativeTemplateSourceDirectory is passed on to the controls created by your "master" control.

在调用LoadControl方法之前设置这个值是非常重要的,因为您的“master”控件所创建的控件的值将被传递到控件的值。

How to obtain the correct value to set on your property? Use the static AppDomainAppVirtualPath on the HttpRuntime class. Soo, to sum it up... this should work;

如何获得对您的属性设置的正确值?在HttpRuntime类上使用静态AppDomainAppVirtualPath。Soo,总结一下……这应该工作;

[WebMethod(EnableSession = true)]
public string GetControl(int parma1, int param2)
{
    /* ...do some stuff with params... */
    var pageHolder = new Page() { AppRelativeTemplateSourceDirectory = HttpRuntime.AppDomainAppVirtualPath };

    var viewControl = (UserControl)pageHolder.LoadControl("~/ascx/mycontrol.ascx");
    var viewControlType = viewControl.GetType();

    /* ...set control properties with reflection... */

    pageHolder.Controls.Add(viewControl);
    var output = new StringWriter();
    HttpContext.Current.Server.Execute(pageHolder, output, false);

    return output.ToString();
}

#2


0  

The tildy pust the path in the root of the app, so its going to produce a the results you are seeing. You will want to use:

tildy在应用程序的根路径上,所以它会产生你看到的结果。您将希望使用:

NavigateUrl="./whatever.aspx"

EDIT:
Here is a link that may also prove helpful...http://msdn.microsoft.com/en-us/library/ms178116.aspx

编辑:这里有一个链接可能也很有用…http://msdn.microsoft.com/en-us/library/ms178116.aspx

#3


0  

I find the /MyApp/ root causes all sorts of issues. It doesn't really answer your question 'why is doesn't work the normal way', but do you realize you can get rid of the /MyApp/ and host your website at http:/localhost/...?

我发现/MyApp/ root引起了各种各样的问题。它并没有真正回答你的问题“为什么不能正常工作”,但是你意识到你可以摆脱/MyApp/并在http:/localhost/…上托管你的网站吗?

Just set Virtual Path in the website properties to '/'.

在网站属性中设置虚拟路径为'/'。

This clears everything up, unless of course you are trying to host multiple apps on the development PC at the same time.

这可以清除所有的问题,除非你想同时在开发PC上托管多个应用程序。

#4


0  

It might be that the new page object does not have "MyApp" as root, so it is resolved to the server root as default.

可能是新页面对象没有“MyApp”作为根,所以它被解析为默认的服务器根。

My question is rather why it works with Page.ResolveUrl(...).
Maybe ResolveUrl does some more investigation about the location of the usercontrol, and resolves based on that.

我的问题是为什么它使用Page.ResolveUrl(…)。也许ResolveUrl会对usercontrol的位置进行更多的调查,并基于此进行解析。

#5


0  

Weird, I recreated the example. The hyperlink renders as <a id="ctl00_hlRawr" href="Default.aspx"></a> for a given navigation url of ~/Default.aspx. My guess is that it has something to do with the RequestMethod. On a regular page it is "GET" but on a webservice call it is a "POST".

奇怪的是,我重新创建了这个例子。超链接呈现为对于给定的~/Default.aspx导航url。我猜这与RequestMethod有关。在普通的页面上,它是“GET”,但在web服务调用中,它是“POST”。

I was unable to recreate your results with hl.NavigateUrl = Page.ResolveUrl("~/mypage.aspx") The control always rendered as <a id="ctl00_hlRawr" href="Default.aspx"></a> given a virtual path. (Page.ResolveUrl gives me "~/Default.aspx")

我无法用hl复制你的结果。NavigateUrl = Page.ResolveUrl("~/mypage.aspx")控件始终呈现为给出了一个虚拟路径。(页面。ResolveUrl给我~ / default . aspx)

I would suggest doing something like this to avoid the trouble in the future.

我建议做这样的事,以避免将来的麻烦。

protected void Page_Load(object sender, EventArgs e)
{
    hlRawr.NavigateUrl = FullyQualifiedApplicationPath + "/Default.aspx";
}

public static string FullyQualifiedApplicationPath
{
    get
    {
        //Return variable declaration
        string appPath = null;

        //Getting the current context of HTTP request
        HttpContext context = HttpContext.Current;

        //Checking the current context content
        if (context != null)
        {
            //Formatting the fully qualified website url/name
            appPath = string.Format("{0}://{1}{2}{3}",
            context.Request.Url.Scheme,
            context.Request.Url.Host,
            (context.Request.Url.Port == 80 ? string.Empty : ":" + context.Request.Url.Port),
            context.Request.ApplicationPath);
        }

        return appPath;
    }
}

Regards,

问候,

#6


0  

It is hard to tell what you are trying to achieve without posting the line that actually sets the Url on of the HyperLink, but I think I understand your directory structure.

很难告诉您,您想要实现什么,而不需要发布实际上设置超链接的Url的行,但是我想我理解您的目录结构。

However, I have never run into a situation that couldn't be solved one way or another with the ResolveUrl() method. String parsing for a temporary path that won't be used in production is not recommended because it will add more complexity to your project.

但是,我从来没有遇到过用ResolveUrl()方法无法解决的情况。不推荐使用不会在生产中使用的临时路径的字符串解析,因为这会增加项目的复杂性。

This code will resolve in any object that inherits from page (including a usercontrol):

该代码将解析从页面继承的任何对象(包括usercontrol):

Page page = (Page)Context.Handler;
string Url = page.ResolveUrl("~/Anything.aspx");

Another thing you could try is something like this:

你可以尝试的另一件事是:

Me.Parent.ResolveUrl("~/Anything.aspx");

If these aren't working, you may want to check your IIS settings to make sure your site is configured as an application.

如果这些都不起作用,您可能需要检查IIS设置,以确保站点被配置为应用程序。

#1


4  

The problem is that the Page-class is not intented for instantiating just like that. If we fire up Reflector we'll quickly see that the Asp.Net internals sets an important property after instantiating a Page class an returning it as a IHttpHandler. You would have to set AppRelativeTemplateSourceDirectory. This is a property that exists on the Control class and internally it sets the TemplateControlVirtualDirectory property which is used by for instance HyperLink to resolve the correct url for "~" in a link.

问题是,页面类并没有像这样进行实例化。如果我们启动反射器,我们将很快看到Asp。Net internals在将一个页面类实例化为IHttpHandler后设置一个重要属性。你需要设置一个外贸目录。这是一个存在于控件类上的属性,它在内部设置TemplateControlVirtualDirectory属性,例如,HyperLink使用该属性来解析链接中“~”的正确url。

Its important that you set this value before calling the LoadControl method, since the value of AppRelativeTemplateSourceDirectory is passed on to the controls created by your "master" control.

在调用LoadControl方法之前设置这个值是非常重要的,因为您的“master”控件所创建的控件的值将被传递到控件的值。

How to obtain the correct value to set on your property? Use the static AppDomainAppVirtualPath on the HttpRuntime class. Soo, to sum it up... this should work;

如何获得对您的属性设置的正确值?在HttpRuntime类上使用静态AppDomainAppVirtualPath。Soo,总结一下……这应该工作;

[WebMethod(EnableSession = true)]
public string GetControl(int parma1, int param2)
{
    /* ...do some stuff with params... */
    var pageHolder = new Page() { AppRelativeTemplateSourceDirectory = HttpRuntime.AppDomainAppVirtualPath };

    var viewControl = (UserControl)pageHolder.LoadControl("~/ascx/mycontrol.ascx");
    var viewControlType = viewControl.GetType();

    /* ...set control properties with reflection... */

    pageHolder.Controls.Add(viewControl);
    var output = new StringWriter();
    HttpContext.Current.Server.Execute(pageHolder, output, false);

    return output.ToString();
}

#2


0  

The tildy pust the path in the root of the app, so its going to produce a the results you are seeing. You will want to use:

tildy在应用程序的根路径上,所以它会产生你看到的结果。您将希望使用:

NavigateUrl="./whatever.aspx"

EDIT:
Here is a link that may also prove helpful...http://msdn.microsoft.com/en-us/library/ms178116.aspx

编辑:这里有一个链接可能也很有用…http://msdn.microsoft.com/en-us/library/ms178116.aspx

#3


0  

I find the /MyApp/ root causes all sorts of issues. It doesn't really answer your question 'why is doesn't work the normal way', but do you realize you can get rid of the /MyApp/ and host your website at http:/localhost/...?

我发现/MyApp/ root引起了各种各样的问题。它并没有真正回答你的问题“为什么不能正常工作”,但是你意识到你可以摆脱/MyApp/并在http:/localhost/…上托管你的网站吗?

Just set Virtual Path in the website properties to '/'.

在网站属性中设置虚拟路径为'/'。

This clears everything up, unless of course you are trying to host multiple apps on the development PC at the same time.

这可以清除所有的问题,除非你想同时在开发PC上托管多个应用程序。

#4


0  

It might be that the new page object does not have "MyApp" as root, so it is resolved to the server root as default.

可能是新页面对象没有“MyApp”作为根,所以它被解析为默认的服务器根。

My question is rather why it works with Page.ResolveUrl(...).
Maybe ResolveUrl does some more investigation about the location of the usercontrol, and resolves based on that.

我的问题是为什么它使用Page.ResolveUrl(…)。也许ResolveUrl会对usercontrol的位置进行更多的调查,并基于此进行解析。

#5


0  

Weird, I recreated the example. The hyperlink renders as <a id="ctl00_hlRawr" href="Default.aspx"></a> for a given navigation url of ~/Default.aspx. My guess is that it has something to do with the RequestMethod. On a regular page it is "GET" but on a webservice call it is a "POST".

奇怪的是,我重新创建了这个例子。超链接呈现为对于给定的~/Default.aspx导航url。我猜这与RequestMethod有关。在普通的页面上,它是“GET”,但在web服务调用中,它是“POST”。

I was unable to recreate your results with hl.NavigateUrl = Page.ResolveUrl("~/mypage.aspx") The control always rendered as <a id="ctl00_hlRawr" href="Default.aspx"></a> given a virtual path. (Page.ResolveUrl gives me "~/Default.aspx")

我无法用hl复制你的结果。NavigateUrl = Page.ResolveUrl("~/mypage.aspx")控件始终呈现为给出了一个虚拟路径。(页面。ResolveUrl给我~ / default . aspx)

I would suggest doing something like this to avoid the trouble in the future.

我建议做这样的事,以避免将来的麻烦。

protected void Page_Load(object sender, EventArgs e)
{
    hlRawr.NavigateUrl = FullyQualifiedApplicationPath + "/Default.aspx";
}

public static string FullyQualifiedApplicationPath
{
    get
    {
        //Return variable declaration
        string appPath = null;

        //Getting the current context of HTTP request
        HttpContext context = HttpContext.Current;

        //Checking the current context content
        if (context != null)
        {
            //Formatting the fully qualified website url/name
            appPath = string.Format("{0}://{1}{2}{3}",
            context.Request.Url.Scheme,
            context.Request.Url.Host,
            (context.Request.Url.Port == 80 ? string.Empty : ":" + context.Request.Url.Port),
            context.Request.ApplicationPath);
        }

        return appPath;
    }
}

Regards,

问候,

#6


0  

It is hard to tell what you are trying to achieve without posting the line that actually sets the Url on of the HyperLink, but I think I understand your directory structure.

很难告诉您,您想要实现什么,而不需要发布实际上设置超链接的Url的行,但是我想我理解您的目录结构。

However, I have never run into a situation that couldn't be solved one way or another with the ResolveUrl() method. String parsing for a temporary path that won't be used in production is not recommended because it will add more complexity to your project.

但是,我从来没有遇到过用ResolveUrl()方法无法解决的情况。不推荐使用不会在生产中使用的临时路径的字符串解析,因为这会增加项目的复杂性。

This code will resolve in any object that inherits from page (including a usercontrol):

该代码将解析从页面继承的任何对象(包括usercontrol):

Page page = (Page)Context.Handler;
string Url = page.ResolveUrl("~/Anything.aspx");

Another thing you could try is something like this:

你可以尝试的另一件事是:

Me.Parent.ResolveUrl("~/Anything.aspx");

If these aren't working, you may want to check your IIS settings to make sure your site is configured as an application.

如果这些都不起作用,您可能需要检查IIS设置,以确保站点被配置为应用程序。