ASP.NET使用StructureMap等依賴注入元件時最重要就是EntityFramework的DbContext物件要保證在每次HttpRequest只有一個DbContext例項,這裡將使用第三方提供的HttpSimulator進行測試。
1.定義IDependency介面
建立遮蔽不同依賴注入元件使用差別的介面。
public interface IDependency { void Build(); void EndRequest(); void AddTransient(Type from, Type to, object instance = null); void AddScoped(Type from, Type to, object instance = null); void AddSingleton(Type from, Type to, object instance = null); object GetInstance(Type type); IEnumerable GetAllInstances(Type type); }
2.提供StructureMap的適配類StructureMapAdapter
public class StructureMapAdapter : IDependency, IDisposable { private bool _disposed = false; private Container _container; private Registry _registry; public StructureMapAdapter() { this._registry = new Registry(); } public void Build() { _container = new Container(_registry); } public void EndRequest() { HttpContextLifecycle.DisposeAndClearAll(); } public void AddTransient(Type from, Type to, object instance = null) { if (instance == null) { _registry.For(from).Use(to).LifecycleIs<TransientLifecycle>(); } else { _registry.For(from).Use(instance).LifecycleIs<TransientLifecycle>(); } } public void AddScoped(Type from, Type to, object instance = null) { if (instance == null) { _registry.For(from).Use(to).LifecycleIs<HttpContextLifecycle>(); } else { _registry.For(from).Use(instance).LifecycleIs<HttpContextLifecycle>(); } } public void AddSingleton(Type from, Type to, object instance = null) { if (instance == null) { _registry.For(from).Use(to).LifecycleIs<SingletonLifecycle>(); } else { _registry.For(from).Use(instance).LifecycleIs<SingletonLifecycle>(); } } public object GetInstance(Type type) { return _container.GetInstance(type); } public IEnumerable GetAllInstances(Type type) { return _container.GetAllInstances(type); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { this._container.Dispose(); } _disposed = true; } } }
3.使用HttpSimulator進行單元測試
public class StructureMapAdapterTest { [Fact] public void TransientTest() { IDependency dependency = new StructureMapAdapter(); dependency.AddTransient(typeof(ITest), typeof(Test)); dependency.Build(); var version1 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; var version2 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; Assert.NotEqual(version1, version2); } [Fact] public void SingletonTest() { IDependency dependency = new StructureMapAdapter(); dependency.AddSingleton(typeof(ITest), typeof(Test)); dependency.Build(); var version1 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; var version2 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; Assert.Equal(version1, version2); } [Fact] public void ScopedTest() { var version1 = ""; var version2 = ""; using (HttpSimulator simulator = new HttpSimulator()) { IDependency dependency = new StructureMapAdapter(); dependency.AddScoped(typeof(ITest), typeof(Test)); dependency.Build(); simulator.SimulateRequest(new Uri("http://localhost/")); version1 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; version2 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; Assert.Equal(version1, version2); } using (HttpSimulator simulator = new HttpSimulator()) { IDependency dependency = new StructureMapAdapter(); dependency.AddScoped(typeof(ITest), typeof(Test)); dependency.Build(); simulator.SimulateRequest(new Uri("http://localhost/")); version1 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; } using (HttpSimulator simulator = new HttpSimulator()) { IDependency dependency = new StructureMapAdapter(); dependency.AddScoped(typeof(ITest), typeof(Test)); dependency.Build(); simulator.SimulateRequest(new Uri("http://localhost/")); version2 = ((ITest)dependency.GetInstance(typeof(ITest))).Version; } Assert.NotEqual(version1, version2); } } public interface ITest { String Version { get; } } public class Test : ITest { private string _version = Guid.NewGuid().ToString(); public string Version { get { return this._version; } } }
執行結果: