Introduction
ValidationScope
is used to collect all input errors in a context although validation code exists in independent APIs. We don't need to return error messages and throw exceptions explicitly. It like transaction context is managed by TransactionScope
and we don't need to transmit transaction instances. It's thread safe.
ValidationScope
implements the interface IDisposable
that we can initialize a scope by using block. And in a block, you can add errors into the scope that the using block disposal throws an exception with all added errors if there is one. And ValidationScope
supports nest. A validation scope and its nested scopes share the same validation context so that it is possible to write independent APIs with great coordination on validation.
Background
ValidationScope
is included in CommonLibrary
of RapidWebDev
. RapidWebDev
is an infrastructure that helps engineers to develop enterprise software solutions in Microsoft .NET easily and productively. It consists of an extendable and maintainable web system architecture with a suite of generic business model, APIs and services as fundamental functionalities needed in development for almost all business solutions. So when engineers develop solutions in RapidWebDev, they can have a lot of reusable and ready things, then they can focus more on business logics implementation. In practice, we can save more than 50% time on developing a high quality and performance business solution than traditional ASP.NET development.
Source Code
The source code of the implementation, sample and test cases can be found in RapidWebDev source package which you can download from the official website.
Using the Code
- Project:
RapidWebDev.Common
- Namespace:
RapidWebDev.Common.Validation
There are four constructors for ValidationScope
:
ValidationScope()
ValidationScope(Type thrownExceptionType)
ValidationScope(bool forceToThrowExceptionIfHasErrorsWhenDisposing)
ValidationScope(bool forceToThrowExceptionIfHasErrorsWhenDisposing, Type thrownExceptionType)
Parameters:
thrownExceptionType
is to specify type of exceptions which are thrown in disposal if there are errors logged. By default, BaoJianSoft.Common.Validation.ValidationException
is thrown.forceToThrowExceptionIfHasErrorsWhenDisposing
is True
to indicate that the disposal for nested validation scope throws an exception directly if there are errors. The ancestor validation scope catches and integrates all errors from its nested scope with it equals to False
.
A simple sample using ValidationScope
is as below. An InvalidOperationException
instance with 2 error messages is thrown in disposal of this using
block. If you don't specify typeof(InvalidOperationException)
explicitly, a ValidationException
instance is thrown instead.
using (ValidationScope scope = new ValidationScope(typeof(InvalidOperationException)))
{
if (true)
scope.Error("Name cannot be empty!");
if (true)
scope.Error("Password cannot be empty!");
}
A nested validation scope sample is as follows. You can imagine that the NestedMethod1
and NestedMethod2
are from independent APIs. The ancestor scope disposal throws a validation exception with all 5 error messages in this case. But if you construct the first nested validation scope using 3rd/4th constructor with forceToThrowExceptionIfHasErrorsWhenDisposing
to True
, the thrown exception only contains the top 3 error messages.
public void NestedValidationScopeTest()
{
using (ValidationScope scope = new ValidationScope())
{
scope.Error("Error 1");
NestedMethod1();
NestedMethod2();
}
}
private void NestedMethod1()
{
using (ValidationScope scope = new ValidationScope())
{
scope.Error("Error 2");
scope.Error("Error 3");
}
}
private void NestedMethod2()
{
using (ValidationScope scope = new ValidationScope())
{
scope.Error("Error 4");
scope.Error("Error 5");
}
}
You can also call method Throw()
of validation scope which throws an exception for current validation scope immediately in nested or ancestor scope if there are errors logged.