重新整理.net core 計1400篇[九] (.net core 中的依賴注入的服務的消費)

前言

包含服務註冊信息IServiceCollection 集合最終被用來創建作爲依賴注入容器的IServiceProvider 對象。

當需要創建某個服務實例的時候(服務消費),我們通過指定服務類型調用IServiceProvider 接口GetService 方法即可。

那麼來看下和IServiceProvider 相關的東西吧。

IServiceProvider

這裏面只有一個提供服務的方法:

/// <summary>Defines a mechanism for retrieving a service object; that is, an object that provides custom support to other objects.</summary>
public interface IServiceProvider
{
	/// <summary>Gets the service object of the specified type.</summary>
	/// <param name="serviceType">An object that specifies the type of service object to get.</param>
	/// <returns>A service object of type <paramref name="serviceType">serviceType</paramref>.  
	///  -or-  
	///  null if there is no service object of type <paramref name="serviceType">serviceType</paramref>.</returns>
	object GetService(Type serviceType);
}

在創建IServiceProvider的對象創建上,有三個構造函數:

public static class ServiceCollectionContainerBuilderExtensions
{
	/// <summary>
	/// Creates a <see cref="T:Microsoft.Extensions.DependencyInjection.ServiceProvider" /> containing services from the provided <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" />.
	/// </summary>
	/// <param name="services">The <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" /> containing service descriptors.</param>
	/// <returns>The <see cref="T:Microsoft.Extensions.DependencyInjection.ServiceProvider" />.</returns>
	public static ServiceProvider BuildServiceProvider(this IServiceCollection services)
	{
		return services.BuildServiceProvider(ServiceProviderOptions.Default);
	}

	/// <summary>
	/// Creates a <see cref="T:Microsoft.Extensions.DependencyInjection.ServiceProvider" /> containing services from the provided <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" />
	/// optionally enabling scope validation.
	/// </summary>
	/// <param name="services">The <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" /> containing service descriptors.</param>
	/// <param name="validateScopes">
	/// <c>true</c> to perform check verifying that scoped services never gets resolved from root provider; otherwise <c>false</c>.
	/// </param>
	/// <returns>The <see cref="T:Microsoft.Extensions.DependencyInjection.ServiceProvider" />.</returns>
	public static ServiceProvider BuildServiceProvider(this IServiceCollection services, bool validateScopes)
	{
		return services.BuildServiceProvider(new ServiceProviderOptions
		{
			ValidateScopes = validateScopes
		});
	}

	/// <summary>
	/// Creates a <see cref="T:Microsoft.Extensions.DependencyInjection.ServiceProvider" /> containing services from the provided <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" />
	/// optionally enabling scope validation.
	/// </summary>
	/// <param name="services">The <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection" /> containing service descriptors.</param>
	/// <param name="options">
	/// Configures various service provider behaviors.
	/// </param>
	/// <returns>The <see cref="T:Microsoft.Extensions.DependencyInjection.ServiceProvider" />.</returns>
	public static ServiceProvider BuildServiceProvider(this IServiceCollection services, ServiceProviderOptions options)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		if (services == null)
		{
			throw new ArgumentNullException("services");
		}
		if (options == null)
		{
			throw new ArgumentNullException("options");
		}
		return new ServiceProvider((IEnumerable<ServiceDescriptor>)services, options);
	}
}

我們看到無論其如何構造,那麼都有一個ServiceProviderOptions配置類。

這個配置我前面8中解釋過,就是對注入服務的範圍檢測。

那麼還有一個重要的問題,難道我們只能根據getservice 去獲取服務對象?來看看獲取服務的擴展。

查看ServiceProviderServiceExtensions類:

裏面有一些:

public static T GetService<T>(this IServiceProvider provider)
{
	//IL_0008: Unknown result type (might be due to invalid IL or missing references)
	if (provider == null)
	{
		throw new ArgumentNullException("provider");
	}
	return (T)provider.GetService(Type.GetTypeFromHandle(typeof(T).TypeHandle));
}

/// <summary>
/// Get service of type <paramref name="serviceType" /> from the <see cref="T:System.IServiceProvider" />.
/// </summary>
/// <param name="provider">The <see cref="T:System.IServiceProvider" /> to retrieve the service object from.</param>
/// <param name="serviceType">An object that specifies the type of service object to get.</param>
/// <returns>A service object of type <paramref name="serviceType" />.</returns>
/// <exception cref="T:System.InvalidOperationException">There is no service of type <paramref name="serviceType" />.</exception>
public static object GetRequiredService(this IServiceProvider provider, Type serviceType)
{
	//IL_0008: Unknown result type (might be due to invalid IL or missing references)
	//IL_001c: Unknown result type (might be due to invalid IL or missing references)
	//IL_0044: Unknown result type (might be due to invalid IL or missing references)
	if (provider == null)
	{
		throw new ArgumentNullException("provider");
	}
	if (serviceType == (Type)null)
	{
		throw new ArgumentNullException("serviceType");
	}
	ISupportRequiredService supportRequiredService = provider as ISupportRequiredService;
	if (supportRequiredService != null)
	{
		return supportRequiredService.GetRequiredService(serviceType);
	}
	object service = provider.GetService(serviceType);
	if (service == null)
	{
		throw new InvalidOperationException(Resources.FormatNoServiceRegistered(serviceType));
	}
	return service;
}

