Here is a simplified version of a couple of classes in my solution and the interfaces they implement. They both share one interface and also implement a dedicated interface.
public interface ISharedContract
{
void ImplementSharedContract();
}
public interface IConcreteOne
{
void ImplementConcreteOne();
}
public interface IConcreteTwo
{
void ImplementConcreteTwo();
}
public class ConcreteOne : BaseConcrete, IConcreteOne, ISharedContract
{
public void ImplementSharedContract()
{
this.ImplementConcreteOne();
}
public void ImplementConcreteOne()
{
}
}
public class ConcreteTwo : BaseConcrete, IConcreteTwo, ISharedContract
{
public void ImplementSharedContract()
{
this.ImplementConcreteTwo();
}
public void ImplementConcreteTwo()
{
}
}
My StructureMap registry registers these dependencies as follows:
public class MyRegistry : Registry
{
public MyRegistry()
{
this.For<ISharedContract>().Use<ConcreteOne>().Named("cOne");
this.For<ISharedContract>().Use<ConcreteTwo>().Named("cTwo");
this.For<IConcreteOne>().Use<ConcreteOne>();
this.For<IConcreteTwo>().Use<ConcreteTwo>();
}
}
Finally I have a class which injects these dependencies in the constructor as follows:
public MyDependent(ISomethingElse somethingElse, ISharedContract cOne, ISharedContract cTwo)
{
this.collection = new List<ISharedContract>()
{
cOne,
cTwo
};
}
At runtime I observe that cOne and cTwo are both injected instances of ConcreteTwo. If I swap the order of the two named registrations in the StructureMap registry then cOne and cTwo are both instances of ConcreteOne.
This isn't the first time I've used named instances but I've not observed this before. Is there something I'm missing? I've checked and double-checked that the values passed to the Named method correspond with the parameter names in the constructor.
Update
Here is the updated registry entry which is needed to make my example case work. Thanks to #jeremy-d-miller for the info I needed:
this.For<IMyDependent>().Use<MyDependent>()
.Ctor<ISharedContract>("cOne").Is<ConcreteOne>()
.Ctor<ISharedContract>("cTwo").Is<ConcreteTwo>();
StructureMap doesn't have any magic functionality here that is matching your constructor parameter names to the named instance of that type. You would have to explicitly map the inline dependencies in this case: http://structuremap.github.io/registration/inline-dependencies/
In this code:
this.For<ISharedContract>().Use<ConcreteOne>().Named("cOne");
this.For<ISharedContract>().Use<ConcreteTwo>().Named("cTwo");
You're setting the default ISharedContext to ConcreteOne, then immediately overriding that to ConcreteTwo. Last one wins in this case. When you're building your MyDependent class, StructureMap is just using auto-wiring to push in the default instance of ISharedContext.
Related
Given I have a factory class responsible for constructing instances of a certain service that has constructor parameters that can only be resolved at runtime, is there a way to leverage container-driven decoration?
Consider the following class which relies on a parameter that is only defined at runtime:
interface IFooService
{
void DoServicyStuff();
}
class MyFooService : IFooService
{
public MyFooService(string somePeskyRuntimeArgument)
{
this.peskyValue = somePeskyRuntimeArgument;
}
public void DoServicyStuff()
{
// do some stuff here with the peskyValue...
}
}
Since the value can only be provided at runtime, we need to move away from the constructor injection and into a method-level parameter passing. This is commonly achieved using a factory implementation like this:
interface IFooServiceFactory
{
IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter);
}
class FooServiceFactory : IFooServiceFactory
{
public IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
{
return new MyFooService(heyItsNowAMethodLevelPeskyParameter);
}
}
While this works fine if the intent is to just abstract away the construction of the service, it poses a challenge to decorate the IFooService instance.
For scenarios where no runtime parameter is involved, this can be easily achieved by tapping into the container to provide our service for us. The example below uses the Scrutor library to decorate the interface with a logging decorator implementation:
class FooServiceFactory : IFooServiceFactory
{
private readonly IServiceProvider serviceProvider;
public FooServiceFactory(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider
}
public IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
{
return this.serviceProvider.GetRequiredInstance<IFooService>();
}
}
...
services
.AddTransient<IFooService, MyFooService>()
.AddTransient<IFooServiceFactory, FooServiceFactory>()
.Decorate<IFooService, LoggingFooService>();
But since MyFooService takes a primitive value as an argument, we cannot rely on GetRequiredService<T> to obtain the instance, as it will fail to find "a registration for string" when building the concrete class.
Similarly, changing the factory to rely on ActivatorUtilities's .CreateInstance or .CreateFactory methods will end up creating the objects while completely ignoring the container registrations, thus leaving us without any decorator.
I know I have at least 2 options to decorate the objects manually, namely:
Using the factory itself to manually create the decorator:
public IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
{
return new LoggingService(
new MyFooService(heyItsNowAMethodLevelPeskyParameter));
}
Using a factory decorator to inject a decorator after the instance is created:
abstract class FooServiceFactoryDecorator : IFooServiceFactory
{
private readonly IFooServiceFactory fooServiceFactory;
protected FooServiceFactory(IFooServiceFactory fooServiceFactory)
{
this.fooServiceFactory = fooServiceFactory;
}
public virtual IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
{
return this.fooServiceFactory.CreateService(heyItsNowAMethodLevelPeskyParameter);
}
}
class LoggingFooServiceFactory : FooServiceFactoryDecorator
{
private readonly IFooServiceFactory fooServiceFactory;
public FooServiceFactory(IFooServiceFactory fooServiceFactory)
{
this.fooServiceFactory = fooServiceFactory;
}
public override IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
{
return new LoggingFooService(
this.fooServiceFactory.CreateService(heyItsNowAMethodLevelPeskyParameter));
}
}
...
services
.AddTransient<IFooServiceFactory, FooServiceFactory>()
.Decorate<IFooServiceFactory, LoggingFooServiceFactory>()
Neither of these allows me to directly use .Decorate on top of the service interface. The first option works but is heavily coupled (meaning I'd have to keep changing it if I want to add other decorators into the mix), while the second version is less coupled, but still forces me to writing one factory decorator per service decorator and thus leads into a much more complex solution.
Another pain point is dependencies on the decorators themselves (for example, ILogger<T> on the LoggingFooService), which I could potentially solve by leveraging ActivatorUtilities to create the decorators instead of newing them up manually.
I could also potentially generalize the "factory decorator" so that the decoration function is parameterized and thus the class can be reused, but it is still very convoluted and hard to maintain, while also not providing as good a syntax for consumers to add new decorators.
class DecoratedFooServiceFactory<TDecorator> : FooServiceFactoryDecorator
where TDecorator : IFooService
{
private readonly IFooServiceFactory fooServiceFactory;
private readonly IServiceProvider serviceProvider;
public FooServiceFactory(
IFooServiceFactory fooServiceFactory,
IServiceProvider serviceProvider)
{
this.fooServiceFactory = fooServiceFactory;
this.serviceProvider = serviceProvider;
}
public override IFooService CreateService(string heyItsNowAMethodLevelPeskyParameter)
{
return ActivatorUtilities.CreateInstance<TDecorator>(
this.serviceProvider,
this.fooServiceFactory.CreateService(heyItsNowAMethodLevelPeskyParameter));
}
}
...
services
.AddTransient<IFooServiceFactory, FooServiceFactory>()
.Decorate<IFooServiceFactory, DecoratedFooServiceFactory<LoggingFooService>>()
And finally, if I ever want to move away from using a factory and want to change to using the service directly, this will cause a significant setup change where I'd then have to configure all the decorators again in the container directly instead of just removing the factory registration as one normally would do.
How can I use a factory like this, while still keeping the capability of configuring decorators at the container level using the simple Scrutor syntax?
Ok, a couple of disclaimers first:
I agree with Steven here in that this looks like an anti-pattern and you will probably be better off redesigning your code to not require run-time values on service construction.
I additionally want to caution against using scrutor-like Decorate. While much less confident in this than in the first point, I believe hiding logging in decorators is much less convenient in the long run than it seems at first. Or at least that's what I saw after about a year of trying them out.
That said, let's see what can be done.
First, let's put some constraints on where the value is coming from. Specifically, let's say we can have a service providing that value, that looks like this:
public interface IValueProvider
{
string Get();
}
This actually allows us to have quite a bit of range. Implementation of that interface can:
Get value from external API - once or periodically in the background. It can even call it every time Get is called, but this is a very bad idea, as it will make construction asynchronous.
Get value that is stored in memory and allow some other service to update it. Say, expose a 'configuration' endpoint where a user can set a new value every once in a while.
Calculate the value based on some algorithm of your choice.
Once you have this service, you can register it like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IValueProvider, AwesomeValueProvider>();
services.AddSingleton<IFooServiceFactory, FooServiceFactory>();
services.AddTransient<IFooService>(sp =>
{
var factory = sp.GetRequiredService<IFooServiceFactory>();
var valueProvider = sp.GetRequiredService<IValueProvider>();
return factory.Create(valueProvider.Get());
});
}
Hope this helps
I've a java binding for android which somewhat works bar the new feature I'm trying to integrate with. Only now I have realised that the intended callback is not happening. Here are the classes (decompiled to java) in question:
At the top level we have
public interface MyPackage {
MyPackage.Companion Companion = MyPackage.Companion.$$INSTANCE;
public static final class Companion {
#Nullable
private static MyEventHandler myEventHandler;
// $FF: synthetic field
static final MyPackage.Companion $$INSTANCE;
#Nullable
public final MyEventHandler getMyEventHandler() {
return myEventHandler;
}
public final void setMyEventHandler(#Nullable MyEventHandler var1) {
myEventHandler = var1;
}
private Companion() {
}
static {
MyPackage.Companion var0 = new MyPackage.Companion();
$$INSTANCE = var0;
}
}
}
MyEventHandler class:
public abstract class MyEventHandler {
public abstract void handleEvent(#NotNull String var1, #NotNull Properties var2);
}
Properties class:
import java.util.Map;
public class Properties extends r {
public Properties() {
}
Properties(Map<String, Object> var1) {
super(var1);
}
public Properties a(String var1, Object var2) {
super.b(var1, var2);
return this;
}
}
and the problematic r class:
public class r implements Map<String, Object> {
private final Map<String, Object> a;
various implementations...
}
So I noticed the issue when I couldnt override the HandleEvent method at the integration level and started looking at the Binding logs and found:
Warning=>
BINDINGSGENERATOR: Warning BG8801: Invalid parameter type MyPackage...Properties in method HandleEvent in managed type MyPackage.MyEventHandler. (BG8801)
And in build logs:
message BG0000: warning BG8102: Class MyPackage....Properties has unknown base type MyPackage....r.
warning BG8801: Invalid parameter type MyPackage...Properties in method HandleEvent in managed type MyPackage.MyEventHandler.
As it was obvious r is an obfuscated class I need to make chagnes to my Metadata so I went ahead and popped in:
<attr path="/api/package[#name='MyPackage']/class[#name='r']" name="obfuscated">false</attr>
Which resulted in the R being generated but now I get the 5 following compile error:
Error CS0535: 'R' does not implement interface member 'IMap.EntrySet()' (CS0535)
Error CS0738: 'R' does not implement interface member 'IMap.KeySet()'. 'R.KeySet()' cannot implement 'IMap.KeySet()' because it does not have the matching return type of 'ICollection'. (CS0738)
Error CS0535: 'R' does not implement interface member 'IMap.Put(Object?, Object?)' (CS0535)
Error CS0535: 'R' does not implement interface member 'IMap.PutAll(IDictionary?)' (CS0535)
Error CS0738: 'R' does not implement interface member 'IMap.Values()'. 'R.Values()' cannot implement 'IMap.Values()' because it does not have the matching return type of 'ICollection'. (CS0738)
I tried to make a managed return using
<attr path="/api/package[#name='MyPackage']/class[#name='r']/method[#name='entrySet' and count(parameter)=0]" name="managedReturn">Java.Util.IMap</attr>
With same number of compile error as above. Then I tried removing the node using:
<remove-node path="/api/package[#name='MyPackage']/class[#name='r']/method[#name='entrySet']"/>
Still no luck. :(
What am I missing here? Any pointers/suggestions will be appreciated!
It seems like you are trying to expose a Map to C# and as you stated, Java Generics are not handled very well.
In a very popular social network you received an answer from #mattleibow. I do not take credit for his answer but I went to check nonetheless and it seems fine.
If you look at the description of the Java.Lang.HashMap type
https://learn.microsoft.com/en-us/dotnet/api/java.util.hashmap?view=xamarin-android-sdk-9 it's a good candidate for you to expose.
You can also try with the corresponding interface for better safety https://learn.microsoft.com/en-us/dotnet/api/java.util.imap?view=xamarin-android-sdk-9
If it works you will still have to cast the types yourself.
Please answer to the comment to say that problem is solved for the sake of future generations arriving on this post :D
Credit is not mine so don't give it to me :-)
John,
I got arround fixing it by providing implementation of the the said methods in a partial class. Basically added a new file called R.cs under Additions folder as follows:
namespace YourNameSpace
{
public partial class R
{
public void PutAll(System.Collections.IDictionary p0)
{
PutAll(p0);
}
public Java.Lang.Object Put(Java.Lang.Object key, Java.Lang.Object value)
{
return Put(key, value);
}
public System.Collections.ICollection EntrySet()
{
return EntrySet();
}
public System.Collections.ICollection KeySet()
{
return KeySet();
}
public System.Collections.ICollection Values()
{
return Values();
}
}
}
I couldn't get it to work by adding XML transformation, but I think there was some tooling issue.
I have a following problem. I register my components and initialize them in Unity like this (example is for a Console application):
public class SharePointBootstrapper : UnityBootstrapper
{
...
public object Initialize(Type type, object parameter) =>
Container.Resolve(type,
new DependencyOverride<IClientContext>(Container.Resolve<IClientContext>(parameter.ToString())),
new DependencyOverride<ITenantRepository>(Container.Resolve<ITenantRepository>(parameter.ToString())));
public void RegisterComponents()
{
Container
.RegisterType<IClientContext, SharePointOnlineClientContext>(SharePointClientContext.Online.ToString())
.RegisterType<IClientContext, SharePointOnPremiseClientContext>(SharePointClientContext.OnPremise.ToString())
.RegisterType<ITenantRepository, DocumentDbTenantRepository>(SharePointClientContext.Online.ToString())
.RegisterType<ITenantRepository, JsonTenantRepository>(SharePointClientContext.OnPremise.ToString());
}
}
public enum SharePointClientContext
{
Online,
OnPremise
}
class Program
{
static void Main(string[] args)
{
...
bootstrap.RegisterComponents();
var bla = bootstrap.Initialize(typeof(ISharePointManager), SharePointClientContext.Online);
}
}
So, I register my components in MVC, WCF, Console etc. once with RegisterComponents() and initialize them with Initialize().
My question is, if I want to initialize specific named registration at runtime, from e.g. user input, can it be done otherwise as the code presented (with InjectionFactory or similar)?
This code works fine, but I'm not happy with its implementation. I have a feeling that it could be written in RegisterComponents() instead of Initialize() so that it accepts a parameter of some type, but I don't know how to do it.
Or, is maybe my whole concept wrong? If so, what would you suggest? I need to resolve named registration from a parameter that is only known at runtime, regardless of the technology (MVC, WCF, Console, ...).
Thanks!
Instead of doing different registrations, I would do different resolves.
Let's say that you need to inject IClientContext, but you want different implementations depending on a runtime parameter.
I wrote a similiar answer here. Instead of injecting IClientContext, you could inject IClientContextFactory, which would be responsible for returning the correct IClientContext. It's called Strategy Pattern.
public interface IClientContextFactory
{
string Context { get; } // Add context to the interface.
}
public class SharePointOnlineClientContext : IClientContextFactory
{
public string Context
{
get
{
return SharePointClientContext.Online.ToString();
}
}
}
// Factory for resolving IClientContext.
public class ClientContextFactory : IClientContextFactory
{
public IEnumerable<IClientContext> _clientContexts;
public Factory(IClientContext[] clientContexts)
{
_clientContexts = clientContexts;
}
public IClientContext GetClientContext(string parameter)
{
IClientContext clientContext = _clientContexts.FirstOrDefault(x => x.Context == parameter);
return clientContext;
}
}
Register them all, just as you did. But instead of injecting IClientContext you inject IClientContextFactor.
There also another solution where you use a Func-factory. Look at option 3, in this answer. One may argue that this is a wrapper for the service locator-pattern, but I'll leave that discussion for another time.
public class ClientContextFactory : IClientContextFactory
{
private readonly Func<string, IClientContext> _createFunc;
public Factory(Func<string, IClientContext> createFunc)
{
_createFunc = createFunc;
}
public IClientContext CreateClientContext(string writesTo)
{
return _createFunc(writesTo);
}
}
And use named registrations:
container.RegisterType<IClientContext, SharePointOnlineClientContext>(SharePointClientContext.Online.ToString());
container.RegisterType<IClientContext, SharePointOnPremiseClientContext>(SharePointClientContext.OnPremise.ToString());
container.RegisterType<IFactory, Factory>(
new ContainerControlledLifetimeManager(), // Or any other lifetimemanager.
new InjectionConstructor(
new Func<string, IClientContext>(
context => container.Resolve<IClientContext>(context));
Usage:
public class MyService
{
public MyService(IClientContextFactory clientContextFactory)
{
_clientContextFactory = clientContextFactory;
}
public void DoStuff();
{
var myContext = SharePointClientContext.Online.ToString();
IClientContextclientContext = _clientContextFactory.CreateClientContext(myContext);
}
}
In our project we have following modules scout.client, scout.server, scout.shared and backend.
backend has no dependencies to scout.server and scout.shared, but scout.server has dependencies to backend.
Inside the backend project we have all business logic and calling all outside services.
We use the Scout Bean Manager to manage the instances of the Backend-Services in our scout.server:
BEANS.getBeanManager().registerClass(CarService.class);
BEANS.getBeanManager().registerClass(PartnerService.class);
Both, CarService.class and PartnerService.class are in the backend.
Is this registration correct? Or should I register the classes using the registerBean(..) method instead of registerClass(..)?
Question derived from an other question asked by #marko-zadravec
As explained in the registerClass(..) JavaDoc, if you do:
public class RegisterBeansListener implements IPlatformListener {
#Override
public void stateChanged(PlatformEvent event) {
if (event.getState() == IPlatform.State.BeanManagerPrepared) {
// register the class directly:
BEANS.getBeanManager().registerClass(BeanSingletonClass.class);
}
}
}
This is the same as:
public class RegisterBeansListener implements IPlatformListener {
#Override
public void stateChanged(PlatformEvent event) {
if (event.getState() == IPlatform.State.BeanManagerPrepared) {
// register with meta information
BeanMetaData beanData = new BeanMetaData(PartnerService.class);
BEANS.getBeanManager().registerBean(beanData);
}
}
}
Meaning that you will get a new instance of the PartnerService each time you call BEANS.get(IPartnerService.class). (see Bean Scopes in the Scout Docs).
If you want your bean to have only one instance for your entire application you should register it like that:
public class RegisterBeansListener implements IPlatformListener {
#Override
public void stateChanged(PlatformEvent event) {
if (event.getState() == IPlatform.State.BeanManagerPrepared) {
// register with meta information
BeanMetaData beanData = new BeanMetaData(PartnerService.class)
.withApplicationScoped(true);
BEANS.getBeanManager().registerBean(beanData);
}
}
}
I recommend setting a specific Order like in this answer only for test purpose.
We are using classes inheriting from Registry to configure our StructureMap container in our ASP.NET MVC 4 application startup.
Some excerpt from one of the registry-classes:
For<ISomeInterface>().HybridHttpOrThreadLocalScoped().Use<SomeImplementation>();
We would like use different instances of our interfaces depending on the context. (For example switching from database "online" mode to "maintenance" mode where everything is saved on filesystem; therefore using other interfaces (i.e. repositories) all over the place in our application)
For example by default it should use SomeImplementation but when passing some kind of querystring in the url (to name a simple "context" scenario) it should use SomeOtherImplementation.
How can this be achieved for multiple interfaces/types?
Should we use named instances for this? Like:
For<ISomeInterface>().HybridHttpOrThreadLocalScoped().Use<SomeOtherImplementation>().Named("other");
I read about StructureMap Profiles but i'm not sure if this is the right way to go.
Should we use profiles for this? Like i.e.:
Profile("other", profileExpression =>
{
For<ISomeInterface>().HybridHttpOrThreadLocalScoped().Use<SomeOtherImplementation>();
});
How can we switch different configurations on the fly?
ObjectFactory.Container.SetDefaultsToProfile("other");
This way? (At what stage in mvc "life-cycle" this can happen at the earliest?)
Can this be a temporary switch for just the current request or current users session?
Thanks in advance!
From my experience, runtime configuration like this is best achieved using an abstract factory that is responsible for creating your dependency during runtime.
This dependency can then be registered with StructureMap like so:
Your registry:
public class StorageRegistry : Registry
{
public StorageRegistry()
{
...
this.For<IDataStoreInstance>().Use(ctx => ctx.GetInstance<DataStoreAbstractFactory>().ConfigureStorage());
...
}
}
Now your DataStoreAbstractFactory is responsible for creating and configure the necessary storage instance based on your configuration. As DataStoreAbstractFactory is now registered with StructureMap you're able to inject the necessary dependencies into it for determining which storage method to use.
Implementation example:
public class DataStoreAbstractFactory
{
public DataStoreAbstractFactory()
{
// Dependencies to figure out data storage method can be injected here.
}
public IDataStoreInstance ConfigureStorage()
{
// This method can be used to return type of storage based on your configuration (ie: online or maintenance)
}
}
public interface IDataStoreInstance
{
void Save();
}
public class DatabaseStorage : IDataStoreInstance
{
public void Save()
{
// Implementation details of persisting data in a database
}
}
public class FileStorage : IDataStoreInstance
{
public void Save()
{
// Implementation details of persisting data in a file system
}
}
Usage:
Your controller/services or whatever are now completely unaware of what storage method they're using when accessing and persisting data.
public class UpdateController : Controller
{
public IDataStoreInstance StorageInstance { get; set; }
public UpdateController(IDataStoreInstance storageInstance)
{
StorageInstance = storageInstance;
}
[HttpPost]
public ActionResult Index()
{
...
this.StorageInstance.Save();
...
}
...
}