Отрисовка единого элемента управления Asp.Net для вызовов AJAX

Я пытаюсь реализовать что-то похожее на this или это.

Я создал пользовательский элемент управления, веб-службу и веб-метод для возврата визуализированного html элемента управления, выполняя вызовы ajax через jQuery.

Все работает нормально, но если я помещаю что-то в пользовательский элемент управления, который использует относительный путь (в моем случае HyperLink с NavigateUrl = "~ / mypage.aspx"), разрешение относительного пути на моем развивающемся сервере не выполняется.

Я ожидаю: http://localhost:999/MyApp/mypage.aspx

Но я получаю: http://localhost:999/mypage.aspx

Отсутствует "Мое приложение" ...

Я думаю, проблема в создании страницы, используемой для загрузки элемента управления:

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

Но я не могу понять, почему ....

РЕДАКТИРОВАТЬ Для ясности

Мой пользовательский элемент управления расположен в ~/ascx/mycontrol.ascx и содержит действительно простую структуру: на данный момент это просто гиперссылка с NavigateUrl, например "~/mypage.aspx". И «mypage.aspx» действительно находится в корне.

Затем я создал веб-сервис, чтобы вернуть в 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();
    }
}

HTML-код отображается правильно, но относительный путь в NavigateUrl гиперссылки неправильно разрешен, потому что, когда я выполняю проект с сервера разработки VS2008, корнем моего приложения является

http://localhost:999/MyApp/

и это нормально, но NavigateUrl разрешается как

http://localhost:999/mypage.aspx

проигрывает / MyApp /. Конечно, если я помещаю свой ascx на реальную страницу вместо экземпляра pageHolder, используемого в ws, все работает нормально.

Еще одна странность заключается в том, что если я установил hl.NavigateUrl = Page.ResolveUrl("~/mypage.aspx"), я получаю правильный URL-адрес страницы: http://localhost:999/MyApp/mypage.aspx

И сейчас я сделаю это, но я пойму, ПОЧЕМУ это не работает нормально. Любая идея?


person tanathos    schedule 30.06.2010    source источник
comment
Где в жизненном цикле страницы / элемента управления вы называете hl.NavigateUrl = Page.ResolveUrl("~/mypage.aspx")? До этого вы запускали hl.NavigateUrl = "~/mypage.aspx" в этом же месте кода?   -  person awe    schedule 15.09.2010


Ответы (6)


Проблема в том, что класс Page не предназначен для создания экземпляров просто так. Если мы запустим Reflector, мы быстро увидим, что внутренние компоненты Asp.Net устанавливают важное свойство после создания экземпляра класса Page и возврата его как IHttpHandler. Вам нужно будет установить AppRelativeTemplateSourceDirectory. Это свойство, которое существует в классе Control, и внутренне оно устанавливает свойство TemplateControlVirtualDirectory, которое используется, например, HyperLink для разрешения правильного URL-адреса для «~» в ссылке.

Важно установить это значение перед вызовом метода LoadControl, поскольку значение AppRelativeTemplateSourceDirectory передается элементам управления, созданным вашим «главным» элементом управления.

Как получить правильную стоимость для вашей собственности? Используйте статический AppDomainAppVirtualPath в классе HttpRuntime. Итак, подведем итог ... это должно сработать;

[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();
}
person Pauli Østerø    schedule 19.10.2010

Tildy вставляет путь в корень приложения, поэтому он будет давать результаты, которые вы видите. Вы захотите использовать:

NavigateUrl="./whatever.aspx"

ИЗМЕНИТЬ:
Вот ссылка, которая также может оказаться полезной ... http://msdn.microsoft.com/en-us/library/ms178116.aspx

person AGoodDisplayName    schedule 30.06.2010
comment
Но мне нужен путь к приложению на моем URL-адресе, он мне нужен для моего локального сервера разработки. URL-адрес localhost: 999 / mypage.aspx просто не существует. Если я помещаю ascx на страницу, все относительные пути разрешаются как localhost: 999 / MyApp / something.something ... и это правильно. - person tanathos; 30.06.2010
comment
Можете ли вы показать разметку для регистрации страницы для ascx и, возможно, простое объяснение структуры вашего сайта (где находятся страницы, где находятся элементы управления)? У меня такое чувство, потому что элементы управления / страницы находятся в разных каталогах. - person AGoodDisplayName; 30.06.2010

