From 2f5e5c701f3db74e12e0b72793664b61bff0f42b Mon Sep 17 00:00:00 2001 From: eeichinger Date: Mon, 22 Sep 2008 17:10:59 +0000 Subject: [PATCH] SPRNET-1038 added missing validation to SpringAir "SuggestedFlights" view --- BreakingChanges-1.2.txt | 2 + .../Web/BookTrip/SuggestedFlights.aspx | 6 +- .../Web/BookTrip/SuggestedFlights.aspx.cs | 42 +- .../DataBinding/AbstractBinding.cs | 414 ++++++++------ .../DataBinding/AbstractSimpleBinding.cs | 476 ++++++++-------- .../DataBinding/BaseBindingContainer.cs | 520 +++++++++--------- .../DataBinding/BindingErrorMessage.cs | 112 ++++ .../Spring.Core/Spring.Core.2003.csproj | 14 + .../Spring.Core/Spring.Core.2005.csproj | 1 + .../Spring.Core/Spring.Core.2008.csproj | 3 +- .../Spring.Core/Validation/ErrorMessage.cs | 43 +- .../DataBinding/BaseBindingManagerTests.cs | 19 +- .../Web/UI/Controls/ValidationErrorTests.cs | 118 ---- 13 files changed, 935 insertions(+), 835 deletions(-) create mode 100644 src/Spring/Spring.Core/DataBinding/BindingErrorMessage.cs delete mode 100644 test/Spring/Spring.Web.Tests/Web/UI/Controls/ValidationErrorTests.cs diff --git a/BreakingChanges-1.2.txt b/BreakingChanges-1.2.txt index 97e182c4..f95d052b 100644 --- a/BreakingChanges-1.2.txt +++ b/BreakingChanges-1.2.txt @@ -9,6 +9,8 @@ Spring.Core 3. Removed getter property of IResourceLoader in IResourceLoaderAware +4. AbstractBinding.IsValid property changed to method AbstractBinding.IsValid( IValidationErrors ) + Spring.Services --------------- 1. Removed WebServiceProxyFactory.ClientProtocolType property (obsolete) diff --git a/examples/Spring/SpringAir/src/SpringAir.Web.2005/Web/BookTrip/SuggestedFlights.aspx b/examples/Spring/SpringAir/src/SpringAir.Web.2005/Web/BookTrip/SuggestedFlights.aspx index 4e057dbc..e3b45913 100644 --- a/examples/Spring/SpringAir/src/SpringAir.Web.2005/Web/BookTrip/SuggestedFlights.aspx +++ b/examples/Spring/SpringAir/src/SpringAir.Web.2005/Web/BookTrip/SuggestedFlights.aspx @@ -3,10 +3,12 @@

-

- +
+ + +
 
