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
e1abb5b0
Commit
e1abb5b0
authored
May 15, 2019
by
阿星Plus
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
UnitOfWorkRegistrar.Initialize
✔
✔
✔
parent
56ba1ef1
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
557 additions
and
1 deletion
+557
-1
Extensions.cs
src/Plus/Collections/Extensions.cs
+6
-0
UnitOfWorkAttribute.cs
src/Plus/Domain/Uow/UnitOfWorkAttribute.cs
+159
-0
UnitOfWorkDefaultOptionsExtensions.cs
src/Plus/Domain/Uow/UnitOfWorkDefaultOptionsExtensions.cs
+38
-0
UnitOfWorkHelper.cs
src/Plus/Domain/Uow/UnitOfWorkHelper.cs
+19
-0
UnitOfWorkInterceptor.cs
src/Plus/Domain/Uow/UnitOfWorkInterceptor.cs
+104
-0
UnitOfWorkRegistrar.cs
src/Plus/Domain/Uow/UnitOfWorkRegistrar.cs
+61
-0
InternalAsyncHelper.cs
src/Plus/InternalAsyncHelper.cs
+168
-0
PlusStarter.cs
src/Plus/PlusStarter.cs
+2
-1
No files found.
src/Plus/Collections/Extensions.cs
View file @
e1abb5b0
...
...
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using
System.Linq
;
using
System.Reflection
;
using
System.Runtime.ExceptionServices
;
using
System.Threading.Tasks
;
namespace
Plus.Collections
{
...
...
@@ -11,6 +12,11 @@ namespace Plus.Collections
/// </summary>
public
static
class
Extensions
{
public
static
bool
IsAsync
(
this
MethodInfo
method
)
{
return
method
.
ReturnType
==
typeof
(
Task
)
||
(
method
.
ReturnType
.
GetTypeInfo
().
IsGenericType
&&
method
.
ReturnType
.
GetGenericTypeDefinition
()
==
typeof
(
Task
<>));
}
public
static
List
<
T
>
SortByDependencies
<
T
>(
this
IEnumerable
<
T
>
source
,
Func
<
T
,
IEnumerable
<
T
>>
getDependencies
)
{
var
sorted
=
new
List
<
T
>();
...
...
src/Plus/Domain/Uow/UnitOfWorkAttribute.cs
0 → 100644
View file @
e1abb5b0
using
System
;
using
System.Transactions
;
namespace
Plus.Domain.Uow
{
/// <summary>
/// This attribute is used to indicate that declaring method is atomic and should be considered as a unit of work.
/// A method that has this attribute is intercepted, a database connection is opened and a transaction is started before call the method.
/// At the end of method call, transaction is committed and all changes applied to the database if there is no exception,
/// otherwise it's rolled back.
/// </summary>
/// <remarks>
/// This attribute has no effect if there is already a unit of work before calling this method, if so, it uses the same transaction.
/// </remarks>
[
AttributeUsage
(
AttributeTargets
.
Method
|
AttributeTargets
.
Class
|
AttributeTargets
.
Interface
)]
public
class
UnitOfWorkAttribute
:
Attribute
{
/// <summary>
/// Scope option.
/// </summary>
public
TransactionScopeOption
?
Scope
{
get
;
set
;
}
/// <summary>
/// Is this UOW transactional?
/// Uses default value if not supplied.
/// </summary>
public
bool
?
IsTransactional
{
get
;
set
;
}
/// <summary>
/// Timeout of UOW As milliseconds.
/// Uses default value if not supplied.
/// </summary>
public
TimeSpan
?
Timeout
{
get
;
set
;
}
/// <summary>
/// If this UOW is transactional, this option indicated the isolation level of the transaction.
/// Uses default value if not supplied.
/// </summary>
public
IsolationLevel
?
IsolationLevel
{
get
;
set
;
}
/// <summary>
/// Used to prevent starting a unit of work for the method.
/// If there is already a started unit of work, this property is ignored.
/// Default: false.
/// </summary>
public
bool
IsDisabled
{
get
;
set
;
}
/// <summary>
/// Creates a new UnitOfWorkAttribute object.
/// </summary>
public
UnitOfWorkAttribute
()
{
}
/// <summary>
/// Creates a new <see cref="UnitOfWorkAttribute"/> object.
/// </summary>
/// <param name="isTransactional">
/// Is this unit of work will be transactional?
/// </param>
public
UnitOfWorkAttribute
(
bool
isTransactional
)
{
IsTransactional
=
isTransactional
;
}
/// <summary>
/// Creates a new <see cref="UnitOfWorkAttribute"/> object.
/// </summary>
/// <param name="timeout">As milliseconds</param>
public
UnitOfWorkAttribute
(
int
timeout
)
{
Timeout
=
TimeSpan
.
FromMilliseconds
(
timeout
);
}
/// <summary>
/// Creates a new <see cref="UnitOfWorkAttribute"/> object.
/// </summary>
/// <param name="isTransactional">Is this unit of work will be transactional?</param>
/// <param name="timeout">As milliseconds</param>
public
UnitOfWorkAttribute
(
bool
isTransactional
,
int
timeout
)
{
IsTransactional
=
isTransactional
;
Timeout
=
TimeSpan
.
FromMilliseconds
(
timeout
);
}
/// <summary>
/// Creates a new <see cref="UnitOfWorkAttribute"/> object.
/// <see cref="IsTransactional"/> is automatically set to true.
/// </summary>
/// <param name="isolationLevel">Transaction isolation level</param>
public
UnitOfWorkAttribute
(
IsolationLevel
isolationLevel
)
{
IsTransactional
=
true
;
IsolationLevel
=
isolationLevel
;
}
/// <summary>
/// Creates a new <see cref="UnitOfWorkAttribute"/> object.
/// <see cref="IsTransactional"/> is automatically set to true.
/// </summary>
/// <param name="isolationLevel">Transaction isolation level</param>
/// <param name="timeout">Transaction timeout as milliseconds</param>
public
UnitOfWorkAttribute
(
IsolationLevel
isolationLevel
,
int
timeout
)
{
IsTransactional
=
true
;
IsolationLevel
=
isolationLevel
;
Timeout
=
TimeSpan
.
FromMilliseconds
(
timeout
);
}
/// <summary>
/// Creates a new <see cref="UnitOfWorkAttribute"/> object.
/// <see cref="IsTransactional"/> is automatically set to true.
/// </summary>
/// <param name="scope">Transaction scope</param>
public
UnitOfWorkAttribute
(
TransactionScopeOption
scope
)
{
IsTransactional
=
true
;
Scope
=
scope
;
}
/// <summary>
/// Creates a new <see cref="UnitOfWorkAttribute"/> object.
/// </summary>
/// <param name="scope">Transaction scope</param>
/// <param name="isTransactional">
/// Is this unit of work will be transactional?
/// </param>
public
UnitOfWorkAttribute
(
TransactionScopeOption
scope
,
bool
isTransactional
)
{
Scope
=
scope
;
IsTransactional
=
isTransactional
;
}
/// <summary>
/// Creates a new <see cref="UnitOfWorkAttribute"/> object.
/// <see cref="IsTransactional"/> is automatically set to true.
/// </summary>
/// <param name="scope">Transaction scope</param>
/// <param name="timeout">Transaction timeout as milliseconds</param>
public
UnitOfWorkAttribute
(
TransactionScopeOption
scope
,
int
timeout
)
{
IsTransactional
=
true
;
Scope
=
scope
;
Timeout
=
TimeSpan
.
FromMilliseconds
(
timeout
);
}
internal
UnitOfWorkOptions
CreateOptions
()
{
return
new
UnitOfWorkOptions
{
IsTransactional
=
IsTransactional
,
IsolationLevel
=
IsolationLevel
,
Timeout
=
Timeout
,
Scope
=
Scope
};
}
}
}
\ No newline at end of file
src/Plus/Domain/Uow/UnitOfWorkDefaultOptionsExtensions.cs
0 → 100644
View file @
e1abb5b0
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Reflection
;
using
System.Text
;
namespace
Plus.Domain.Uow
{
internal
static
class
UnitOfWorkDefaultOptionsExtensions
{
public
static
UnitOfWorkAttribute
GetUnitOfWorkAttributeOrNull
(
this
IUnitOfWorkDefaultOptions
unitOfWorkDefaultOptions
,
MethodInfo
methodInfo
)
{
var
attrs
=
methodInfo
.
GetCustomAttributes
(
true
).
OfType
<
UnitOfWorkAttribute
>().
ToArray
();
if
(
attrs
.
Length
>
0
)
{
return
attrs
[
0
];
}
attrs
=
methodInfo
.
DeclaringType
.
GetTypeInfo
().
GetCustomAttributes
(
true
).
OfType
<
UnitOfWorkAttribute
>().
ToArray
();
if
(
attrs
.
Length
>
0
)
{
return
attrs
[
0
];
}
if
(
unitOfWorkDefaultOptions
.
IsConventionalUowClass
(
methodInfo
.
DeclaringType
))
{
return
new
UnitOfWorkAttribute
();
//Default
}
return
null
;
}
public
static
bool
IsConventionalUowClass
(
this
IUnitOfWorkDefaultOptions
unitOfWorkDefaultOptions
,
Type
type
)
{
return
unitOfWorkDefaultOptions
.
ConventionalUowSelectors
.
Any
(
selector
=>
selector
(
type
));
}
}
}
\ No newline at end of file
src/Plus/Domain/Uow/UnitOfWorkHelper.cs
0 → 100644
View file @
e1abb5b0
using
System.Reflection
;
namespace
Plus.Domain.Uow
{
/// <summary>
/// A helper class to simplify unit of work process.
/// </summary>
internal
static
class
UnitOfWorkHelper
{
/// <summary>
/// Returns true if given method has UnitOfWorkAttribute attribute.
/// </summary>
/// <param name="memberInfo">Method info to check</param>
public
static
bool
HasUnitOfWorkAttribute
(
MemberInfo
memberInfo
)
{
return
memberInfo
.
IsDefined
(
typeof
(
UnitOfWorkAttribute
),
true
);
}
}
}
\ No newline at end of file
src/Plus/Domain/Uow/UnitOfWorkInterceptor.cs
0 → 100644
View file @
e1abb5b0
using
Castle.DynamicProxy
;
using
Plus.Collections
;
using
System.Reflection
;
using
System.Threading.Tasks
;
namespace
Plus.Domain.Uow
{
/// <summary>
/// This interceptor is used to manage database connection and transactions.
/// </summary>
internal
class
UnitOfWorkInterceptor
:
IInterceptor
{
private
readonly
IUnitOfWorkManager
_unitOfWorkManager
;
private
readonly
IUnitOfWorkDefaultOptions
_unitOfWorkOptions
;
public
UnitOfWorkInterceptor
(
IUnitOfWorkManager
unitOfWorkManager
,
IUnitOfWorkDefaultOptions
unitOfWorkOptions
)
{
_unitOfWorkManager
=
unitOfWorkManager
;
_unitOfWorkOptions
=
unitOfWorkOptions
;
}
/// <summary>
/// Intercepts a method.
/// </summary>
/// <param name="invocation">Method invocation arguments</param>
public
void
Intercept
(
IInvocation
invocation
)
{
MethodInfo
method
;
try
{
method
=
invocation
.
MethodInvocationTarget
;
}
catch
{
method
=
invocation
.
GetConcreteMethod
();
}
var
unitOfWorkAttr
=
_unitOfWorkOptions
.
GetUnitOfWorkAttributeOrNull
(
method
);
if
(
unitOfWorkAttr
==
null
||
unitOfWorkAttr
.
IsDisabled
)
{
//No need to a uow
invocation
.
Proceed
();
return
;
}
//No current uow, run a new one
PerformUow
(
invocation
,
unitOfWorkAttr
.
CreateOptions
());
}
private
void
PerformUow
(
IInvocation
invocation
,
UnitOfWorkOptions
options
)
{
if
(
invocation
.
Method
.
IsAsync
())
{
PerformAsyncUow
(
invocation
,
options
);
}
else
{
PerformSyncUow
(
invocation
,
options
);
}
}
private
void
PerformSyncUow
(
IInvocation
invocation
,
UnitOfWorkOptions
options
)
{
using
(
var
uow
=
_unitOfWorkManager
.
Begin
(
options
))
{
invocation
.
Proceed
();
uow
.
Complete
();
}
}
private
void
PerformAsyncUow
(
IInvocation
invocation
,
UnitOfWorkOptions
options
)
{
var
uow
=
_unitOfWorkManager
.
Begin
(
options
);
try
{
invocation
.
Proceed
();
}
catch
{
uow
.
Dispose
();
throw
;
}
if
(
invocation
.
Method
.
ReturnType
==
typeof
(
Task
))
{
invocation
.
ReturnValue
=
InternalAsyncHelper
.
AwaitTaskWithPostActionAndFinally
(
(
Task
)
invocation
.
ReturnValue
,
async
()
=>
await
uow
.
CompleteAsync
(),
exception
=>
uow
.
Dispose
()
);
}
else
//Task<TResult>
{
invocation
.
ReturnValue
=
InternalAsyncHelper
.
CallAwaitTaskWithPostActionAndFinallyAndGetResult
(
invocation
.
Method
.
ReturnType
.
GenericTypeArguments
[
0
],
invocation
.
ReturnValue
,
async
()
=>
await
uow
.
CompleteAsync
(),
exception
=>
uow
.
Dispose
()
);
}
}
}
}
\ No newline at end of file
src/Plus/Domain/Uow/UnitOfWorkRegistrar.cs
0 → 100644
View file @
e1abb5b0
using
Castle.Core
;
using
Castle.MicroKernel
;
using
Plus.Dependency
;
using
System.Linq
;
using
System.Reflection
;
namespace
Plus.Domain.Uow
{
internal
static
class
UnitOfWorkRegistrar
{
/// <summary>
/// Initializes the registerer.
/// </summary>
/// <param name="iocManager">IOC manager</param>
public
static
void
Initialize
(
IIocManager
iocManager
)
{
iocManager
.
IocContainer
.
Kernel
.
ComponentRegistered
+=
(
key
,
handler
)
=>
{
var
implementationType
=
handler
.
ComponentModel
.
Implementation
.
GetTypeInfo
();
HandleTypesWithUnitOfWorkAttribute
(
implementationType
,
handler
);
HandleConventionalUnitOfWorkTypes
(
iocManager
,
implementationType
,
handler
);
};
}
private
static
void
HandleTypesWithUnitOfWorkAttribute
(
TypeInfo
implementationType
,
IHandler
handler
)
{
if
(
IsUnitOfWorkType
(
implementationType
)
||
AnyMethodHasUnitOfWork
(
implementationType
))
{
handler
.
ComponentModel
.
Interceptors
.
Add
(
new
InterceptorReference
(
typeof
(
UnitOfWorkInterceptor
)));
}
}
private
static
void
HandleConventionalUnitOfWorkTypes
(
IIocManager
iocManager
,
TypeInfo
implementationType
,
IHandler
handler
)
{
if
(!
iocManager
.
IsRegistered
<
IUnitOfWorkDefaultOptions
>())
{
return
;
}
var
uowOptions
=
iocManager
.
Resolve
<
IUnitOfWorkDefaultOptions
>();
if
(
uowOptions
.
IsConventionalUowClass
(
implementationType
.
AsType
()))
{
handler
.
ComponentModel
.
Interceptors
.
Add
(
new
InterceptorReference
(
typeof
(
UnitOfWorkInterceptor
)));
}
}
private
static
bool
IsUnitOfWorkType
(
TypeInfo
implementationType
)
{
return
UnitOfWorkHelper
.
HasUnitOfWorkAttribute
(
implementationType
);
}
private
static
bool
AnyMethodHasUnitOfWork
(
TypeInfo
implementationType
)
{
return
implementationType
.
GetMethods
(
BindingFlags
.
Instance
|
BindingFlags
.
Public
|
BindingFlags
.
NonPublic
)
.
Any
(
UnitOfWorkHelper
.
HasUnitOfWorkAttribute
);
}
}
}
\ No newline at end of file
src/Plus/InternalAsyncHelper.cs
0 → 100644
View file @
e1abb5b0
using
System
;
using
System.Reflection
;
using
System.Threading.Tasks
;
namespace
Plus
{
internal
static
class
InternalAsyncHelper
{
public
static
async
Task
AwaitTaskWithFinally
(
Task
actualReturnValue
,
Action
<
Exception
>
finalAction
)
{
Exception
exception
=
null
;
try
{
await
actualReturnValue
;
}
catch
(
Exception
ex
)
{
exception
=
ex
;
throw
;
}
finally
{
finalAction
(
exception
);
}
}
public
static
async
Task
AwaitTaskWithPostActionAndFinally
(
Task
actualReturnValue
,
Func
<
Task
>
postAction
,
Action
<
Exception
>
finalAction
)
{
Exception
exception
=
null
;
try
{
await
actualReturnValue
;
await
postAction
();
}
catch
(
Exception
ex
)
{
exception
=
ex
;
throw
;
}
finally
{
finalAction
(
exception
);
}
}
public
static
async
Task
AwaitTaskWithPreActionAndPostActionAndFinally
(
Func
<
Task
>
actualReturnValue
,
Func
<
Task
>
preAction
=
null
,
Func
<
Task
>
postAction
=
null
,
Action
<
Exception
>
finalAction
=
null
)
{
Exception
exception
=
null
;
try
{
if
(
preAction
!=
null
)
{
await
preAction
();
}
await
actualReturnValue
();
if
(
postAction
!=
null
)
{
await
postAction
();
}
}
catch
(
Exception
ex
)
{
exception
=
ex
;
throw
;
}
finally
{
finalAction
?.
Invoke
(
exception
);
}
}
public
static
async
Task
<
T
>
AwaitTaskWithFinallyAndGetResult
<
T
>(
Task
<
T
>
actualReturnValue
,
Action
<
Exception
>
finalAction
)
{
Exception
exception
=
null
;
try
{
return
await
actualReturnValue
;
}
catch
(
Exception
ex
)
{
exception
=
ex
;
throw
;
}
finally
{
finalAction
(
exception
);
}
}
public
static
object
CallAwaitTaskWithFinallyAndGetResult
(
Type
taskReturnType
,
object
actualReturnValue
,
Action
<
Exception
>
finalAction
)
{
return
typeof
(
InternalAsyncHelper
).
GetMethod
(
"AwaitTaskWithFinallyAndGetResult"
,
BindingFlags
.
Static
|
BindingFlags
.
Public
).
MakeGenericMethod
(
taskReturnType
).
Invoke
(
null
,
new
object
[
2
]
{
actualReturnValue
,
finalAction
});
}
public
static
async
Task
<
T
>
AwaitTaskWithPostActionAndFinallyAndGetResult
<
T
>(
Task
<
T
>
actualReturnValue
,
Func
<
Task
>
postAction
,
Action
<
Exception
>
finalAction
)
{
Exception
exception
=
null
;
try
{
T
result
=
await
actualReturnValue
;
await
postAction
();
return
result
;
}
catch
(
Exception
ex
)
{
exception
=
ex
;
throw
;
}
finally
{
finalAction
(
exception
);
}
}
public
static
object
CallAwaitTaskWithPostActionAndFinallyAndGetResult
(
Type
taskReturnType
,
object
actualReturnValue
,
Func
<
Task
>
action
,
Action
<
Exception
>
finalAction
)
{
return
typeof
(
InternalAsyncHelper
).
GetMethod
(
"AwaitTaskWithPostActionAndFinallyAndGetResult"
,
BindingFlags
.
Static
|
BindingFlags
.
Public
).
MakeGenericMethod
(
taskReturnType
).
Invoke
(
null
,
new
object
[
3
]
{
actualReturnValue
,
action
,
finalAction
});
}
public
static
async
Task
<
T
>
AwaitTaskWithPreActionAndPostActionAndFinallyAndGetResult
<
T
>(
Func
<
Task
<
T
>>
actualReturnValue
,
Func
<
Task
>
preAction
=
null
,
Func
<
Task
>
postAction
=
null
,
Action
<
Exception
>
finalAction
=
null
)
{
Exception
exception
=
null
;
try
{
if
(
preAction
!=
null
)
{
await
preAction
();
}
T
result
=
await
actualReturnValue
();
if
(
postAction
!=
null
)
{
await
postAction
();
}
return
result
;
}
catch
(
Exception
ex
)
{
exception
=
ex
;
throw
;
}
finally
{
finalAction
?.
Invoke
(
exception
);
}
}
public
static
object
CallAwaitTaskWithPreActionAndPostActionAndFinallyAndGetResult
(
Type
taskReturnType
,
Func
<
object
>
actualReturnValue
,
Func
<
Task
>
preAction
=
null
,
Func
<
Task
>
postAction
=
null
,
Action
<
Exception
>
finalAction
=
null
)
{
return
typeof
(
InternalAsyncHelper
).
GetMethod
(
"AwaitTaskWithPreActionAndPostActionAndFinallyAndGetResult"
,
BindingFlags
.
Static
|
BindingFlags
.
Public
).
MakeGenericMethod
(
taskReturnType
).
Invoke
(
null
,
new
object
[
4
]
{
actualReturnValue
,
preAction
,
postAction
,
finalAction
});
}
}
}
\ No newline at end of file
src/Plus/PlusStarter.cs
View file @
e1abb5b0
...
...
@@ -3,6 +3,7 @@ using Castle.MicroKernel.Registration;
using
Plus.Configuration.Startup
;
using
Plus.Dependency
;
using
Plus.Dependency.Installers
;
using
Plus.Domain.Uow
;
using
Plus.Modules
;
using
Plus.Runtime.Validation.Interception
;
using
System
;
...
...
@@ -99,7 +100,7 @@ namespace Plus
public
void
AddInterceptorRegistrars
()
{
ValidationInterceptorRegistrar
.
Initialize
(
IocManager
);
//
UnitOfWorkRegistrar.Initialize(IocManager);
UnitOfWorkRegistrar
.
Initialize
(
IocManager
);
}
}
}
\ 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