#region License
/*
* Copyright 2002-2004 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#endregion
#region Imports
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Web.UI;
using Spring.Collections;
using Spring.Validation;
using Spring.Web.UI.Controls;
using IValidatorSpring.Validation.IValidator;
#if NET_2_0
using Spring.Context;
using Spring.Context.Support;
using Spring.Globalization;
using Spring.Util;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Resources;
using System.Web;
using System.Web.Compilation;
using Spring.Web.Support;
#endif
#endregion Imports
namespace Spring.Web.UI{
#if !NET_2_0
#region ASP.NET 1.1 Spring Master Page Implementation
/// <summary>
/// Spring.NET Master Page implementation for ASP.NET 1.1
/// </summary>
/// <author>Aleksandar Seovic</author>
public class MasterPage : UserControl
{
/// <summary>
/// Initializes master page.
/// </summary>
public void Initialize(Page childPage)
{
InitializeAsUserControl(childPage);
this.ID = "masterPage";
Control[] controls = new Control[childPage.Controls.Count];
childPage.Controls.CopyTo(controls, 0);
for (int i = 0; i < controls.Length; i++)
{
if (controls[i] is Content)
{
Content content = (Content) controls[i];
ContentPlaceHolder placeholder = (ContentPlaceHolder) this.FindControl(content.ContentPlaceHolderID);
if (placeholder == null)
{
throw new ArgumentException("Content placeholder " + content.ContentPlaceHolderID + " does not exist in the master page.");
}
placeholder.Content = content;
}
}
childPage.Controls.AddAt(0, this);
}
/// <summary>
/// Delegate validation errors to the owning page.
/// </summary>
public override IValidationErrors ValidationErrors
{
get { return Page.ValidationErrors; }
}
}
#endregion
#else
#region ASP.NET 2.0 Spring Master Page Implementation
/// <summary>
/// Spring.NET Master Page implementation for ASP.NET 2.0
/// </summary>
/// <author>Aleksandar Seovic</author>
public class MasterPage : System.Web.UI.MasterPage, IApplicationContextAware, ISupportsWebDependencyInjection, IWebNavigable
{
#region Instance Fields
private ILocalizer localizer;
private IValidationErrors validationErrors = new ValidationErrors();
private IMessageSource messageSource;
private IApplicationContext applicationContext;
private IApplicationContext defaultApplicationContext;
private IWebNavigator webNavigator;
private IDictionary args;
#endregion
#region Lifecycle methods
/// <summary>
/// Initialize a new MasterPage instance.
/// </summary>
public MasterPage()
{
InitializeNavigationSupport();
}
/// <summary>
/// Initializes user control.
/// </summary>
protected override void OnInit(EventArgs e)
{
InitializeMessageSource();
base.OnInit(e);
// initialize controls
OnInitializeControls(EventArgs.Empty);
}
/// <summary>
/// Binds data from the data model into controls and raises
/// PreRender event afterwards.
/// </summary>
/// <param name="e">Event arguments.</param>
protected override void OnPreRender(EventArgs e)
{
if (localizer != null)
{
localizer.ApplyResources(this, messageSource, UserCulture);
}
else if (Page.Localizer != null)
{
Page.Localizer.ApplyResources(this, messageSource, UserCulture);
}
base.OnPreRender(e);
}
/// <summary>
/// This event is raised before Load event and should be used to initialize
/// controls as necessary.
/// </summary>
public event EventHandler InitializeControls;
/// <summary>
/// Raises InitializeControls event.
/// </summary>
/// <param name="e">Event arguments.</param>
protected virtual void OnInitializeControls(EventArgs e)
{
if (InitializeControls != null)
{
InitializeControls(this, e);
}
}
/// <summary>
/// Obtains a <see cref="T:System.Web.UI.UserControl"/> object from a user control file
/// and injects dependencies according to Spring config file.
/// </summary>
/// <param name="virtualPath">The virtual path to a user control file.</param>
/// <returns>
/// Returns the specified <see langword="UserControl"/> object, with dependencies injected.
/// </returns>
protected virtual new Control LoadControl(string virtualPath)
{
Control control = base.LoadControl(virtualPath);
control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext,control);
return control;
}
/// <summary>
/// Obtains a <see cref="T:System.Web.UI.UserControl"/> object by type
/// and injects dependencies according to Spring config file.
/// </summary>
/// <param name="t">The type of a user control.</param>
/// <param name="parameters">parameters to pass to the control</param>
/// <returns>
/// Returns the specified <see langword="UserControl"/> object, with dependencies injected.
/// </returns>
protected virtual new Control LoadControl( Type t, params object[] parameters)
{
Control control = base.LoadControl( t, parameters );
control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext,control);
return control;
}
#endregion Control lifecycle methods
#region Data binding events
/// <summary>
/// This event is raised after all controls have been populated with values
/// from the data model.
/// </summary>
public event EventHandler DataBound;
/// <summary>
/// Raises DataBound event.
/// </summary>
/// <param name="e">Event arguments.</param>
protected virtual void OnDataBound(EventArgs e)
{
if (DataBound != null)
{
DataBound(this, e);
}
}
/// <summary>
/// This event is raised after data model has been populated with values from
/// web controls.
/// </summary>
public event EventHandler DataUnbound;
/// <summary>
/// Raises DataBound event.
/// </summary>
/// <param name="e">Event arguments.</param>
protected virtual void OnDataUnbound(EventArgs e)
{
if (DataUnbound != null)
{
DataUnbound(this, e);
}
}
#endregion
#region Application context support
/// <summary>
/// Gets or sets the <see cref="Spring.Context.IApplicationContext"/> that this
/// object runs in.
/// </summary>
/// <value></value>
/// <remarks>
/// <p>
/// Normally this call will be used to initialize the object.
/// </p>
/// <p>
/// Invoked after population of normal object properties but before an
/// init callback such as
/// <see cref="Spring.Objects.Factory.IInitializingObject"/>'s
/// <see cref="Spring.Objects.Factory.IInitializingObject.AfterPropertiesSet"/>
/// or a custom init-method. Invoked after the setting of any
/// <see cref="Spring.Context.IResourceLoaderAware"/>'s
/// <see cref="Spring.Context.IResourceLoaderAware.ResourceLoader"/>
/// property.
/// </p>
/// </remarks>
/// <exception cref="Spring.Context.ApplicationContextException">
/// In the case of application context initialization errors.
/// </exception>
/// <exception cref="Spring.Objects.ObjectsException">
/// If thrown by any application context methods.
/// </exception>
/// <exception cref="Spring.Objects.Factory.ObjectInitializationException"/>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual IApplicationContext ApplicationContext
{
get { return applicationContext; }
set { applicationContext = value; }
}
#endregion
#region Message source and localization support
/// <summary>
/// Gets or sets the localizer.
/// </summary>
/// <value>The localizer.</value>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ILocalizer Localizer
{
get { return localizer; }
set
{
localizer = value;
if (localizer.ResourceCache is NullResourceCache)
{
localizer.ResourceCache = new AspNetResourceCache();
}
}
}
/// <summary>
/// Gets or sets the local message source.
/// </summary>
/// <value>The local message source.</value>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public IMessageSource MessageSource
{
get { return messageSource; }
set
{
messageSource = value;
if (messageSource != null && messageSource is AbstractMessageSource)
{
((AbstractMessageSource) messageSource).ParentMessageSource = applicationContext;
}
}
}
/// <summary>
/// Initializes local message source
/// </summary>
protected void InitializeMessageSource()
{
if (MessageSource == null)
{
string key = GetType().FullName + ".MessageSource";
MessageSource = (IMessageSource) Context.Cache.Get(key);
if (MessageSource == null)
{
ResourceSetMessageSource defaultMessageSource = new ResourceSetMessageSource();
ResourceManager rm = GetLocalResourceManager();
if (rm != null)
{
defaultMessageSource.ResourceManagers.Add(rm);
}
Context.Cache.Insert(key, defaultMessageSource);
MessageSource = defaultMessageSource;
}
}
}
/// <summary>
/// Creates and returns local ResourceManager for this page.
/// </summary>
/// <remarks>
/// <para>
/// In ASP.NET 1.1, this method loads local resources from the web application assembly.
/// </para>
/// <para>
/// However, in ASP.NET 2.0, local resources are compiled into the dynamic assembly,
/// so we need to find that assembly instead and load the resources from it.
/// </para>
/// </remarks>
/// <returns>Local ResourceManager instance.</returns>
private ResourceManager GetLocalResourceManager()
{
return LocalResourceManager.GetLocalResourceManager(this);
}
/// <summary>
/// Returns message for the specified resource name.
/// </summary>
/// <param name="name">Resource name.</param>
/// <returns>Message text.</returns>
public string GetMessage(string name)
{
return messageSource.GetMessage(name, UserCulture);
}
/// <summary>
/// Returns message for the specified resource name.
/// </summary>
/// <param name="name">Resource name.</param>
/// <param name="args">Message arguments that will be used to format return value.</param>
/// <returns>Formatted message text.</returns>
public string GetMessage(string name, params object[] args)
{
return messageSource.GetMessage(name, UserCulture, args);
}
/// <summary>
/// Returns resource object for the specified resource name.
/// </summary>
/// <param name="name">Resource name.</param>
/// <returns>Resource object.</returns>
public object GetResourceObject(string name)
{
return messageSource.GetResourceObject(name, UserCulture);
}
/// <summary>
/// Gets or sets user's culture
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual CultureInfo UserCulture
{
get { return Page.UserCulture; }
set { Page.UserCulture = value; }
}
#endregion
#region Result support
/// <summary>
/// Ensure, that <see cref="WebNavigator"/> is set to a valid instance.
/// </summary>
/// <remarks>
/// If <see cref="WebNavigator"/> is not already set, creates and sets a new <see cref="WebFormsResultWebNavigator"/> instance.<br/>
/// Override this method if you don't want to inject a navigator, but need a different default.
/// </remarks>
protected virtual void InitializeNavigationSupport()
{
webNavigator = new WebFormsResultWebNavigator(this, null, null, true);
}
/// <summary>
/// Gets/Sets the navigator to be used for handling <see cref="SetResult(string, object)"/> calls.
/// </summary>
public IWebNavigator WebNavigator
{
get
{
return webNavigator;
}
set
{
webNavigator = value;
}
}
/// <summary>
/// Gets or sets map of result names to target URLs
/// </summary>
/// <remarks>
/// Using <see cref="Results"/> requires <see cref="WebNavigator"/> to implement <see cref="IResultWebNavigator"/>.
/// </remarks>
[Browsable( false )]
[DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )]
public virtual IDictionary Results
{
get
{
if (WebNavigator is IResultWebNavigator)
{
return ((IResultWebNavigator)WebNavigator).Results;
}
return null;
}
set
{
if (WebNavigator is IResultWebNavigator)
{
((IResultWebNavigator)WebNavigator).Results = value;
return;
}
throw new NotSupportedException("WebNavigator must be of type IResultWebNavigator to support Results");
}
}
/// <summary>
/// A convenience, case-insensitive table that may be used to e.g. pass data into SpEL expressions"/>.
/// </summary>
/// <remarks>
/// By default, e.g. <see cref="SetResult(string)"/> passes the control instance into an expression. Using
/// <see cref="Args"/> is an easy way to pass additional parameters into the expression
/// <example>
/// // config:
///
/// <property Name="Results">
/// <dictionary>
/// <entry key="ok_clicked" value="redirect:~/ShowResult.aspx?result=%{Args['result']}" />
/// </dictionary>
/// </property>
///
/// // code:
///
/// void OnOkClicked(object sender, EventArgs e)
/// {
/// Args["result"] = txtUserInput.Text;
/// SetResult("ok_clicked");
/// }
/// </example>
/// </remarks>
public IDictionary Args
{
get
{
if (args == null)
{
args = new CaseInsensitiveHashtable();
}
return args;
}
}
/// <summary>
/// Redirects user to a URL mapped to specified result name.
/// </summary>
/// <param name="resultName">Result name.</param>
protected void SetResult( string resultName )
{
WebNavigator.NavigateTo( resultName, this, null );
}
/// <summary>
/// Redirects user to a URL mapped to specified result name.
/// </summary>
/// <param name="resultName">Name of the result.</param>
/// <param name="context">The context to use for evaluating the SpEL expression in the Result.</param>
protected void SetResult( string resultName, object context )
{
WebNavigator.NavigateTo( resultName, this, context );
}
/// <summary>
/// Returns a redirect url string that points to the
/// <see cref="Spring.Web.Support.Result.TargetPage"/> defined by this
/// result evaluated using this Page for expression
/// </summary>
/// <param name="resultName">Name of the result.</param>
/// <returns>A redirect url string.</returns>
protected string GetResultUrl( string resultName )
{
return ResolveUrl( WebNavigator.GetResultUri( resultName, this, null ) );
}
/// <summary>
/// Returns a redirect url string that points to the
/// <see cref="Spring.Web.Support.Result.TargetPage"/> defined by this
/// result evaluated using this Page for expression
/// </summary>
/// <param name="resultName">Name of the result.</param>
/// <param name="context">The context to use for evaluating the SpEL expression in the Result</param>
/// <returns>A redirect url string.</returns>
protected string GetResultUrl( string resultName, object context )
{
return ResolveUrl( WebNavigator.GetResultUri( resultName, this, context ) );
}
#endregion
#region Validation support
/// <summary>
/// Evaluates specified validators and returns <c>True</c> if all of them are valid.
/// </summary>
/// <remarks>
/// <p>
/// Each validator can itself represent a collection of other validators if it is
/// an instance of <see cref="ValidatorGroup"/> or one of its derived types.
/// </p>
/// <p>
/// Please see the Validation Framework section in the documentation for more info.
/// </p>
/// </remarks>
/// <param name="validationContext">Object to validate.</param>
/// <param name="validators">Validators to evaluate.</param>
/// <returns>
/// <c>True</c> if all of the specified validators are valid, <c>False</c> otherwise.
/// </returns>
public virtual bool Validate(object validationContext, params IValidator[] validators)
{
IDictionary contextParams = CreateValidatorParameters();
bool result = true;
foreach (IValidator validator in validators)
{
if (validator == null)
{
throw new ArgumentException("Validator is not defined.");
}
result = validator.Validate(validationContext, contextParams, this.validationErrors) && result;
}
return result;
}
/// <summary>
/// Gets the validation errors container.
/// </summary>
/// <value>The validation errors container.</value>
public virtual IValidationErrors ValidationErrors
{
get { return validationErrors; }
}
/// <summary>
/// Creates the validator parameters.
/// </summary>
/// <remarks>
/// <para>
/// This method can be overriden if you want to pass additional parameters
/// to the validation framework, but you should make sure that you call
/// this base implementation in order to add page, session, application,
/// request, response and context to the variables collection.
/// </para>
/// </remarks>
/// <returns>
/// Dictionary containing parameters that should be passed to
/// the data validation framework.
/// </returns>
protected virtual IDictionary CreateValidatorParameters()
{
IDictionary parameters = new ListDictionary();
parameters["page"] = this.Page;
parameters["usercontrol"] = this;
parameters["session"] = this.Session;
parameters["application"] = this.Application;
parameters["request"] = this.Request;
parameters["response"] = this.Response;
parameters["context"] = this.Context;
return parameters;
}
#endregion
#region Spring Page support
/// <summary>
/// Overrides Page property to return <see cref="Spring.Web.UI.Page"/>
/// instead of <see cref="System.Web.UI.Page"/>.
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new Page Page
{
get { return (Page) base.Page; }
}
#endregion
#region Dependency Injection Support
/// <summary>
/// Holds the default ApplicationContext to be used during DI.
/// </summary>
IApplicationContext ISupportsWebDependencyInjection.DefaultApplicationContext
{
get { return defaultApplicationContext; }
set { defaultApplicationContext = value; }
}
/// <summary>
/// Injects dependencies before adding the control.
/// </summary>
protected override void AddedControl(Control control,int index)
{
control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext,control);
base.AddedControl(control,index);
}
#endregion Dependency Injection Support
}
#endregion
#endif
}
|