2009-06-17 10 views
0

J'ai un site Web qui utilise l'authentification ASP.NET Login Controls et Forms. J'ai placé le contrôle asp: LoginStatus dans un autre contrôle d'utilisateur Web qui gère l'affichage de la partie en-tête de mon site. Le problème que j'ai, c'est que le ReturnURL présenté par le contrôle LoginStatus référence le chemin vers le contrôle d'en-tête, pas la page sur laquelle l'utilisateur est actuellement. Cela est probablement dû à la hiérarchie des classes et que le contrôle d'en-tête (ascx) utilise réellement Server.Execute sur un fichier .aspx pour générer le code HTML. Il s'agit d'un travail pour éviter le problème de ne pas avoir plus d'un formulaire côté serveur sur une page.Contrôle ASP.NET LoginStatus - Remplacement du retourURL dans QueryString généré

Ainsi, la hiérarchie de classe réelle de la page est comme suit:

Default.aspx - Uses Page.Master 
Page.Master includes <foo:Header> 
    (with a reference to "~/Controls/Components/Header.ascx") 
Header.ascx simply includes an <asp:Literal> 
    on Page_Load performs a Server.Execute ("~/Controls/Pages/Header.aspx") 
    and writes the content out to the Literal 
Header.aspx includes <asp:LoginStatus> 

Lorsque l'utilisateur clique sur le lien de connexion, ils sont correctement redirigés vers Login.aspx, mais le ReturnURL affiché est (à tort - même si je peut comprendre pourquoi) "ReturnUrl=%2fControls%2fPages%2fHeader.aspx".

Une fois sur la page de connexion, je peux très bien gérer l'événement LoggedIn pour rediriger correctement l'utilisateur au bon endroit. Ce que je voudrais faire est soit: 1) Supprimer le ReturnURL de la chaîne de requête complètement 2) Être en mesure de contrôler le ReturnURL lorsque le contrôle LoginStatus est rendu.

J'ai fait quelques réflecteur-ing du System.Web.UI.WebControls.LoginStatus et il semble qu'il est codé en dur pour utiliser toujours un ReturnURL, basé sur le code suivant:

private string NavigateUrl 
{ 
    get 
    { 
     if (!base.DesignMode) 
     { 
      return FormsAuthentication.GetLoginPage(null, true); 
     } 
     return "url"; 
    } 
} 

Il définit toujours reuseReturnURL sur true.

Peut-être que mon seul choix est de lancer mon propre contrôle LoginStatus?

[EDIT: A l'origine par souci de concision, j'omis les détails suivants]

Voici un exemple très simple de ce que je suis en train de acheive:

projet d'application Web présente la structure suivante: WebSite - Contrôles - Composants - Footer.ascx - Header.ascx - MasterPages - Site.master - Default.aspx - Login.aspx

Les annotations de page sont ci-dessous si vous êtes intéressé.

J'ai créé le contrôle d'utilisateur Web pour la séparation des préoccupations, mais sur la page de connexion pour utiliser les contrôles asp: Login, ils doivent être imbriqués dans un formulaire (côté serveur). Le contrôle asp: LoginStatus doit également être imbriqué dans un formulaire (côté serveur). Comme vous ne pouvez pas avoir plus d'un formulaire côté serveur sur une page, cela casse.

En outre, la réponse ne consiste pas simplement à supprimer le contrôle LoginStatus sur la page de connexion. Imaginez si je voulais juste ajouter un peu de contrôle de recherche sur la page principale, qui reposerait également sur un formulaire (côté serveur). D'où la raison d'utiliser un Server.Execute et de générer une page à partir d'un ASPX. Cela "astuces" .NET en permettant plusieurs formulaires côté serveur sur une page. (Ne me demandez pas comment ... je ne sais pas!

Peut-être que toute la conception de mon architecture est erronée, mais comment les autres ont-ils plusieurs contrôles utilisateur Web sur une page qui nécessite des formulaires côté serveur? Ou n'est-ce pas?

balisage Site.master:

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="WebSite.MasterPages.Site" %> 

<%@ Register TagPrefix="bs" TagName="Footer" Src="~/Controls/Components/Footer.ascx" %> 
<%@ Register TagPrefix="bs" TagName="Header" Src="~/Controls/Components/Header.ascx" %> 

<!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" > 
<head runat="server"> 
    <title></title> 
    <asp:ContentPlaceHolder ID="head" runat="server"> 
    </asp:ContentPlaceHolder> 
</head> 
<body id="Body" runat="server"> 
    <div id="container"> 
     <!-- start header --> 
     <bs:Header ID="Header" runat="server" /> 
     <!-- end header --> 
     <div id="central"> 
      <div id="main"> 
       <asp:PlaceHolder ID="MainContentPlaceHolder" runat="server"> 
        <!-- start main content --> 
        <div> 
         <asp:ContentPlaceHolder ID="MainContent" runat="server" /> 
        </div> 
        <!-- end main content --> 
       </asp:PlaceHolder> 
      </div> 
     </div> 
     <!-- start footer --> 
     <bs:Footer ID="Footer" runat="server" /> 
     <!-- end footer --> 
    </div> 

</body> 
</html> 

balisage Default.aspx:

<%@ Page MasterPageFile="~/MasterPages/Site.Master" Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebSite._Default" %> 

<asp:Content ID="Content1" runat="server" ContentPlaceHolderID="MainContent"> 
    Main Body Content <br /> 
    <br /> 

