[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(4)
2015-05-24 14:31
489 查看
这个系列已经写了6篇,链接地址如下:
[Asp.net 5] DependencyInjection项目代码分析
[Asp.net 5] DependencyInjection项目代码分析2-Autofac
[Asp.net 5] DependencyInjection项目代码分析3-Ninject
[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1)
[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2)
[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(3)
如果想对本篇有个更好的了解,建议需要先看
“[Asp.net 5] DependencyInjection项目代码分析”
“[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1)”
“[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2)”。
"[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(3)"
继续[b][b]ServiceProvider类[/b][/b]
在之前的讲解中我们提到过Service类调用CreateCallSite方法时会递归调用,但是我们没具体说明如何递归调的。实际上Service类,通过反射创建实例的时候,会实例化的参数对象,而实例话参数对象通过[b]ServiceProvider[/b]类创建,而[b]ServiceProvider[/b]类创建参数的实例,又需要通过Service类(如果是通过Type注册的)创建。下面我们把Service的CreateInstanceCallSite方法以及[b]ServiceProvider[/b]相关的方法列出来。
View Code
该工程所有类的关系图(包括内部类以及一些接口),如下所示:
补充说明
IServiceCallSite中定义了Build方法,该方法使用了Expression,但是该篇文章没有对其进行具体的研究,并且Build方法是相对独立的。
对于OpenIEnumerableService泛型省略详解。
示例测试代码:
[Asp.net 5] DependencyInjection项目代码分析
[Asp.net 5] DependencyInjection项目代码分析2-Autofac
[Asp.net 5] DependencyInjection项目代码分析3-Ninject
[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1)
[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2)
[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(3)
如果想对本篇有个更好的了解,建议需要先看
“[Asp.net 5] DependencyInjection项目代码分析”
“[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1)”
“[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2)”。
"[Asp.net 5] DependencyInjection项目代码分析4-微软的实现(3)"
继续[b][b]ServiceProvider类[/b][/b]
在之前的讲解中我们提到过Service类调用CreateCallSite方法时会递归调用,但是我们没具体说明如何递归调的。实际上Service类,通过反射创建实例的时候,会实例化的参数对象,而实例话参数对象通过[b]ServiceProvider[/b]类创建,而[b]ServiceProvider[/b]类创建参数的实例,又需要通过Service类(如果是通过Type注册的)创建。下面我们把Service的CreateInstanceCallSite方法以及[b]ServiceProvider[/b]相关的方法列出来。
private class EmptyIEnumerableCallSite : IServiceCallSite { private readonly object _serviceInstance; private readonly Type _serviceType; public EmptyIEnumerableCallSite(Type serviceType, object serviceInstance) { _serviceType = serviceType; _serviceInstance = serviceInstance; } public object Invoke(ServiceProvider provider) { return _serviceInstance; } public Expression Build(Expression provider) { return Expression.Constant(_serviceInstance, _serviceType); } } private class TransientCallSite : IServiceCallSite { private readonly IServiceCallSite _service; public TransientCallSite(IServiceCallSite service) { _service = service; } public object Invoke(ServiceProvider provider) { return provider.CaptureDisposable(_service.Invoke(provider)); } public Expression Build(Expression provider) { return Expression.Call( provider, CaptureDisposableMethodInfo, _service.Build(provider)); } } private class ScopedCallSite : IServiceCallSite { private readonly IService _key; private readonly IServiceCallSite _serviceCallSite; public ScopedCallSite(IService key, IServiceCallSite serviceCallSite) { _key = key; _serviceCallSite = serviceCallSite; } public virtual object Invoke(ServiceProvider provider) { object resolved; lock (provider._sync) { if (!provider._resolvedServices.TryGetValue(_key, out resolved)) { resolved = provider.CaptureDisposable(_serviceCallSite.Invoke(provider)); provider._resolvedServices.Add(_key, resolved); } } return resolved; } public virtual Expression Build(Expression providerExpression) { var keyExpression = Expression.Constant( _key, typeof(IService)); var resolvedExpression = Expression.Variable(typeof(object), "resolved"); var resolvedServicesExpression = Expression.Field( providerExpression, "_resolvedServices"); var tryGetValueExpression = Expression.Call( resolvedServicesExpression, TryGetValueMethodInfo, keyExpression, resolvedExpression); var captureDisposableExpression = Expression.Assign( resolvedExpression, Expression.Call( providerExpression, CaptureDisposableMethodInfo, _serviceCallSite.Build(providerExpression))); var addValueExpression = Expression.Call( resolvedServicesExpression, AddMethodInfo, keyExpression, resolvedExpression); var blockExpression = Expression.Block( typeof(object), new[] { resolvedExpression }, Expression.IfThen( Expression.Not(tryGetValueExpression), Expression.Block(captureDisposableExpression, addValueExpression)), resolvedExpression); return Lock(providerExpression, blockExpression); } private static Expression Lock(Expression providerExpression, Expression body) { // The C# compiler would copy the lock object to guard against mutation. // We don't, since we know the lock object is readonly. var syncField = Expression.Field(providerExpression, "_sync"); var lockWasTaken = Expression.Variable(typeof(bool), "lockWasTaken"); var monitorEnter = Expression.Call(MonitorEnterMethodInfo, syncField, lockWasTaken); var monitorExit = Expression.Call(MonitorExitMethodInfo, syncField); var tryBody = Expression.Block(monitorEnter, body); var finallyBody = Expression.IfThen(lockWasTaken, monitorExit); return Expression.Block( typeof(object), new[] { lockWasTaken }, Expression.TryFinally(tryBody, finallyBody)); } } private class SingletonCallSite : ScopedCallSite { public SingletonCallSite(IService key, IServiceCallSite serviceCallSite) : base(key, serviceCallSite) { } public override object Invoke(ServiceProvider provider) { return base.Invoke(provider._root); } public override Expression Build(Expression provider) { return base.Build(Expression.Field(provider, "_root")); } }
View Code
该工程所有类的关系图(包括内部类以及一些接口),如下所示:
补充说明
IServiceCallSite中定义了Build方法,该方法使用了Expression,但是该篇文章没有对其进行具体的研究,并且Build方法是相对独立的。
对于OpenIEnumerableService泛型省略详解。
示例测试代码:
public static class TestServices { public static IServiceCollection DefaultServices() { var services = new ServiceCollection(); services.AddTransient<IFakeService, FakeService>(); services.AddTransient<IFakeMultipleService, FakeOneMultipleService>(); services.AddTransient<IFakeMultipleService, FakeTwoMultipleService>(); services.AddTransient<IFakeOuterService, FakeOuterService>(); services.AddInstance<IFakeServiceInstance>(new FakeService() { Message = "Instance" }); services.AddScoped<IFakeScopedService, FakeService>(); services.AddSingleton<IFakeSingletonService, FakeService>(); services.AddTransient<IDependOnNonexistentService, DependOnNonexistentService>(); services.AddTransient<IFakeOpenGenericService<string>, FakeService>(); services.AddTransient(typeof(IFakeOpenGenericService<>), typeof(FakeOpenGenericService<>)); services.AddTransient<IFactoryService>(provider => { var fakeService = provider.GetService<IFakeService>(); return new TransientFactoryService { FakeService = fakeService, Value = 42 }; }); services.AddScoped(provider => { var fakeService = provider.GetService<IFakeService>(); return new ScopedFactoryService { FakeService = fakeService, }; }); services.AddTransient<ServiceAcceptingFactoryService, ServiceAcceptingFactoryService>(); return services; } } public class ServiceProviderContainerTests : ScopingContainerTestBase { protected override IServiceProvider CreateContainer() { return TestServices.DefaultServices().BuildServiceProvider(); } [Fact] public void ScopedServiceCanBeResolved() { IServiceProvider container = CreateContainer(); var scopeFactory = container.GetService<IServiceScopeFactory>(); using (var scope = scopeFactory.CreateScope()) { var containerScopedService = container.GetService<IFakeScopedService>(); var scopedService1 = scope.ServiceProvider.GetService<IFakeScopedService>(); Thread.Sleep(200); var scopedService2 = scope.ServiceProvider.GetService<IFakeScopedService>(); Assert.NotEqual(containerScopedService, scopedService1); Assert.Equal(scopedService1, scopedService2); } } }
相关文章推荐
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(1)
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(2)
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(3)
- [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable<>补充)
- [Asp.net 5] DependencyInjection项目代码分析
- [Asp.net 5] DependencyInjection项目代码分析2-Autofac
- [Asp.net 5] DependencyInjection项目代码分析3-Ninject
- [Asp.net 5] DependencyInjection项目代码分析-目录
- 微软Asp.Net架构与项目团队管理建设模型分析
- 微软Asp.Net架构与项目团队管理建设模型分析
- Asp.net 2.0 自定义控件开发[实现GridView多行表头固定表体滚动效果][示例代码下载]
- 在 ASP.NET 网页中不经过回发而实现客户端回调(附Gridview无刷新代码)
- 在 ASP.NET 网页中不经过回发而实现客户端回调(附Gridview无刷新代码)
- asp.net 实现购物车详细代码
- Asp.net 2.0 用 FileUpload 控件实现多文件上传 用户控件(示例代码下载)
- Asp.net在线压缩和解压缩简单实现(附项目源码)
- 在ASP.Net中实现flv视频转换的代码
- 在ASP.Net中实现flv视频转换的代码
- ASP.NET 2.0客户端回调的实现分析
- asp.net +C# +sql2000 实现仿csdn的图片轮换代码