rework of result navigation support: sprnet-1040, sprnet-1052, sprnet-958, sprnet-567

added navigation demo to WebQuickStart
This commit is contained in:
eeichinger
2008-10-12 12:40:54 +00:00
parent 71331f7bb4
commit 99b8a6f9eb
41 changed files with 1869 additions and 384 deletions

View File

@@ -19,7 +19,7 @@ Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "Spring.WebQuickStart.2005",
Release.AspNetCompiler.ForceOverwrite = "true"
Release.AspNetCompiler.FixedNames = "false"
Release.AspNetCompiler.Debug = "False"
VWDPort = "81"
VWDPort = "4724"
DefaultWebSiteLanguage = "Visual C#"
EndProjectSection
EndProject

View File

@@ -68,6 +68,10 @@
compose advanced validation rules that leverage validation groups, conditional validation,
validator composition, as well as how to create and use your custom validators.
</p>
<h3><a href="Navigation/Default.aspx">Navigation Flow</a></h3>
<p>
Demoes configurable navigation flow capabilities.
</p>
</div>
</body>
</html>

View File

@@ -0,0 +1,32 @@
<%@ Page Language="C#" EnableViewState="true" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="Navigation_Default" %>
<%@ Register TagPrefix="spring" Namespace="Spring.Web.UI.Controls" Assembly="Spring.Web" %>
<asp:Content runat="server" ContentPlaceHolderId="content">
<p>
Just like in the previous example, you should put a breakpoint
on the Debug.Write(Employee) statement in the event handler for the Save button,
so you can see how Employee object was populated by the framework.
</p>
<spring:DataBindingPanel runat="server">
<table cellpadding="3" cellspacing="3" border="0">
<spring:Panel VisibleIf="Context.Request['fromInvalidInput'] != null" runat="server">
<tr>
<td></td>
<td>
You need to enter a value greater than 21 to pass.
</td>
</tr>
</spring:Panel>
<tr>
<td>Your age:</td>
<td>
<asp:TextBox ID="txtAge" runat="server" BindingTarget="Age" />
</td>
</tr>
<tr>
<td><asp:Button ID="btnReset" runat="server" Text="Reset" OnClick="btnReset_Click" /></td>
<td><asp:Button ID="btnContinue" runat="server" Text="Continue" OnClick="btnContinue_Click" /></td>
</tr>
</table>
</spring:DataBindingPanel>
</asp:Content>

View File

@@ -0,0 +1,38 @@
using System;
/// <summary>
/// Notice that your web page has to extend Spring.Web.UI.Page class
/// in order to enable data binding and many other features.
/// </summary>
public partial class Navigation_Default : Spring.Web.UI.Page
{
public int Age;
protected override void FrameworkInitialize()
{
this.MasterPageFile = "Master.master";
base.FrameworkInitialize();
}
protected void Page_Load( object sender, EventArgs e )
{ }
protected void btnContinue_Click( object sender, EventArgs e )
{
if (Age > 21)
{
SetResult( "ok" );
}
else
{
Args["input"] = txtAge.Text;
SetResult( "invalid_input" );
}
}
protected void btnReset_Click( object sender, EventArgs e )
{
SetResult( "start" );
}
}

View File

@@ -0,0 +1,22 @@
<%@ Page Language="C#" EnableViewState="true" AutoEventWireup="true" CodeFile="InvalidInput.aspx.cs" Inherits="Navigation_InvalidInput" %>
<%@ Register TagPrefix="spring" Namespace="Spring.Web.UI.Controls" Assembly="Spring.Web" %>
<asp:Content runat="server" contentPlaceHolderId="content">
<p>
The value you entered is invalid
</p>
<spring:DataBindingPanel runat="server">
<table cellpadding="3" cellspacing="3" border="0">
<tr>
<td>Age you entered:</td>
<td>
<asp:Label ID="lblInput" runat="server" EnableViewState="false" BindingSource="Text" BindingTarget="Context.Items['input']" BindingDirection="TargetToSource" />
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td><asp:Button ID="btnBack" runat="server" Text="Back" OnClick="btnBack_Click" /></td>
</tr>
</table>
</spring:DataBindingPanel>
</asp:Content>

View File

@@ -0,0 +1,21 @@
using System;
using System.Diagnostics;
/// <summary>
/// Notice that your web page has to extend Spring.Web.UI.Page class
/// in order to enable data binding and many other features.
/// </summary>
public partial class Navigation_InvalidInput : Spring.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string input = (string) this.Context.Items["input"];
}
protected void btnBack_Click(object sender, EventArgs e)
{
SetResult("start");
}
}

View File

@@ -0,0 +1,21 @@
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="Master.master.cs" Inherits="Navigation_Master" %>
<!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>Prefix!</title>
<asp:ContentPlaceHolder id="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<h2><a href="../Default.aspx">Welcome to Spring.NET Web Framework Quick Start Guide</a></h2>
<form id="form1" runat="server">
<div>
<h2>Navigation example</h2>
<asp:ContentPlaceHolder id="content" runat="server">
</asp:ContentPlaceHolder>
</div>
</form>
</body>
</html>

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class Navigation_Master : Spring.Web.UI.MasterPage
{
protected void Page_Load( object sender, EventArgs e )
{
}
}

View File

@@ -0,0 +1,21 @@
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Ok.aspx.cs" Inherits="Navigation_Ok" %>
<asp:Content runat="server" contentPlaceHolderId="content">
<p>
Passcode you entered was ok
</p>
<spring:DataBindingPanel runat="server">
<table cellpadding="3" cellspacing="3" border="0">
<tr>
<td>The passcode is correct:</td>
<td>
<asp:Label ID="lblInput" runat="server" BindingSource="Text" BindingTarget="Request['age']" BindingDirection="TargetToSource" />
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td><asp:Button ID="btnRestart" runat="server" Text="Back" OnClick="btnRestart_Click" /></td>
</tr>
</table>
</spring:DataBindingPanel>
</asp:Content>

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class Navigation_Ok : Spring.Web.UI.Page
{
protected void Page_Load( object sender, EventArgs e )
{
}
protected void btnRestart_Click(object sender, EventArgs e)
{
SetResult("start");
}
}

View File

@@ -0,0 +1,59 @@
<?xml version="1.0"?>
<configuration>
<spring>
<context>
<resource uri="config://spring/objects"/>
</context>
<objects xmlns="http://www.springframework.net">
<object type="Master.master">
<property name="Results">
<dictionary>
<entry key="start" value="redirect:Default.aspx" />
</dictionary>
</property>
</object>
<object name="standardPage" abstract="true">
<property name="MasterPageFile" value="Master.master" />
</object>
<!-- use the filename of your Page for the 'type' attribute to configure DI for a Page -->
<object type="Default.aspx" parent="standardPage">
<property name="Title" value="Navigation Flow Sample - Start Page"/>
<property name="Results">
<dictionary>
<entry key="ok" value="redirect:Ok.aspx?age=%{Age}" />
<entry key="invalid_input" value="transfer:InvalidInput.aspx?input=%{Args['input']}" />
</dictionary>
</property>
</object>
<object type="InvalidInput.aspx" parent="standardPage">
<property name="Title" value="Navigation Flow Sample - Invalid Input Page"/>
<property name="Results">
<dictionary>
<!-- altough Master.master defines a 'start' result, you can always override it -->
<entry key="start" value="redirect:Default.aspx?fromInvalidInput=true" />
</dictionary>
</property>
</object>
<!--
Ok.aspx doesn't have an explicit results. Instead it relies on "bubbling" results up the hierarchy,
in our case up to Master.master (see above)
-->
<object type="Ok.aspx" parent="standardPage">
<property name="Title" value="Navigation Flow Sample - Done"/>
<property name="Results">
<dictionary>
</dictionary>
</property>
</object>
</objects>
</spring>
<system.web>
</system.web>
</configuration>

View File