</asp:Content> 

balisage Header.ascx:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Header.ascx.cs" Inherits="WebSite.Controls.Components.Header" %> 
<div id="header"> 
    Header Content <br /> 
    <div id="loginstatus"> 
     <form id="Form1" runat="server"> 
     <asp:LoginView ID="displayloginname" runat="server"> 
      <AnonymousTemplate> 
       <a href="../../Registration.aspx">Register</a> 
      </AnonymousTemplate> 
      <LoggedInTemplate> 
       Welcome 
       <asp:LoginName runat="server" ID="ctlLoginName" /> 
      </LoggedInTemplate> 
     </asp:LoginView> 
     <asp:LoginStatus ID="displayloginstatus" runat="server" LoginText="Login" LogoutPageUrl="~/Default.aspx" 
      LogoutAction="Redirect" /> 
     </form> 

     <br /> 
    </div> 
</div> 

balisage Footer.ascx:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Footer.ascx.cs" Inherits="Website.Controls.Components.Footer" %> 

     <div id="footer"> 
      Footer Content 
      <ul class="links"> 
      <asp:PlaceHolder ID="ListItems" Runat="server"> 
       <li><a runat="server" id="HomeLink" href="~/">Home</a></li> 
       <li><a runat="server" href="~/" ID="A1">About Us</a></li> 
       <li><a id="A2" runat="server" href="~/">Contact Us</a></li> 
       <li><a id="A3" runat="server" href="~/">Privacy Policy</a></li> 
       <li><a id="A4" runat="server" href="~/">Accessibility Policy</a></li> 
       <li><a id="A5" runat="server" href="~/">Legal Notices</a></li> 
       <li><a id="A6" runat="server" href="~/">Sitemap</a></li> 
       <li><a id="A7" runat="server" href="~/">RSS Feeds</a></li> 
      </asp:PlaceHolder> 
      </ul> 

     </div> 

balisage Login.aspx:

<%@ Page MasterPageFile="~/MasterPages/Site.Master" Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="Website.Login" %> 

<asp:Content ID="Content1" runat="server" ContentPlaceHolderID="MainContent"> 
    Main Body Content <br /> 
    <br /> 
    <form id="form1" runat="server"> 
    <div> 

     <asp:Login ID="Login1" runat="server"> 
     </asp:Login> 

    </div> 
    </form> 
</asp:Content> 

Répondre

0

Je vois deux options:

  1. Mettez votre balise form dans votre page maître. Juste en dessous du <div id="container"> et en enveloppant tout le contenu de cette div.
  2. Modifiez votre en-tête pour ne pas avoir besoin d'un formulaire ASP.NET. Vous ne savez pas si LoginView ou LoginStatus nécessitent un formulaire ASP.NET. Et puis vous pouvez laisser la balise de formulaire pour les fichiers aspx qui utilisent la page maître (comme vous avez dans Login.aspx). C'est ce que je préfère est de mettre seulement des étiquettes de forme dans les pages aspx (pas dans les fichiers maîtres) et assurez-vous que les en-têtes et pieds n'ont pas besoin d'un formulaire ASP.NET (ils pourraient utiliser une forme régulière).
+0

Merci pour les suggestions, Jeff, je vais les essayer. – plancake

0

Pourquoi faites-vous une Server.Execute du Header.aspx de votre Header.ascx? Pourquoi ne pas simplement mettre le code Header.aspx dans Header.ascx. De cette façon, ReturnUrl sera la page que vous attendez.

0

Quelque chose ne semble pas tout à fait ici:

sur Page_Load effectue un Server.Execute ("~/Contrôle/Pages/Header.aspx")
et écrit le contenu sur la littérales

Je ne comprends pas pourquoi vous faites cela? Vous mentionnez que c'est parce que vous essayez de contourner le problème de ASP.NET ne permettant pas plus d'un HtmlForm sur une page. Mais si vous mettez simplement le contenu html de header.aspx dans un littéral, alors vous n'utilisez pas un HtmlForm ?? Alors pouvez-vous simplement placer le contenu de Header.aspx dans une balise de formulaire normale (sans runat = server)? Ou le contrôle d'état de connexion peut-il être placé en dehors du formulaire entièrement? Est-ce que le contenu de Header.aspx a vraiment besoin d'un formulaire en premier lieu? Je regarderais bien pourquoi vous écrivez le contenu de votre page header.aspx sur un littéral et essayez de résoudre le problème là-bas au lieu de plonger dans le contrôle LoginStatus et le changer pour faire quelque chose qu'il n'est pas destiné à faire.

Autre suggestion possible: Si vous avez vraiment besoin de charger l'en-tête dans un littéral, pouvez-vous utiliser Page.LoadUserControl à la place? Cela peut résoudre automatiquement les URL pour vous? Pas 100% sûr cependant.

+0

Je vais modifier ma question pour fournir un peu plus d'informations ... – plancake

+0

En réponse à vos questions ... 1) asp: le contrôle LoginStatus nécessite un formulaire côté serveur, donc oui, mon en-tête (Control ou Page, peu importe lequel) nécessite un formulaire côté serveur. 2) ASP: Le contrôle de connexion nécessite également un formulaire côté serveur. Peut-être que c'est là où mon problème réside, comment puis-je avoir deux contrôles utilisateur Web sur la même page qui nécessitent tous deux des formulaires côté serveur? – plancake

Questions connexes