2010-11-15 14 views
4

J'essaie de trouver une manière élégante d'avoir un formulaire de connexion dans la page maître. Cela signifie que, sauf si l'utilisateur se connecte, le formulaire de connexion doit apparaître sur chaque page. (Ceci est très fréquent de nos jours)ASP.NET MVC2 Formulaire de connexion dans le gabarit

Prenant l'exemple qui vient avec l'application MVC2 dans Visual Studio J'ai créé ceci:

public class MasterViewModel 
{ 
    public string User { get; set; } // omitted validation attributes 
    public string Pass{ get; set; } 
    public bool RememberMe { get; set; } 
} 

Chaque modèle de vue hérite de MasterViewModel

public class RegisterViewModel : MasterViewModel 
{ 
    public string UserName { get; set; } 
    public string Email { get; set; } 
    public string Password { get; set; } 
    public string ConfirmPassword { get; set; } 
} 

Mon maître page rend la vue partielle

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<MyLogon.ViewModels.MasterViewModel>" %> 
..... 
      <div id="logindisplay"> 
       <% Html.RenderPartial("LogOn"); %> 
      </div> 
...... 

Forte v d partielle IEW:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MyLogon.ViewModels.MasterViewModel>" %> 
    <% 
     if (Request.IsAuthenticated) { 
    %> 
      Welcome <b><%= Html.Encode(Page.User.Identity.Name) %></b>! 
      <div>[ <%= Html.ActionLink("Change Password", "ChangePassword", "Account") %> ]</div>   
      <div>[ <%= Html.ActionLink("Log Off", "LogOff", "Account") %> ]</div> 
    <% 
     } 
     else { 
    %> 
     <%= Html.ValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.") %> 

     <% using (Html.BeginForm("LogOn", "Account",FormMethod.Post)) { %> 
      <div> 
       <fieldset> 
        <legend>Account Information</legend> 

        <div class="editor-label"> 
         <%= Html.LabelFor(m => m.User) %> 
        </div> 
        <div class="editor-field"> 
         <%= Html.TextBoxFor(m => m.User) %> 
         <%= Html.ValidationMessageFor(m => m.User) %> 
        </div> 

        <div class="editor-label"> 
         <%= Html.LabelFor(m => m.Pass) %> 
        </div> 
        <div class="editor-field"> 
         <%= Html.PasswordFor(m => m.Pass) %> 
         <%= Html.ValidationMessageFor(m => m.Pass) %> 
        </div> 

        <div class="editor-label"> 
         <%= Html.CheckBoxFor(m => m.RememberMe) %> 
         <%= Html.LabelFor(m => m.RememberMe) %> 
        </div>    
        <p> 
         <input type="submit" value="Log On" /> 
        </p> 
       </fieldset> 
      </div> 
     <% } %> 
    <% 
     } 
    %> 

page Registre:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyLogon.Models.RegisterViewModel>" %> 
... 
    <h2>Create a New Account</h2> 
    <p> 
     Use the form below to create a new account. 
    </p> 
    <p> 
     Passwords are required to be a minimum of <%= Html.Encode(ViewData["PasswordLength"]) %> characters in length. 
    </p> 

    <% using (Html.BeginForm("Register", "Account" ,FormMethod.Post)) 
     { %> 
     <%= Html.ValidationSummary(true, "Account creation was unsuccessful. Please correct the errors and try again.") %> 
     <div> 
      <fieldset> 
       <legend>Account Information</legend> 

       <div class="editor-label"> 
        <%= Html.LabelFor(m => m.UserName) %> 
       </div> 
       <div class="editor-field"> 
        <%= Html.TextBoxFor(m => m.UserName) %> 
        <%= Html.ValidationMessageFor(m => m.UserName) %> 
       </div> 

       <div class="editor-label"> 
        <%= Html.LabelFor(m => m.Email) %> 
       </div> 
       <div class="editor-field"> 
        <%= Html.TextBoxFor(m => m.Email) %> 
        <%= Html.ValidationMessageFor(m => m.Email) %> 
       </div> 

       <div class="editor-label"> 
        <%= Html.LabelFor(m => m.Password) %> 
       </div> 
       <div class="editor-field"> 
        <%= Html.PasswordFor(m => m.Password) %> 
        <%= Html.ValidationMessageFor(m => m.Password) %> 
       </div> 

       <div class="editor-label"> 
        <%= Html.LabelFor(m => m.ConfirmPassword) %> 
       </div> 
       <div class="editor-field"> 
        <%= Html.PasswordFor(m => m.ConfirmPassword) %> 
        <%= Html.ValidationMessageFor(m => m.ConfirmPassword) %> 
       </div> 

       <p> 
        <input type="submit" value="Register" /> 
       </p> 
      </fieldset> 
     </div> 
    <% } %> 