@@ -1843,7 +1843,7 @@ namespace Spring.Objects.Factory.Support
|| suppressConfigure)
{
// Clone ObjectDefinition
mergedObjectDefinition = new RootObjectDefinition( mergedObjectDefinition );
mergedObjectDefinition = CreateRootObjectDefinition(mergedObjectDefinition);
mergedObjectDefinition.IsSingleton = false;
if (arguments != null)
{

View File

@@ -39,7 +39,7 @@ namespace Spring.Objects.Factory.Support
/// <author>Aleksandar Seovic</author>
public sealed class WebObjectUtils
{
private static ILog s_log = LogManager.GetLogger(typeof(WebObjectUtils));
private static ILog s_log = LogManager.GetLogger( typeof( WebObjectUtils ) );
// CLOVER:OFF
@@ -64,7 +64,7 @@ namespace Spring.Objects.Factory.Support
/// </p>
/// </remarks>
private WebObjectUtils()
{}
{ }
// CLOVER:ON
@@ -84,51 +84,33 @@ namespace Spring.Objects.Factory.Support
/// page could not be instantiated (for whatever reason, such as the
/// ASPX <paramref name="pageUrl"/> not actually existing).
/// </exception>
public static IHttpHandler CreatePageInstance(string pageUrl)
public static IHttpHandler CreatePageInstance( string pageUrl )
{
if (s_log.IsDebugEnabled)
{
s_log.Debug("creating page instance '" + pageUrl + "'");
s_log.Debug( "creating page instance '" + pageUrl + "'" );
}
if (HttpContext.Current == null)
HttpContext ctx = HttpContext.Current;
if (ctx == null)
{
throw new ObjectCreationException(
"Unable to instantiate page. HttpContext is not defined.");
"Unable to instantiate page. HttpContext is not defined." );
}
IHttpHandler page = null;
try
{
#if NET_1_1
HttpContext context = HttpContext.Current;
string physicalPath = context.Server.MapPath(pageUrl);
s_log.Debug(string.Format("constructing page virtual path '{0}' from physical file '{1}'", pageUrl, physicalPath));
page = PageParser.GetCompiledPageInstance(pageUrl, physicalPath, context);
#else
HttpContext ctx = HttpContext.Current;
if (ctx == null)
{
throw new ObjectCreationException("Unable to get page type. HttpContext is not defined.");
}
string rootedVPath = WebUtils.CombineVirtualPaths(ctx.Request.CurrentExecutionFilePath, pageUrl);
if (s_log.IsDebugEnabled)
{
s_log.Debug("page vpath is " + rootedVPath);
}
page = BuildManager.CreateInstanceFromVirtualPath(rootedVPath,
typeof(IHttpHandler)) as IHttpHandler;
#endif
page = CreateHandler( ctx, pageUrl );
}
catch (HttpException httpEx)
{
string msg = String.Format("Unable to instantiate page [{0}]: {1}", pageUrl, httpEx.Message);
if(httpEx.GetHttpCode() == 404)
string msg = String.Format( "Unable to instantiate page [{0}]: {1}", pageUrl, httpEx.Message );
if (httpEx.GetHttpCode() == 404)
{
throw new FileNotFoundException(msg);
throw new FileNotFoundException( msg );
}
s_log.Error(msg, httpEx);
throw new ObjectCreationException(msg, httpEx);
s_log.Error( msg, httpEx );
throw new ObjectCreationException( msg, httpEx );
}
catch (Exception ex)
{
@@ -136,17 +118,42 @@ namespace Spring.Objects.Factory.Support
FileNotFoundException fnfe = ex as FileNotFoundException;
if (fnfe != null)
{
string fmsg = String.Format("Unable to instantiate page [{0}]: The file '{1}' does not exist.", pageUrl, fnfe.Message);
throw new FileNotFoundException(fmsg);
string fmsg = String.Format( "Unable to instantiate page [{0}]: The file '{1}' does not exist.", pageUrl, fnfe.Message );
throw new FileNotFoundException( fmsg );
}
string msg = String.Format("Unable to instantiate page [{0}]", pageUrl);
s_log.Error(msg, ex);
throw new ObjectCreationException(msg, ex);
string msg = String.Format( "Unable to instantiate page [{0}]", pageUrl );
s_log.Error( msg, ex );
throw new ObjectCreationException( msg, ex );
}
return page;
}
/// <summary>
/// Creates the raw handler instance without any exception handling
/// </summary>
/// <param name="ctx"></param>
/// <param name="pageUrl"></param>
/// <returns></returns>
internal static IHttpHandler CreateHandler( HttpContext ctx, string pageUrl )
{
IHttpHandler page;
#if NET_1_1
string physicalPath = ctx.Server.MapPath(pageUrl);
s_log.Debug(string.Format("constructing page virtual path '{0}' from physical file '{1}'", pageUrl, physicalPath));
page = PageParser.GetCompiledPageInstance(pageUrl, physicalPath, ctx);
#else
string rootedVPath = WebUtils.CombineVirtualPaths( ctx.Request.CurrentExecutionFilePath, pageUrl );
if (s_log.IsDebugEnabled)
{
s_log.Debug( "page vpath is " + rootedVPath );
}
page = BuildManager.CreateInstanceFromVirtualPath( rootedVPath, typeof( IHttpHandler ) ) as IHttpHandler;
#endif
return page;
}
/// <summary>
/// Returns the <see cref="System.Type"/> of the ASPX page
/// referred to by the supplied <paramref name="pageUrl"/>.
@@ -177,26 +184,26 @@ namespace Spring.Objects.Factory.Support
/// page could not be instantiated (for whatever reason, such as the
/// ASPX <paramref name="pageUrl"/> not actually existing).
/// </exception>
public static Type GetPageType(string pageUrl)
public static Type GetPageType( string pageUrl )
{
AssertUtils.ArgumentHasText(pageUrl, "pageUrl");
AssertUtils.ArgumentHasText( pageUrl, "pageUrl" );
HttpContext ctx = HttpContext.Current;
if (ctx == null)
{
throw new ObjectCreationException("Unable to get page type. HttpContext is not defined.");
throw new ObjectCreationException( "Unable to get page type. HttpContext is not defined." );
}
try
{
Type pageType = GetCompiledPageType(pageUrl);
Type pageType = GetCompiledPageType( pageUrl );
return pageType;
}
catch (Exception ex)
{
string msg = String.Format("Unable to get page type for url [{0}]", pageUrl);
s_log.Error(msg, ex);
throw new ObjectCreationException(msg, ex);
string msg = String.Format( "Unable to get page type for url [{0}]", pageUrl );
s_log.Error( msg, ex );
throw new ObjectCreationException( msg, ex );
}
}
@@ -211,29 +218,29 @@ namespace Spring.Objects.Factory.Support
/// The <see cref="System.Type"/> of the ASPX page
/// referred to by the supplied <paramref name="pageUrl"/>.
/// </returns>
public static Type GetCompiledPageType(string pageUrl)
public static Type GetCompiledPageType( string pageUrl )
{
if (s_log.IsDebugEnabled)
{
s_log.Debug("getting page type for " + pageUrl);
s_log.Debug( "getting page type for " + pageUrl );
}
string rootedVPath = WebUtils.CombineVirtualPaths(HttpContext.Current.Request.CurrentExecutionFilePath, pageUrl);
string rootedVPath = WebUtils.CombineVirtualPaths( HttpContext.Current.Request.CurrentExecutionFilePath, pageUrl );
if (s_log.IsDebugEnabled)
{
s_log.Debug("page vpath is " + rootedVPath);
s_log.Debug( "page vpath is " + rootedVPath );
}
Type pageType = null;
#if NET_2_0
pageType = BuildManager.GetCompiledType(rootedVPath); // requires rooted virtual path!
pageType = BuildManager.GetCompiledType( rootedVPath ); // requires rooted virtual path!
#else
pageType = CreatePageInstance(pageUrl).GetType();
#endif
if (s_log.IsDebugEnabled)
{
s_log.Debug(string.Format("got page type '{0}' for vpath '{1}'", pageType.FullName, rootedVPath));
s_log.Debug( string.Format( "got page type '{0}' for vpath '{1}'", pageType.FullName, rootedVPath ) );
}
return pageType;
}
@@ -242,49 +249,49 @@ namespace Spring.Objects.Factory.Support
/// <summary>
/// Gets the controls type from a given filename
/// </summary>
public static Type GetControlType(string controlName)
public static Type GetControlType( string controlName )
{
AssertUtils.ArgumentHasText(controlName, "controlName");
AssertUtils.ArgumentHasText( controlName, "controlName" );
if (s_log.IsDebugEnabled)
{
s_log.Debug("getting control type for " + controlName);
s_log.Debug( "getting control type for " + controlName );
}
HttpContext ctx = HttpContext.Current;
if (ctx == null)
{
throw new ObjectCreationException("Unable to get control type. HttpContext is not defined.");
throw new ObjectCreationException( "Unable to get control type. HttpContext is not defined." );
}
string rootedVPath = WebUtils.CombineVirtualPaths(ctx.Request.CurrentExecutionFilePath, controlName);
string rootedVPath = WebUtils.CombineVirtualPaths( ctx.Request.CurrentExecutionFilePath, controlName );
if (s_log.IsDebugEnabled)
{
s_log.Debug("control vpath is " + rootedVPath);
s_log.Debug( "control vpath is " + rootedVPath );
}
Type controlType = null;
try
{
#if NET_2_0
controlType = BuildManager.GetCompiledType(rootedVPath); // requires rooted virtual path!
controlType = BuildManager.GetCompiledType( rootedVPath ); // requires rooted virtual path!
#else
controlType = (Type) miGetCompiledUserControlType.Invoke(null, new object[] { rootedVPath, null, ctx });
#endif
}
catch(HttpException httpEx)
catch (HttpException httpEx)
{
// for better error-handling suppress 404 HttpExceptions here
if (httpEx.GetHttpCode() == 404)
{
throw new FileNotFoundException(string.Format("Control '{0}' does not exist", rootedVPath));
throw new FileNotFoundException( string.Format( "Control '{0}' does not exist", rootedVPath ) );
}
throw;
}
if (s_log.IsDebugEnabled)
{
s_log.Debug(string.Format("got control type '{0}' for vpath '{1}'", controlType.FullName, rootedVPath));
s_log.Debug( string.Format( "got control type '{0}' for vpath '{1}'", controlType.FullName, rootedVPath ) );
}
return controlType;
}

View File

@@ -295,21 +295,6 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Process\IProcess.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Process\IProcessAware.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Process\ProcessManager.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Providers\ConfigurableActiveDirectoryMembershipProvider.cs"
SubType = "Code"
@@ -390,11 +375,6 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\AbstractProcessHandler.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\ContextMonitor.cs"
SubType = "Code"
@@ -405,6 +385,16 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\DefaultResultFactory.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\IHierarchicalWebNavigator.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\IInterceptionStrategy.cs"
SubType = "Code"
@@ -421,7 +411,17 @@
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\ISharedStateAware.cs"
RelPath = "Web\Support\IResult.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\IResultFactory.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\IResultWebNavigator.cs"
SubType = "Code"
BuildAction = "Compile"
/>
@@ -430,6 +430,16 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\IWebNavigable.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\IWebNavigator.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\MimeMediaType.cs"
SubType = "Code"
@@ -445,11 +455,21 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\ResultFactoryRegistry.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\ResultMode.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\ResultWebNavigator.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\Script.cs"
SubType = "Code"
@@ -480,6 +500,11 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\WebFormsResultWebNavigator.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\UI\AbstractWizard.cs"
SubType = "ASPXCodeBehind"

View File

@@ -124,6 +124,15 @@
<SubType>Code</SubType>
</Compile>
<Compile Include="Util\ISessionState.cs" />
<Compile Include="Web\Support\DefaultResultFactory.cs" />
<Compile Include="Web\Support\IResult.cs" />
<Compile Include="Web\Support\IResultFactory.cs" />
<Compile Include="Web\Support\ResultFactoryRegistry.cs" />
<Compile Include="Web\Support\WebFormsResultWebNavigator.cs" />
<Compile Include="Web\Support\IHierarchicalWebNavigator.cs" />
<Compile Include="Web\Support\IResultWebNavigator.cs" />
<Compile Include="Web\Support\IWebNavigable.cs" />
<Compile Include="Web\Support\IWebNavigator.cs" />
<Compile Include="Web\UI\IValidationContainer.cs" />
<Compile Include="Web\Support\MimeMediaType.cs" />
<Compile Include="Web\Support\SharedStateResourceCache.cs">
@@ -260,6 +269,7 @@
<Compile Include="Web\UI\Page.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>
<Compile Include="Web\Support\ResultWebNavigator.cs" />
<Compile Include="Web\UI\UserControl.cs">
<SubType>ASPXCodeBehind</SubType>
</Compile>

View File

@@ -21,8 +21,7 @@
#region Imports
using System;
using System.Web.UI;
#endregion
@@ -241,5 +240,51 @@ namespace Spring.Util
}
return appRelativeVirtualPath;
}
///<summary>
/// Returns the 'logical' parent of the specified control. Technically when dealing with masterpages and control hierarchy,
/// the order goes controls-&gtmasterpage-&gtpage. But one often wants the more logical order controls-&gtpage-&gtmasterpage.
///</summary>
///<param name="control">the control, who's parent is to be determined.</param>
///<returns>the logical parent or <c>null</c> if the top of the hierarchy is reached.</returns>
/// <exception cref="ArgumentNullException">if <paramref name="control"/> is <c>null</c></exception>
public static Control GetLogicalParent(Control control)
{
AssertUtils.ArgumentNotNull(control, "control");
// to determine "correct" order of bubbling control->page->masterpage,
// the trick below is necessary because technically the hierarchy goes
// control->masterpage->page
if (control is System.Web.UI.Page)
{
#if !NET_2_0
control = ((Spring.Web.UI.Page)control).Master;
#else
control = ((System.Web.UI.Page)control).Master;
#endif
}
else if (IsMaster(control))
{
control = null;
}
else if (IsMaster(control.Parent))
{
control = control.Page;
}
else
{
control = control.Parent;
}
return control;
}
private static bool IsMaster(Control control)
{
#if !NET_2_0
return (control is Spring.Web.UI.MasterPage);
#else
return (control is System.Web.UI.MasterPage);
#endif
}
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright <20> 2002-2005 the original author or authors.
* Copyright <20> 2002-2008 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.

