forked from anjoy8/Blog.Core
-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathBlogLogAOP.cs
More file actions
223 lines (193 loc) · 7.96 KB
/
BlogLogAOP.cs
File metadata and controls
223 lines (193 loc) · 7.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
using Blog.Core.Common.LogHelper;
using Blog.Core.Hubs;
using Blog.Core.Model.Models;
using Castle.DynamicProxy;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.SignalR;
using Newtonsoft.Json;
using StackExchange.Profiling;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
namespace Blog.Core.AOP
{
/// <summary>
/// 拦截器BlogLogAOP 继承IInterceptor接口
/// </summary>
public class BlogLogAOP : IInterceptor
{
private readonly IHubContext<ChatHub> _hubContext;
private readonly IHttpContextAccessor _accessor;
public BlogLogAOP(IHubContext<ChatHub> hubContext, IHttpContextAccessor accessor)
{
_hubContext = hubContext;
_accessor = accessor;
}
/// <summary>
/// 实例化IInterceptor唯一方法
/// </summary>
/// <param name="invocation">包含被拦截方法的信息</param>
public void Intercept(IInvocation invocation)
{
string UserName = _accessor.HttpContext?.User?.Identity?.Name;
//记录被拦截方法信息的日志信息
var dataIntercept = "" +
$"【当前操作用户】:{ UserName} \r\n" +
$"【当前执行方法】:{ invocation.Method.Name} \r\n" +
$"【携带的参数有】: {string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray())} \r\n";
try
{
MiniProfiler.Current.Step($"执行Service方法:{invocation.Method.Name}() -> ");
//在被拦截的方法执行完毕后 继续执行当前方法,注意是被拦截的是异步的
invocation.Proceed();
// 异步获取异常,先执行
if (IsAsyncMethod(invocation.Method))
{
#region 方案一
//Wait task execution and modify return value
if (invocation.Method.ReturnType == typeof(Task))
{
invocation.ReturnValue = InternalAsyncHelper.AwaitTaskWithPostActionAndFinally(
(Task)invocation.ReturnValue,
async () => await SuccessAction(invocation, dataIntercept),/*成功时执行*/
ex =>
{
LogEx(ex, dataIntercept);
});
}
//Task<TResult>
else
{
invocation.ReturnValue = InternalAsyncHelper.CallAwaitTaskWithPostActionAndFinallyAndGetResult(
invocation.Method.ReturnType.GenericTypeArguments[0],
invocation.ReturnValue,
//async () => await SuccessAction(invocation, dataIntercept),/*成功时执行*/
async (o) => await SuccessAction(invocation, dataIntercept, o),/*成功时执行*/
ex =>
{
LogEx(ex, dataIntercept);
});
}
#endregion
// 如果方案一不行,试试这个方案
#region 方案二
//var type = invocation.Method.ReturnType;
//var resultProperty = type.GetProperty("Result");
//dataIntercept += ($"【执行完成结果】:{JsonConvert.SerializeObject(resultProperty.GetValue(invocation.ReturnValue))}");
//Parallel.For(0, 1, e =>
//{
// LogLock.OutSql2Log("AOPLog", new string[] { dataIntercept });
//});
#endregion
}
else
{// 同步1
dataIntercept += ($"【执行完成结果】:{invocation.ReturnValue}");
Parallel.For(0, 1, e =>
{
LogLock.OutSql2Log("AOPLog", new string[] { dataIntercept });
});
}
}
catch (Exception ex)// 同步2
{
LogEx(ex, dataIntercept);
}
_hubContext.Clients.All.SendAsync("ReceiveUpdate", LogLock.GetLogData()).Wait();
}
private async Task SuccessAction(IInvocation invocation, string dataIntercept, object o = null)
{
invocation.ReturnValue = o;
var type = invocation.Method.ReturnType;
if (typeof(Task).IsAssignableFrom(type))
{
var resultProperty = type.GetProperty("Result");
//类型错误 都可以不要invocation参数,直接将o系列化保存到日记中
dataIntercept += ($"【执行完成结果】:{JsonConvert.SerializeObject(invocation.ReturnValue)}");
}
else
{
dataIntercept += ($"【执行完成结果】:{invocation.ReturnValue}");
}
await Task.Run(() =>
{
Parallel.For(0, 1, e =>
{
LogLock.OutSql2Log("AOPLog", new string[] { dataIntercept });
});
});
}
private void LogEx(Exception ex, string dataIntercept)
{
if (ex != null)
{
//执行的 service 中,收录异常
MiniProfiler.Current.CustomTiming("Errors:", ex.Message);
//执行的 service 中,捕获异常
dataIntercept += ($"【执行完成结果】:方法中出现异常:{ex.Message + ex.InnerException}\r\n");
// 异常日志里有详细的堆栈信息
Parallel.For(0, 1, e =>
{
LogLock.OutSql2Log("AOPLog", new string[] { dataIntercept });
});
}
}
public static bool IsAsyncMethod(MethodInfo method)
{
return (
method.ReturnType == typeof(Task) ||
(method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
);
}
}
internal static class InternalAsyncHelper
{
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;
}
finally
{
finalAction(exception);
}
}
public static async Task<T> AwaitTaskWithPostActionAndFinallyAndGetResult<T>(Task<T> actualReturnValue, Func<object, Task> postAction, Action<Exception> finalAction)
{
Exception exception = null;
try
{
var result = await actualReturnValue;
await postAction(result);
return result;
}
catch (Exception ex)
{
exception = ex;
throw;
}
finally
{
finalAction(exception);
}
}
public static object CallAwaitTaskWithPostActionAndFinallyAndGetResult(Type taskReturnType, object actualReturnValue, Func<object, Task> action, Action<Exception> finalAction)
{
return typeof(InternalAsyncHelper)
.GetMethod("AwaitTaskWithPostActionAndFinallyAndGetResult", BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(taskReturnType)
.Invoke(null, new object[] { actualReturnValue, action, finalAction });
}
}
}