2010-06-30 11 views
6

Ich versuche, etwas Ähnliches zu implementieren this oder this.Asp.Net Single Control Render für AJAX Anrufe

Ich habe ein Benutzersteuerelement, einen Webdienst und eine Webmethode erstellt, um das gerenderte HTML des Steuerelements zurückzugeben und die Ajaxaufrufe über jQuery auszuführen.

Alles funktioniert gut, aber wenn ich etwas in das Benutzersteuerelement, das einen relativen Pfad verwendet (in meinem Fall ein HyperLink mit NavigateUrl = "~/mypage.aspx"), schlägt die Auflösung des relativen Pfades in meinem Entwicklungsserver.

Ich erwarte: http://localhost:999/MyApp/mypage.aspx

Aber ich bekomme: http://localhost:999/mypage.aspx

fehlt 'MeineAnw' ...

Ich denke, das Problem auf die Schaffung der Seite verwendet laden die Steuerung:

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

Aber ich kann nicht herausfinden, warum ....

EDIT Gerade für Klarheit

Meine Benutzerkontrolle bei ~/ascx/mycontrol.ascx und enthält eine wirklich einfache Struktur befindet: jetzt nur einen Hyperlink mit NavigateUrl wie "~/mypage.aspx". Und "mypage.aspx" liegt wirklich auf der Wurzel.

dann die teilweise gemacht Kontrolle Ajax Ich habe einen Web-Service aus zurück:

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

Die HTML korrekt gerendert wird, aber der relative Pfad im NavigateUrl Hyperlink falsch behoben ist, denn wenn ich führe sie das Projekt vom Server von VS2008 entwickeln, die Wurzel meiner Anwendung ist

http://localhost:999/MyApp/

und es ist in Ordnung, aber die NavigateUrl als

aufgelöst

http://localhost:999/mypage.aspx

verlieren/MyApp /. Natürlich, wenn ich meine Ascx in eine reale Seite statt der pageHolder-Instanz in der WS verwendet, funktioniert alles gut.

Eine weitere seltsame Sache ist, dass, wenn ich die hl.NavigateUrl = Page.ResolveUrl("~/mypage.aspx") stelle ich die richtige URL der Seite zu erhalten: http://localhost:999/MyApp/mypage.aspx

Und jetzt werde ich das tun, aber ich würde verstehen, warum es nicht in die funktioniert normale Art und Weise. Irgendeine Idee?

+0

Wo auf der Seite/Steuerung Lebenszyklus nennt man 'hl.NavigateUrl = Page.ResolveUrl ("~/MyPage.aspx")'? Bevor Sie dies getan haben, haben Sie einfach 'hl.NavigateUrl =" ~/mypage.aspx "' an derselben Stelle im Code ausgeführt? – awe

Antwort

4

Das Problem ist, dass die Page-Klasse nicht zum Instanziieren genau so gedacht ist. Wenn wir Reflector starten, sehen wir schnell, dass die Asp.Net-Interna eine wichtige Eigenschaft festlegen, nachdem sie eine Page-Klasse instanziiert und als IHttpHandler zurückgegeben haben. Sie müssten AppRelativeTemplateSourceDirectory festlegen. Dies ist eine Eigenschaft, die in der Control-Klasse vorhanden ist, und intern legt sie die Eigenschaft TemplateControlVirtualDirectory fest, die beispielsweise von HyperLink verwendet wird, um die korrekte URL für "~" in einem Link aufzulösen.

Es ist wichtig, dass Sie diesen Wert vor dem Aufrufen der LoadControl-Methode festlegen, da der Wert von AppRelativeTemplateSourceDirectory an die von Ihrem Steuerelement "master" erstellten Steuerelemente übergeben wird.

Wie erhält man den richtigen Wert, der auf Ihrer Immobilie festgelegt wird? Verwenden Sie das statische AppDomainAppVirtualPath für die HttpRuntime-Klasse. Soo, um es zusammenzufassen ... das sollte funktionieren;