View File

@@ -0,0 +1,34 @@
#region License
/*
* Copyright <20> 2002-2008 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
#endregion
namespace Spring.Web.Support
{
public class DefaultResultFactory : IResultFactory
{
public IResult CreateResult(string resultMode, string resultText)
{
return new Result(resultMode, resultText);
}
}
}

View File

@@ -0,0 +1,31 @@
#region License
/*
* Copyright 2002-2008 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
#endregion
namespace Spring.Web.Support
{
public interface IHierarchicalWebNavigator : IWebNavigator
{
IWebNavigator ParentNavigator { get; }
}
}

View File

@@ -0,0 +1,8 @@
namespace Spring.Web.Support
{
public interface IResult
{
void Navigate( object context );
string GetRedirectUri( object context );
}
}

View File

@@ -0,0 +1,7 @@
namespace Spring.Web.Support
{
public interface IResultFactory
{
IResult CreateResult( string resultMode, string resultText );
}
}

View File

@@ -0,0 +1,33 @@
#region License
/*
* Copyright <20> 2002-2008 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.Collections;
#endregion
namespace Spring.Web.Support
{
public interface IResultWebNavigator : IHierarchicalWebNavigator
{
IDictionary Results { get; set; }
}
}

View File

@@ -0,0 +1,33 @@
#region License
/*
* Copyright 2002-2008 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
#endregion
namespace Spring.Web.Support
{
public interface IWebNavigable
{
IWebNavigator WebNavigator { get; }
}
}

View File

@@ -0,0 +1,39 @@
#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
#endregion
namespace Spring.Web.Support
{
public interface IWebNavigator
{
/// <summary>
/// Determines, whether this navigator or one of its parents can
/// navigate to the result specified in <paramref name="resultName"/>.
/// </summary>
/// <param name="resultName">the name of the result</param>
/// <returns>true, if this navigator or one of its parents can navigate to the result.</returns>
bool CanNavigateTo( string resultName );
void NavigateTo( string resultName, object context );
string GetResultUri( string resultName, object context );
}
}

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2004 the original author or authors.
* Copyright 2002-2008 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.
@@ -118,7 +118,8 @@ namespace Spring.Web.Support
}
else
{
handler = WebObjectUtils.CreatePageInstance(url);
handler = WebObjectUtils.CreateHandler(context, url);
// is this a nested call (HttpServerUtility.Transfer() or HttpServerUtility.Execute())?
if (context.Handler != null)
{

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright <20> 2002-2005 the original author or authors.
* Copyright <20> 2002-2008 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.
@@ -24,6 +24,7 @@ using System;
using System.Collections;
using System.Text;
using System.Web;
using Spring.Collections;
using Spring.Expressions;
using Spring.Util;
@@ -73,7 +74,7 @@ namespace Spring.Web.Support
/// <author>Aleksandar Seovic</author>
/// <author>Matan Shapira</author>
[Serializable]
public class Result
public class Result : IResult
{
#region Constants
@@ -122,15 +123,52 @@ namespace Spring.Web.Support
/// If the supplied <paramref name="result"/> is <see langword="null"/> or
/// contains only whitespace character(s).
/// </exception>
public Result(string result)
/// <exception cref="ArgumentOutOfRangeException">if the result mode is unknown.</exception>
public Result( string result )
{
AssertUtils.ArgumentHasText(result, "result");
result = ExtractAndSetResultMode(result);
int indexOfQueryStringDelimiter = result.IndexOf('?');
AssertUtils.ArgumentHasText( result, "result" );
result = ExtractAndSetResultMode( result );
int indexOfQueryStringDelimiter = result.IndexOf( '?' );
if (indexOfQueryStringDelimiter > 0)
{
ParseParameters(result.Substring(indexOfQueryStringDelimiter + 1));
result = result.Substring(0, indexOfQueryStringDelimiter);
ParseParameters( result.Substring( indexOfQueryStringDelimiter + 1 ) );
result = result.Substring( 0, indexOfQueryStringDelimiter );
}
targetPage = result.Trim();
}
/// <summary>
/// Creates a new instance of the <see cref="Spring.Web.Support.Result"/> class.
/// </summary>
/// <remarks>
/// <p>
/// See both the class documentation (<see cref="Spring.Web.Support.Result"/>)
/// and the reference documentation for the Spring.Web library for a
/// discussion and examples of what values the supplied <paramref name="result"/>
/// can have.
/// </p>
/// </remarks>
/// <param name="resultMode">The desired result mode. May be null to use default mode.</param>
/// <param name="resultText">The result descriptor (without resultMode prefix!).</param>
/// <exception cref="System.ArgumentNullException">
/// If the supplied <paramref name="resultText"/> is <see langword="null"/> or
/// contains only whitespace character(s).
/// </exception>
/// <exception cref="ArgumentOutOfRangeException">if the result mode is unknown.</exception>
public Result( string resultMode, string resultText )
{
AssertUtils.ArgumentHasText( resultText, "resultText" );
this.SetResultMode( resultMode );
string result = resultText;
int indexOfQueryStringDelimiter = result.IndexOf( '?' );
if (indexOfQueryStringDelimiter > 0)
{
ParseParameters( result.Substring( indexOfQueryStringDelimiter + 1 ) );
result = result.Substring( 0, indexOfQueryStringDelimiter );
}
targetPage = result.Trim();
}
@@ -202,23 +240,23 @@ namespace Spring.Web.Support
/// Navigates to the <see cref="Spring.Web.Support.Result.TargetPage"/>
/// defined by this result.
/// </summary>
/// <param name="page">
/// <param name="context">
/// The context object for parameter resolution. This is typically
/// a <see cref="System.Web.UI.Page"/>.
/// </param>
public virtual void Navigate(object page)
public virtual void Navigate( object context )
{
switch (Mode)
{
case ResultMode.Redirect:
DoRedirect(page);
DoRedirect( context );
break;
case ResultMode.Transfer:
case ResultMode.TransferNoPreserve:
DoTransfer(page);
DoTransfer( context );
break;
default:
throw new ArgumentOutOfRangeException(string.Format("Unknown ResultMode {0}", Mode));
throw new ArgumentOutOfRangeException( string.Format( "Unknown ResultMode {0}", Mode ) );
}
}
@@ -226,33 +264,33 @@ namespace Spring.Web.Support
/// Performs a server-side transfer to the
/// <see cref="Spring.Web.Support.Result.TargetPage"/> defined by this result.
/// </summary>
/// <param name="page">
/// <param name="context">
/// The context object for parameter resolution. This is typically
/// a <see cref="System.Web.UI.Page"/>.
/// </param>
/// <seealso cref="System.Web.HttpServerUtility.Transfer(string,bool)"/>
protected virtual void DoTransfer(object page)
protected virtual void DoTransfer( object context )
{
HttpContext ctx = HttpContext.Current;
SetTransferParameters(ctx.Items, page);
ctx.Server.Transfer(TargetPage, PreserveForm);
SetTransferParameters( ctx.Items, context );
ctx.Server.Transfer( GetResolvedTargetPage( context ), PreserveForm );
}
/// <summary>
/// Resolves transfer parameters and stores them into <see cref="IDictionary" /> instance.
/// </summary>
/// <param name="contextDictionary"></param>
/// <param name="page"></param>
protected void SetTransferParameters(IDictionary contextDictionary, object page)
/// <param name="context"></param>
protected void SetTransferParameters( IDictionary contextDictionary, object context )
{
if (this.parameters != null && this.parameters.Count > 0)
{
foreach (DictionaryEntry entry in this.parameters)
{
string value = entry.Value.ToString();
if (IsRuntimeExpression(value))
if (IsRuntimeExpression( value ))
{
contextDictionary[entry.Key] = ResolveRuntimeExpression(page, value);
contextDictionary[entry.Key] = ResolveRuntimeExpression( context, value );
}
else
{
@@ -267,14 +305,14 @@ namespace Spring.Web.Support
/// <see cref="Spring.Web.Support.Result.TargetPage"/> defined by this
/// result.
/// </summary>
/// <param name="page">
/// <param name="context">
/// The context object for parameter resolution. This is typically
/// a <see cref="System.Web.UI.Page"/>.
/// </param>
/// <seealso cref="System.Web.HttpResponse.Redirect(string)"/>
protected virtual void DoRedirect(object page)
protected virtual void DoRedirect( object context )
{
HttpContext.Current.Response.Redirect(GetRedirectUri(page));
HttpContext.Current.Response.Redirect( GetRedirectUri( context ) );
}
/// <summary>
@@ -282,45 +320,74 @@ namespace Spring.Web.Support
/// <see cref="Spring.Web.Support.Result.TargetPage"/> defined by this
/// result.
/// </summary>
/// <param name="page">
/// <param name="context">
/// A redirect url string.
/// </param>
public string GetRedirectUri(object page)
public virtual string GetRedirectUri( object context )
{
StringBuilder url = new StringBuilder(256);
url.Append(TargetPage);
if (parameters != null && parameters.Count > 0)
string path = GetResolvedTargetPage( context );
IDictionary resolvedParameters = null;
if (this.Parameters != null && this.Parameters.Count > 0)
{
resolvedParameters = new CaseInsensitiveHashtable();
foreach (DictionaryEntry entry in this.Parameters)
{
object key = ResolveRuntimeExpressionIfNecessary( context, entry.Key.ToString() );
object value = ResolveRuntimeExpressionIfNecessary( context, entry.Value.ToString() );
resolvedParameters[key] = value;
}
}
return BuildUrl( path, resolvedParameters );
}
protected virtual string BuildUrl( string resolvedPath, IDictionary resolvedParameters )
{
StringBuilder url = new StringBuilder( 256 );
url.Append( resolvedPath );
if (resolvedParameters != null && resolvedParameters.Count > 0)
{
char separator = '?';
foreach (DictionaryEntry entry in parameters)
foreach (DictionaryEntry entry in resolvedParameters)
{
url.Append(separator);
url.Append(entry.Key).Append('=');
string value = entry.Value.ToString();
if (IsRuntimeExpression(value))
{
url.Append(HttpContext.Current.Server.UrlEncode(
ResolveRuntimeExpression(page, value).ToString()));
}
else
{
url.Append(HttpContext.Current.Server.UrlEncode(value));
}
url.Append( separator );
url.Append( BuildUrlParameter( entry.Key.ToString(), entry.Value.ToString() ) );
separator = '&';
}
}
return url.ToString();
}
private static bool IsRuntimeExpression(string value)
protected virtual string BuildUrlParameter( string key, string value )
{
// allow for 2 alternative prefixes (SPRNET-864)
return (value.StartsWith("${") || value.StartsWith("%{")) && value.EndsWith("}");
return UrlEncode( key ) + "=" + UrlEncode( value );
}
private static object ResolveRuntimeExpression(object page, string value)
protected static string UrlEncode( string value )
{
return ExpressionEvaluator.GetValue(page, value.Substring(2, value.Length - 3));
HttpContext ctx = HttpContext.Current;
return (ctx == null) ? HttpUtility.UrlEncode( value ) : ctx.Server.UrlEncode( value );
}
protected object ResolveRuntimeExpressionIfNecessary( object context, string value )
{
if (IsRuntimeExpression( value ))
{
return ResolveRuntimeExpression( context, value );
}
return value;
}
private static bool IsRuntimeExpression( string value )
{
// allow for 2 alternative prefixes (SPRNET-864)
return (value.StartsWith( "${" ) || value.StartsWith( "%{" )) && value.EndsWith( "}" );
}
private static object ResolveRuntimeExpression( object context, string value )
{
return ExpressionEvaluator.GetValue( context, value.Substring( 2, value.Length - 3 ) );
}
/// <summary>
@@ -345,44 +412,61 @@ namespace Spring.Web.Support
/// If the supplied <paramref name="result"/> starts with an illegal
/// result mode (see <see cref="Spring.Web.Support.ResultMode"/>).
/// </exception>
private string ExtractAndSetResultMode(string result)
private string ExtractAndSetResultMode( string result )
{
int indexOfResultModeDelimiter = result.IndexOf(':');
int indexOfResultModeDelimiter = result.IndexOf( ':' );
if (indexOfResultModeDelimiter > 0)
{
try
{
Mode = (ResultMode)Enum.Parse(typeof(ResultMode),
result.Substring(0, indexOfResultModeDelimiter), true);
return result.Substring(indexOfResultModeDelimiter + 1);
}
catch
{
throw new ArgumentOutOfRangeException("result", result, "Illegal result mode.");
}
string resultMode = result.Substring( 0, indexOfResultModeDelimiter );
SetResultMode( resultMode );
return result.Substring( indexOfResultModeDelimiter + 1 );
}
return result;
}
/// <summary>
/// Set the actual <see cref="Mode"/> from the parsed <paramref name="resultMode"/> string.
/// </summary>
/// <param name="resultMode">the parsed result mode</param>
protected virtual void SetResultMode( string resultMode )
{
try
{
if (StringUtils.HasText( resultMode ))
{
Mode = (ResultMode)Enum.Parse( typeof( ResultMode ), resultMode, true );
}
}
catch
{
throw new ArgumentOutOfRangeException( "resultMode", resultMode, "Illegal result mode." );
}
}
protected string GetResolvedTargetPage( object context )
{
return ResolveRuntimeExpressionIfNecessary( context, TargetPage ).ToString();
}
/// <summary>
/// Parses query parameters from the supplied <paramref name="queryString"/>.
/// </summary>
/// <param name="queryString">
/// The query string (may be <cref lang="null"/>).
/// </param>
private void ParseParameters(string queryString)
private void ParseParameters( string queryString )
{
if (StringUtils.HasText(queryString))
if (StringUtils.HasText( queryString ))
{
this.parameters = new Hashtable();
string[] nameValuePairs = queryString.Split("&,".ToCharArray());
this.parameters = new CaseInsensitiveHashtable();
string[] nameValuePairs = queryString.Split( "&,".ToCharArray() );
foreach (string pair in nameValuePairs)
{
int n = pair.IndexOf('=');
int n = pair.IndexOf( '=' );
if (n > 0)
{
string name = pair.Substring(0, n);
string val = pair.Substring(n + 1).Trim();
string name = pair.Substring( 0, n );
string val = pair.Substring( n + 1 ).Trim();
this.parameters[name] = val;
}
}

View File

@@ -0,0 +1,101 @@
#region License
/*
* Copyright <20> 2002-2008 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 Spring.Collections;
using Spring.Util;
#endregion
namespace Spring.Web.Support
{
public class ResultFactoryRegistry
{
private static readonly IDictionary s_registeredFactories = new CaseInsensitiveHashtable();
private static volatile IResultFactory s_defaultFactory;
static ResultFactoryRegistry()
{
Reset();
}
public static void Reset()
{
s_defaultFactory = null;
s_registeredFactories.Clear();
SetDefaultFactory( new DefaultResultFactory() );
foreach(string resultMode in Enum.GetNames(typeof(ResultMode)))
{
RegisterResultMode( resultMode, DefaultResultFactory );
}
}
public static IResultFactory DefaultResultFactory
{
get { return s_defaultFactory; }
}
public static IResultFactory SetDefaultFactory(IResultFactory resultFactory)
{
AssertUtils.ArgumentNotNull(resultFactory, "resultFactory");
IResultFactory prevFactory = s_defaultFactory;
s_defaultFactory = resultFactory;
return prevFactory;
}
public static IResultFactory RegisterResultMode( string resultMode, IResultFactory resultFactory )
{
lock (s_registeredFactories.SyncRoot)
{
IResultFactory prevFactory = (IResultFactory) s_registeredFactories[resultMode];
s_registeredFactories[resultMode] = resultFactory;
return prevFactory;
}
}
public static IResult CreateResult( string resultText )
{
IResultFactory resultFactory = null;
string resultMode = null;
int indexOfResultModeDelimiter = resultText.IndexOf( ':' );
if (indexOfResultModeDelimiter > 0)
{
resultMode = resultText.Substring( 0, indexOfResultModeDelimiter ).Trim();
resultFactory = (IResultFactory) s_registeredFactories[resultMode];
resultText = resultText.Substring( indexOfResultModeDelimiter + 1 );
}
if (resultFactory == null)
{
resultFactory = s_defaultFactory;
}
IResult result = resultFactory.CreateResult( resultMode, resultText );
AssertUtils.ArgumentNotNull(result, "ResultFactories must not return null results");
return result;
}
}
}

View File

@@ -0,0 +1,169 @@
#region License
/*
* Copyright 2002-2008 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 Spring.Collections;
using Spring.Core;
using Spring.Util;
#endregion
namespace Spring.Web.Support
{
public class ResultWebNavigator : IResultWebNavigator
{
private IWebNavigator _parentNavigator;
private bool _ignoreCase;
private IDictionary _results;
public bool IsCaseSensitive
{
get { return !_ignoreCase; }
}
public virtual IWebNavigator ParentNavigator
{
get { return _parentNavigator; }
set
{
if (_parentNavigator != null)
{
AssertUtils.ArgumentNotNull( _parentNavigator, "Parent", "Navigator already has a parent" );
}
_parentNavigator = value;
}
}
/// <summary>
/// Gets or sets map of result names to target URLs
/// </summary>
public IDictionary Results
{
get
{
return _results;
}
set
{
_results = CreateResultsDictionary(value);
}
}
public ResultWebNavigator()
:this(null, null, true)
{}
public ResultWebNavigator( IWebNavigator parent, IDictionary results, bool ignoreCase )
{
this._parentNavigator = parent;
this._ignoreCase = ignoreCase;
this._results = CreateResultsDictionary( results );
}
protected virtual IDictionary CreateResultsDictionary( IDictionary initialResults )
{
IDictionary newResults = (_ignoreCase) ? new CaseInsensitiveHashtable() : new Hashtable();
if (initialResults != null)
{
foreach(DictionaryEntry entry in initialResults)
{
newResults[entry.Key.ToString()] = entry.Value;
}
}
return newResults;
}
public virtual bool CanNavigateTo( string resultName )
{
if (_results.Contains( resultName ))
{
return true;
}
return (ParentNavigator != null) ? ParentNavigator.CanNavigateTo( resultName ) : false;
}
/// <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>
public virtual void NavigateTo( string resultName, object context )
{
IResult result = GetResult( resultName );
if (result == null)
{
if (ParentNavigator != null)
{
ParentNavigator.NavigateTo( resultName, context );
return;
}
throw new ArgumentException( string.Format( "No result mapping found for the specified name '{0}'.", resultName ), "resultName" );
}
result.Navigate( 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>
/// <param name="context">The context to use for evaluating the SpEL expression in the Result</param>
/// <returns>A redirect url string.</returns>
public virtual string GetResultUri( string resultName, object context )
{
IResult result = GetResult( resultName );
if (result == null)
{
if (ParentNavigator != null)
{
return result.GetRedirectUri( context );
}
throw new ArgumentException( string.Format( "No result mapping found for the specified name '{0}'.", resultName ), "resultName" );
}
return result.GetRedirectUri( context );
}
protected IResult GetResult( string name )
{
object val = _results[name];
if (val == null)
{
return null;
}
else if (val is IResult)
{
return (IResult)val;
}
else if (val is String)
{
return ResultFactoryRegistry.CreateResult( (string)val );
}
else
{
throw new TypeMismatchException(
"Unable to create result object. Please use either String or Result instances to define results." );
}
}
}
}

View File

@@ -0,0 +1,98 @@
#region License
/*
* Copyright 2002-2008 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.Collections;
using System.Web.UI;
using Spring.Util;
#endregion
namespace Spring.Web.Support
{
/// <summary>
/// An implementation of <see cref="IHierarchicalWebNavigator"/> specific for <see cref="Control"/>s.
/// The navigator hierarchy equals the control hierarchy when using a <see cref="WebFormsResultWebNavigator"/>.
/// </summary>
public class WebFormsResultWebNavigator : ResultWebNavigator
{
/// <summary>
/// Finds the next <see cref="IWebNavigator"/> up the control hierarchy,
/// starting at the specified <paramref name="control"/>.
/// </summary>
/// <remarks>
/// This method checks both, for controls implementing <see cref="IWebNavigator"/> or <see cref="IWebNavigable"/>. In addition
/// when MasterPages are used, it interprets the control hierarchy as control-&gt;page-&gt;masterpage.
/// </remarks>
/// <param name="control">the control to start the search with.</param>
/// <param name="includeSelf">include checking the control itself or start search with its parent.</param>
/// <returns>If found, the next <see cref="IWebNavigator"/> up the hierarchy. <c>null</c> otherwise</returns>
public static IWebNavigator FindWebNavigator( Control control, bool includeSelf )
{
while (control != null)
{
if (!includeSelf)
{
// Get next parent in hierarchy
control = WebUtils.GetLogicalParent( control );
}
includeSelf = false;
if (control is IWebNavigable || control is IWebNavigator)
{
return (control is IWebNavigable) ? ((IWebNavigable)control).WebNavigator : (IWebNavigator)control;
}
}
return null;
}
private Control _owner;
/// <summary>
/// Creates a new instance of a <see cref="IHierarchicalWebNavigator"/> for the specified control.
/// </summary>
/// <param name="owner">the control to be associated with this navigator.</param>
/// <param name="results">a dictionary containing results</param>
/// <param name="ignoreCase">determines, whether to interpret result names case-sensitive or not.</param>
public WebFormsResultWebNavigator( Control owner, IDictionary results, bool ignoreCase )
: base( null, results, ignoreCase )
{
AssertUtils.ArgumentNotNull(owner, "owner");
_owner = owner;
}
public override IWebNavigator ParentNavigator
{
get
{
if (base.ParentNavigator == null)
{
base.ParentNavigator = FindWebNavigator(_owner, false);
}
return base.ParentNavigator;
}
set
{
throw new System.NotSupportedException("cannot set parent navigator on a WebFormsResultWebNavigator");
}
}
}
}

View File

@@ -280,6 +280,7 @@ namespace Spring.Web.UI.Controls
attributeCollection.Remove(ATTR_BINDINGTARGET);
attributeCollection.Remove(ATTR_BINDINGSOURCE);
attributeCollection.Remove(ATTR_BINDINGTYPE);
attributeCollection.Remove(ATTR_BINDINGDIRECTION);
attributeCollection.Remove(ATTR_BINDINGFORMATTER);
}

View File

@@ -71,7 +71,11 @@ namespace Spring.Web.UI.Controls
/// <remarks>
/// The url specified here is only rendered, if <see cref="SuppressAction"/> is true.
/// </remarks>
#if !NET_2_0
public string Action
#else
public new string Action
#endif
{
get { return this.action; }
set { this.action = value; }

View File

@@ -88,6 +88,13 @@ namespace Spring.Web.UI.Controls
private bool _suppressDependencyInjection;
private bool _renderContainerTag;
private string _visibleConditionExpression;
public string VisibleIf
{
get { return _visibleConditionExpression; }
set { _visibleConditionExpression = value; }
}
/// <summary>
/// This flag controls, whether DI on child controls will be done or not
@@ -114,6 +121,12 @@ namespace Spring.Web.UI.Controls
/// <param name="writer"></param>
protected override void Render(HtmlTextWriter writer)
{
bool visible = (_visibleConditionExpression != null)
? Spring.Expressions.ExpressionEvaluator.GetValue(this, _visibleConditionExpression).Equals(true)
: this.Visible;
if (!visible) return;
if (_renderContainerTag)
{
base.Render(writer);

View File

@@ -24,6 +24,7 @@ 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 IValidator = Spring.Validation.IValidator;
@@ -100,13 +101,12 @@ namespace Spring.Web.UI
#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
public class MasterPage : System.Web.UI.MasterPage, IApplicationContextAware, ISupportsWebDependencyInjection, IWebNavigable
{
#region Instance Fields
@@ -115,11 +115,21 @@ namespace Spring.Web.UI
private IMessageSource messageSource;
private IApplicationContext applicationContext;
private IApplicationContext defaultApplicationContext;
private IWebNavigator webNavigator;
private IDictionary args;
#endregion
#region Control lifecycle methods
#region Lifecycle methods
/// <summary>
/// Initialize a new MasterPage instance.
/// </summary>
public MasterPage()
{
InitializeNavigationSupport();
}
/// <summary>
/// Initializes user control.
/// </summary>
@@ -416,6 +426,148 @@ namespace Spring.Web.UI
#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, 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:
///
/// &lt;property Name=&quot;Results&quot;&gt;
/// &lt;dictionary&gt;
/// &lt;entry key=&quot;ok_clicked&quot; value=&quot;redirect:~/ShowResult.aspx?result=%{Args['result']}&quot; /&gt;
/// &lt;/dictionary&gt;
/// &lt;/property&gt;
///
/// // code:
///
/// void OnOkClicked(object sender, EventArgs e)
/// {
/// Args[&quot;result&quot;] = txtUserInput.Text;
/// SetResult(&quot;ok_clicked&quot;);
/// }
/// </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 );
}
/// <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, 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 ) );
}
/// <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, context ) );
}
#endregion
#region Validation support
/// <summary>

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright 2002-2004 the original author or authors.
* Copyright 2002-2008 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.
@@ -31,9 +31,9 @@ using System.Security.Permissions;
using System.Threading;
using System.Web;
using System.Web.UI;
using Spring.Collections;
using Spring.Context;
using Spring.Context.Support;
using Spring.Core;
using Spring.DataBinding;
using Spring.Globalization;
using Spring.Globalization.Resolvers;
@@ -50,6 +50,10 @@ using IValidator = Spring.Validation.IValidator;
namespace Spring.Web.UI
{
#region Result support
#endregion
/// <summary>
/// Represents an .aspx file, also known as a Web Forms page, requested from a
/// server that hosts an ASP.NET Web application.
@@ -73,7 +77,7 @@ namespace Spring.Web.UI
[AspNetHostingPermission( SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal )]
[AspNetHostingPermission( SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal )]
public class Page : System.Web.UI.Page, IHttpHandler, IApplicationContextAware, ISharedStateAware,
ISupportsWebDependencyInjection, IWebDataBound, IValidationContainer
ISupportsWebDependencyInjection, IWebDataBound, IValidationContainer, IWebNavigable
{
#region Constants
@@ -108,15 +112,15 @@ namespace Spring.Web.UI
private String masterPageFile;
#endif
private object controller;
private IDictionary sharedState;
private IDictionary sharedState = new CaseInsensitiveHashtable();
private ILocalizer localizer;
private ICultureResolver cultureResolver = new DefaultWebCultureResolver();
private IMessageSource messageSource;
private IBindingContainer bindingManager;
private IValidationErrors validationErrors = new ValidationErrors();
private IDictionary results;
private IWebNavigator webNavigator;
private IDictionary args;
private IApplicationContext applicationContext;
private IApplicationContext defaultApplicationContext;
private static readonly string traceCategory = "Spring.Page";
@@ -132,6 +136,11 @@ namespace Spring.Web.UI
#region Page lifecycle methods
public Page()
{
InitializeNavigationSupport();
}
#if !NET_2_0
/// <summary>
/// Determines the type of request made for the Page class.
@@ -1027,39 +1036,97 @@ namespace Spring.Web.UI
#region Result support
/// <summary>
/// Gets or sets map of result names to target URLs
/// Ensure, that <see cref="WebNavigator"/> is set to a valid instance.
/// </summary>
[Browsable( false )]
[DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )]
public IDictionary Results
/// <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, true );
}
/// <summary>
/// Gets/Sets the navigator to be used for handling <see cref="SetResult(string, object)"/> calls.
/// </summary>
public virtual IWebNavigator WebNavigator
{
get
{
if (results == null)
{
results = new Hashtable();
}
return results;
return webNavigator;
}
set
{
results = new Hashtable();
foreach (DictionaryEntry entry in value)
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)
{
if (entry.Value is Result)
{
results[entry.Key] = entry.Value;
}
else if (entry.Value is String)
{
results[entry.Key] = new Result( (string)entry.Value );
}
else
{
throw new TypeMismatchException(
"Unable to create result object. Please use either String or Result instances to define results." );
}
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>
/// This example shows how to pass an arbitrary value 'age' into a result expression.
/// <code>
/// // config:
///
/// &lt;property Name=&quot;Results&quot;&gt;
/// &lt;dictionary&gt;
/// &lt;entry key=&quot;ok_clicked&quot; value=&quot;redirect:~/ShowResult.aspx?age=%{Args['age']}&quot; /&gt;
/// &lt;/dictionary&gt;
/// &lt;/property&gt;
///
/// // code:
///
/// void OnOkClicked(object sender, EventArgs e)
/// {
/// Args[&quot;result&quot;] = txtAge.Text;
/// SetResult(&quot;ok_clicked&quot;);
/// }
/// </code>
/// </example>
/// </remarks>
public IDictionary Args
{
get
{
if (args == null)
{
args = new CaseInsensitiveHashtable();
}
return args;
}
}
@@ -1067,23 +1134,21 @@ namespace Spring.Web.UI
/// Redirects user to a URL mapped to specified result name.
/// </summary>
/// <param name="resultName">Result name.</param>
protected internal void SetResult( string resultName )
protected void SetResult( string resultName )
{
GetResult( resultName ).Navigate( this );
WebNavigator.NavigateTo( resultName, this );
}
/// <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 internal void SetResult( string resultName, object context )
protected void SetResult( string resultName, object context )
{
GetResult( resultName ).Navigate( context );
WebNavigator.NavigateTo( resultName, context );
}
/// <summary>
/// Returns a redirect url string that points to the
/// <see cref="Spring.Web.Support.Result.TargetPage"/> defined by this
@@ -1091,10 +1156,9 @@ namespace Spring.Web.UI
/// </summary>
/// <param name="resultName">Name of the result.</param>
/// <returns>A redirect url string.</returns>
protected internal string GetResultUrl( string resultName )
protected string GetResultUrl( string resultName )
{
Result result = GetResult( resultName );
return ResolveUrl( result.GetRedirectUri( this ) );
return ResolveUrl( WebNavigator.GetResultUri( resultName, this ) );
}
/// <summary>
@@ -1105,26 +1169,11 @@ namespace Spring.Web.UI
/// <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 internal string GetResultUrl( string resultName, object context )
protected string GetResultUrl( string resultName, object context )
{
Result result = GetResult( resultName );
return ResolveUrl( result.GetRedirectUri( context ) );
return ResolveUrl( WebNavigator.GetResultUri( resultName, context ) );
}
private Result GetResult( string resultName )
{
Result result = (Result)Results[resultName];
if (result == null)
{
throw new ArgumentException(
string.Format( "No URL mapping found for the specified result '{0}'.", resultName ), "resultName" );
}
return result;
}
#endregion
#region Validation support

View File

@@ -38,6 +38,7 @@ using Spring.Context.Support;
using Spring.Core;
using Spring.DataBinding;
using Spring.Globalization;
using Spring.Util;
using Spring.Validation;
using Spring.Web.Support;
using IValidator = Spring.Validation.IValidator;
@@ -51,7 +52,7 @@ namespace Spring.Web.UI
/// </summary>
/// <author>Aleksandar Seovic</author>
public class UserControl : System.Web.UI.UserControl, IApplicationContextAware, IWebDataBound, ISupportsWebDependencyInjection,
IPostBackDataHandler,IValidationContainer
IPostBackDataHandler, IValidationContainer, IWebNavigable
{
#region Static fields
@@ -67,10 +68,11 @@ namespace Spring.Web.UI
private object controller;
private ILocalizer localizer;
private IMessageSource messageSource;
private IDictionary sharedState;
private IDictionary sharedState = new CaseInsensitiveHashtable();
private IBindingContainer bindingManager;
private IValidationErrors validationErrors = new ValidationErrors();
private IDictionary results;
private IWebNavigator webNavigator;
private IDictionary args;
private IApplicationContext applicationContext;
private IApplicationContext defaultApplicationContext;
private bool needsUnbind = false;
@@ -79,6 +81,14 @@ namespace Spring.Web.UI
#region Control lifecycle methods
/// <summary>
/// Initialize a new UserControl instance.
/// </summary>
public UserControl()
{
InitializeNavigationSupport();
}
#if !NET_2_0
/// <summary>
/// Gets a value indicating whether this instance is in design mode.
@@ -113,7 +123,7 @@ namespace Spring.Web.UI
/// <summary>
/// Initializes user control.
/// </summary>
protected override void OnInit(EventArgs e)
protected override void OnInit( EventArgs e )
{
InitializeMessageSource();
InitializeBindingManager();
@@ -124,23 +134,23 @@ namespace Spring.Web.UI
}
else
{
LoadModel(LoadModelFromPersistenceMedium());
LoadModel( LoadModelFromPersistenceMedium() );
}
base.OnInit(e);
base.OnInit( e );
OnInitializeControls(EventArgs.Empty);
OnInitializeControls( EventArgs.Empty );
}
/// <summary>
/// Raises the <see cref="PreLoadViewState"/> event after page initialization.
/// </summary>
protected internal virtual void OnPreLoadViewState(EventArgs e)
protected internal virtual void OnPreLoadViewState( EventArgs e )
{
EventHandler handler = (EventHandler) base.Events[EventPreLoadViewState];
EventHandler handler = (EventHandler)base.Events[EventPreLoadViewState];
if (handler != null)
{
handler(this, e);
handler( this, e );
}
}
@@ -158,8 +168,8 @@ namespace Spring.Web.UI
/// </remarks>
public event EventHandler PreLoadViewState
{
add { base.Events.AddHandler(EventPreLoadViewState, value); }
remove { base.Events.RemoveHandler(EventPreLoadViewState, value); }
add { base.Events.AddHandler( EventPreLoadViewState, value ); }
remove { base.Events.RemoveHandler( EventPreLoadViewState, value ); }
}
/// <summary>
@@ -170,16 +180,16 @@ namespace Spring.Web.UI
/// has been called during <see cref="OnPreRender"/>
/// </remarks>
/// <returns>true if the server control's state changes as a result of the post back; otherwise false.</returns>
bool IPostBackDataHandler.LoadPostData(string postDataKey, NameValueCollection postCollection)
bool IPostBackDataHandler.LoadPostData( string postDataKey, NameValueCollection postCollection )
{
return LoadPostData(postDataKey, postCollection);
return LoadPostData( postDataKey, postCollection );
}
/// <summary>
/// This method is called during a postback if this control has been visible when being rendered to the client.
/// </summary>
/// <returns>true if the server control's state changes as a result of the post back; otherwise false.</returns>
protected virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection)
protected virtual bool LoadPostData( string postDataKey, NameValueCollection postCollection )
{
// mark this control for unbinding form data during OnLoad()
this.needsUnbind = true;
@@ -210,14 +220,14 @@ namespace Spring.Web.UI
/// then raises Load event in order to execute all associated handlers.
/// </summary>
/// <param name="e">Event arguments.</param>
protected override void OnLoad(EventArgs e)
protected override void OnLoad( EventArgs e )
{
if (IsPostBack && needsUnbind)
{
// unbind form data
UnbindFormData();
}
base.OnLoad(e);
base.OnLoad( e );
}
/// <summary>
@@ -225,32 +235,32 @@ namespace Spring.Web.UI
/// PreRender event afterwards.
/// </summary>
/// <param name="e">Event arguments.</param>
protected override void OnPreRender(EventArgs e)
protected override void OnPreRender( EventArgs e )
{
if (Visible)
{
// causes IPostBackDataHandler.LoadPostData() to be called on next postback.
// this is used for indicating a required call to UnbindFormData()
Page.RegisterRequiresPostBack(this);
Page.RegisterRequiresPostBack( this );
BindFormData();
if (localizer != null)
{
localizer.ApplyResources(this, messageSource, UserCulture);
localizer.ApplyResources( this, messageSource, UserCulture );
}
else if (Page.Localizer != null)
{
Page.Localizer.ApplyResources(this, messageSource, UserCulture);
Page.Localizer.ApplyResources( this, messageSource, UserCulture );
}
}
base.OnPreRender(e);
base.OnPreRender( e );
object modelToSave = SaveModel();
if (modelToSave != null)
{
SaveModelToPersistenceMedium(modelToSave);
SaveModelToPersistenceMedium( modelToSave );
}
}
@@ -264,11 +274,11 @@ namespace Spring.Web.UI
/// Raises InitializeControls event.
/// </summary>
/// <param name="e">Event arguments.</param>
protected virtual void OnInitializeControls(EventArgs e)
protected virtual void OnInitializeControls( EventArgs e )
{
if (InitializeControls != null)
{
InitializeControls(this, e);
InitializeControls( this, e );
}
}
@@ -280,10 +290,10 @@ namespace Spring.Web.UI
/// <returns>
/// Returns the specified <see langword="UserControl"/> object, with dependencies injected.
/// </returns>
protected virtual new Control LoadControl(string virtualPath)
protected virtual new Control LoadControl( string virtualPath )
{
Control control = base.LoadControl(virtualPath);
control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control);
Control control = base.LoadControl( virtualPath );
control = WebDependencyInjectionUtils.InjectDependenciesRecursive( defaultApplicationContext, control );
return control;
}
@@ -297,10 +307,10 @@ namespace Spring.Web.UI
/// <returns>
/// Returns the specified <see langword="UserControl"/> object, with dependencies injected.
/// </returns>
protected virtual new Control LoadControl( Type t, params object[] parameters)
protected virtual new Control LoadControl( Type t, params object[] parameters )
{
Control control = base.LoadControl( t, parameters );
control = WebDependencyInjectionUtils.InjectDependenciesRecursive(defaultApplicationContext, control);
control = WebDependencyInjectionUtils.InjectDependenciesRecursive( defaultApplicationContext, control );
return control;
}
#endif
@@ -339,7 +349,7 @@ namespace Spring.Web.UI
/// The default implementation uses <see cref="System.Web.UI.Page.Session"/> to store and retrieve
/// the model for the current <see cref="System.Web.HttpRequest.CurrentExecutionFilePath" />
/// </remarks>
protected virtual void SaveModelToPersistenceMedium(object modelToSave)
protected virtual void SaveModelToPersistenceMedium( object modelToSave )
{
Session[Request.CurrentExecutionFilePath + this.UniqueID + ".Model"] = modelToSave;
}
@@ -351,7 +361,7 @@ namespace Spring.Web.UI
/// This method should be overriden by the developer
/// in order to load data model for the page.
/// </remarks>
protected virtual void LoadModel(object savedModel)
protected virtual void LoadModel( object savedModel )
{
}
@@ -386,7 +396,7 @@ namespace Spring.Web.UI
public object Controller
{
get { return GetController(); }
set { SetController(value); }
set { SetController( value ); }
}
/// <summary>
@@ -397,7 +407,7 @@ namespace Spring.Web.UI
/// but must ensure to also change the behaviour of <see cref="GetController"/> accordingly.
/// </remarks>
/// <param name="controller">Controller for the control.</param>
protected virtual void SetController(object controller)
protected virtual void SetController( object controller )
{
this.controller = controller;
}
@@ -425,7 +435,7 @@ namespace Spring.Web.UI
/// </returns>
protected virtual object GetController()
{
if(controller == null)
if (controller == null)
{
return this;
}
@@ -440,8 +450,8 @@ namespace Spring.Web.UI
/// Returns a thread-safe dictionary that contains state that is shared by
/// all instances of this control.
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable( false )]
[DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )]
protected IDictionary SharedState
{
get
@@ -451,7 +461,7 @@ namespace Spring.Web.UI
string thisTypeKey = this.GetType().FullName + this.GetType().GetHashCode() + ".SharedState";
sharedState = Application[thisTypeKey] as IDictionary;
if (sharedState==null)
if (sharedState == null)
{
Application.Lock();
try
@@ -460,7 +470,7 @@ namespace Spring.Web.UI
if (sharedState == null)
{
sharedState = new SynchronizedHashtable();
Application.Add(thisTypeKey, sharedState);
Application.Add( thisTypeKey, sharedState );
}
}
finally
@@ -478,103 +488,141 @@ namespace Spring.Web.UI
#region Result support
/// <summary>
/// Gets or sets map of result names to target URLs
/// Ensure, that <see cref="WebNavigator"/> is set to a valid instance.
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public IDictionary Results
/// <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, true);
}
/// <summary>
/// Gets/Sets the navigator to be used for handling <see cref="SetResult(string, object)"/> calls.
/// </summary>
public IWebNavigator WebNavigator
{
get
{
if (results == null)
{
results = new Hashtable();
}
return results;
return webNavigator;
}
set
{
results = new Hashtable();
foreach (DictionaryEntry entry in value)
{
if (entry.Value is Result)
{
results[entry.Key] = entry.Value;
}
else if (entry.Value is String)
{
results[entry.Key] = new Result((string)entry.Value);
}
else
{
throw new TypeMismatchException(
"Unable to create result object. Please use either String or Result instances to define results.");
}
}
webNavigator = value;
}
}
/// <summary>
/// Redirects user to a URL mapped to specified result name.
/// Gets or sets map of result names to target URLs
/// </summary>
/// <param name="resultName">Result name.</param>
protected void SetResult(string resultName)
/// <remarks>
/// Using <see cref="Results"/> requires <see cref="WebNavigator"/> to implement <see cref="IResultWebNavigator"/>.
/// </remarks>
[Browsable( false )]
[DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )]
public virtual IDictionary Results
{
Result result = (Result)Results[resultName];
if (result == null)
get
{
// bubble up result in the hierarchy
Control parent = this.Parent;
while(parent != null)
if (WebNavigator is IResultWebNavigator)
{
if (parent is UserControl)
{
((UserControl)parent).SetResult(resultName);
return;
}
else if (parent is Page)
{
((Page) parent).SetResult(resultName);
return;
}
parent = parent.Parent;
return ((IResultWebNavigator)WebNavigator).Results;
}
throw new ArgumentException(string.Format("No URL mapping found for the specified result '{0}'.", resultName), "resultName");
return null;
}
set
{
if (WebNavigator is IResultWebNavigator)
{
((IResultWebNavigator)WebNavigator).Results = value;
return;
}
throw new NotSupportedException("WebNavigator must be of type IResultWebNavigator to support Results");
}
}
result.Navigate(this);
/// <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:
///
/// &lt;property Name=&quot;Results&quot;&gt;
/// &lt;dictionary&gt;
/// &lt;entry key=&quot;ok_clicked&quot; value=&quot;redirect:~/ShowResult.aspx?result=%{Args['result']}&quot; /&gt;
/// &lt;/dictionary&gt;
/// &lt;/property&gt;
///
/// // code:
///
/// void OnOkClicked(object sender, EventArgs e)
/// {
/// Args[&quot;result&quot;] = txtUserInput.Text;
/// SetResult(&quot;ok_clicked&quot;);
/// }
/// </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 );
}
/// <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)
protected void SetResult( string resultName, object context )
{
Result result = (Result)Results[resultName];
if (result == null)
{
// bubble up result in the hierarchy
Control parent = this.Parent;
while (parent != null)
{
if (parent is UserControl)
{
((UserControl)parent).SetResult(resultName, context);
return;
}
else if (parent is Page)
{
((Page)parent).SetResult(resultName, context);
return;
}
parent = parent.Parent;
}
throw new ArgumentException(string.Format("No URL mapping found for the specified result '{0}'.", resultName), "resultName");
}
WebNavigator.NavigateTo( resultName, context );
}
result.Navigate(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 ) );
}
/// <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, context ) );
}
#endregion
@@ -598,7 +646,7 @@ namespace Spring.Web.UI
/// <returns>
/// <c>True</c> if all of the specified validators are valid, <c>False</c> otherwise.
/// </returns>
public bool Validate(object validationContext, params IValidator[] validators)
public bool Validate( object validationContext, params IValidator[] validators )
{
IDictionary contextParams = CreateValidatorParameters();
bool result = true;
@@ -606,9 +654,9 @@ namespace Spring.Web.UI
{
if (validator == null)
{
throw new ArgumentException("Validator is not defined.");
throw new ArgumentException( "Validator is not defined." );
}
result = validator.Validate(validationContext, contextParams, this.validationErrors) && result;
result = validator.Validate( validationContext, contextParams, this.validationErrors ) && result;
}
return result;
@@ -660,7 +708,7 @@ namespace Spring.Web.UI
/// Initializes the data bindings.
/// </summary>
protected virtual void InitializeDataBindings()
{}
{ }
/// <summary>
/// Returns the key to be used for looking up a cached
@@ -707,7 +755,7 @@ namespace Spring.Web.UI
this.bindingManager = sharedState[key] as BaseBindingManager;
if (this.bindingManager == null)
{
lock(sharedState.SyncRoot)
lock (sharedState.SyncRoot)
{
this.bindingManager = sharedState[key] as BaseBindingManager;
if (this.bindingManager == null)
@@ -715,10 +763,10 @@ namespace Spring.Web.UI
try
{
this.bindingManager = CreateBindingManager();
if(bindingManager == null)
if (bindingManager == null)
{
throw new ArgumentNullException("bindingManager",
"CreateBindingManager() must not return null");
throw new ArgumentNullException( "bindingManager",
"CreateBindingManager() must not return null" );
}
InitializeDataBindings();
}
@@ -728,7 +776,7 @@ namespace Spring.Web.UI
throw;
}
sharedState[key] = this.bindingManager;
this.OnDataBindingsInitialized(EventArgs.Empty);
this.OnDataBindingsInitialized( EventArgs.Empty );
}
}
}
@@ -737,13 +785,13 @@ namespace Spring.Web.UI
/// <summary>
/// Raises the <see cref="DataBindingsInitialized"/> event.
/// </summary>
protected virtual void OnDataBindingsInitialized(EventArgs e)
protected virtual void OnDataBindingsInitialized( EventArgs e )
{
EventHandler handler = (EventHandler)base.Events[EventDataBindingsInitialized];
if(handler != null)
if (handler != null)
{
handler(this, e);
handler( this, e );
}
}
@@ -754,11 +802,11 @@ namespace Spring.Web.UI
{
add
{
base.Events.AddHandler(EventDataBindingsInitialized, value);
base.Events.AddHandler( EventDataBindingsInitialized, value );
}
remove
{
base.Events.RemoveHandler(EventDataBindingsInitialized, value);
base.Events.RemoveHandler( EventDataBindingsInitialized, value );
}
}
@@ -767,11 +815,11 @@ namespace Spring.Web.UI
/// </summary>
protected internal virtual void BindFormData()
{
if(BindingManager.HasBindings)
if (BindingManager.HasBindings)
{
BindingManager.BindTargetToSource(this, Controller, Page.ValidationErrors);
BindingManager.BindTargetToSource( this, Controller, Page.ValidationErrors );
}
OnDataBound(EventArgs.Empty);
OnDataBound( EventArgs.Empty );
}
/// <summary>
@@ -779,11 +827,11 @@ namespace Spring.Web.UI
/// </summary>
protected internal virtual void UnbindFormData()
{
if(BindingManager.HasBindings)
if (BindingManager.HasBindings)
{
BindingManager.BindSourceToTarget(this, Controller, Page.ValidationErrors);
BindingManager.BindSourceToTarget( this, Controller, Page.ValidationErrors );
}
OnDataUnbound(EventArgs.Empty);
OnDataUnbound( EventArgs.Empty );
}
/// <summary>
@@ -794,11 +842,11 @@ namespace Spring.Web.UI
{
add
{
base.Events.AddHandler(EventDataBound, value);
base.Events.AddHandler( EventDataBound, value );
}
remove
{
base.Events.RemoveHandler(EventDataBound, value);
base.Events.RemoveHandler( EventDataBound, value );
}
}
@@ -806,12 +854,12 @@ namespace Spring.Web.UI
/// Raises DataBound event.
/// </summary>
/// <param name="e">Event arguments.</param>
protected virtual void OnDataBound(EventArgs e)
protected virtual void OnDataBound( EventArgs e )
{
EventHandler handler = (EventHandler) base.Events[EventDataBound];
EventHandler handler = (EventHandler)base.Events[EventDataBound];
if (handler != null)
{
handler(this, e);
handler( this, e );
}
}
@@ -823,11 +871,11 @@ namespace Spring.Web.UI
{
add
{
base.Events.AddHandler(EventDataUnbound, value);
base.Events.AddHandler( EventDataUnbound, value );
}
remove
{
base.Events.RemoveHandler(EventDataUnbound, value);
base.Events.RemoveHandler( EventDataUnbound, value );
}
}
@@ -835,12 +883,12 @@ namespace Spring.Web.UI
/// Raises DataBound event.
/// </summary>
/// <param name="e">Event arguments.</param>
protected virtual void OnDataUnbound(EventArgs e)
protected virtual void OnDataUnbound( EventArgs e )
{
EventHandler handler = (EventHandler) base.Events[EventDataUnbound];
EventHandler handler = (EventHandler)base.Events[EventDataUnbound];
if (handler != null)
{
handler(this, e);
handler( this, e );
}
}
@@ -875,8 +923,8 @@ namespace Spring.Web.UI
/// If thrown by any application context methods.
/// </exception>
/// <exception cref="Spring.Objects.Factory.ObjectInitializationException"/>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable( false )]
[DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )]
public virtual IApplicationContext ApplicationContext
{
get { return applicationContext; }
@@ -891,8 +939,8 @@ namespace Spring.Web.UI
/// Gets or sets the localizer.
/// </summary>
/// <value>The localizer.</value>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable( false )]
[DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )]
public ILocalizer Localizer
{
get { return localizer; }
@@ -910,8 +958,8 @@ namespace Spring.Web.UI
/// Gets or sets the local message source.
/// </summary>
/// <value>The local message source.</value>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable( false )]
[DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )]
public IMessageSource MessageSource
{
get { return messageSource; }
@@ -920,7 +968,7 @@ namespace Spring.Web.UI
messageSource = value;
if (messageSource != null && messageSource is AbstractMessageSource)
{
((AbstractMessageSource) messageSource).ParentMessageSource = applicationContext;
((AbstractMessageSource)messageSource).ParentMessageSource = applicationContext;
}
}
}
@@ -932,12 +980,12 @@ namespace Spring.Web.UI
{
if (this.MessageSource == null)
{
string key = CreateSharedStateKey("MessageSource");
string key = CreateSharedStateKey( "MessageSource" );
IDictionary sharedState = this.SharedState;
IMessageSource messageSource = sharedState[key] as IMessageSource;
if (messageSource == null)
{
lock(sharedState.SyncRoot)
lock (sharedState.SyncRoot)
{
messageSource = sharedState[key] as IMessageSource;
if (messageSource == null)
@@ -947,7 +995,7 @@ namespace Spring.Web.UI
ResourceManager rm = GetLocalResourceManager();
if (rm != null)
{
defaultMessageSource.ResourceManagers.Add(rm);
defaultMessageSource.ResourceManagers.Add( rm );
}
sharedState[key] = defaultMessageSource;
messageSource = defaultMessageSource;
@@ -978,13 +1026,13 @@ namespace Spring.Web.UI
}
#else
{
object resourceProvider = Page.GetLocalResourceProvider.Invoke(typeof(ResourceExpressionBuilder), new object[] {this});
object resourceProvider = Page.GetLocalResourceProvider.Invoke( typeof( ResourceExpressionBuilder ), new object[] { this } );
MethodInfo GetLocalResourceAssembly =
resourceProvider.GetType().GetMethod("GetLocalResourceAssembly", BindingFlags.NonPublic | BindingFlags.Instance);
Assembly localResourceAssembly = (Assembly) GetLocalResourceAssembly.Invoke(resourceProvider, null);
resourceProvider.GetType().GetMethod( "GetLocalResourceAssembly", BindingFlags.NonPublic | BindingFlags.Instance );
Assembly localResourceAssembly = (Assembly)GetLocalResourceAssembly.Invoke( resourceProvider, null );
if (localResourceAssembly != null)
{
return new ResourceManager(VirtualPathUtility.GetFileName(this.AppRelativeVirtualPath), localResourceAssembly);
return new ResourceManager( VirtualPathUtility.GetFileName( this.AppRelativeVirtualPath ), localResourceAssembly );
}
return null;
}
@@ -995,9 +1043,9 @@ namespace Spring.Web.UI
/// </summary>
/// <param name="name">Resource name.</param>
/// <returns>Message text.</returns>
public string GetMessage(string name)
public string GetMessage( string name )
{
return messageSource.GetMessage(name, UserCulture);
return messageSource.GetMessage( name, UserCulture );
}
/// <summary>
@@ -1006,9 +1054,9 @@ namespace Spring.Web.UI
/// <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)
public string GetMessage( string name, params object[] args )
{
return messageSource.GetMessage(name, UserCulture, args);
return messageSource.GetMessage( name, UserCulture, args );
}
/// <summary>
@@ -1016,16 +1064,16 @@ namespace Spring.Web.UI
/// </summary>
/// <param name="name">Resource name.</param>
/// <returns>Resource object.</returns>
public object GetResourceObject(string name)
public object GetResourceObject( string name )
{
return messageSource.GetResourceObject(name, UserCulture);
return messageSource.GetResourceObject( name, UserCulture );
}
/// <summary>
/// Gets or sets user's culture
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable( false )]
[DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )]
public virtual CultureInfo UserCulture
{
get { return Page.UserCulture; }
@@ -1040,11 +1088,11 @@ namespace Spring.Web.UI
/// 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)]
[Browsable( false )]
[DesignerSerializationVisibility( DesignerSerializationVisibility.Hidden )]
public new Page Page
{
get { return (Page) base.Page; }
get { return (Page)base.Page; }
}
#endregion
@@ -1057,7 +1105,7 @@ namespace Spring.Web.UI
/// </summary>
/// <param name="key">Key suffix</param>
/// <returns>Generated unique shared state key.</returns>
protected string CreateSharedStateKey(string key)
protected string CreateSharedStateKey( string key )
{
return key;
}
@@ -1072,16 +1120,16 @@ namespace Spring.Web.UI
IApplicationContext ISupportsWebDependencyInjection.DefaultApplicationContext
{
get { return defaultApplicationContext; }
set { defaultApplicationContext = value; }
set { defaultApplicationContext = value; }
}
/// <summary>
/// Injects dependencies into control before adding it.
/// </summary>
protected override void AddedControl(Control control,int index)
protected override void AddedControl( Control control, int index )
{
WebDependencyInjectionUtils.InjectDependenciesRecursive( defaultApplicationContext, control );
base.AddedControl(control,index);
base.AddedControl( control, index );
}
#endregion Dependency Injection Support

View File

@@ -328,6 +328,11 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\ResultFactoryRegistryTests.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "Web\Support\ResultTests.cs"
SubType = "Code"

View File

@@ -125,6 +125,7 @@
<Compile Include="Web\Support\AbstractHandlerFactoryTests.cs" />
<Compile Include="Web\Support\MimeMediaTypeTests.cs" />
<Compile Include="Web\Support\PageHandlerFactoryTests.cs" />
<Compile Include="Web\Support\ResultFactoryRegistryTests.cs" />
<Compile Include="Web\Support\ResultTests.cs">
<SubType>Code</SubType>
</Compile>

View File

@@ -0,0 +1,189 @@
#region License
/*
* Copyright <20> 2002-2008 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 NUnit.Framework;
using Rhino.Mocks;
using Spring.Util;
#endregion
namespace Spring.Web.Support
{
/// <summary>
///
/// </summary>
/// <author>Erich Eichinger</author>
[TestFixture]
public class ResultFactoryRegistryTests
{
[SetUp]
public void SetUp()
{
ResultFactoryRegistry.Reset();
}
[Test]
public void SetDefaultFactory()
{
MockRepository mocks = new MockRepository();
IResultFactory resultFactory = (IResultFactory)mocks.CreateMock( typeof( IResultFactory ) );
IResultFactory prevFactory = ResultFactoryRegistry.DefaultResultFactory;
Assert.AreSame( prevFactory, ResultFactoryRegistry.SetDefaultFactory( resultFactory ) );
Assert.AreSame( resultFactory, ResultFactoryRegistry.DefaultResultFactory );
// verify default factory is used for unknown result mode
using (Record( mocks ))
{
Expect.Call( resultFactory.CreateResult( null, "resultText" ) ).Return( new Result() );
Expect.Call( resultFactory.CreateResult( "resultMode", "resultText" ) ).Return( new Result() );
}
using (Playback( mocks ))
{
ResultFactoryRegistry.CreateResult( "resultText" );
ResultFactoryRegistry.CreateResult( "resultMode:resultText" );
}
}
[Test]
public void ResultModeValuesHavePredefinedFactories()
{
MockRepository mocks = new MockRepository();
IResultFactory defaultFactory = (IResultFactory)mocks.CreateMock( typeof( IResultFactory ) );
ResultFactoryRegistry.SetDefaultFactory( defaultFactory );
// verify factory registry knows all ResultModes
using (Record( mocks ))
{
// defaultFactory must never be called!
}
using (Playback( mocks ))
{
foreach (string resultMode in Enum.GetNames( typeof( ResultMode ) ))
{
Assert.IsNotNull( ResultFactoryRegistry.CreateResult( resultMode+":resultText" ) );
}
}
}
[Test]
public void SelectsFactoryByResultMode()
{
MockRepository mocks = new MockRepository();
IResultFactory resultFactory = (IResultFactory)mocks.CreateMock( typeof( IResultFactory ) );
ResultFactoryRegistry.RegisterResultMode( "resultMode", resultFactory );
Result result = new Result();
// verify factory registry does not allow nulls to be returned
using (Record( mocks ))
{
Expect.Call( resultFactory.CreateResult( "resultMode", "resultText" ) ).Return( result );
}
using (Playback( mocks ))
{
Assert.AreSame( result, ResultFactoryRegistry.CreateResult( "resultMode:resultText" ) );
}
}
[Test]
[ExpectedException( typeof( ArgumentNullException ) )]
public void BailsOnNullReturnedFromFactory()
{
MockRepository mocks = new MockRepository();
IResultFactory resultFactory = (IResultFactory)mocks.CreateMock( typeof( IResultFactory ) );
ResultFactoryRegistry.RegisterResultMode( "resultMode", resultFactory );
// verify factory registry does not allow nulls to be returned
using (Record( mocks ))
{
Expect.Call( resultFactory.CreateResult( "resultMode", "resultText" ) ).Return( null );
}
using (Playback( mocks ))
{
ResultFactoryRegistry.CreateResult( "resultMode:resultText" );
}
}
#region Rhino.Mocks Compatibility Adapter
private static IDisposable Record( MockRepository mocks )
{
#if !NET_1_1
return mocks.Record();
#else
return new RecordModeChanger(mocks);
#endif
}
private static IDisposable Playback( MockRepository mocks )
{
#if !NET_1_1
return mocks.Playback();
#else
return new PlaybackModeChanger(mocks);
#endif
}
#if NET_1_1
private class RecordModeChanger : IDisposable
{
private MockRepository _mocks;
public RecordModeChanger(MockRepository mocks)
{
_mocks = mocks;
}
public void Dispose()
{
_mocks.ReplayAll();
}
}
private class PlaybackModeChanger : IDisposable
{
private MockRepository _mocks;
public PlaybackModeChanger(MockRepository mocks)
{
_mocks = mocks;
}
public void Dispose()
{
_mocks.VerifyAll();
}
}
#endif
#endregion Rhino.Mocks Compatibility Adapter
}
}

View File

@@ -21,7 +21,9 @@
#region Imports
using System;
using System.Collections;
using NUnit.Framework;
using Spring.Util;
#endregion
@@ -333,5 +335,32 @@ namespace Spring.Web.Support
"The TargetPage property is not being correctly extracted " +
"from the result string passed into the ctor.");
}
[Test]
public void TargetPageMayBeRuntimeExpression()
{
Result result = new Result("%{['var1']}");
string resultUri = result.GetRedirectUri( MakeDictionary("var1", "val1") );
Assert.AreEqual( "val1", resultUri );
}
[Test]
public void ParameterKeysAndValuesMayBeRuntimeExpression()
{
Result result = new Result("redirect:%{['var1']}?%{['var2']}=%{['var3']}");
string resultUri = result.GetRedirectUri( MakeDictionary("var1", "val1", "var2", "val2", "var3", "val3") );
Assert.AreEqual( "val1?val2=val3", resultUri );
}
private IDictionary MakeDictionary( params object[] args)
{
AssertUtils.IsTrue(args.Length % 2 == 0);
Hashtable ht= new Hashtable();
for(int i=0;i<args.Length;i+=2)
{
ht[args[i]] = args[i+1];
}
return ht;
}
}
}

View File

@@ -97,7 +97,7 @@ namespace Spring.Web.UI
}
catch(ArgumentException ae)
{
string expected = string.Format("No URL mapping found for the specified result '{0}'.", RESULTNAME);
string expected = string.Format("No result mapping found for the specified name '{0}'.", RESULTNAME);
string msg = ae.Message.Substring(0, expected.Length);
Assert.AreEqual(expected, msg);
}

View File

@@ -41,19 +41,39 @@ namespace Spring.Web.UI
{
public class TestUserControl : UserControl
{
private static int instanceCount = 0;
public TestUserControl()
:this(string.Format("_ctl_{0}", instanceCount++), null)
{
}
public TestUserControl(string id)
:this(id, null)
{
}
public TestUserControl(Control parent)
:this(null, parent)
{
parent.Controls.Add(this);
}
public TestUserControl(string id, Control parent)
{
this.ID = id;
if (parent != null) parent.Controls.Add(this);
}
public new void SetResult(string name)
{
base.SetResult(name);
}
public override string ToString()
{
return string.Format("{0}[{1}]", base.ToString(), this.ClientID);
}
}
[Test]
@@ -85,7 +105,8 @@ namespace Spring.Web.UI
using (mocks.Ordered())
{
theResult.Navigate(c1);
// context is the control, that SetResult() was called on
theResult.Navigate(c111);
}
mocks.ReplayAll();