Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
netcoreplus
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
tsai
netcoreplus
Commits
56ba1ef1
Commit
56ba1ef1
authored
May 15, 2019
by
阿星Plus
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Validation Interceptor Registrar
parent
6e8bd479
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
1017 additions
and
1 deletion
+1017
-1
PlusCrossCuttingConcerns.cs
src/Plus/Aspects/PlusCrossCuttingConcerns.cs
+70
-0
ITypeList.cs
src/Plus/Collections/ITypeList.cs
+19
-0
TypeList.cs
src/Plus/Collections/TypeList.cs
+109
-0
IValidationConfiguration.cs
src/Plus/Configuration/Startup/IValidationConfiguration.cs
+17
-0
DisposeAction.cs
src/Plus/DisposeAction.cs
+29
-0
IHasLogSeverity.cs
src/Plus/Logging/IHasLogSeverity.cs
+7
-0
LogSeverity.cs
src/Plus/Logging/LogSeverity.cs
+11
-0
Plus.csproj
src/Plus/Plus.csproj
+1
-0
PlusStarter.cs
src/Plus/PlusStarter.cs
+2
-1
ReflectionHelper.cs
src/Plus/Reflection/ReflectionHelper.cs
+269
-0
TypeHelper.cs
src/Plus/Reflection/TypeHelper.cs
+67
-0
DisableValidationAttribute.cs
src/Plus/Runtime/Validation/DisableValidationAttribute.cs
+10
-0
EnableValidationAttribute.cs
src/Plus/Runtime/Validation/EnableValidationAttribute.cs
+10
-0
IShouldNormalize.cs
src/Plus/Runtime/Validation/IShouldNormalize.cs
+13
-0
IMethodParameterValidator.cs
...time/Validation/Interception/IMethodParameterValidator.cs
+11
-0
MethodInvocationValidator.cs
...time/Validation/Interception/MethodInvocationValidator.cs
+245
-0
ValidationInterceptor.cs
.../Runtime/Validation/Interception/ValidationInterceptor.cs
+36
-0
ValidationInterceptorRegistrar.cs
...Validation/Interception/ValidationInterceptorRegistrar.cs
+24
-0
PlusValidationException.cs
src/Plus/Runtime/Validation/PlusValidationException.cs
+50
-0
IApplicationService.cs
src/Plus/Service/IApplicationService.cs
+8
-0
IAvoidDuplicateCrossCuttingConcerns.cs
src/Plus/Service/IAvoidDuplicateCrossCuttingConcerns.cs
+9
-0
No files found.
src/Plus/Aspects/PlusCrossCuttingConcerns.cs
0 → 100644
View file @
56ba1ef1
using
Plus.Collections
;
using
Plus.Service
;
using
System
;
namespace
Plus.Aspects
{
internal
class
PlusCrossCuttingConcerns
{
public
const
string
Validation
=
"PlusValidation"
;
public
const
string
UnitOfWork
=
"PlusUnitOfWork"
;
public
static
void
AddApplied
(
object
obj
,
params
string
[]
concerns
)
{
if
(
concerns
.
IsNullOrEmpty
())
{
throw
new
ArgumentNullException
(
nameof
(
concerns
),
$"
{
nameof
(
concerns
)}
should be provided!"
);
}
(
obj
as
IAvoidDuplicateCrossCuttingConcerns
)?.
AppliedCrossCuttingConcerns
.
AddRange
(
concerns
);
}
public
static
void
RemoveApplied
(
object
obj
,
params
string
[]
concerns
)
{
if
(
concerns
.
IsNullOrEmpty
())
{
throw
new
ArgumentNullException
(
nameof
(
concerns
),
$"
{
nameof
(
concerns
)}
should be provided!"
);
}
if
(
obj
is
IAvoidDuplicateCrossCuttingConcerns
avoidDuplicateCrossCuttingConcerns
)
{
foreach
(
string
concern
in
concerns
)
{
avoidDuplicateCrossCuttingConcerns
.
AppliedCrossCuttingConcerns
.
RemoveAll
((
string
c
)
=>
c
==
concern
);
}
}
}
public
static
bool
IsApplied
(
object
obj
,
string
concern
)
{
if
(
obj
==
null
)
{
throw
new
ArgumentNullException
(
"obj"
);
}
if
(
concern
==
null
)
{
throw
new
ArgumentNullException
(
"concern"
);
}
return
(
obj
as
IAvoidDuplicateCrossCuttingConcerns
)?.
AppliedCrossCuttingConcerns
.
Contains
(
concern
)
??
false
;
}
public
static
IDisposable
Applying
(
object
obj
,
params
string
[]
concerns
)
{
AddApplied
(
obj
,
concerns
);
return
new
DisposeAction
(()
=>
{
RemoveApplied
(
obj
,
concerns
);
});
}
public
static
string
[]
GetApplieds
(
object
obj
)
{
if
(!(
obj
is
IAvoidDuplicateCrossCuttingConcerns
crossCuttingEnabledObj
))
{
return
new
string
[
0
];
}
return
crossCuttingEnabledObj
.
AppliedCrossCuttingConcerns
.
ToArray
();
}
}
}
\ No newline at end of file
src/Plus/Collections/ITypeList.cs
0 → 100644
View file @
56ba1ef1
using
System
;
using
System.Collections.Generic
;
namespace
Plus.Collections
{
public
interface
ITypeList
:
ITypeList
<
object
>
{
}
public
interface
ITypeList
<
in
TBaseType
>
:
IList
<
Type
>
{
void
Add
<
T
>()
where
T
:
TBaseType
;
bool
Contains
<
T
>()
where
T
:
TBaseType
;
void
Remove
<
T
>()
where
T
:
TBaseType
;
}
}
\ No newline at end of file
src/Plus/Collections/TypeList.cs
0 → 100644
View file @
56ba1ef1
using
System
;
using
System.Collections
;
using
System.Collections.Generic
;
using
System.Reflection
;
namespace
Plus.Collections
{
public
class
TypeList
:
TypeList
<
object
>,
ITypeList
{
}
public
class
TypeList
<
TBaseType
>
:
ITypeList
<
TBaseType
>
{
public
int
Count
{
get
{
return
_typeList
.
Count
;
}
}
public
bool
IsReadOnly
{
get
{
return
false
;
}
}
public
Type
this
[
int
index
]
{
get
{
return
_typeList
[
index
];
}
set
{
CheckType
(
value
);
_typeList
[
index
]
=
value
;
}
}
private
readonly
List
<
Type
>
_typeList
;
public
TypeList
()
{
_typeList
=
new
List
<
Type
>();
}
public
void
Add
<
T
>()
where
T
:
TBaseType
{
_typeList
.
Add
(
typeof
(
T
));
}
public
void
Add
(
Type
item
)
{
CheckType
(
item
);
_typeList
.
Add
(
item
);
}
public
void
Insert
(
int
index
,
Type
item
)
{
_typeList
.
Insert
(
index
,
item
);
}
public
int
IndexOf
(
Type
item
)
{
return
_typeList
.
IndexOf
(
item
);
}
public
bool
Contains
<
T
>()
where
T
:
TBaseType
{
return
Contains
(
typeof
(
T
));
}
public
bool
Contains
(
Type
item
)
{
return
_typeList
.
Contains
(
item
);
}
public
void
Remove
<
T
>()
where
T
:
TBaseType
{
_typeList
.
Remove
(
typeof
(
T
));
}
public
bool
Remove
(
Type
item
)
{
return
_typeList
.
Remove
(
item
);
}
public
void
RemoveAt
(
int
index
)
{
_typeList
.
RemoveAt
(
index
);
}
public
void
Clear
()
{
_typeList
.
Clear
();
}
public
void
CopyTo
(
Type
[]
array
,
int
arrayIndex
)
{
_typeList
.
CopyTo
(
array
,
arrayIndex
);
}
public
IEnumerator
<
Type
>
GetEnumerator
()
{
return
_typeList
.
GetEnumerator
();
}
IEnumerator
IEnumerable
.
GetEnumerator
()
{
return
_typeList
.
GetEnumerator
();
}
private
static
void
CheckType
(
Type
item
)
{
if
(!
typeof
(
TBaseType
).
GetTypeInfo
().
IsAssignableFrom
(
item
))
{
throw
new
ArgumentException
(
"Given item is not type of "
+
typeof
(
TBaseType
).
AssemblyQualifiedName
,
"item"
);
}
}
}
}
\ No newline at end of file
src/Plus/Configuration/Startup/IValidationConfiguration.cs
0 → 100644
View file @
56ba1ef1
using
Plus.Collections
;
using
Plus.Runtime.Validation.Interception
;
using
System
;
using
System.Collections.Generic
;
namespace
Plus.Configuration.Startup
{
public
interface
IValidationConfiguration
{
List
<
Type
>
IgnoredTypes
{
get
;
}
/// <summary>
/// 方法参数验证器的列表
/// </summary>
ITypeList
<
IMethodParameterValidator
>
Validators
{
get
;
}
}
}
\ No newline at end of file
src/Plus/DisposeAction.cs
0 → 100644
View file @
56ba1ef1
using
System
;
using
System.Threading
;
namespace
Plus
{
/// <summary>
/// 这个类可用于在调用Dipose方法时提供一个操作
/// </summary>
public
class
DisposeAction
:
IDisposable
{
public
static
readonly
DisposeAction
Empty
=
new
DisposeAction
(
null
);
private
Action
_action
;
/// <summary>
/// 创建一个新的 <see cref="DisposeAction"/> 对象。
/// </summary>
/// <param name="action"></param>
public
DisposeAction
(
Action
action
)
{
_action
=
action
;
}
public
void
Dispose
()
{
Interlocked
.
Exchange
(
ref
_action
,
null
)?.
Invoke
();
}
}
}
\ No newline at end of file
src/Plus/Logging/IHasLogSeverity.cs
0 → 100644
View file @
56ba1ef1
namespace
Plus.Logging
{
public
interface
IHasLogSeverity
{
LogSeverity
Severity
{
get
;
set
;
}
}
}
\ No newline at end of file
src/Plus/Logging/LogSeverity.cs
0 → 100644
View file @
56ba1ef1
namespace
Plus.Logging
{
public
enum
LogSeverity
{
Debug
,
Info
,
Warn
,
Error
,
Fatal
}
}
\ No newline at end of file
src/Plus/Plus.csproj
View file @
56ba1ef1
...
@@ -8,6 +8,7 @@
...
@@ -8,6 +8,7 @@
<PackageReference Include="Castle.Core" Version="4.4.0" />
<PackageReference Include="Castle.Core" Version="4.4.0" />
<PackageReference Include="Castle.Windsor" Version="5.0.0" />
<PackageReference Include="Castle.Windsor" Version="5.0.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
</ItemGroup>
</ItemGroup>
</Project>
</Project>
src/Plus/PlusStarter.cs
View file @
56ba1ef1
...
@@ -4,6 +4,7 @@ using Plus.Configuration.Startup;
...
@@ -4,6 +4,7 @@ using Plus.Configuration.Startup;
using
Plus.Dependency
;
using
Plus.Dependency
;
using
Plus.Dependency.Installers
;
using
Plus.Dependency.Installers
;
using
Plus.Modules
;
using
Plus.Modules
;
using
Plus.Runtime.Validation.Interception
;
using
System
;
using
System
;
using
System.Reflection
;
using
System.Reflection
;
...
@@ -97,7 +98,7 @@ namespace Plus
...
@@ -97,7 +98,7 @@ namespace Plus
public
void
AddInterceptorRegistrars
()
public
void
AddInterceptorRegistrars
()
{
{
//
ValidationInterceptorRegistrar.Initialize(IocManager);
ValidationInterceptorRegistrar
.
Initialize
(
IocManager
);
//UnitOfWorkRegistrar.Initialize(IocManager);
//UnitOfWorkRegistrar.Initialize(IocManager);
}
}
}
}
...
...
src/Plus/Reflection/ReflectionHelper.cs
0 → 100644
View file @
56ba1ef1
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Reflection
;
namespace
Plus.Reflection
{
/// <summary>
/// 反射帮助类
/// </summary>
internal
static
class
ReflectionHelper
{
/// <summary>
/// Checks whether <paramref name="givenType"/> implements/inherits <paramref name="genericType"/>.
/// </summary>
/// <param name="givenType">Type to check</param>
/// <param name="genericType">Generic type</param>
public
static
bool
IsAssignableToGenericType
(
Type
givenType
,
Type
genericType
)
{
var
givenTypeInfo
=
givenType
.
GetTypeInfo
();
if
(
givenTypeInfo
.
IsGenericType
&&
givenType
.
GetGenericTypeDefinition
()
==
genericType
)
{
return
true
;
}
foreach
(
var
interfaceType
in
givenType
.
GetInterfaces
())
{
if
(
interfaceType
.
GetTypeInfo
().
IsGenericType
&&
interfaceType
.
GetGenericTypeDefinition
()
==
genericType
)
{
return
true
;
}
}
if
(
givenTypeInfo
.
BaseType
==
null
)
{
return
false
;
}
return
IsAssignableToGenericType
(
givenTypeInfo
.
BaseType
,
genericType
);
}
/// <summary>
/// Gets a list of attributes defined for a class member and it's declaring type including inherited attributes.
/// </summary>
/// <param name="inherit">Inherit attribute from base classes</param>
/// <param name="memberInfo">MemberInfo</param>
public
static
List
<
object
>
GetAttributesOfMemberAndDeclaringType
(
MemberInfo
memberInfo
,
bool
inherit
=
true
)
{
var
attributeList
=
new
List
<
object
>();
attributeList
.
AddRange
(
memberInfo
.
GetCustomAttributes
(
inherit
));
if
(
memberInfo
.
DeclaringType
!=
null
)
{
attributeList
.
AddRange
(
memberInfo
.
DeclaringType
.
GetTypeInfo
().
GetCustomAttributes
(
inherit
));
}
return
attributeList
;
}
/// <summary>
/// Gets a list of attributes defined for a class member and type including inherited attributes.
/// </summary>
/// <param name="memberInfo">MemberInfo</param>
/// <param name="type">Type</param>
/// <param name="inherit">Inherit attribute from base classes</param>
public
static
List
<
object
>
GetAttributesOfMemberAndType
(
MemberInfo
memberInfo
,
Type
type
,
bool
inherit
=
true
)
{
var
attributeList
=
new
List
<
object
>();
attributeList
.
AddRange
(
memberInfo
.
GetCustomAttributes
(
inherit
));
attributeList
.
AddRange
(
type
.
GetTypeInfo
().
GetCustomAttributes
(
inherit
));
return
attributeList
;
}
/// <summary>
/// Gets a list of attributes defined for a class member and it's declaring type including inherited attributes.
/// </summary>
/// <typeparam name="TAttribute">Type of the attribute</typeparam>
/// <param name="memberInfo">MemberInfo</param>
/// <param name="inherit">Inherit attribute from base classes</param>
public
static
List
<
TAttribute
>
GetAttributesOfMemberAndDeclaringType
<
TAttribute
>(
MemberInfo
memberInfo
,
bool
inherit
=
true
)
where
TAttribute
:
Attribute
{
var
attributeList
=
new
List
<
TAttribute
>();
if
(
memberInfo
.
IsDefined
(
typeof
(
TAttribute
),
inherit
))
{
attributeList
.
AddRange
(
memberInfo
.
GetCustomAttributes
(
typeof
(
TAttribute
),
inherit
).
Cast
<
TAttribute
>());
}
if
(
memberInfo
.
DeclaringType
!=
null
&&
memberInfo
.
DeclaringType
.
GetTypeInfo
().
IsDefined
(
typeof
(
TAttribute
),
inherit
))
{
attributeList
.
AddRange
(
memberInfo
.
DeclaringType
.
GetTypeInfo
().
GetCustomAttributes
(
typeof
(
TAttribute
),
inherit
).
Cast
<
TAttribute
>());
}
return
attributeList
;
}
/// <summary>
/// Gets a list of attributes defined for a class member and type including inherited attributes.
/// </summary>
/// <typeparam name="TAttribute">Type of the attribute</typeparam>
/// <param name="memberInfo">MemberInfo</param>
/// <param name="type">Type</param>
/// <param name="inherit">Inherit attribute from base classes</param>
public
static
List
<
TAttribute
>
GetAttributesOfMemberAndType
<
TAttribute
>(
MemberInfo
memberInfo
,
Type
type
,
bool
inherit
=
true
)
where
TAttribute
:
Attribute
{
var
attributeList
=
new
List
<
TAttribute
>();
if
(
memberInfo
.
IsDefined
(
typeof
(
TAttribute
),
inherit
))
{
attributeList
.
AddRange
(
memberInfo
.
GetCustomAttributes
(
typeof
(
TAttribute
),
inherit
).
Cast
<
TAttribute
>());
}
if
(
type
.
GetTypeInfo
().
IsDefined
(
typeof
(
TAttribute
),
inherit
))
{
attributeList
.
AddRange
(
type
.
GetTypeInfo
().
GetCustomAttributes
(
typeof
(
TAttribute
),
inherit
).
Cast
<
TAttribute
>());
}
return
attributeList
;
}
/// <summary>
/// Tries to gets an of attribute defined for a class member and it's declaring type including inherited attributes.
/// Returns default value if it's not declared at all.
/// </summary>
/// <typeparam name="TAttribute">Type of the attribute</typeparam>
/// <param name="memberInfo">MemberInfo</param>
/// <param name="defaultValue">Default value (null as default)</param>
/// <param name="inherit">Inherit attribute from base classes</param>
public
static
TAttribute
GetSingleAttributeOfMemberOrDeclaringTypeOrDefault
<
TAttribute
>(
MemberInfo
memberInfo
,
TAttribute
defaultValue
=
default
(
TAttribute
),
bool
inherit
=
true
)
where
TAttribute
:
class
{
return
memberInfo
.
GetCustomAttributes
(
true
).
OfType
<
TAttribute
>().
FirstOrDefault
()
??
memberInfo
.
ReflectedType
?.
GetTypeInfo
().
GetCustomAttributes
(
true
).
OfType
<
TAttribute
>().
FirstOrDefault
()
??
defaultValue
;
}
/// <summary>
/// Tries to gets an of attribute defined for a class member and it's declaring type including inherited attributes.
/// Returns default value if it's not declared at all.
/// </summary>
/// <typeparam name="TAttribute">Type of the attribute</typeparam>
/// <param name="memberInfo">MemberInfo</param>
/// <param name="defaultValue">Default value (null as default)</param>
/// <param name="inherit">Inherit attribute from base classes</param>
public
static
TAttribute
GetSingleAttributeOrDefault
<
TAttribute
>(
MemberInfo
memberInfo
,
TAttribute
defaultValue
=
default
(
TAttribute
),
bool
inherit
=
true
)
where
TAttribute
:
Attribute
{
//Get attribute on the member
if
(
memberInfo
.
IsDefined
(
typeof
(
TAttribute
),
inherit
))
{
return
memberInfo
.
GetCustomAttributes
(
typeof
(
TAttribute
),
inherit
).
Cast
<
TAttribute
>().
First
();
}
return
defaultValue
;
}
/// <summary>
/// Gets a property by it's full path from given object
/// </summary>
/// <param name="obj">Object to get value from</param>
/// <param name="objectType">Type of given object</param>
/// <param name="propertyPath">Full path of property</param>
/// <returns></returns>
internal
static
object
GetPropertyByPath
(
object
obj
,
Type
objectType
,
string
propertyPath
)
{
var
property
=
obj
;
var
currentType
=
objectType
;
var
objectPath
=
currentType
.
FullName
;
var
absolutePropertyPath
=
propertyPath
;
if
(
absolutePropertyPath
.
StartsWith
(
objectPath
))
{
absolutePropertyPath
=
absolutePropertyPath
.
Replace
(
objectPath
+
"."
,
""
);
}
foreach
(
var
propertyName
in
absolutePropertyPath
.
Split
(
'.'
))
{
property
=
currentType
.
GetProperty
(
propertyName
);
currentType
=
((
PropertyInfo
)
property
).
PropertyType
;
}
return
property
;
}
/// <summary>
/// Gets value of a property by it's full path from given object
/// </summary>
/// <param name="obj">Object to get value from</param>
/// <param name="objectType">Type of given object</param>
/// <param name="propertyPath">Full path of property</param>
/// <returns></returns>
internal
static
object
GetValueByPath
(
object
obj
,
Type
objectType
,
string
propertyPath
)
{
var
value
=
obj
;
var
currentType
=
objectType
;
var
objectPath
=
currentType
.
FullName
;
var
absolutePropertyPath
=
propertyPath
;
if
(
absolutePropertyPath
.
StartsWith
(
objectPath
))
{
absolutePropertyPath
=
absolutePropertyPath
.
Replace
(
objectPath
+
"."
,
""
);
}
foreach
(
var
propertyName
in
absolutePropertyPath
.
Split
(
'.'
))
{
var
property
=
currentType
.
GetProperty
(
propertyName
);
value
=
property
.
GetValue
(
value
,
null
);
currentType
=
property
.
PropertyType
;
}
return
value
;
}
/// <summary>
/// Sets value of a property by it's full path on given object
/// </summary>
/// <param name="obj"></param>
/// <param name="objectType"></param>
/// <param name="propertyPath"></param>
/// <param name="value"></param>
internal
static
void
SetValueByPath
(
object
obj
,
Type
objectType
,
string
propertyPath
,
object
value
)
{
var
currentType
=
objectType
;
PropertyInfo
property
;
var
objectPath
=
currentType
.
FullName
;
var
absolutePropertyPath
=
propertyPath
;
if
(
absolutePropertyPath
.
StartsWith
(
objectPath
))
{
absolutePropertyPath
=
absolutePropertyPath
.
Replace
(
objectPath
+
"."
,
""
);
}
var
properties
=
absolutePropertyPath
.
Split
(
'.'
);
if
(
properties
.
Length
==
1
)
{
property
=
objectType
.
GetProperty
(
properties
.
First
());
property
.
SetValue
(
obj
,
value
);
return
;
}
for
(
int
i
=
0
;
i
<
properties
.
Length
-
1
;
i
++)
{
property
=
currentType
.
GetProperty
(
properties
[
i
]);
obj
=
property
.
GetValue
(
obj
,
null
);
currentType
=
property
.
PropertyType
;
}
property
=
currentType
.
GetProperty
(
properties
.
Last
());
property
.
SetValue
(
obj
,
value
);
}
internal
static
bool
IsPropertyGetterSetterMethod
(
MethodInfo
method
,
Type
type
)
{
if
(!
method
.
IsSpecialName
)
{
return
false
;
}
if
(
method
.
Name
.
Length
<
5
)
{
return
false
;
}
return
type
.
GetProperty
(
method
.
Name
.
Substring
(
4
),
BindingFlags
.
Instance
|
BindingFlags
.
Static
|
BindingFlags
.
NonPublic
)
!=
null
;
}
}
}
\ No newline at end of file
src/Plus/Reflection/TypeHelper.cs
0 → 100644
View file @
56ba1ef1
using
System
;
using
System.Reflection
;
namespace
Plus.Reflection
{
/// <summary>
/// 一些内部使用的简单类型检查方法
/// </summary>
internal
static
class
TypeHelper
{
public
static
bool
IsFunc
(
object
obj
)
{
if
(
obj
==
null
)
{
return
false
;
}
var
type
=
obj
.
GetType
();
if
(!
type
.
GetTypeInfo
().
IsGenericType
)
{
return
false
;
}
return
type
.
GetGenericTypeDefinition
()
==
typeof
(
Func
<>);
}
public
static
bool
IsFunc
<
TReturn
>(
object
obj
)
{
return
obj
!=
null
&&
obj
.
GetType
()
==
typeof
(
Func
<
TReturn
>);
}
public
static
bool
IsPrimitiveExtendedIncludingNullable
(
Type
type
,
bool
includeEnums
=
false
)
{
if
(
IsPrimitiveExtended
(
type
,
includeEnums
))
{
return
true
;
}
if
(
type
.
GetTypeInfo
().
IsGenericType
&&
type
.
GetGenericTypeDefinition
()
==
typeof
(
Nullable
<>))
{
return
IsPrimitiveExtended
(
type
.
GenericTypeArguments
[
0
],
includeEnums
);
}
return
false
;
}
private
static
bool
IsPrimitiveExtended
(
Type
type
,
bool
includeEnums
)
{
if
(
type
.
GetTypeInfo
().
IsPrimitive
)
{
return
true
;
}
if
(
includeEnums
&&
type
.
GetTypeInfo
().
IsEnum
)
{
return
true
;
}
return
type
==
typeof
(
string
)
||
type
==
typeof
(
decimal
)
||
type
==
typeof
(
DateTime
)
||
type
==
typeof
(
DateTimeOffset
)
||
type
==
typeof
(
TimeSpan
)
||
type
==
typeof
(
Guid
);
}
}
}
\ No newline at end of file
src/Plus/Runtime/Validation/DisableValidationAttribute.cs
0 → 100644
View file @
56ba1ef1
using
System
;
namespace
Plus.Runtime.Validation
{
[
AttributeUsage
(
AttributeTargets
.
Method
|
AttributeTargets
.
Class
|
AttributeTargets
.
Property
)]
public
class
DisableValidationAttribute
:
Attribute
{
}
}
\ No newline at end of file
src/Plus/Runtime/Validation/EnableValidationAttribute.cs
0 → 100644
View file @
56ba1ef1
using
System
;
namespace
Plus.Runtime.Validation
{
[
AttributeUsage
(
AttributeTargets
.
Method
)]
public
class
EnableValidationAttribute
:
Attribute
{
}
}
\ No newline at end of file
src/Plus/Runtime/Validation/IShouldNormalize.cs
0 → 100644
View file @
56ba1ef1
namespace
Plus.Runtime.Validation
{
/// <summary>
/// 此接口用于在方法执行之前对输入进行规范化
/// </summary>
public
interface
IShouldNormalize
{
/// <summary>
/// 方法最后在方法执行之前调用(如果存在,则在验证之后调用)
/// </summary>
void
Normalize
();
}
}
\ No newline at end of file
src/Plus/Runtime/Validation/Interception/IMethodParameterValidator.cs
0 → 100644
View file @
56ba1ef1
using
Plus.Dependency
;
using
System.Collections.Generic
;
using
System.ComponentModel.DataAnnotations
;
namespace
Plus.Runtime.Validation.Interception
{
public
interface
IMethodParameterValidator
:
ITransientDependency
{
IReadOnlyList
<
ValidationResult
>
Validate
(
object
validatingObject
);
}
}
\ No newline at end of file
src/Plus/Runtime/Validation/Interception/MethodInvocationValidator.cs
0 → 100644
View file @
56ba1ef1
using
Plus.Dependency
;
using
System
;
using
System.Collections.Generic
;
using
System.Text
;
using
System.Collections
;
using
System.ComponentModel
;
using
System.Linq
;
using
System.Reflection
;
using
Plus
;
using
Plus.Configuration.Startup
;
using
Plus.Runtime.Validation
;
using
Plus.Runtime.Validation.Interception
;
using
System.ComponentModel.DataAnnotations
;
using
Plus.Collections
;
using
Plus.Reflection
;
namespace
Plus.Runtime.Validation.Interception
{
/// <summary>
/// 该类用于验证方法参数
/// </summary>
public
class
MethodInvocationValidator
:
ITransientDependency
{
private
const
int
MaxRecursiveParameterValidationDepth
=
8
;
protected
MethodInfo
Method
{
get
;
private
set
;
}
protected
object
[]
ParameterValues
{
get
;
private
set
;
}
protected
ParameterInfo
[]
Parameters
{
get
;
private
set
;
}
protected
List
<
ValidationResult
>
ValidationErrors
{
get
;
}
protected
List
<
IShouldNormalize
>
ObjectsToBeNormalized
{
get
;
}
private
readonly
IValidationConfiguration
_configuration
;
private
readonly
IIocResolver
_iocResolver
;
/// <summary>
/// Creates a new <see cref="MethodInvocationValidator"/> instance.
/// </summary>
public
MethodInvocationValidator
(
IValidationConfiguration
configuration
,
IIocResolver
iocResolver
)
{
_configuration
=
configuration
;
_iocResolver
=
iocResolver
;
ValidationErrors
=
new
List
<
ValidationResult
>();
ObjectsToBeNormalized
=
new
List
<
IShouldNormalize
>();
}
/// <param name="method">Method to be validated</param>
/// <param name="parameterValues">List of arguments those are used to call the <paramref name="method"/>.</param>
public
virtual
void
Initialize
(
MethodInfo
method
,
object
[]
parameterValues
)
{
Method
=
method
;
ParameterValues
=
parameterValues
;
Parameters
=
method
.
GetParameters
();
}
/// <summary>
/// Validates the method invocation.
/// </summary>
public
void
Validate
()
{
CheckInitialized
();
if
(
Parameters
.
IsNullOrEmpty
())
{
return
;
}
if
(!
Method
.
IsPublic
)
{
return
;
}
if
(
IsValidationDisabled
())
{
return
;
}
if
(
Parameters
.
Length
!=
ParameterValues
.
Length
)
{
throw
new
Exception
(
"Method parameter count does not match with argument count!"
);
}
for
(
var
i
=
0
;
i
<
Parameters
.
Length
;
i
++)
{
ValidateMethodParameter
(
Parameters
[
i
],
ParameterValues
[
i
]);
}
if
(
ValidationErrors
.
Any
())
{
ThrowValidationError
();
}
foreach
(
var
objectToBeNormalized
in
ObjectsToBeNormalized
)
{
objectToBeNormalized
.
Normalize
();
}
}
protected
virtual
void
CheckInitialized
()
{
if
(
Method
==
null
)
{
throw
new
PlusException
(
"This object has not been initialized. Call Initialize method first."
);
}
}
protected
virtual
bool
IsValidationDisabled
()
{
if
(
Method
.
IsDefined
(
typeof
(
EnableValidationAttribute
),
true
))
{
return
false
;
}
return
ReflectionHelper
.
GetSingleAttributeOfMemberOrDeclaringTypeOrDefault
<
DisableValidationAttribute
>(
Method
)
!=
null
;
}
protected
virtual
void
ThrowValidationError
()
{
throw
new
PlusValidationException
(
"方法参数是无效的!有关详细信息,请参阅ValidationErrors:"
,
ValidationErrors
);
}
/// <summary>
/// Validates given parameter for given value.
/// </summary>
/// <param name="parameterInfo">Parameter of the method to validate</param>
/// <param name="parameterValue">Value to validate</param>
protected
virtual
void
ValidateMethodParameter
(
ParameterInfo
parameterInfo
,
object
parameterValue
)
{
if
(
parameterValue
==
null
)
{
if
(!
parameterInfo
.
IsOptional
&&
!
parameterInfo
.
IsOut
&&
!
TypeHelper
.
IsPrimitiveExtendedIncludingNullable
(
parameterInfo
.
ParameterType
,
includeEnums
:
true
))
{
ValidationErrors
.
Add
(
new
ValidationResult
(
parameterInfo
.
Name
+
" is null!"
,
new
[]
{
parameterInfo
.
Name
}));
}
return
;
}
ValidateObjectRecursively
(
parameterValue
,
1
);
}
protected
virtual
void
ValidateObjectRecursively
(
object
validatingObject
,
int
currentDepth
)
{
if
(
currentDepth
>
MaxRecursiveParameterValidationDepth
)
{
return
;
}
if
(
validatingObject
==
null
)
{
return
;
}
if
(
_configuration
.
IgnoredTypes
.
Any
(
t
=>
t
.
IsInstanceOfType
(
validatingObject
)))
{
return
;
}
if
(
TypeHelper
.
IsPrimitiveExtendedIncludingNullable
(
validatingObject
.
GetType
()))
{
return
;
}
SetValidationErrors
(
validatingObject
);
// Validate items of enumerable
if
(
IsEnumerable
(
validatingObject
))
{
foreach
(
var
item
in
(
IEnumerable
)
validatingObject
)
{
ValidateObjectRecursively
(
item
,
currentDepth
+
1
);
}
}
// Add list to be normalized later
if
(
validatingObject
is
IShouldNormalize
)
{
ObjectsToBeNormalized
.
Add
(
validatingObject
as
IShouldNormalize
);
}
if
(
ShouldMakeDeepValidation
(
validatingObject
))
{
var
properties
=
TypeDescriptor
.
GetProperties
(
validatingObject
).
Cast
<
PropertyDescriptor
>();
foreach
(
var
property
in
properties
)
{
if
(
property
.
Attributes
.
OfType
<
DisableValidationAttribute
>().
Any
())
{
continue
;
}
ValidateObjectRecursively
(
property
.
GetValue
(
validatingObject
),
currentDepth
+
1
);
}
}
}
protected
virtual
void
SetValidationErrors
(
object
validatingObject
)
{
foreach
(
var
validatorType
in
_configuration
.
Validators
)
{
if
(
ShouldValidateUsingValidator
(
validatingObject
,
validatorType
))
{
using
(
var
validator
=
_iocResolver
.
ResolveAsDisposable
<
IMethodParameterValidator
>(
validatorType
))
{
var
validationResults
=
validator
.
Object
.
Validate
(
validatingObject
);
ValidationErrors
.
AddRange
(
validationResults
);
}
}
}
}
protected
virtual
bool
ShouldValidateUsingValidator
(
object
validatingObject
,
Type
validatorType
)
{
return
true
;
}
protected
virtual
bool
ShouldMakeDeepValidation
(
object
validatingObject
)
{
// Do not recursively validate for enumerable objects
if
(
validatingObject
is
IEnumerable
)
{
return
false
;
}
var
validatingObjectType
=
validatingObject
.
GetType
();
// Do not recursively validate for primitive objects
if
(
TypeHelper
.
IsPrimitiveExtendedIncludingNullable
(
validatingObjectType
))
{
return
false
;
}
return
true
;
}
private
bool
IsEnumerable
(
object
validatingObject
)
{
return
validatingObject
is
IEnumerable
&&
!(
validatingObject
is
IQueryable
)
&&
!
TypeHelper
.
IsPrimitiveExtendedIncludingNullable
(
validatingObject
.
GetType
());
}
}
}
\ No newline at end of file
src/Plus/Runtime/Validation/Interception/ValidationInterceptor.cs
0 → 100644
View file @
56ba1ef1
using
Castle.DynamicProxy
;
using
Plus.Aspects
;
using
Plus.Dependency
;
namespace
Plus.Runtime.Validation.Interception
{
/// <summary>
/// 这个拦截器用于拦截类的方法调用,类的方法必须经过验证。
/// </summary>
public
class
ValidationInterceptor
:
IInterceptor
{
private
readonly
IIocResolver
_iocResolver
;
public
ValidationInterceptor
(
IIocResolver
iocResolver
)
{
_iocResolver
=
iocResolver
;
}
public
void
Intercept
(
IInvocation
invocation
)
{
if
(
PlusCrossCuttingConcerns
.
IsApplied
(
invocation
.
InvocationTarget
,
PlusCrossCuttingConcerns
.
Validation
))
{
invocation
.
Proceed
();
return
;
}
using
(
var
validator
=
_iocResolver
.
ResolveAsDisposable
<
MethodInvocationValidator
>())
{
validator
.
Object
.
Initialize
(
invocation
.
MethodInvocationTarget
,
invocation
.
Arguments
);
validator
.
Object
.
Validate
();
}
invocation
.
Proceed
();
}
}
}
\ No newline at end of file
src/Plus/Runtime/Validation/Interception/ValidationInterceptorRegistrar.cs
0 → 100644
View file @
56ba1ef1
using
Castle.Core
;
using
Castle.MicroKernel
;
using
Plus.Dependency
;
using
Plus.Service
;
using
System.Reflection
;
namespace
Plus.Runtime.Validation.Interception
{
internal
static
class
ValidationInterceptorRegistrar
{
public
static
void
Initialize
(
IIocManager
iocManager
)
{
iocManager
.
IocContainer
.
Kernel
.
ComponentRegistered
+=
Kernel_ComponentRegistered
;
}
private
static
void
Kernel_ComponentRegistered
(
string
key
,
IHandler
handler
)
{
if
(
typeof
(
IApplicationService
).
GetTypeInfo
().
IsAssignableFrom
(
handler
.
ComponentModel
.
Implementation
))
{
handler
.
ComponentModel
.
Interceptors
.
Add
(
new
InterceptorReference
(
typeof
(
ValidationInterceptor
)));
}
}
}
}
\ No newline at end of file
src/Plus/Runtime/Validation/PlusValidationException.cs
0 → 100644
View file @
56ba1ef1
using
Plus.Logging
;
using
System
;
using
System.Collections.Generic
;
using
System.ComponentModel.DataAnnotations
;
using
System.Runtime.Serialization
;
namespace
Plus.Runtime.Validation
{
[
Serializable
]
public
class
PlusValidationException
:
PlusException
,
IHasLogSeverity
{
public
IList
<
ValidationResult
>
ValidationErrors
{
get
;
set
;
}
public
LogSeverity
Severity
{
get
;
set
;
}
public
PlusValidationException
()
{
ValidationErrors
=
new
List
<
ValidationResult
>();
Severity
=
LogSeverity
.
Warn
;
}
public
PlusValidationException
(
SerializationInfo
serializationInfo
,
StreamingContext
context
)
:
base
(
serializationInfo
,
context
)
{
ValidationErrors
=
new
List
<
ValidationResult
>();
Severity
=
LogSeverity
.
Warn
;
}
public
PlusValidationException
(
string
message
)
:
base
(
message
)
{
ValidationErrors
=
new
List
<
ValidationResult
>();
Severity
=
LogSeverity
.
Warn
;
}
public
PlusValidationException
(
string
message
,
IList
<
ValidationResult
>
validationErrors
)
:
base
(
message
)
{
ValidationErrors
=
validationErrors
;
Severity
=
LogSeverity
.
Warn
;
}
public
PlusValidationException
(
string
message
,
Exception
innerException
)
:
base
(
message
,
innerException
)
{
ValidationErrors
=
new
List
<
ValidationResult
>();
Severity
=
LogSeverity
.
Warn
;
}
}
}
\ No newline at end of file
src/Plus/Service/IApplicationService.cs
0 → 100644
View file @
56ba1ef1
using
Plus.Dependency
;
namespace
Plus.Service
{
interface
IApplicationService
:
ITransientDependency
{
}
}
\ No newline at end of file
src/Plus/Service/IAvoidDuplicateCrossCuttingConcerns.cs
0 → 100644
View file @
56ba1ef1
using
System.Collections.Generic
;
namespace
Plus.Service
{
public
interface
IAvoidDuplicateCrossCuttingConcerns
{
List
<
string
>
AppliedCrossCuttingConcerns
{
get
;
}
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment