Элемент управления ASP.NET LoginStatus - переопределение ReturnURL в сгенерированном QueryString

StackOverflow https://stackoverflow.com/questions/1004630

  •  05-07-2019
  •  | 
  •  

Вопрос

У меня есть веб-сайт, который использует элементы управления входом ASP.NET Аутентификация по формам. Я поместил элемент управления asp: LoginStatus в другой элемент управления веб-пользователя, который управляет отображением заголовочной части моего сайта.

У меня проблема в том, что ReturnURL, представленный элементом управления LoginStatus, ссылается на путь к элементу управления заголовком, а не на страницу, на которой в данный момент находится пользователь. Вероятно, это связано с иерархией классов и тем, что элемент управления заголовком (ascx) фактически использует Server.Execute в файле .aspx для генерации HTML. Это обходной путь, позволяющий избежать проблемы, связанной с тем, что на странице не должно быть более одной серверной формы.

Таким образом, фактическая иерархия страниц выглядит следующим образом:

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>

Когда пользователь нажимает на ссылку входа в систему, он правильно перенаправляется в Login.aspx, однако отображается ReturnURL (неправильно - хотя я могу понять, почему) "ReturnUrl=%2fControls%2fPages%2fHeader.aspx".

Однажды на странице входа в систему я вполне могу обработать событие LoggedIn, чтобы правильно перенаправить пользователя в нужное место. То, что я хотел бы сделать, это либо: 1) Удалить ReturnURL из строки запроса в целом 2) Уметь управлять ReturnURL при визуализации элемента управления LoginStatus.

Я сделал несколько рефлекторов System.Web.UI.WebControls.LoginStatus, и кажется, что он всегда жестко запрограммирован на ReturnURL на основе следующего кода:

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

Он всегда устанавливает для reuseReturnURL значение true.

Возможно, мой единственный выбор - развернуть свой собственный элемент управления LoginStatus?

[РЕДАКТИРОВАТЬ: Первоначально ради краткости я пропустил следующие детали]

Вот очень простой пример того, что я пытаюсь достичь:

Проект веб-приложения имеет следующую структуру: Веб-сайт  - Управление    - Компоненты      - Footer.ascx      - Header.ascx  - MasterPages    - Site.Master  - Default.aspx  - Login.aspx

Разметки страницы ниже, если вам интересно.

Я создал пользовательский веб-элемент управления для разделения задач, однако на странице входа в систему для использования элементов управления asp: Login они должны быть вложены в (на стороне сервера) форму. Элемент управления asp: LoginStatus также должен быть вложен в (на стороне сервера) форму. Поскольку на странице не может быть более одной серверной формы, это нарушается.

Кроме того, ответ заключается не только в подавлении элемента управления LoginStatus на странице входа в систему. Представьте себе, если бы я просто хотел добавить небольшой элемент управления поиском на главной странице, который также опирался бы на форму (на стороне сервера). Отсюда и причина использования Server.Execute и создания страницы из ASPX. Этот & Трюк & Quot; .NET в разрешении нескольких серверных форм на странице. (Не спрашивайте меня, как ... я не знаю!)

Может быть, весь мой архитектурный дизайн неправильный, но как другим иметь несколько веб-элементов управления на странице, которые требуют серверных форм? Или нет?

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>

Разметка 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>

Разметка 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>

Разметка 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>

Разметка 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>
Это было полезно?

Решение

Я вижу два варианта:

<Ол>
  • Поместите тег формы на свою главную страницу. Чуть ниже <div id="container" & Gt; и завернуть все содержимое в этом div.
  • Измените заголовок, чтобы он не требовал формы ASP.NET. Не уверен, что для LoginView или LoginStatus требуется форма ASP.NET. И тогда вы можете оставить тег формы для файлов aspx, которые используют главную страницу (как у вас в Login.aspx). Я предпочитаю размещать теги формы только на страницах aspx (не в основных файлах) и следить за тем, чтобы верхние и нижние колонтитулы не нуждались в форме ASP.NET (они могли бы использовать обычный тег формы, но не с runat = server).
  • Другие советы

    Почему вы делаете Server.Execute из Header.aspx из вашего Header.ascx? Почему бы вам просто не поместить код Header.aspx в Header.ascx. Таким образом, ReturnUrl будет той страницей, на которой вы ожидаете.

    Что-то здесь звучит не совсем правильно:

      

    в Page_Load выполняет Server.Execute (" ~ / Controls / Pages / Header.aspx ")
      и записывает содержимое в литерал

    Я не понимаю, зачем ты это делаешь? Вы упоминаете, что это потому, что вы пытаетесь обойти проблему ASP.NET, не позволяющую использовать более одной HtmlForm на странице. Но если вы просто помещаете html-содержимое из header.aspx в литерал, тогда вы не используете HtmlForm ?? Так что вы можете просто поместить содержимое Header.aspx в обычный тег формы (без runat = server)? Или можно полностью контролировать состояние входа в систему за пределы формы? Действительно ли содержимое Header.aspx действительно нуждается в форме?

    Я бы хорошо посмотрел, почему вы записываете содержимое своей страницы header.aspx в литерал, и попытался бы устранить проблему вместо того, чтобы погрузиться в элемент управления LoginStatus и изменить его, чтобы он выполнял что-то, для чего он не предназначен делать.

    Еще одно возможное предложение: если вам действительно нужно загрузить Header в литерал, можете ли вы использовать Page.LoadUserControl вместо этого? Это может автоматически разрешить URL для вас? Хотя не уверен на 100%.

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top