Единый элемент управления Asp.Net для вызовов AJAX - PullRequest
6 голосов
/ 30 июня 2010

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

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

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

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

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

Отсутствует «MyApp» ...

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

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

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

EDIT Просто для наглядности

Мой пользовательский элемент управления находится на ~/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

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

Ответы [ 6 ]

4 голосов
/ 20 октября 2010

Проблема в том, что класс 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();
}
0 голосов
/ 11 октября 2010

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

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

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

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

Еще одна вещь, которую вы можете попробовать, выглядит примерно так:

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

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

0 голосов
/ 16 сентября 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;
    }
}

С уважением,

0 голосов
/ 15 сентября 2010

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

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

0 голосов
/ 09 июля 2010

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

Просто установите Виртуальный путь в свойствах сайта на '/'.

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

0 голосов
/ 30 июня 2010

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

NavigateUrl="./whatever.aspx"

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

...