</asp:Content> 

Comme tous les modèles de vue héritent de MasterViewModel LogOn vue partielle est toujours satisfait, mais je trouve cette solution très inélégante. Y a-t-il un autre moyen d'y parvenir?

Répondre

2

Utilisez une vue partielle telle que vous êtes, mais avec des vues différentes en fonction de l'état de connexion. Renvoyer une vue pour les utilisateurs anonymes avec un formulaire de connexion/lien à la page d'inscription et une deuxième vue pour les utilisateurs connectés.

Les vues partielles peuvent avoir leurs propres modèles qui n'ont pas besoin d'hériter du modèle de vue principale. Hériter des modèles peut causer des problèmes plus tard (il rend l'utilisation html.EditForModel() ou .DisplayForModel() difficile car ils rendront les champs communs de vue principale aussi). Oh, et en général, c'est une mauvaise pratique pour que la vue repose sur quoi que ce soit en dehors du modèle - votre test sur Request.IsAuthenticated peut être correct pour le moment mais si vous voulez être absolument correct, vous devriez avoir une propriété model.IsAuthenticated par l'action. Cela dit, changer de vue permettra d'éviter complètement ce problème.

Modifier: Une dernière amélioration. Sur les lignes comme celle-ci:

Welcome <b><%= Html.Encode(Page.User.Identity.Name) %></b>! 

Au lieu de cela faire:

Welcome <b><%: Page.User.Identity.Name %></b>! 

fait encore mieux serait de ne frapper le modèle:

Welcome <b><%: model.Username %></b>! 

(Notez le <%: pas <%=). Cette forme de tag indique que le contenu doit être codé en HTML. Ce qui est encore mieux, c'est que s'il rencontre un string, il l'encodera. S'il rencontre un HTMLString, ce ne sera pas le cas. Toutes les fonctions .Net MVC retour chaîne ou une chaîne de HTML appropriée afin que vous puissiez le faire:

<%: html.EditFor(x => x.fieldname) %> 
<%: model.somefield %> 

Le premier ne sera PAS codé html comme EditFor() retourne un HTMLString.La seconde sera codée (si somefield est une chaîne standard)

Cela rendra votre code à la fois plus net et plus robuste. Vous pouvez également utiliser ceci pour générer dynamiquement du HTML si nécessaire et le faire encoder/non comme approprié. Par exemple, nous avons quelques fonctions d'aide à gérer, y compris CSS/JS. Ils reviennent HTMLStrings ...

<%: Helper.IncludeCSS("SomeCSS.css") %> 
+0

« Utilisez une vue partielle que vous êtes, mais ont des vues différentes sur la base du statut d'accès. Retour un point de vue pour les utilisateurs anonymes avec un formulaire de connexion/lunk à la page du registre et un second vue pour les utilisateurs connectés. " Désolé, je ne sais pas Si j'ai bien compris. Ce que vous avez fourni est fourni avec l'application MVC2 par défaut. L'idée est d'avoir Login sur TOUTES les pages jusqu'à ce que l'utilisateur se connecte. Donc, en cliquant sur Register, deux formulaires seront affichés. J'utilise <% = not <%: parce que je travaille avec Visual Studio 2008 –

+0

Ah, ok, ma seule expérience avec MVC est MVC2 donc mes informations peuvent être suspectes pour MVC. Certainement dans MVC2, j'aurais un RenderPartial sur la masterpage qui pointe sur une action. Cette action renvoie l'une des deux vues basées sur Request.IsAuthenticated. Si elle n'est pas authentifiée, elle renvoie la vue LogonPartial, sinon elle renvoie la vue Authentifiée. Évidemment, l'un de ceux-ci est un lien de forme/enregistrement de connexion et l'autre est un lien de déconnexion. FWIW Je vous recommande fortement d'envisager une mise à niveau vers 2010 si possible - Il y a d'énormes améliorations. – Basic