[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

Großartig, ich mag diesen Weg! – tanathos

0

Die Tildy pust den Pfad in der Wurzel der App, so dass es die Ergebnisse, die Sie sehen, zu produzieren. Sie verwenden möchten:

NavigateUrl="./whatever.aspx" 

EDIT:
Hier ist ein Link, der auch als hilfreich erweisen kann ...http://msdn.microsoft.com/en-us/library/ms178116.aspx

+0

Aber ich möchte den App-Pfad auf meiner URL, ich brauche es für meine lokalen Entwickler-Server. Die URL http: // localhost: 999/mypage.aspx existiert einfach nicht. Wenn ich den Ascx auf eine Seite lege, werden alle relativen Pfade als http: // localhost: 999/MyApp/something.etwas ... aufgelöst und es ist korrekt. – tanathos

+0

Können Sie die Markierung für die Seitenregistrierung für die Ascx anzeigen und vielleicht eine einfache Erklärung Ihrer Struktur Ihrer Website (wo befinden sich die Seiten, wo befinden sich die Steuerelemente)? Ich habe das Gefühl, dies ist, weil die Steuerelemente/Seiten in verschiedenen Verzeichnissen sind. – AGoodDisplayName

0

Ich finde die/MyApp/root verursacht alle Arten von Problemen. Es beantwortet nicht wirklich Ihre Frage "Warum funktioniert das nicht normal?", Aber ist Ihnen klar, dass Sie die/MyApp/loswerden und Ihre Website unter http:/localhost/... hosten können?

Setzen Sie den virtuellen Pfad in den Website-Eigenschaften auf '/'.

Damit wird alles gelöscht, es sei denn, Sie versuchen, mehrere Anwendungen gleichzeitig auf dem Entwicklungs-PC zu hosten.

+0

Das Problem ist, dass ich viele Anwendungen für die Entwicklung konfiguriert habe ... inzwischen habe ich dieses Problem mit Page.ResolveUrl ("~/mypage.aspx") umgangen, aber ich würde wirklich gerne verstehen, warum :) – tanathos

0

Es kann sein, dass das neue Seitenobjekt nicht "MyApp" als root hat, daher wird es standardmäßig im Server root aufgelöst.

Meine Frage ist eher, warum es mit Page.ResolveUrl(...) funktioniert.
Vielleicht ResolveUrl führt einige weitere Untersuchungen über den Speicherort der Benutzersteuerung, und löst basierend darauf.

0

Seltsam, ich habe das Beispiel neu erstellt. Der Hyperlink wird als für eine bestimmte Navigations-URL von ~/Default.aspx gerendert. Meine Vermutung ist, dass es etwas mit der RequestMethod zu tun hat. Auf einer normalen Seite ist es "GET", aber bei einem Webservice-Aufruf ist es ein "POST".

Ich konnte Ihre Ergebnisse mit hl.NavigateUrl = Page.ResolveUrl("~/mypage.aspx") nicht neu erstellen Das Steuerelement gerendert immer als gegeben einen virtuellen Pfad. (Page.ResolveUrl gibt mir "~/Default.aspx")

Ich würde vorschlagen, so etwas zu tun, um die Probleme in der Zukunft zu vermeiden.

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

Grüße,

0

Es ist schwer zu sagen, was Sie ohne die Buchung der Linie zu erreichen versuchen, die tatsächlich die URL setzt auf der HyperLink, aber ich denke, dass ich die Verzeichnisstruktur zu verstehen.

Allerdings habe ich noch nie in eine Situation geraten, die mit der ResolveUrl() -Methode nicht auf die eine oder andere Weise gelöst werden konnte. String-Parsing für einen temporären Pfad, der nicht in der Produktion verwendet wird, wird nicht empfohlen, da dies Ihrem Projekt mehr Komplexität hinzufügt.

Dieser Code wird in einem Objekt lösen, die (einschließlich eines Usercontrol) ab Seite erbt:

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

Eine andere Sache, die Sie so etwas wie dies versuchen könnte, ist:

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

Wenn diese nicht Wenn Sie arbeiten, sollten Sie Ihre IIS-Einstellungen überprüfen, um sicherzustellen, dass Ihre Site als Anwendung konfiguriert ist.

+0

Eine Benutzerkontrolle kann nicht von Seite erfolgen!? Und das Aufrufen von Parent für ein Page-Objekt gibt sich selbst zurück, so dass es nicht benötigt wird. –

+0

@BurningIce - Danke, dass Sie das bemerkt haben. Ich wollte das Parent des Usercontrols verwenden. Ich habe das Codebeispiel mit der Korrektur aktualisiert. – NightOwl888

+0

aber immer noch Ihre obigen Code mit Fehler, da dann Handler für die Anfrage wird nicht vom Typ Seite sein, aber wahrscheinlich WebServiceHandler, da das Dokument tanathos am wahrscheinlichsten hat die Erweiterung .asmx oder .svc (nicht. Aspx). –