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的站点配置信息:
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: }
未完、待续……