/// <summary>
/// Get service of type <typeparamref name="T" /> from the <see cref="T:System.IServiceProvider" />.
/// </summary>
/// <typeparam name="T">The type of service object to get.</typeparam>
/// <param name="provider">The <see cref="T:System.IServiceProvider" /> to retrieve the service object from.</param>
/// <returns>A service object of type <typeparamref name="T" />.</returns>
/// <exception cref="T:System.InvalidOperationException">There is no service of type <typeparamref name="T" />.</exception>
public static T GetRequiredService<T>(this IServiceProvider provider)
{
	//IL_0008: Unknown result type (might be due to invalid IL or missing references)
	if (provider == null)
	{
		throw new ArgumentNullException("provider");
	}
	return (T)provider.GetRequiredService(Type.GetTypeFromHandle(typeof(T).TypeHandle));
}

/// <summary>
/// Get an enumeration of services of type <typeparamref name="T" /> from the <see cref="T:System.IServiceProvider" />.
/// </summary>
/// <typeparam name="T">The type of service object to get.</typeparam>
/// <param name="provider">The <see cref="T:System.IServiceProvider" /> to retrieve the services from.</param>
/// <returns>An enumeration of services of type <typeparamref name="T" />.</returns>
public static IEnumerable<T> GetServices<T>(this IServiceProvider provider)
{
	//IL_0008: Unknown result type (might be due to invalid IL or missing references)
	if (provider == null)
	{
		throw new ArgumentNullException("provider");
	}
	return provider.GetRequiredService<IEnumerable<T>>();
}

其餘的可以自己去查看。

服務的創建

我們知道服務的創建一般都是ioc自動選擇的,那麼假如我們一個class 裏面有多個構造函數,那麼會選擇哪一個呢?

public interface IFoo { }
public interface IBar { }
public interface IBaz { }
public interface IQux { }

public class Foo : IFoo { }
public class Bar : IBar { }
public class Baz : IBaz { }
public class Qux : IQux
{
	public Qux(IFoo foo) => Console.WriteLine("Selected constructor: Qux(IFoo)");
	public Qux(IFoo foo, IBar bar) => Console.WriteLine("Selected constructor: Qux(IFoo, IBar)");
	public Qux(IFoo foo, IBar bar, IBaz baz) => Console.WriteLine("Selected constructor: Qux(IFoo, IBar, IBaz)");
}
static void Main()
{
	new ServiceCollection()
		.AddTransient<IFoo, Foo>()
		.AddTransient<IBar, Bar>()
		.AddTransient<IQux, Qux>()
		.BuildServiceProvider()
		.GetServices<IQux>();
	Console.ReadKey();
}

上面Qux有三個控制類,那麼選擇哪一個呢?

看下結果:

那麼爲什麼會是這一個呢?

第一:IBaz類型沒有註冊,那麼會排除掉Qux(IFoo foo, IBar bar, IBaz baz)

第二就是裏面的一個規則:每一個候選構造參數類型的集合都是這個構造函數參數類型的子集。

好的,那麼好了,剩下:Qux(IFoo foo, IBar bar) 包含了Qux(IFoo foo) 那麼就是Qux(IFoo foo, IBar bar),如果沒有包含全部子集的那麼就會報錯。

Qux(IFoo foo, IBar bar) 也就是超集的意思。

改一下:

public interface IFoo { }
public interface IBar { }
public interface IBaz { }
public interface IQux { }

public class Foo : IFoo { }
public class Bar : IBar { }
public class Baz : IBaz { }
public class Qux : IQux
{
	public Qux(IFoo foo, IBaz baz) => Console.WriteLine("Selected constructor: Qux(IFoo, IBar)");
	public Qux(IFoo foo, IBar bar) => Console.WriteLine("Selected constructor: Qux(IFoo, IBar, IBaz)");
}
static void Main()
{
	new ServiceCollection()
		.AddTransient<IFoo, Foo>()
		.AddTransient<IBar, Bar>()
		.AddTransient<IBaz,Baz>()
		.AddTransient<IQux, Qux>()
		.BuildServiceProvider()
		.GetServices<IQux>();
	Console.ReadKey();
}

這時候報錯爲:

下一節

服務的生命週期

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章