Я считаю, что / MyApp / корень вызывает всевозможные проблемы. На самом деле он не отвечает на ваш вопрос «почему это не работает нормально?», Но понимаете ли вы, что можете избавиться от / MyApp / и разместить свой веб-сайт по адресу http: / localhost / ...?

Просто установите Virtual Path в свойствах веб-сайта на '/'.

Это проясняет все, если, конечно, вы не пытаетесь одновременно разместить несколько приложений на ПК для разработки.

person James Gaunt    schedule 09.07.2010
comment
проблема в том, что у меня много приложений, настроенных для разработки ... к настоящему времени я обошел эту проблему с помощью Page.ResolveUrl (~ / mypage.aspx), но мне действительно хотелось бы понять, ПОЧЕМУ :) - person tanathos; 09.07.2010

Может случиться так, что у нового объекта страницы нет «MyApp» в качестве корневого, поэтому по умолчанию он разрешен в корневой каталог сервера.

Мой вопрос скорее в том, почему он работает с Page.ResolveUrl(...).
Может быть, ResolveUrl проведет еще какое-то исследование о расположении пользовательского элемента управления и решит на основании этого.

person awe    schedule 15.09.2010

Странно, но я воссоздал этот пример. Гиперссылка отображается как <a id="ctl00_hlRawr" href="Default.aspx"></a> для данного URL-адреса навигации ~ / Default.aspx. Я предполагаю, что это как-то связано с RequestMethod. На обычной странице это «GET», но при вызове веб-службы это «POST».

Мне не удалось воссоздать ваши результаты с hl.NavigateUrl = Page.ResolveUrl("~/mypage.aspx") Элемент управления всегда отображался как <a id="ctl00_hlRawr" href="Default.aspx"></a> с учетом виртуального пути. (Page.ResolveUrl дает мне "~ / Default.aspx")

Я бы посоветовал сделать что-то подобное, чтобы избежать неприятностей в будущем.

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

С уважением,

person Biff MaGriff    schedule 15.09.2010

Трудно сказать, чего вы пытаетесь достичь, не опубликовав строку, которая фактически устанавливает URL-адрес гиперссылки, но я думаю, что понимаю вашу структуру каталогов.

Однако я никогда не сталкивался с ситуацией, которую нельзя было бы так или иначе решить с помощью метода ResolveUrl (). Синтаксический анализ строки для временного пути, который не будет использоваться в производственной среде, не рекомендуется, поскольку он усложнит ваш проект.

Этот код будет разрешен в любом объекте, который наследуется от страницы (включая пользовательский элемент управления):

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

Еще одна вещь, которую вы можете попробовать, - это что-то вроде этого:

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

Если они не работают, вы можете проверить настройки IIS, чтобы убедиться, что ваш сайт настроен как приложение.

person NightOwl888    schedule 11.10.2010
comment
Пользовательское управление не прерывается со страницы!? И вызов Parent для объекта Page возвращает сам себя, так что в этом нет необходимости. - person Pauli Østerø; 20.10.2010
comment
@BurningIce - Спасибо, что заметили это. Я хотел использовать родительский элемент usercontrol. Я обновил пример кода с исправлением. - person NightOwl888; 20.10.2010
comment
но все же ваш приведенный выше код не работает, поскольку тогда обработчик запроса не будет иметь тип Page, а скорее всего будет WebServiceHandler, поскольку запрашиваемый tanathos документ, скорее всего, имеет расширение .asmx или .svc (не .aspx). - person Pauli Østerø; 20.10.2010
comment
@BurningIce - обратите внимание, что OP указал, что это пользовательский элемент управления, который не работает. Вы правы, что этот код не будет работать в веб-сервисе. - person NightOwl888; 20.10.2010