ASP.NET MVC 開源專案Kigg解讀(2)——Kigg.Core第一部分
Kigg是一個很好的ASP.NET MVC範例專案,本著研究的目的,對Kigg進行解讀。
上一篇中,我們介紹了Kigg的啟動、後臺任務和事件聚合器。這一篇,我們來看看Kigg的核心類庫Kigg.Core
一、類庫一覽
Kigg.Core是Kigg的靈魂所在,主要包含:
- ConfigurationSettings:站點設定
- DomainObjects:領域模型
- Extension:對.NET物件的擴充套件
- Helper:一些幫助方法
- Infrastructure:基礎架構
- Repository:資料訪問
- Service:資料服務
二、雜項 在想到底用什麼來描述ConfigurationSettings,Extension,Helper,第一印象是雜項,那麼就叫雜項吧!ORZ~ 1、配置資訊 ConfigurationSettings其實是Kigg的站點配置資訊:
Kigg是通過在Unity的配置檔案中來設定這些配置資訊的
1: <type type="IConfigurationSettings" mapTo="ConfigurationSettings"> 2: <lifetime type="Singleton"/> 3: <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration"> 4: <property name="RootUrl" propertyType="System.String"> 5: <value type="System.String" value="http://localhost:4252"/> 6: </property> 7: <property name="WebmasterEmail" propertyType="System.String"> 8: <value type="System.String" value=""/> 9: </property> 10: // 省略…… 11: </typeConfig> 12: </type>
2、Extension
再來看Extension:
Extension包含了對集合、列舉物件、Guid、DateTime以及String的擴充套件,有興趣的同學可以去看看。
第一篇中的ForEach就來自於EnumerableExtension
1: public static class EnumerableExtension 2: { 3: [DebuggerStepThrough] 4: public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action) 5: { 6: foreach (T item in enumerable) 7: { 8: action(item); 9: } 10: } 11: }
3、Helper
最後看看Helper
這裡包含了一些幫助類庫:
CheckArgument是引數檢驗,比如:
1:
2: [DebuggerStepThrough]
3: public static void IsNotEmpty(Guid argument, string argumentName)
4: {
5: if (argument == Guid.Empty)
6: {
7: throw new ArgumentException(""{0}" cannot be empty guid.".FormatWith(argumentName), argumentName);
8: }
9: }
CheckArgument廣泛的運用在Kigg.Core的方法中,比如第一部分中的
1: public StartBackgroundTasks(IBackgroundTask[] tasks)
2: {
3: Check.Argument.IsNotEmpty(tasks, "tasks");
4: _tasks = tasks; 10:
5: }
PagedResult是個有意思的玩意,如果你使用過Subsonic,你會發現這個和PagedList有點像。PagedResult在Kigg中作為獲取列表方法的返回型別,包含了結果集和總記錄數,因此分頁就比較方便了。
1: public class PagedResult<T>
2: {
3: private readonly ReadOnlyCollection<T> _result;
4: private readonly int _total;
5:
6: public PagedResult(IEnumerable<T> result, int total)
7: {
8: Check.Argument.IsNotNull(result, "result");
9: Check.Argument.IsNotNegative(total, "total");
10:
11: _result = new ReadOnlyCollection<T>(new List<T>(result));
12: _total = total;
13: }
14:
15: public PagedResult() : this(new List<T>(), 0)
16: {
17: }
18:
19: public ICollection<T> Result
20: {
21: [DebuggerStepThrough]
22: get
23: {
24: return _result;
25: }
26: }
27:
28: public int Total
29: {
30: [DebuggerStepThrough]
31: get
32: {
33: return _total;
34: }
35: }
36:
37: public bool IsEmpty
38: {
39: [DebuggerStepThrough]
40: get
41: {
42: return _result.Count == 0;
43: }
44: }
45: }
三、基礎架構
話說,這一塊是Kigg比較核心的部分。
這裡包含了前面提到的Boot、BackgroundTask和EventAggrator,在這裡就不再多說了。
1、IOC
IOC是Kigg的基石,大部分的類的例項化和狀態維持都由它來實現。Kigg使用Unity來作為IOC工具,想要簡單的話,直接使用Unity就可以了,但是為了解除與Unity的依賴,Kigg特地抽象出一個介面IDependencyResolver:
1: public interface IDependencyResolver : IDisposable
2: {
3: void Register<T>(T instance);
4:
5: void Inject<T>(T existing);
6:
7: T Resolve<T>(Type type);
8:
9: T Resolve<T>(Type type, string name);
10:
11: T Resolve<T>();
12:
13: T Resolve<T>(string name);
14:
15: IEnumerable<T> ResolveAll<T>();
16: }
這樣,不管使用什麼IOC工具,只需要實現這個介面就可以了。
在沒用IOC的時候,要建立一個藉口的例項怎麼做?用工廠模式唄!這樣在AppSetting中配置下dependencyResolverTypeName就可以了
1: public interface IDependencyResolverFactory
2: {
3: IDependencyResolver CreateInstance();
4: }
5: public class DependencyResolverFactory : IDependencyResolverFactory
6: {
7: private readonly Type _resolverType;
8:
9: public DependencyResolverFactory(string resolverTypeName)
10: {
11: Check.Argument.IsNotEmpty(resolverTypeName, "resolverTypeName");
12:
13: _resolverType = Type.GetType(resolverTypeName, true, true);
14: }
15:
16: public DependencyResolverFactory() : this(new ConfigurationManagerWrapper().AppSettings["dependencyResolverTypeName"])
17: {
18: }
19:
20: public IDependencyResolver CreateInstance()
21: {
22: return Activator.CreateInstance(_resolverType) as IDependencyResolver;
23: }
24: }
為了方便使用IOC,Kigg特定建立了一個靜態類庫IOC:
1: public static class IoC
2: {
3: private static IDependencyResolver _resolver;
4:
5: [DebuggerStepThrough]
6: public static void InitializeWith(IDependencyResolverFactory factory)
7: {
8: Check.Argument.IsNotNull(factory, "factory");
9:
10: _resolver = factory.CreateInstance();
11: }
12:
13: [DebuggerStepThrough]
14: public static void Register<T>(T instance)
15: {
16: Check.Argument.IsNotNull(instance, "instance");
17:
18: _resolver.Register(instance);
19: }
20:
21: [DebuggerStepThrough]
22: public static void Inject<T>(T existing)
23: {
24: Check.Argument.IsNotNull(existing, "existing");
25:
26: _resolver.Inject(existing);
27: }
28:
29: [DebuggerStepThrough]
30: public static T Resolve<T>(Type type)
31: {
32: Check.Argument.IsNotNull(type, "type");
33:
34: return _resolver.Resolve<T>(type);
35: }
36:
37: [DebuggerStepThrough]
38: public static T Resolve<T>(Type type, string name)
39: {
40: Check.Argument.IsNotNull(type, "type");
41: Check.Argument.IsNotEmpty(name, "name");
42:
43: return _resolver.Resolve<T>(type, name);
44: }
45:
46: [DebuggerStepThrough]
47: public static T Resolve<T>()
48: {
49: return _resolver.Resolve<T>();
50: }
51:
52: [DebuggerStepThrough]
53: public static T Resolve<T>(string name)
54: {
55: Check.Argument.IsNotEmpty(name, "name");
56:
57: return _resolver.Resolve<T>(name);
58: }
59:
60: [DebuggerStepThrough]
61: public static IEnumerable<T> ResolveAll<T>()
62: {
63: return _resolver.ResolveAll<T>();
64: }
65:
66: [DebuggerStepThrough]
67: public static void Reset()
68: {
69: if (_resolver != null)
70: {
71: _resolver.Dispose();
72: }
73: }
74: }
在使用的使用,需要先呼叫IoC.InitializeWith(),初始化IoC內部的靜態欄位_resolver,然後就可以直接方便的使用IOC了,回顧第一篇的程式碼:
1: public static class Bootstrapper
2: {
3: static Bootstrapper()
4: {
5: try
6: {
7: IoC.InitializeWith(new DependencyResolverFactory());
8: }
9: catch (ArgumentException)
10: {
11: // Config file is Missing
12: }
13: }
14:
15: public static void Run()
16: {
17: IoC.ResolveAll<IBootstrapperTask>().ForEach(t => t.Execute());
18: }
19: }
2、快取
快取元件很多,Kigg選用的是Enterprise Library。同樣的為了消除與快取元件的依賴,Kigg定義了自己的快取介面:
1: public interface ICache
2: {
3: int Count
4: {
5: get;
6: }
7:
8: void Clear();
9:
10: bool Contains(string key);
11:
12: T Get<T>(string key);
13:
14: bool TryGet<T>(string key, out T value);
15:
16: void Set<T>(string key, T value);
17:
18: void Set<T>(string key, T value, DateTime absoluteExpiration);
19:
20: void Set<T>(string key, T value, TimeSpan slidingExpiration);
21:
22: void Remove(string key);
23: }
同樣的,為了方便呼叫,Kigg建立了Cache靜態類,這次,採用的是一個靜態屬性,注意下InternalCache是通過IOC初始化的。這樣,只需要在IOC的配置檔案中指定下哪個具體的類實現了ICache介面就可以了。
1: public static class Cache
2: {
3: public static int Count
4: {
5: [DebuggerStepThrough]
6: get
7: {
8: return InternalCache.Count;
9: }
10: }
11:
12: private static ICache InternalCache
13: {
14: [DebuggerStepThrough]
15: get
16: {
17: return IoC.Resolve<ICache>();
18: }
19: }
20:
21: [DebuggerStepThrough]
22: public static void Clear()
23: {
24: InternalCache.Clear();
25: }
26:
27: [DebuggerStepThrough]
28: public static bool Contains(string key)
29: {
30: Check.Argument.IsNotEmpty(key, "key");
31:
32: return InternalCache.Contains(key);
33: }
34:
35: [DebuggerStepThrough]
36: public static T Get<T>(string key)
37: {
38: Check.Argument.IsNotEmpty(key, "key");
39:
40: return InternalCache.Get<T>(key);
41: }
42:
43: [DebuggerStepThrough]
44: public static bool TryGet<T>(string key, out T value)
45: {
46: Check.Argument.IsNotEmpty(key, "key");
47:
48: return InternalCache.TryGet(key, out value);
49: }
50:
51: [DebuggerStepThrough]
52: public static void Set<T>(string key, T value)
53: {
54: Check.Argument.IsNotEmpty(key, "key");
55:
56: InternalCache.Set(key, value);
57: } // 以下省略
84: }
3、日誌
日誌和快取同樣一個道理,有一個Log介面
1: public interface ILog
2: {
3: void Info(string message);
4:
5: void Warning(string message);
6:
7: void Error(string message);
8:
9: void Exception(Exception exception);
10: }
然後一個靜態類Log,這裡沒有用一個靜態的欄位或屬性來快取ILog介面,而是一個GetLog()方法,效率上不如前面的Cache,算是一個小瑕疵吧。
1: public static class Log
2: {
3: [MethodImpl(MethodImplOptions.NoInlining)]
4: [DebuggerStepThrough]
5: public static void Info(string message)
6: {
7: Check.Argument.IsNotEmpty(message, "message");
8:
9: GetLog().Info(message);
10: }
11:
12: // 省略部分程式碼
13:
14: [MethodImpl(MethodImplOptions.NoInlining)]
15: private static ILog GetLog()
16: {
17: return IoC.Resolve<ILog>();
18: }
19:
20: [MethodImpl(MethodImplOptions.NoInlining)]
21: private static string Format(string format, params object[] args)
22: {
23: Check.Argument.IsNotEmpty(format, "format");
24:
25: return format.FormatWith(args);
26: }
27: }
未完、待續……