How to register multiple implementations of the same interface in Asp.Net Core?

I have services derived from a single interface

public interface IService { } public class ServiceA : IService { } public class ServiceB : IService { } public class ServiceC : IService { } 

Usually, other IOC containers such as Unity allow you to register specific implementations with some Key that distinguishes them.

In Asp.Net Core, how do I register these services and solve them at runtime based on some kind of key?

I don’t see any of the Add Service methods accepting a key or name parameter, which is usually used to distinguish a specific implementation.

  public void ConfigureServices(IServiceCollection services) { // How do I register services here of the same interface } public MyController:Controller { public void DoSomeThing(string key) { // How do get service based on key } } 

Is Factory the only option here?

Update1
I read an article here that shows how to use the factory template to get service instances when we have several attempts to create instantiation. However, this is not a complete solution. when I _serviceProvider.GetService() method _serviceProvider.GetService() I can not enter data into the constructor. For example, consider this example.

 public class ServiceA : IService { private string _efConnectionString; ServiceA(string efconnectionString) { _efConnecttionString = efConnectionString; } } public class ServiceB : IService { private string _mongoConnectionString; public ServiceB(string mongoConnectionString) { _mongoConnectionString = mongoConnectionString; } } public class ServiceC : IService { private string _someOtherConnectionString public ServiceC(string someOtherConnectionString) { _someOtherConnectionString = someOtherConnectionString; } } 

How can _serviceProvider.GetService() enter the appropriate connection string? In Unity or any other IOC, we can do this during type registration. I can use IOption, however I need to enter all the settings, I can not enter a specific connection string in the service.

Also note that I try to avoid using other containers (including Unity), because then I need to register everything else (for example, controllers) with the new container.

Also using the factory template to instantiate the service against DIP, as the factory increases the number of dependencies that the client is forced to depend on the data here

So I think that by default DI in ASP.NET core is missing 2 things
1> Registering instances using the key
2> Insert static data into the constructor during registration

+152
c # asp.net-core asp.net-core-mvc coreclr
Aug 26 '16 at 21:42 on
source share
18 answers

I made a simple workaround using Func when I found myself in this situation.

 services.AddTransient<Consumer>(); services.AddTransient<ServiceA>(); services.AddTransient<ServiceB>(); services.AddTransient<ServiceC>(); services.AddTransient<Func<string, IService>>(serviceProvider => key => { switch(key) { case "A": return serviceProvider.GetService<ServiceA>(); case "B": return serviceProvider.GetService<ServiceB>(); case "C": return serviceProvider.GetService<ServiceC>(); default: throw new KeyNotFoundException(); // or maybe return null, up to you } }); 

And use it from any class registered in DI, for example:

 public class Consumer { private readonly Func<string, IService> serviceAccessor; public Consumer(Func<string, IService> serviceAccessor) { this.serviceAccessor = serviceAccesor; } public void UseServiceA() { //use serviceAccessor field to resolve desired type serviceAccessor("A").DoIServiceOperation(); } } 

UPDATE

Keep in mind that in this example, the key to resolving is the string, for simplicity and because the OP requested this particular case.

But you can use any custom permission type as a key, since you usually don't want a huge n-register to switch your code. Depends on how your application scales.

UPDATE 2

For readability, you can wrap Func<string, IService> inside a delegate such as public delegate IService ServiceResolver(string key) , and use ServiceResolver instead, where you will use the Func version.

+145
May 25 '17 at 10:14 a.m.
source share

Another option is to use the GetServices extension GetServices from Microsoft.Extensions.DependencyInjection .

Register your services as:

 services.AddSingleton<IService, ServiceA>(); services.AddSingleton<IService, ServiceB>(); services.AddSingleton<IService, ServiceC>(); 

Then enable a bit of Linq:

 var services = serviceProvider.GetServices<IService>(); var serviceB = services.First(o => o.GetType() == typeof(ServiceB)); 

or

 var serviceZ = services.First(o => o.Name.Equals("Z")); 

(assuming IService has a string property called "Name")

Mandatory using Microsoft.Extensions.DependencyInjection;

Refresh

AspNet 2.1 Source: GetServices

+59
Jul 03 '17 at 18:22
source share

It is not supported by Microsoft.Extensions.DependencyInjection .

But you can connect another dependency injection mechanism, for example, StructureMap View Home Page and GitHub Project .

It's not hard:

  • Add a link to StructureMap in your project.json :

     "Structuremap.Microsoft.DependencyInjection" : "1.0.1", 
  • Add it to the ASP.NET pipeline inside ConfigureServices and register your classes (see docs)

     public IServiceProvider ConfigureServices(IServiceCollection services) // returns IServiceProvider ! { // Add framework services. services.AddMvc(); services.AddWhatever(); //using StructureMap; var container = new Container(); container.Configure(config => { // Register stuff in container, using the StructureMap APIs... config.For<IPet>().Add(new Cat("CatA")).Named("A"); config.For<IPet>().Add(new Cat("CatB")).Named("B"); config.For<IPet>().Use("A"); // Optionally set a default config.Populate(services); }); return container.GetInstance<IServiceProvider>(); } 
  • Then, to get the named instance, you will need to query IContainer

     public class HomeController : Controller { public HomeController(IContainer injectedContainer) { var myPet = injectedContainer.GetInstance<IPet>("B"); string name = myPet.Name; // Returns "CatB" 

What is it.

To build an example you need

  public interface IPet { string Name { get; set; } } public class Cat : IPet { public Cat(string name) { Name = name; } public string Name {get; set; } } 
+15
Aug 26 '16 at 23:59 on
source share

I faced the same problem and want to share how I solved it and why.

As you mentioned, there are two problems. First:

In Asp.Net Core, how can I register these services and solve them at runtime based on some key?

So what are our options? People offer two:

  • Use a custom factory (e.g. _myFactory.GetServiceByKey(key) )

  • Use a different DI engine (e.g. _unityContainer.Resolve<IService>(key) )

Is a factory template the only option here?

In fact, both options are factories, because each IoC container is also a factory (very customizable and complex). And it seems to me that the other options are also variations of the factory pattern.

So which option is better? Here, I agree with @Sock, who suggested using a custom factory, and that is why.

First, I always try to avoid adding new dependencies when they are not really needed. Therefore, I agree with you on this issue. Moreover, using two DI structures is worse than creating a custom factory abstraction. In the second case, you need to add a new package dependency (for example, Unity), but depending on the new factory interface, here is less evil. I believe that the basic idea of ​​ASP.NET Core DI is simplicity. It supports a minimal set of functions following the KISS Principle . If you need an additional function, do DIY or use the appropriate Plungin , which implements the desired function (Open Closed Principle).

Secondly, often we need to introduce many named dependencies for a single service. In the case of Unity, you may need to provide names for constructor parameters (using the InjectionConstructor ). This registration uses reflection and some intelligent logic to guess the arguments for the constructor. It can also lead to runtime errors if registration does not match the constructor arguments. On the other hand, when using your own factory, you have full control over how to provide constructor parameters. This is more readable and resolved at compile time. KISS principle .

The second problem:

How can _serviceProvider.GetService () enter an appropriate connection string?

First, I agree with you that depending on new things like IOptions (and therefore on the Microsoft.Extensions.Options.ConfigurationExtensions package), this is not a good idea. I saw some discussing the issue of IOptions , where there were different opinions about its benefits. Again, I try to avoid adding new dependencies when they are not really needed. Is it really necessary? I think no. Otherwise, each implementation would have to depend on it without any obvious need for this implementation (for me, this looks like an ISP violation, where I also agree with you). This is also true depending on the factory, but in this case it can be avoided.

The ASP.NET Core DI kernel provides very good overload for this purpose:

 var mongoConnection = //... var efConnection = //... var otherConnection = //... services.AddTransient<IMyFactory>( s => new MyFactoryImpl( mongoConnection, efConnection, otherConnection, s.GetService<ISomeDependency1>(), s.GetService<ISomeDependency2>()))); 
+11
Aug 31 '16 at
source share

You are right, the built-in container ASP.NET Core does not have the concept of registering several services and then getting a certain factory, as you think, is the only real solution in this case.

Alternatively, you can switch to a third-party container, for example Unity or StructureMap, which provides the solution you need (described here: https://docs.asp.net/en/latest/fundamentals/dependency-injection.html?#replacing-the -default-services-container ).

+10
Aug 26 '16 at 23:43
source share

I just add IEnumerable

ConfigureServices in Startup.cs

 Assembly.GetEntryAssembly().GetTypesAssignableFrom<IService>().ForEach((t)=> { services.AddScoped(typeof(IService), t); }); 

Service Folder

 public interface IService { string Name { get; set; } } public class ServiceA : IService { public string Name { get { return "A"; } } } public class ServiceB : IService { public string Name { get { return "B"; } } } public class ServiceC : IService { public string Name { get { return "C"; } } } 

Mycontroller.cs

 public class MyController { private readonly IEnumerable<IService> _services; public MyController(IEnumerable<IService> services) { _services = services; } public void DoSomething() { var service = _services.Where(s => s.Name == "A").Single(); } ... } 

Extensions.cs

  public static List<Type> GetTypesAssignableFrom<T>(this Assembly assembly) { return assembly.GetTypesAssignableFrom(typeof(T)); } public static List<Type> GetTypesAssignableFrom(this Assembly assembly, Type compareType) { List<Type> ret = new List<Type>(); foreach (var type in assembly.DefinedTypes) { if (compareType.IsAssignableFrom(type) && compareType != type) { ret.Add(type); } } return ret; } 
+6
Aug 31 '18 at 21:04
source share

Apparently, you can just enter IEnumerable of your service interface! And then find the instance you want to use LINQ.

My example is for AWS SNS, but you can do the same for any embedded service.

Launch

 foreach (string snsRegion in Configuration["SNSRegions"].Split(',', StringSplitOptions.RemoveEmptyEntries)) { services.AddAWSService<IAmazonSimpleNotificationService>( string.IsNullOrEmpty(snsRegion) ? null : new AWSOptions() { Region = RegionEndpoint.GetBySystemName(snsRegion) } ); } services.AddSingleton<ISNSFactory, SNSFactory>(); services.Configure<SNSConfig>(Configuration); 

SNSConfig

 public class SNSConfig { public string SNSDefaultRegion { get; set; } public string SNSSMSRegion { get; set; } } 

appsettings.json

  "SNSRegions": "ap-south-1,us-west-2", "SNSDefaultRegion": "ap-south-1", "SNSSMSRegion": "us-west-2", 

SNS Factory

 public class SNSFactory : ISNSFactory { private readonly SNSConfig _snsConfig; private readonly IEnumerable<IAmazonSimpleNotificationService> _snsServices; public SNSFactory( IOptions<SNSConfig> snsConfig, IEnumerable<IAmazonSimpleNotificationService> snsServices ) { _snsConfig = snsConfig.Value; _snsServices = snsServices; } public IAmazonSimpleNotificationService ForDefault() { return GetSNS(_snsConfig.SNSDefaultRegion); } public IAmazonSimpleNotificationService ForSMS() { return GetSNS(_snsConfig.SNSSMSRegion); } private IAmazonSimpleNotificationService GetSNS(string region) { return GetSNS(RegionEndpoint.GetBySystemName(region)); } private IAmazonSimpleNotificationService GetSNS(RegionEndpoint region) { IAmazonSimpleNotificationService service = _snsServices.FirstOrDefault(sns => sns.Config.RegionEndpoint == region); if (service == null) { throw new Exception($"No SNS service registered for region: {region}"); } return service; } } public interface ISNSFactory { IAmazonSimpleNotificationService ForDefault(); IAmazonSimpleNotificationService ForSMS(); } 

Now you can get the SNS service for the region you want in your custom service or controller

 public class SmsSender : ISmsSender { private readonly IAmazonSimpleNotificationService _sns; public SmsSender(ISNSFactory snsFactory) { _sns = snsFactory.ForSMS(); } ....... } public class DeviceController : Controller { private readonly IAmazonSimpleNotificationService _sns; public DeviceController(ISNSFactory snsFactory) { _sns = snsFactory.ForDefault(); } ......... } 
+4
25 Oct '17 at 3:47 on
source share

Although it seems that @Miguel A. Arilla made that clear, and I voted for him, I created on top of his useful solution another solution that looks neat, but requires a lot more work.

It definitely depends on the above solution. So basically I created something similar to Func<string, IService>> and I called it IServiceAccessor as an interface, and then I had to add a few more extensions to IServiceCollection as such:

 public static IServiceCollection AddSingleton<TService, TImplementation, TServiceAccessor>( this IServiceCollection services, string instanceName ) where TService : class where TImplementation : class, TService where TServiceAccessor : class, IServiceAccessor<TService> { services.AddSingleton<TService, TImplementation>(); services.AddSingleton<TServiceAccessor>(); var provider = services.BuildServiceProvider(); var implementationInstance = provider.GetServices<TService>().Last(); var accessor = provider.GetServices<TServiceAccessor>().First(); var serviceDescriptors = services.Where(d => d.ServiceType == typeof(TServiceAccessor)); while (serviceDescriptors.Any()) { services.Remove(serviceDescriptors.First()); } accessor.SetService(implementationInstance, instanceName); services.AddSingleton<TServiceAccessor>(prvd => accessor); return services; } 

The service accessory looks like this:

  public interface IServiceAccessor<TService> { void Register(TService service,string name); TService Resolve(string name); } 

Ultimately, you will be able to register services with names or named instances, as we are used to doing with other containers. For example:

  services.AddSingleton<IEncryptionService, SymmetricEncryptionService, EncyptionServiceAccessor>("Symmetric"); services.AddSingleton<IEncryptionService, AsymmetricEncryptionService, EncyptionServiceAccessor>("Asymmetric"); 

This is sufficient at the moment, but to complete your work, it is better to add additional extension methods so that you can cover all types of registrations, following the same approach.

There was another entry in stackoverflow, but I can’t find it, where the poster explained in detail why this function is not supported and how to get around it, basically similar to what @Miguel said. It was a good post, although I disagree with every point, because I think there is a situation where you really need named instances. I will post this link here when I find it again.

Essentially, you do not need to pass this selector or Accessor:

I am using the following code in my project and it has worked well so far.

  /// <summary> /// Adds the singleton. /// </summary> /// <typeparam name="TService">The type of the t service.</typeparam> /// <typeparam name="TImplementation">The type of the t implementation.</typeparam> /// <param name="services">The services.</param> /// <param name="instanceName">Name of the instance.</param> /// <returns>IServiceCollection.</returns> public static IServiceCollection AddSingleton<TService, TImplementation>( this IServiceCollection services, string instanceName ) where TService : class where TImplementation : class, TService { var provider = services.BuildServiceProvider(); var implementationInstance = provider.GetServices<TService>().LastOrDefault(); if (implementationInstance.IsNull()) { services.AddSingleton<TService, TImplementation>(); provider = services.BuildServiceProvider(); implementationInstance = provider.GetServices<TService>().Single(); } return services.RegisterInternal(instanceName, provider, implementationInstance); } private static IServiceCollection RegisterInternal<TService>(this IServiceCollection services, string instanceName, ServiceProvider provider, TService implementationInstance) where TService : class { var accessor = provider.GetServices<IServiceAccessor<TService>>().LastOrDefault(); if (accessor.IsNull()) { services.AddSingleton<ServiceAccessor<TService>>(); provider = services.BuildServiceProvider(); accessor = provider.GetServices<ServiceAccessor<TService>>().Single(); } else { var serviceDescriptors = services.Where(d => d.ServiceType == typeof(IServiceAccessor<TService>)); while (serviceDescriptors.Any()) { services.Remove(serviceDescriptors.First()); } } accessor.Register(implementationInstance, instanceName); services.AddSingleton<TService>(prvd => implementationInstance); services.AddSingleton<IServiceAccessor<TService>>(prvd => accessor); return services; } // // Summary: // Adds a singleton service of the type specified in TService with an instance specified // in implementationInstance to the specified Microsoft.Extensions.DependencyInjection.IServiceCollection. // // Parameters: // services: // The Microsoft.Extensions.DependencyInjection.IServiceCollection to add the service // to. // implementationInstance: // The instance of the service. // instanceName: // The name of the instance. // // Returns: // A reference to this instance after the operation has completed. public static IServiceCollection AddSingleton<TService>( this IServiceCollection services, TService implementationInstance, string instanceName) where TService : class { var provider = services.BuildServiceProvider(); return RegisterInternal(services, instanceName, provider, implementationInstance); } /// <summary> /// Registers an interface for a class /// </summary> /// <typeparam name="TInterface">The type of the t interface.</typeparam> /// <param name="services">The services.</param> /// <returns>IServiceCollection.</returns> public static IServiceCollection As<TInterface>(this IServiceCollection services) where TInterface : class { var descriptor = services.Where(d => d.ServiceType.GetInterface(typeof(TInterface).Name) != null).FirstOrDefault(); if (descriptor.IsNotNull()) { var provider = services.BuildServiceProvider(); var implementationInstance = (TInterface)provider?.GetServices(descriptor?.ServiceType)?.Last(); services?.AddSingleton(implementationInstance); } return services; } 
+2
Jun 01 '18 at 10:03
source share
An approach

A factory is definitely viable. Another approach is to use inheritance to create separate interfaces that inherit from IService, implement inherited interfaces in IService implementations, and register inherited interfaces, not the base. Whether adding an inheritance hierarchy or factories is the “right” template, it all depends on who you are talking to. I often have to use this template when working with multiple database providers in a single application that uses a common type, such as IRepository <T> , as the basis for accessing data.

Examples of interfaces and implementations:

  <code> open interface IService
 {
 }

 open interface IServiceA: IService
 {}

 open interface IServiceB: IService
 {}

 public IServiceC: IService
 {}

 public class ServiceA: IServiceA
 {}

 public class ServiceB: IServiceB
 {}

 public class ServiceC: IServiceC
 {}
 Code> 

Container:

  container.Register < IServiceA, ServiceA >(); .  < IServiceB, ServiceB >(); .  < IServiceC, ServiceC >(); > 
+1
Jan 22 '18 at 18:09
source share

My solution for what's worth it ... is considered a switch to Castle Windsor since I cannot say that I liked any of the solutions above. Sorry !!

 public interface IStage<out T> : IStage { } public interface IStage { void DoSomething(); } 

Create your various implementations

 public class YourClassA : IStage<YouClassA> { public void DoSomething() { ...TODO } } public class YourClassB : IStage<YourClassB> { .....etc. } 

Registration

 services.AddTransient<IStage<YourClassA>, YourClassA>() services.AddTransient<IStage<YourClassB>, YourClassB>() 

Using constructor and instance ...

 public class Whatever { private IStage ClassA { get; } public Whatever(IStage<YourClassA> yourClassA) { ClassA = yourClassA; } public void SomeWhateverMethod() { ClassA.DoSomething(); ..... } 
+1
Aug 14 '18 at 15:44
source share

A bit late for this party, but here is my solution: ...

Startup.cs or Program.cs if the common handler ...

 services.AddTransient<IMyInterface<CustomerSavedConsumer>, CustomerSavedConsumer>(); services.AddTransient<IMyInterface<ManagerSavedConsumer>, ManagerSavedConsumer>(); 

Configure IMyInterface T

 public interface IMyInterface<T> where T : class, IMyInterface<T> { Task Consume(); } 

Specific IMyInterface T implementations

 public class CustomerSavedConsumer: IMyInterface<CustomerSavedConsumer> { public async Task Consume(); } public class ManagerSavedConsumer: IMyInterface<ManagerSavedConsumer> { public async Task Consume(); } 

Hopefully if you encounter any problems with this, someone will kindly indicate why this is the wrong way to do this.

+1
Sep 24 '18 at 13:20
source share

Necromancing.
I think that people here invent a bicycle - and it’s bad, if I may say so ...
, :

 System.Collections.Generic.Dictionary<string, IConnectionFactory> dict = new System.Collections.Generic.Dictionary<string, IConnectionFactory>( System.StringComparer.OrdinalIgnoreCase); dict.Add("ReadDB", new ConnectionFactory("connectionString1")); dict.Add("WriteDB", new ConnectionFactory("connectionString2")); dict.Add("TestDB", new ConnectionFactory("connectionString3")); dict.Add("Analytics", new ConnectionFactory("connectionString4")); dict.Add("LogDB", new ConnectionFactory("connectionString5")); 

-:

 services.AddSingleton<System.Collections.Generic.Dictionary<string, IConnectionFactory>>(dict); 

, , :
( / , - )

 services.AddTransient<Func<string, IConnectionFactory>>( delegate (IServiceProvider sp) { return delegate (string key) { System.Collections.Generic.Dictionary<string, IConnectionFactory> dbs = Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService <System.Collections.Generic.Dictionary<string, IConnectionFactory>>(sp); if (dbs.ContainsKey(key)) return dbs[key]; throw new System.Collections.Generic.KeyNotFoundException(key); // or maybe return null, up to you }; }); 

 IConnectionFactory logDB = Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService<Func<string, IConnectionFactory>>(serviceProvider)("LogDB"); logDB.Connection 

or

 System.Collections.Generic.Dictionary<string, IConnectionFactory> dbs = Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService<System.Collections.Generic.Dictionary<string, IConnectionFactory>>(serviceProvider); dbs["logDB"].Connection 

, , , AddTransient ( VB, ):

 IConnectionFactory logDB = Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService<System.Collections.Generic.Dictionary<string, IConnectionFactory>>(serviceProvider)["logDB"]; logDB.Connection 

( , - )

, , Name ( ) :

 services.AddSingleton<IConnectionFactory>(new ConnectionFactory("ReadDB")); services.AddSingleton<IConnectionFactory>(new ConnectionFactory("WriteDB")); services.AddSingleton<IConnectionFactory>(new ConnectionFactory("TestDB")); services.AddSingleton<IConnectionFactory>(new ConnectionFactory("Analytics")); services.AddSingleton<IConnectionFactory>(new ConnectionFactory("LogDB")); // https://stackoverflow.com/questions/39174989/how-to-register-multiple-implementations-of-the-same-interface-in-asp-net-core services.AddTransient<Func<string, IConnectionFactory>>( delegate(IServiceProvider sp) { return delegate(string key) { System.Collections.Generic.IEnumerable<IConnectionFactory> svs = sp.GetServices<IConnectionFactory>(); foreach (IConnectionFactory thisService in svs) { if (key.Equals(thisService.Name, StringComparison.OrdinalIgnoreCase)) return thisService; } return null; }; }); 

, , , ().
, .

$ 0,05

+1
Apr 24 '19 7:53
source share

, , , INamedServiceFactory . , , -

https://github.com/macsux/DotNetDINamedInstances

0
03 '18 17:50
source share

?

INamedService ( .Name), IServiceCollection .GetService ( ), .GetServices(), instance, , INamedService.Name .

Like this:

 public interface INamedService { string Name { get; } } public static T GetService<T>(this IServiceProvider provider, string serviceName) where T : INamedService { var candidates = provider.GetServices<T>(); return candidates.FirstOrDefault(s => s.Name == serviceName); } 

IMyService INamedService, , , ?

, INamedService , , [NamedServiceAttribute ("A")] / , . , Reflection , , , , -, DI. - .

, , " " , . Func <> , , Funcs , . , , , ya, .

0
28 . '18 20:51
source share

, , . , , , , , . , .

- .NET. , .

, Windows MVC?

0
03 . '19 5:54
source share

@rnrneverdies. ToString() : used- 1) , 2) , @Craig Brunetti.

 public interface IService { } public class ServiceA : IService { public override string ToString() { return "A"; } } public class ServiceB : IService { public override string ToString() { return "B"; } } /// <summary> /// extension method that compares with ToString value of an object and returns an object if found /// </summary> public static class ServiceProviderServiceExtensions { public static T GetService<T>(this IServiceProvider provider, string identifier) { var services = provider.GetServices<T>(); var service = services.FirstOrDefault(o => o.ToString() == identifier); return service; } } public void ConfigureServices(IServiceCollection services) { //Initials configurations.... services.AddSingleton<IService, ServiceA>(); services.AddSingleton<IService, ServiceB>(); services.AddSingleton<IService, ServiceC>(); var sp = services.BuildServiceProvider(); var a = sp.GetService<IService>("A"); //returns instance of ServiceA var b = sp.GetService<IService>("B"); //returns instance of ServiceB //Remaining configurations.... } 
0
11 . '19 4:33
source share

:

 public void ConfigureServices(IServiceCollection services) { ... services.AddTransient<IDriverActions, DriverA>(); services.AddTransient<IDriverActions, DriverB>(); } 

:

 public class DriverAController : ControllerBase { readonly IDriverActions _driverAActions; public DriverAController(IEnumerable<IDriverActions> services) { _driverAActions = services.FirstOrDefault(s => s.GetType() == typeof(DriverA); } ... 
-one
26 . '18 18:44
source share

- - , , .

, , , - :

 @Override public void messageArrived(String type, Message message) throws Exception { switch(type) { case "A": do Something with message; break; case "B": do Something else with message; break; ... } } 

, , , :

 @Override public void messageArrived(String type, Message message) throws Exception { messageHandler.getMessageHandler(type).handle(message); } 

It's good? , - ?

,

 @Retention(RUNTIME) @Target({TYPE}) public @interface MessageHandler { String value() } public interface Handler { void handle(MqttMessage message); } 

:

 @MessageHandler("myTopic") public class MyTopicHandler implements Handler { @override public void handle(MqttMessage message) { // do something with the message } } 

, MessageHandler, , , . , getMessageHandler :

 public Handler getMessageHandler(String topic) { if (handlerMap == null) { loadClassesFromClassPath(); // This method should load from classpath all the classes with the annotation MessageHandler and build the handlerMap } return handlerMap.get(topic); } 

, , , . , .

, .

-3
08 . '17 13:22
source share



All Articles