diff --git a/examples/Spring/SpringAir/src/SpringAir.Web.2005/Web/BookTrip/SuggestedFlights.aspx.cs b/examples/Spring/SpringAir/src/SpringAir.Web.2005/Web/BookTrip/SuggestedFlights.aspx.cs index 5185d5a5..7c8b77d4 100644 --- a/examples/Spring/SpringAir/src/SpringAir.Web.2005/Web/BookTrip/SuggestedFlights.aspx.cs +++ b/examples/Spring/SpringAir/src/SpringAir.Web.2005/Web/BookTrip/SuggestedFlights.aspx.cs @@ -82,9 +82,9 @@ public partial class SuggestedFlights : Page protected override void LoadModel(object savedModel) { IDictionary model = (IDictionary)savedModel; - flights = (FlightSuggestions) model["flights"]; - outboundFlightIndex = (int) model["outboundFlightIndex"]; - returnFlightIndex = (int) model["returnFlightIndex"]; + flights = (FlightSuggestions)model["flights"]; + outboundFlightIndex = (int)model["outboundFlightIndex"]; + returnFlightIndex = (int)model["returnFlightIndex"]; } protected override object SaveModel() @@ -103,12 +103,12 @@ public partial class SuggestedFlights : Page } #endregion - + #region Page Lifecycle Methods - protected override void OnInitializeControls(EventArgs e) + protected override void OnLoad(EventArgs e) { - base.OnInitializeControls(e); + base.OnLoad(e); if (!IsPostBack) { @@ -142,13 +142,24 @@ public partial class SuggestedFlights : Page protected void BookFlights(object sender, EventArgs e) { - FlightCollection flightsToBook = GetFlightsToBook(); - Itinerary itinerary = new Itinerary(flightsToBook); - // TODO: forward to next logical page and get user details... - ReservationConfirmation confirmation = bookingAgent.Book( - new Reservation(new Passenger(1, "Aleksandar", "Seovic"), itinerary)); - Session[Constants.ReservationConfirmationKey] = confirmation; - SetResult(ReservationConfirmed); + if ((flights.HasOutboundFlights && !HasOutboundFlight)) + { + this.ValidationErrors.AddError("summary", new ErrorMessage("error.outboundFlight.required")); + } + if ((flights.HasReturnFlights && !HasReturnFlight)) + { + this.ValidationErrors.AddError("summary", new ErrorMessage("error.returnFlight.required")); + } + if (this.ValidationErrors.IsEmpty) + { + FlightCollection flightsToBook = GetFlightsToBook(); + Itinerary itinerary = new Itinerary(flightsToBook); + // TODO: forward to next logical page and get user details... + ReservationConfirmation confirmation = bookingAgent.Book( + new Reservation(new Passenger(1, "Aleksandar", "Seovic"), itinerary)); + Session[Constants.ReservationConfirmationKey] = confirmation; + SetResult(ReservationConfirmed); + } } private FlightCollection GetFlightsToBook() @@ -169,5 +180,10 @@ public partial class SuggestedFlights : Page get { return this.returnFlightIndex != NoFlightSelected; } } + private bool HasOutboundFlight + { + get { return this.outboundFlightIndex != NoFlightSelected; } + } + #endregion } \ No newline at end of file diff --git a/src/Spring/Spring.Core/DataBinding/AbstractBinding.cs b/src/Spring/Spring.Core/DataBinding/AbstractBinding.cs index c36e3316..4ab51109 100644 --- a/src/Spring/Spring.Core/DataBinding/AbstractBinding.cs +++ b/src/Spring/Spring.Core/DataBinding/AbstractBinding.cs @@ -1,180 +1,236 @@ -using System; -using System.Collections; -using Spring.Threading; -using Spring.Util; -using Spring.Validation; - -namespace Spring.DataBinding -{ - /// - /// Abstract base class for implementations. - /// - /// Aleksandar Seovic - public abstract class AbstractBinding : IBinding - { - #region Fields - - // each Binding instance needs its own ID - private readonly string BINDING_ID = Guid.NewGuid().ToString("N"); - - private BindingDirection direction = BindingDirection.Bidirectional; - private ErrorMessage errorMessage; - private string[] errorProviders; - - #endregion - - #region Properties - - /// - /// Gets or sets a flag specifying whether this binding is valid. - /// - /// - /// true if this binding evaluated without errors; - /// false otherwise. - /// - public bool IsValid - { - get - { - object val = LogicalThreadContext.GetData(GetIsValidKey()); - return val == null || (bool)val; - } - set - { - LogicalThreadContext.SetData(GetIsValidKey(), value); - } - } - - /// - /// Gets or sets the . - /// - /// The binding direction. - public BindingDirection Direction - { - get { return direction; } - set { direction = value; } - } - - /// - /// Gets the error message. - /// - /// The error message. - public ErrorMessage ErrorMessage - { - get { return errorMessage; } - } - - /// - /// Gets the error providers. - /// - public string[] ErrorProviders - { - get { return errorProviders; } - } - - #endregion - - #region IBinding Implementation - - /// - /// Binds source object to target object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - public void BindSourceToTarget(object source, object target, IValidationErrors validationErrors) - { - BindSourceToTarget(source, target, validationErrors, null); - } - - /// - /// Binds target object to source object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - public void BindTargetToSource(object source, object target, IValidationErrors validationErrors) - { - BindTargetToSource(source, target, validationErrors, null); - } - - /// - /// Binds source object to target object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public abstract void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, IDictionary variables); - - /// - /// Binds target object to source object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public abstract void BindTargetToSource(object source, object target, IValidationErrors validationErrors, IDictionary variables); - - /// - /// Sets error message that should be displayed in the case - /// of a non-fatal binding error. - /// - /// - /// Resource ID of the error message. - /// - /// - /// List of error providers message should be added to. - /// - public void SetErrorMessage(string messageId, params string[] errorProviders) - { - AssertUtils.ArgumentHasText(messageId, "messageId"); - if (errorProviders == null || errorProviders.Length == 0) - { - throw new ArgumentException("At least one error provider has to be specified.", "providers"); - } - - this.errorMessage = new ErrorMessage(messageId, null); - this.errorProviders = errorProviders; - } - - #endregion - - #region Private Methods - - private string GetIsValidKey() - { - return "Binding." + BINDING_ID + ".IsValid"; - } - - #endregion - } +using System; +using System.Collections; +using Spring.Collections; +using Spring.Util; +using Spring.Validation; + +namespace Spring.DataBinding +{ + /// + /// Abstract base class for implementations. + /// + /// Aleksandar Seovic + public abstract class AbstractBinding : IBinding + { + #region Fields + + /// + /// The name of the always filled error provider + /// + public static readonly string ALL_BINDINGERRORS_PROVIDER = "__all_bindingerrors"; + + // each Binding instance needs its own ID + private readonly string BINDING_ID = Guid.NewGuid().ToString("N"); + + private BindingDirection direction = BindingDirection.Bidirectional; + private BindingErrorMessage errorMessage; + private string[] errorProviders; + + #endregion + + #region Properties + + /// + /// Gets or sets a flag specifying whether this binding is valid. + /// + /// + /// true if this binding evaluated without errors; + /// false otherwise. + /// + public bool IsValid(IValidationErrors errors) + { + if (errors == null) return true; + + IList errorList = errors.GetErrors(ALL_BINDINGERRORS_PROVIDER); + return (errorList == null) || (!errorList.Contains(this.ErrorMessage)); + } + + /// + /// Marks this binding's state as invalid for this validationErrors collection. + /// Returns false if is null. + /// + /// + /// false, if validationErrors is null + protected bool SetInvalid(IValidationErrors validationErrors) + { + if (validationErrors != null) + { + foreach (string provider in this.ErrorProviders) + { + validationErrors.AddError(provider, this.ErrorMessage); + } + return true; + } + return false; + } + + /// + /// Gets the unique ID of this binding instance. + /// + public string Id + { + get { return BINDING_ID; } + } + + /// + /// Gets or sets the . + /// + /// The binding direction. + public BindingDirection Direction + { + get { return direction; } + set { direction = value; } + } + + /// + /// Gets the error message. + /// + /// The error message. + public BindingErrorMessage ErrorMessage + { + get { return errorMessage; } + } + + /// + /// Gets the error providers. + /// + public string[] ErrorProviders + { + get { return errorProviders; } + } + + #endregion + + /// + /// Initializes a new instance of the class. + /// + protected AbstractBinding() + { + this.errorMessage = new BindingErrorMessage( this.Id, "Binding-Error"); + this.errorProviders = new string[] { ALL_BINDINGERRORS_PROVIDER }; + } + + #region IBinding Implementation + + /// + /// Binds source object to target object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + public virtual void BindSourceToTarget(object source, object target, IValidationErrors validationErrors) + { + BindSourceToTarget(source, target, validationErrors, null); + } + + /// + /// Binds target object to source object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + public virtual void BindTargetToSource(object source, object target, IValidationErrors validationErrors) + { + BindTargetToSource(source, target, validationErrors, null); + } + + /// + /// Binds source object to target object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public abstract void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, IDictionary variables); + + /// + /// Binds target object to source object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public abstract void BindTargetToSource(object source, object target, IValidationErrors validationErrors, IDictionary variables); + + /// + /// Sets error message that should be displayed in the case + /// of a non-fatal binding error. + /// + /// + /// Resource ID of the error message. + /// + /// + /// List of error providers message should be added to. + /// + public void SetErrorMessage(string messageId, params string[] errorProviders) + { + AssertUtils.ArgumentHasText(messageId, "messageId"); + if (errorProviders == null || errorProviders.Length == 0) + { + throw new ArgumentException("At least one error provider has to be specified.", "providers"); + } + + this.errorMessage = new BindingErrorMessage(this.BINDING_ID, messageId, null); + Set providers = new HashedSet(); + providers.Add(ALL_BINDINGERRORS_PROVIDER); + providers.AddAll(errorProviders); + errorProviders = new string[providers.Count]; + providers.CopyTo(errorProviders, 0); + this.errorProviders = errorProviders; + } + + #endregion + + /// + ///Determines whether the specified is equal to the current . + /// + /// + ///true if the specified is equal to the current ; otherwise, false. + /// + ///The to compare with the current . 2 + public override bool Equals(object obj) + { + AbstractBinding other = obj as AbstractBinding; + return (other != null) && (this.Id == other.Id); + } + + /// + ///Serves as a hash function for a particular type. is suitable for use in hashing algorithms and data structures like a hash table. + /// + /// + ///A hash code for the current . + /// + public override int GetHashCode() + { + return this.Id.GetHashCode(); + } + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/DataBinding/AbstractSimpleBinding.cs b/src/Spring/Spring.Core/DataBinding/AbstractSimpleBinding.cs index f6a215a4..e3a02573 100644 --- a/src/Spring/Spring.Core/DataBinding/AbstractSimpleBinding.cs +++ b/src/Spring/Spring.Core/DataBinding/AbstractSimpleBinding.cs @@ -1,252 +1,226 @@ -using System; -using System.Collections; -using Spring.Globalization; -using Spring.Validation; - -namespace Spring.DataBinding -{ - /// - /// Abstract base class for simple, one-to-one implementations. - /// - /// Aleksandar Seovic - public abstract class AbstractSimpleBinding : AbstractBinding - { - #region Fields - - private IFormatter formatter; - - #endregion - - #region Constructor(s) - - /// - /// Initialize a new instance of without any - /// - protected AbstractSimpleBinding() - { - } - - /// - /// Initialize a new instance of with the - /// specified . - /// - protected AbstractSimpleBinding(IFormatter formatter) - { - this.formatter = formatter; - } - - #endregion - - #region Properties - - /// - /// Gets or sets the to use. - /// - /// The formatter to use. - public IFormatter Formatter - { - get { return formatter; } - set { formatter = value; } - } - - #endregion - - #region IBinding Implementation - - /// - /// Binds source object to target object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public override void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, - IDictionary variables) - { - if (this.IsValid - && - (this.Direction == BindingDirection.Bidirectional || this.Direction == BindingDirection.SourceToTarget)) - { - try - { - DoBindSourceToTarget(source, target, variables); - this.IsValid = true; - } - catch (Exception) - { - this.IsValid = false; - if (this.ErrorMessage != null && validationErrors != null) - { - foreach (string provider in this.ErrorProviders) - { - validationErrors.AddError(provider, this.ErrorMessage); - } - } - else - { - throw; - } - } - } - } - - /// - /// Concrete implementation if source to target binding. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Variables that should be used during expression evaluation. - /// - protected virtual void DoBindSourceToTarget(object source, object target, IDictionary variables) - { - object value = this.GetSourceValue(source, variables); - if (this.Formatter != null && value is string) - { - value = this.Formatter.Parse((string) value); - } - this.SetTargetValue(target, value, variables); - } - - /// - /// Binds target object to source object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public override void BindTargetToSource(object source, object target, IValidationErrors validationErrors, - IDictionary variables) - { - if (this.IsValid - && - (this.Direction == BindingDirection.Bidirectional || this.Direction == BindingDirection.TargetToSource)) - { - try - { - DoBindTargetToSource(source, target, variables); - this.IsValid = true; - } - catch (Exception) - { - this.IsValid = false; - if (this.ErrorMessage != null && validationErrors != null) - { - foreach (string provider in this.ErrorProviders) - { - validationErrors.AddError(provider, this.ErrorMessage); - } - } - else - { - throw; - } - } - } - } - - /// - /// Concrete implementation of target to source binding. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Variables that should be used during expression evaluation. - /// - protected virtual void DoBindTargetToSource(object source, object target, IDictionary variables) - { - object value = this.GetTargetValue(target, variables); - if (this.Formatter != null) - { - value = this.Formatter.Format(value); - } - this.SetSourceValue(source, value, variables); - } - - #endregion - - #region Abstract Methods - - /// - /// Gets the source value for the binding. - /// - /// - /// Source object to extract value from. - /// - /// - /// Variables for expression evaluation. - /// - /// - /// The source value for the binding. - /// - protected abstract object GetSourceValue(object source, IDictionary variables); - - /// - /// Sets the source value for the binding. - /// - /// - /// The source object to set the value on. - /// - /// - /// The value to set. - /// - /// - /// Variables for expression evaluation. - /// - protected abstract void SetSourceValue(object source, object value, IDictionary variables); - - /// - /// Gets the target value for the binding. - /// - /// - /// Source object to extract value from. - /// - /// - /// Variables for expression evaluation. - /// - /// - /// The target value for the binding. - /// - protected abstract object GetTargetValue(object target, IDictionary variables); - - /// - /// Sets the target value for the binding. - /// - /// - /// The target object to set the value on. - /// - /// - /// The value to set. - /// - /// - /// Variables for expression evaluation. - /// - protected abstract void SetTargetValue(object target, object value, IDictionary variables); - - #endregion - } +using System; +using System.Collections; +using Spring.Globalization; +using Spring.Validation; + +namespace Spring.DataBinding +{ + /// + /// Abstract base class for simple, one-to-one implementations. + /// + /// Aleksandar Seovic + public abstract class AbstractSimpleBinding : AbstractBinding + { + #region Fields + + private IFormatter formatter; + + #endregion + + #region Constructor(s) + + /// + /// Initialize a new instance of without any + /// + protected AbstractSimpleBinding() + { + } + + /// + /// Initialize a new instance of with the + /// specified . + /// + protected AbstractSimpleBinding(IFormatter formatter) + { + this.formatter = formatter; + } + + #endregion + + #region Properties + + /// + /// Gets or sets the to use. + /// + /// The formatter to use. + public IFormatter Formatter + { + get { return formatter; } + set { formatter = value; } + } + + #endregion + + #region IBinding Implementation + + /// + /// Binds source object to target object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public override void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, + IDictionary variables) + { + if (this.IsValid(validationErrors) + && (this.Direction == BindingDirection.Bidirectional || this.Direction == BindingDirection.SourceToTarget)) + { + try + { + DoBindSourceToTarget(source, target, variables); + } + catch (Exception) + { + if (!SetInvalid(validationErrors)) throw; + } + } + } + + /// + /// Concrete implementation if source to target binding. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Variables that should be used during expression evaluation. + /// + protected virtual void DoBindSourceToTarget(object source, object target, IDictionary variables) + { + object value = this.GetSourceValue(source, variables); + if (this.Formatter != null && value is string) + { + value = this.Formatter.Parse((string)value); + } + this.SetTargetValue(target, value, variables); + } + + /// + /// Binds target object to source object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public override void BindTargetToSource(object source, object target, IValidationErrors validationErrors, + IDictionary variables) + { + if (this.IsValid(validationErrors) + && (this.Direction == BindingDirection.Bidirectional || this.Direction == BindingDirection.TargetToSource)) + { + try + { + DoBindTargetToSource(source, target, variables); + } + catch (Exception) + { + if (!SetInvalid(validationErrors)) throw; + } + } + } + + /// + /// Concrete implementation of target to source binding. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Variables that should be used during expression evaluation. + /// + protected virtual void DoBindTargetToSource(object source, object target, IDictionary variables) + { + object value = this.GetTargetValue(target, variables); + if (this.Formatter != null) + { + value = this.Formatter.Format(value); + } + this.SetSourceValue(source, value, variables); + } + + #endregion + + #region Abstract Methods + + /// + /// Gets the source value for the binding. + /// + /// + /// Source object to extract value from. + /// + /// + /// Variables for expression evaluation. + /// + /// + /// The source value for the binding. + /// + protected abstract object GetSourceValue(object source, IDictionary variables); + + /// + /// Sets the source value for the binding. + /// + /// + /// The source object to set the value on. + /// + /// + /// The value to set. + /// + /// + /// Variables for expression evaluation. + /// + protected abstract void SetSourceValue(object source, object value, IDictionary variables); + + /// + /// Gets the target value for the binding. + /// + /// + /// Source object to extract value from. + /// + /// + /// Variables for expression evaluation. + /// + /// + /// The target value for the binding. + /// + protected abstract object GetTargetValue(object target, IDictionary variables); + + /// + /// Sets the target value for the binding. + /// + /// + /// The target object to set the value on. + /// + /// + /// The value to set. + /// + /// + /// Variables for expression evaluation. + /// + protected abstract void SetTargetValue(object target, object value, IDictionary variables); + + #endregion + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/DataBinding/BaseBindingContainer.cs b/src/Spring/Spring.Core/DataBinding/BaseBindingContainer.cs index 1a4f20ca..6f337f19 100644 --- a/src/Spring/Spring.Core/DataBinding/BaseBindingContainer.cs +++ b/src/Spring/Spring.Core/DataBinding/BaseBindingContainer.cs @@ -1,261 +1,261 @@ -using System.Collections; -using Spring.Globalization; -using Spring.Validation; - -namespace Spring.DataBinding -{ - /// - /// Base implementation of the . - /// - /// Aleksandar Seovic - public class BaseBindingContainer : IBindingContainer - { - #region Fields - - private IList bindings = new ArrayList(); - - #endregion - - #region Constructor(s) - - /// - /// Creates a new instance of . - /// - public BaseBindingContainer() - {} - - #endregion - - #region Properties - - /// - /// Gets a list of bindings for this container. - /// - /// - /// A list of bindings for this container. - /// - protected IList Bindings - { - get { return bindings; } - } - - #endregion - - #region IBindingContainer Implementation - - /// - /// Gets a value indicating whether this instance has bindings. - /// - /// - /// true if this instance has bindings; otherwise, false. - /// - public bool HasBindings - { - get { return bindings.Count > 0; } - } - - /// - /// Adds the binding. - /// - /// - /// Binding definition to add. - /// - /// - /// Added instance. - /// - public IBinding AddBinding(IBinding binding) - { - bindings.Add(binding); - return binding; - } - - /// - /// Adds the binding with a default - /// binding direction of . - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - /// - /// Added instance. - /// - public IBinding AddBinding(string sourceExpression, string targetExpression) - { - return AddBinding(sourceExpression, targetExpression, BindingDirection.Bidirectional, null); - } - - /// - /// Adds the binding. - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - /// - /// Binding direction. - /// - /// - /// Added instance. - /// - public IBinding AddBinding(string sourceExpression, string targetExpression, BindingDirection direction) - { - return AddBinding(sourceExpression, targetExpression, direction, null); - } - - /// - /// Adds the binding with a default - /// binding direction of . - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - /// - /// to use for value formatting and parsing. - /// - /// - /// Added instance. - /// - public IBinding AddBinding(string sourceExpression, string targetExpression, IFormatter formatter) - { - return AddBinding(sourceExpression, targetExpression, BindingDirection.Bidirectional, formatter); - } - - /// - /// Adds the binding. - /// - /// - /// The source expression. - /// - /// - /// The target expression. - /// - /// - /// Binding direction. - /// - /// - /// to use for value formatting and parsing. - /// - /// - /// Added instance. - /// - public virtual IBinding AddBinding(string sourceExpression, string targetExpression, - BindingDirection direction, IFormatter formatter) - { - SimpleExpressionBinding binding = new SimpleExpressionBinding(sourceExpression, targetExpression); - binding.Direction = direction; - binding.Formatter = formatter; - bindings.Add(binding); - - return binding; - } - - #endregion - - #region IBinding Implementation - - /// - /// Binds source object to target object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - public void BindSourceToTarget(object source, object target, IValidationErrors validationErrors) - { - BindSourceToTarget(source, target, validationErrors, null); - } - - /// - /// Binds source object to target object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public virtual void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, - IDictionary variables) - { - foreach (IBinding binding in bindings) - { - binding.BindSourceToTarget(source, target, validationErrors); - } - } - - /// - /// Binds target object to source object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - public void BindTargetToSource(object source, object target, IValidationErrors validationErrors) - { - BindTargetToSource(source, target, validationErrors, null); - } - - /// - /// Binds target object to source object. - /// - /// - /// The source object. - /// - /// - /// The target object. - /// - /// - /// Validation errors collection that type conversion errors should be added to. - /// - /// - /// Variables that should be used during expression evaluation. - /// - public virtual void BindTargetToSource(object source, object target, IValidationErrors validationErrors, - IDictionary variables) - { - foreach (IBinding binding in bindings) - { - binding.BindTargetToSource(source, target, validationErrors); - } - } - - /// - /// Sets error message that should be displayed in the case - /// of a non-fatal binding error. - /// - /// - /// Resource ID of the error message. - /// - /// - /// List of error providers message should be added to. - /// - public virtual void SetErrorMessage(string messageId, params string[] errorProviders) - {} - - #endregion - } +using System.Collections; +using Spring.Globalization; +using Spring.Validation; + +namespace Spring.DataBinding +{ + /// + /// Base implementation of the . + /// + /// Aleksandar Seovic + public class BaseBindingContainer : IBindingContainer + { + #region Fields + + private IList bindings = new ArrayList(); + + #endregion + + #region Constructor(s) + + /// + /// Creates a new instance of . + /// + public BaseBindingContainer() + { } + + #endregion + + #region Properties + + /// + /// Gets a list of bindings for this container. + /// + /// + /// A list of bindings for this container. + /// + protected IList Bindings + { + get { return bindings; } + } + + #endregion + + #region IBindingContainer Implementation + + /// + /// Gets a value indicating whether this instance has bindings. + /// + /// + /// true if this instance has bindings; otherwise, false. + /// + public bool HasBindings + { + get { return bindings.Count > 0; } + } + + /// + /// Adds the binding. + /// + /// + /// Binding definition to add. + /// + /// + /// Added instance. + /// + public IBinding AddBinding(IBinding binding) + { + bindings.Add(binding); + return binding; + } + + /// + /// Adds the binding with a default + /// binding direction of . + /// + /// + /// The source expression. + /// + /// + /// The target expression. + /// + /// + /// Added instance. + /// + public IBinding AddBinding(string sourceExpression, string targetExpression) + { + return AddBinding(sourceExpression, targetExpression, BindingDirection.Bidirectional, null); + } + + /// + /// Adds the binding. + /// + /// + /// The source expression. + /// + /// + /// The target expression. + /// + /// + /// Binding direction. + /// + /// + /// Added instance. + /// + public IBinding AddBinding(string sourceExpression, string targetExpression, BindingDirection direction) + { + return AddBinding(sourceExpression, targetExpression, direction, null); + } + + /// + /// Adds the binding with a default + /// binding direction of . + /// + /// + /// The source expression. + /// + /// + /// The target expression. + /// + /// + /// to use for value formatting and parsing. + /// + /// + /// Added instance. + /// + public IBinding AddBinding(string sourceExpression, string targetExpression, IFormatter formatter) + { + return AddBinding(sourceExpression, targetExpression, BindingDirection.Bidirectional, formatter); + } + + /// + /// Adds the binding. + /// + /// + /// The source expression. + /// + /// + /// The target expression. + /// + /// + /// Binding direction. + /// + /// + /// to use for value formatting and parsing. + /// + /// + /// Added instance. + /// + public virtual IBinding AddBinding(string sourceExpression, string targetExpression, + BindingDirection direction, IFormatter formatter) + { + SimpleExpressionBinding binding = new SimpleExpressionBinding(sourceExpression, targetExpression); + binding.Direction = direction; + binding.Formatter = formatter; + bindings.Add(binding); + + return binding; + } + + #endregion + + #region IBinding Implementation + + /// + /// Binds source object to target object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + public virtual void BindSourceToTarget(object source, object target, IValidationErrors validationErrors) + { + BindSourceToTarget(source, target, validationErrors, null); + } + + /// + /// Binds source object to target object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public virtual void BindSourceToTarget(object source, object target, IValidationErrors validationErrors, + IDictionary variables) + { + foreach (IBinding binding in bindings) + { + binding.BindSourceToTarget(source, target, validationErrors); + } + } + + /// + /// Binds target object to source object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + public virtual void BindTargetToSource(object source, object target, IValidationErrors validationErrors) + { + BindTargetToSource(source, target, validationErrors, null); + } + + /// + /// Binds target object to source object. + /// + /// + /// The source object. + /// + /// + /// The target object. + /// + /// + /// Validation errors collection that type conversion errors should be added to. + /// + /// + /// Variables that should be used during expression evaluation. + /// + public virtual void BindTargetToSource(object source, object target, IValidationErrors validationErrors, + IDictionary variables) + { + foreach (IBinding binding in bindings) + { + binding.BindTargetToSource(source, target, validationErrors); + } + } + + /// + /// Implemented as a NOOP for containers. + /// of a non-fatal binding error. + /// + /// + /// Resource ID of the error message. + /// + /// + /// List of error providers message should be added to. + /// + public virtual void SetErrorMessage(string messageId, params string[] errorProviders) + { } + + #endregion + } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/DataBinding/BindingErrorMessage.cs b/src/Spring/Spring.Core/DataBinding/BindingErrorMessage.cs new file mode 100644 index 00000000..8c60f6ed --- /dev/null +++ b/src/Spring/Spring.Core/DataBinding/BindingErrorMessage.cs @@ -0,0 +1,112 @@ +#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 Spring.Util; +using Spring.Validation; + +#endregion + +namespace Spring.DataBinding +{ + /// + /// Represents an ErrorMessage specific to a binding instance. + /// + /// Erich Eichinger + [Serializable] + public class BindingErrorMessage : ErrorMessage + { + private string _bindingId; + + /// + /// Initializes a new instance of the class. + /// + /// the id of the binding this error message is associated with + /// the message id + /// optional parameters to this message + public BindingErrorMessage(string bindingId, string id, params object[] parameters) : base(id, parameters) + { + AssertUtils.ArgumentNotNull(bindingId, "bindingId"); + _bindingId = bindingId; + } + + /// + /// Get the ID of the binding this message instance relates to. + /// + public string BindingId + { + get { return _bindingId; } + } + + /// + /// Generates an object from its XML representation. + /// + /// + /// The stream + /// from which the object is deserialized. + /// + public override void ReadXml(System.Xml.XmlReader reader) + { + base.ReadXml(reader); + _bindingId = reader.GetAttribute("bindingId"); + } + + /// + /// Converts an object into its XML representation. + /// + /// + /// The stream + /// to which the object is serialized. + /// + public override void WriteXml(System.Xml.XmlWriter writer) + { + base.WriteXml(writer); + writer.WriteAttributeString("bindingId", _bindingId); + } + + /// + ///Determines whether the specified is equal to the current . + /// + /// + ///true if the specified is equal to the current ; otherwise, false. + /// + ///The to compare with the current . 2 + public override bool Equals(object obj) + { + BindingErrorMessage other = obj as BindingErrorMessage; + return (other != null) + && (this.BindingId == other.BindingId) + && (base.Equals(obj)); + } + + /// + ///Serves as a hash function for a particular type. is suitable for use in hashing algorithms and data structures like a hash table. + /// + /// + ///A hash code for the current . + /// + public override int GetHashCode() + { + return base.GetHashCode() + 31*this.BindingId.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Core/Spring.Core.2003.csproj b/src/Spring/Spring.Core/Spring.Core.2003.csproj index da583575..58a92d52 100644 --- a/src/Spring/Spring.Core/Spring.Core.2003.csproj +++ b/src/Spring/Spring.Core/Spring.Core.2003.csproj @@ -787,6 +787,11 @@ SubType = "Code" BuildAction = "Compile" /> + + + + diff --git a/src/Spring/Spring.Core/Spring.Core.2008.csproj b/src/Spring/Spring.Core/Spring.Core.2008.csproj index 6eb60ddb..605983ae 100644 --- a/src/Spring/Spring.Core/Spring.Core.2008.csproj +++ b/src/Spring/Spring.Core/Spring.Core.2008.csproj @@ -1,7 +1,7 @@  Local - 9.0.21022 + 9.0.30729 2.0 {710961A3-0DF4-49E4-A26E-F5B9C044AC84} Debug @@ -349,6 +349,7 @@ + diff --git a/src/Spring/Spring.Core/Validation/ErrorMessage.cs b/src/Spring/Spring.Core/Validation/ErrorMessage.cs index e9bd27f5..ee25e528 100644 --- a/src/Spring/Spring.Core/Validation/ErrorMessage.cs +++ b/src/Spring/Spring.Core/Validation/ErrorMessage.cs @@ -57,6 +57,16 @@ namespace Spring.Validation this.parameters = parameters; } + /// + /// Initializes a new instance of the class copying values from another instance. + /// + /// Another Error message instance to copy values from. + protected ErrorMessage(ErrorMessage other) + { + this.id = other.id; + this.parameters = other.parameters; + } + #endregion #region Properties @@ -110,7 +120,7 @@ namespace Spring.Validation /// The stream /// from which the object is deserialized. /// - public void ReadXml(XmlReader reader) + public virtual void ReadXml(XmlReader reader) { id = reader.GetAttribute("Id"); if (!reader.IsEmptyElement) @@ -131,9 +141,9 @@ namespace Spring.Validation /// The stream /// to which the object is serialized. /// - public void WriteXml(XmlWriter writer) + public virtual void WriteXml(XmlWriter writer) { - writer.WriteAttributeString("Id", id.ToString()); + writer.WriteAttributeString("Id", id); if (parameters != null) { @@ -168,7 +178,32 @@ namespace Spring.Validation } #endregion - + + /// + ///Determines whether the specified is equal to the current . + /// + /// + ///true if the specified is equal to the current ; otherwise, false. + /// + ///The to compare with the current . 2 + public override bool Equals(object obj) + { + ErrorMessage other = obj as ErrorMessage; + return (other != null) + && (this.id == other.Id); + } + + /// + ///Serves as a hash function for a particular type. is suitable for use in hashing algorithms and data structures like a hash table. + /// + /// + ///A hash code for the current . + /// + public override int GetHashCode() + { + return id.GetHashCode(); + } + #region Data members private string id; diff --git a/test/Spring/Spring.Core.Tests/DataBinding/BaseBindingManagerTests.cs b/test/Spring/Spring.Core.Tests/DataBinding/BaseBindingManagerTests.cs index 3eebc25c..3a7f2319 100644 --- a/test/Spring/Spring.Core.Tests/DataBinding/BaseBindingManagerTests.cs +++ b/test/Spring/Spring.Core.Tests/DataBinding/BaseBindingManagerTests.cs @@ -187,9 +187,9 @@ namespace Spring.DataBinding catch (TypeMismatchException) {} - // make sure that the old value doesn't override current invalid value + // binding state is not remembered with ValidationErrors=null! dbm.BindTargetToSource(source, target, null); - Assert.AreEqual(false, source["boolValue"]); + Assert.AreEqual(target.DOB, source["boolValue"]); } [Test] @@ -209,9 +209,14 @@ namespace Spring.DataBinding catch (TypeMismatchException) {} - // make sure that the old value doesn't override current invalid value - dbm.BindSourceToTarget(st, st, null); - Assert.AreEqual(new DateTime(1856, 7, 9), st.DOB); + // binding state is not remembered with ValidationErrors=null! + try + { + dbm.BindSourceToTarget(st, st, null); + Assert.Fail("Binding custom Place to date type should throw an exception."); + } + catch (TypeMismatchException) + {} } [Test] @@ -228,7 +233,7 @@ namespace Spring.DataBinding dbm.AddBinding(binding); dbm.BindSourceToTarget(source, target, errors); - Assert.IsFalse(binding.IsValid); + Assert.IsFalse(binding.IsValid(errors)); Assert.IsFalse(errors.IsEmpty); Assert.AreEqual(1, errors.GetErrors("errors").Count); @@ -250,7 +255,7 @@ namespace Spring.DataBinding dbm.AddBinding(binding); dbm.BindTargetToSource(st, st, errors); - Assert.IsFalse(binding.IsValid); + Assert.IsFalse(binding.IsValid(errors)); Assert.IsFalse(errors.IsEmpty); Assert.AreEqual(1, errors.GetErrors("errors").Count); diff --git a/test/Spring/Spring.Web.Tests/Web/UI/Controls/ValidationErrorTests.cs b/test/Spring/Spring.Web.Tests/Web/UI/Controls/ValidationErrorTests.cs deleted file mode 100644 index c68393b0..00000000 --- a/test/Spring/Spring.Web.Tests/Web/UI/Controls/ValidationErrorTests.cs +++ /dev/null @@ -1,118 +0,0 @@ -#region License - -/* - * Copyright © 2002-2007 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.Web; -using System.Web.UI; -using System.Web.UI.HtmlControls; -using Spring.Util; - -#endregion - -namespace Spring.Web.UI.Controls -{ - /// - /// This control allows for suppressing output of the 'action' attribute. - /// - /// - /// the 'action' attribute rendered by the default control causes troubles - /// in case of URL-rewriting. See e.g. 'thescripts.com' forum - /// and also JIRA SPRNET-560 for more info. - /// - /// Erich Eichinger - /// $Id: ValidationErrorTests.cs,v 1.1 2008/03/19 12:07:15 oakinger Exp $ - public class ValidationErrorTests : HtmlForm - { - private bool suppressAction = false; - private string action = null; - - /// - /// Sets or Gets a value indicating if the 'action' attribute shall be rendered. Defaults to 'false' - /// - /// - /// The following possibilites are available: - /// - /// If is 'true', rendering of the 'action' attribute is suppressed. - /// If is 'false' and is not set, - /// 'action' attribute will.be rendered to - /// - /// If is 'false' and is set, - /// 'action' attribute will.be rendered to - /// - /// - /// - public bool SuppressAction - { - get { return this.suppressAction; } - set { this.suppressAction = value; } - } - - /// - /// Sets or Gets an explicit url to be rendered - /// - /// - /// The url specified here is only rendered, if is true. - /// - public string Action - { - get { return this.action; } - set { this.action = value; } - } - - /// - /// Renders attributes but performs 'action' suppressing logic. - /// - /// - protected override void RenderAttributes(HtmlTextWriter writer) - { - base.RenderAttributes(new ActionSupressingHtmlTextWriter(writer)); - if (!this.suppressAction) - { - string url = (StringUtils.HasText(this.action)) ? this.action : Context.Request.RawUrl; - writer.WriteAttribute("action", url, true); - } - } - - #region Nested type: ActionSupressingHtmlTextWriter - - /// - /// This wrapper suppresses output of 'action' attributes. - /// - private class ActionSupressingHtmlTextWriter : HtmlTextWriter - { - public ActionSupressingHtmlTextWriter(HtmlTextWriter wrappedWriter) - : base(wrappedWriter.InnerWriter) - { - } - - public override void WriteAttribute(string name, string value, bool fEncode) - { - if (string.Compare(name, "action", true) != 0) - { - base.WriteAttribute(name, value, fEncode); - } - } - } - - #endregion - } -} \ No newline at end of file