1 //------------------------------------------------------------------------------
2 // <copyright file="LoginView.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 namespace System.Web.UI.WebControls {
9 using System.Collections;
10 using System.ComponentModel;
11 using System.Security.Permissions;
12 using System.Security.Principal;
13 using System.Web.Security;
18 /// Renders exactly one of its templates, chosen by whether a user is logged in
19 /// and the roles that contain the user.
24 PersistChildren(false),
25 Designer("System.Web.UI.Design.WebControls.LoginViewDesigner," + AssemblyRef.SystemDesign),
26 DefaultProperty("CurrentView"),
27 DefaultEvent("ViewChanged"),
30 public class LoginView : Control, INamingContainer {
32 private RoleGroupCollection _roleGroups;
33 private ITemplate _loggedInTemplate;
34 private ITemplate _anonymousTemplate;
36 private int _templateIndex;
38 private const int anonymousTemplateIndex = 0;
39 private const int loggedInTemplateIndex = 1;
40 private const int roleGroupStartingIndex = 2;
42 private static readonly object EventViewChanging = new object();
43 private static readonly object EventViewChanged = new object();
47 /// Template shown when no user is logged in.
52 PersistenceMode(PersistenceMode.InnerProperty),
53 TemplateContainer(typeof(LoginView)),
55 public virtual ITemplate AnonymousTemplate {
57 return _anonymousTemplate;
60 _anonymousTemplate = value;
67 public override bool EnableTheming {
69 return base.EnableTheming;
72 base.EnableTheming = value;
79 public override string SkinID {
91 /// Copied from CompositeControl. This control does not extend CompositeControl because it should not be a WebControl.
93 public override ControlCollection Controls {
95 EnsureChildControls();
102 /// Copied from CompositeControl. This control does not extend CompositeControl because it should not be a WebControl.
103 /// Does not call Base.DataBind(), since we need to call EnsureChildControls() between
104 /// OnDataBinding() and DataBindChildren().
106 public override void DataBind() {
107 // Do our own databinding
108 OnDataBinding(EventArgs.Empty);
110 EnsureChildControls();
112 // Do all of our children's databinding
118 /// Template shown when a user is logged in, but the user is not in any role associated with a template.
123 PersistenceMode(PersistenceMode.InnerProperty),
124 TemplateContainer(typeof(LoginView)),
126 public virtual ITemplate LoggedInTemplate {
128 return _loggedInTemplate;
131 _loggedInTemplate = value;
137 /// Maps groups of roles to templates.
140 WebCategory("Behavior"),
141 MergableProperty(false),
144 PersistenceMode(PersistenceMode.InnerProperty),
145 WebSysDescription(SR.LoginView_RoleGroups)
147 public virtual RoleGroupCollection RoleGroups {
149 if (_roleGroups == null) {
150 _roleGroups = new RoleGroupCollection();
157 /// Index of the template rendered on the previous page load. Saved in ControlState.
158 /// 0: AnonymousTemplate
159 /// 1: LoggedInTemplate
160 /// >=2: RoleGroup template with index n-2
162 private int TemplateIndex {
164 return _templateIndex;
167 if (value != TemplateIndex) {
168 OnViewChanging(EventArgs.Empty);
169 _templateIndex = value;
170 ChildControlsCreated = false;
171 OnViewChanged(EventArgs.Empty);
178 /// Raised after the view is changed.
181 WebCategory("Action"),
182 WebSysDescription(SR.LoginView_ViewChanged)
184 public event EventHandler ViewChanged {
186 Events.AddHandler(EventViewChanged, value);
189 Events.RemoveHandler(EventViewChanged, value);
195 /// Raised before the view is changed. Not cancellable, because the view is changed
196 /// when the logged-in user changes, and it wouldn't make sense to cancel this.
199 WebCategory("Action"),
200 WebSysDescription(SR.LoginView_ViewChanging)
202 public event EventHandler ViewChanging {
204 Events.AddHandler(EventViewChanging, value);
207 Events.RemoveHandler(EventViewChanging, value);
213 /// Instantiate the appropriate template.
215 protected internal override void CreateChildControls() {
218 // For the first request, set _templateIndex now, so the correct template is
219 // instantiated and we do not raise the ViewChanging/ViewChanged events.
221 if (page != null && !page.IsPostBack && !DesignMode) {
222 _templateIndex = GetTemplateIndex();
225 int templateIndex = TemplateIndex;
226 ITemplate template = null;
227 switch (templateIndex) {
228 case anonymousTemplateIndex:
229 template = AnonymousTemplate;
231 case loggedInTemplateIndex:
232 template = LoggedInTemplate;
235 int roleGroupIndex = templateIndex - roleGroupStartingIndex;
236 RoleGroupCollection roleGroups = RoleGroups;
237 if (0 <= roleGroupIndex && roleGroupIndex < roleGroups.Count) {
238 template = roleGroups[roleGroupIndex].ContentTemplate;
243 if (template != null) {
244 Control templateContainer = new Control();
245 template.InstantiateIn(templateContainer);
246 Controls.Add(templateContainer);
251 EditorBrowsable(EditorBrowsableState.Never),
253 public override void Focus() {
254 throw new NotSupportedException(SR.GetString(SR.NoFocusSupport, this.GetType().Name));
258 /// Loads the control state for those properties that should persist across postbacks
259 /// even when EnableViewState=false.
261 protected internal override void LoadControlState(object savedState) {
262 if (savedState != null) {
263 Pair state = (Pair)savedState;
264 if (state.First != null) {
265 base.LoadControlState(state.First);
267 if (state.Second != null) {
268 _templateIndex = (int)state.Second;
274 protected internal override void OnInit(EventArgs e) {
277 Page.RegisterRequiresControlState(this);
283 /// Sets the TemplateIndex based on the current user.
285 protected internal override void OnPreRender(EventArgs e) {
288 TemplateIndex = GetTemplateIndex();
290 // This is called in Control.PreRenderRecursiveInteral, but we need to call it again
291 // since we may have changed the TemplateIndex
292 EnsureChildControls();
297 /// Raises the ViewChanged event.
299 protected virtual void OnViewChanged(EventArgs e) {
300 EventHandler handler = (EventHandler)Events[EventViewChanged];
301 if (handler != null) {
308 /// Raises the ViewChanging event.
310 protected virtual void OnViewChanging(EventArgs e) {
311 EventHandler handler = (EventHandler)Events[EventViewChanging];
312 if (handler != null) {
317 protected internal override void Render(HtmlTextWriter writer) {
318 EnsureChildControls();
323 /// Saves the control state for those properties that should persist across postbacks
324 /// even when EnableViewState=false.
326 protected internal override object SaveControlState() {
327 object baseState = base.SaveControlState();
328 if (baseState != null || _templateIndex != 0) {
329 object templateIndexState = null;
331 if (_templateIndex != 0) {
332 templateIndexState = _templateIndex;
334 return new Pair(baseState, templateIndexState);
341 /// Allows the designer to set the TemplateIndex, so the different templates can be shown in the designer.
343 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)]
344 protected override void SetDesignModeState(IDictionary data) {
346 object o = data["TemplateIndex"];
348 TemplateIndex = (int)o;
350 // Note: we always recreate the child controls in the designer to correctly handle the case of
351 // the currently selected role group being deleted. This is necessary because the
352 // setter for TemplateIndex won't recreate the controls if the TemplateIndex is unchanged,
353 // which is the case when deleting all but the last role group. [Fix for Bug 148406]
354 ChildControlsCreated = false;
359 private int GetTemplateIndex() {
360 if (!DesignMode && Page != null && Page.Request.IsAuthenticated) {
361 IPrincipal user = LoginUtil.GetUser(this);
362 int roleGroupIndex = -1;
364 // Unlikely but possible for Page.Request.IsAuthenticated to be true and
367 roleGroupIndex = RoleGroups.GetMatchingRoleGroupInternal(user);
370 if (roleGroupIndex >= 0) {
371 return roleGroupIndex + roleGroupStartingIndex;
374 return loggedInTemplateIndex;
378 return anonymousTemplateIndex;