Pergunta

Eu tenho um site que usa os controles ASP.NET login e Autenticação de formulários. Eu coloquei o controle asp: LoginStatus dentro de outro controlo de utilizador Web que gerencia a exibição da parte do cabeçalho do meu site.

O problema que tenho é que o ReturnURL apresentado pelas referências de controle LoginStatus o caminho para o controle de cabeçalho, e não a página que o usuário está atualmente em. Isto é provavelmente devido à hierarquia de classes e que o controle de cabeçalho (ascx) realmente usa Server.Execute em um arquivo .aspx para gerar o HTML. Este é um trabalho ao redor para evitar o problema de não ser permitido ter mais de uma forma do lado do servidor em uma página.

Assim, a classe hierarquia real da página é o seguinte:

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>

Quando o usuário clica no Link de Login eles estão correctamente redireccionados para Login.aspx, no entanto, o ReturnURL exibido é (incorretamente - embora eu possa entender por que). "ReturnUrl=%2fControls%2fPages%2fHeader.aspx"

Uma vez na página de login que posso completamente feliz manipular o evento LoggedIn para redirecionar corretamente o usuário para o lugar certo. O que eu gostaria de fazer é: 1) Retire o ReturnURL da string de consulta por completo 2) Ser capaz de controlar a ReturnURL quando o Controle LoginStatus é processado.

Já fiz alguns refletor-ing da System.Web.UI.WebControls.LoginStatus e parece que é codificado para usar sempre um ReturnURL, com base no seguinte código:

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

É sempre a definir reuseReturnURL para true.

Possivelmente, a minha única opção é fazer a minha própria controle LoginStatus?

[EDIT: Originalmente por uma questão de brevidade, eu omiti os seguintes detalhes]

Aqui está um exemplo muito simples do que eu estou tentando para conseguir:

projeto de aplicação Web tem a seguinte estrutura: Local na rede Internet - Controles - Componentes - Footer.ascx - Header.ascx - MasterPages - Site.Master - Default.aspx - Login.aspx

As marcações de página estão abaixo se você estiver interessado.

Eu criei a Web User Control para a separação de preocupações, no entanto na página de login para utilizar a asp: controles Login eles precisam ser aninhados em um formulário (server-side). O controle asp: LoginStatus também precisa de ser encaixado numa forma (do lado do servidor). Como você não pode ter mais de uma forma do lado do servidor em uma página, esta quebra.

Além disso, a resposta é não apenas para suprimir o controle LoginStatus na página Login. Imagine se eu só queria adicionar um pouco de Pesquisa de Controle na página principal, que também contam com um formulário (server-side). Daí a razão para a utilização de um Server.Execute e gerar uma página de um ASPX. Este "truques" .NET para permitir que múltiplas formas do lado do servidor em uma página. (Não me pergunte como ... Eu não sei!)

Talvez toda a minha projeto de arquitetura é errado, mas como outros têm vários controles de usuário da Web em uma página que requerem formas do lado do servidor? Ou não?

Site.Master marcação:

<%@ 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>

Default.aspx marcação:

<%@ 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>

Header.ascx marcação:

<%@ 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>

Footer.ascx marcação:

<%@ 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>

Login.aspx marcação:

<%@ 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>
Foi útil?

Solução

Eu vejo duas opções:

  1. Coloque a sua marca de formulário em sua página mestre. Logo abaixo da <div id="container"> e envolvendo todo o conteúdo do div.
  2. Altere seu cabeçalho para não exigir um formulário ASP.NET. Não tenho certeza se o LoginView ou LoginStatus ambos exigem uma forma ASP.NET. E então você pode deixar a marca de formulário para os arquivos aspx que usam a página mestra (como você tem em Login.aspx). Isto é o que eu prefiro é marcas de formulário só colocar em páginas aspx (não em arquivos mestres) e certifique-se os cabeçalhos e rodapé não precisa de uma forma ASP.NET (que poderia usar um tag forma regular, não apenas com runat = server).

Outras dicas

Por que você faz um Server.Execute do Header.aspx do seu Header.ascx? Por que você não apenas colocar o código Header.aspx na Header.ascx. Dessa forma, o ReturnUrl será a página que você espera que ele seja.

Algo não soa muito bem aqui:

em Page_Load realiza uma Server.Execute ( "~ / Controls / Pages / Header.aspx")
e grava o conteúdo para o Literal

Eu não estou entendendo por que você está fazendo isso? Você menciona que é porque você está tentando contornar o problema do ASP.NET não permitindo que mais de um HtmlForm em uma página. Mas se você está apenas colocando o conteúdo HTML de header.aspx em um literal, então você não está usando um HtmlForm ?? Então você pode simplesmente colocar o conteúdo de Header.aspx em uma etiqueta de forma normal (sem runat = server)? Ou pode o controle de status de login ser colocado fora da forma inteiramente? Não o conteúdo de Header.aspx realmente precisa de um formulário em primeiro lugar?

Gostaria de ter uma boa olhada em porque você está escrevendo o conteúdo da sua página header.aspx para um literal e tentar resolver o problema lá em vez de mergulhar no controle LoginStatus e mudá-lo a fazer algo que não se destina fazer.

Uma outra sugestão possível: Se você realmente precisa fazer para carregar Header em um literal, você pode usar Page.LoadUserControl em vez disso? Isto pode resolver automaticamente as URLs para você? Não 100% de certeza embora.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top