1. 程式人生 > 其它 >ASP.NET MVC 開源專案Kigg解讀(2)——Kigg.Core第一部分

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:      }

未完、待續……