Use ConstructedBy together with the non-generic For - dependency-injection

I have this registration in StructureMap
ObjectFactory.Initialize(x => {
x.For<IPageModel>().UseSpecial(y => y.ConstructedBy( r => ((MvcHandler) HttpContext.Current.Handler).RequestContext.RouteData.GetCurrentModel<IPageModel>()));
});
And then I access this object in my constructor like this
public HomeController(IPageModel model) {}
Now I would like to register all concrete types that implements the interface IPageModel and when asked for I want to use the same For<> statement to get the correct instance.
It seems like i could use Scan together with my own convention to do this but I can't figure out exactly how to do it.
This is some example code
x.Scan(scanner =>
{
scanner.AssembliesFromApplicationBaseDirectory();
scanner.Convention<MySpecialConvetion>();
});
public class MySpecialConvetion : IRegistrationConvention {
public void Process(Type type, Registry registry) {
if(type.IsAssignableFrom(typeof(IPageModel))) {
registry.For<CONCRETE IMPLEMENTATION>().UseSpecial(y => y.ConstructedBy( r => ((MvcHandler) HttpContext.Current.Handler).RequestContext.RouteData.GetCurrentModel<CONCRETE IMPLEMENTATION>()));
}
}
}
Edit: It seems like I need to use the non-generic For, but how can I handle the construction my self using the non-generic For?

I got this working by creating a generic method definition, and used reflection to populate the types. Easier to show than explain:
public class MySpecialConvetion : IRegistrationConvention
{
public static readonly MethodInfo RegisterMethod = typeof (MySpecialConvetion)
.GetMethod("Register", BindingFlags.NonPublic | BindingFlags.Static)
.GetGenericMethodDefinition();
public void Process(Type type, Registry registry)
{
if (type.IsAssignableFrom(typeof (IPageModel)))
{
var specificRegisterMethod = RegisterMethod.MakeGenericMethod(new[] { type });
specificRegisterMethod.Invoke(null, new object[] { registry });
}
}
static private void Register<T>(Registry registry)
where T : IPageModel
{
registry
.For<T>()
.UseSpecial(y => y.ConstructedBy(r => GetCurrentPageModel<T>()));
}
static private T GetCurrentPageModel<T>()
where T : IPageModel
{
var handler = (MvcHandler) HttpContext.Current.Handler;
if (handler == null)
return default(T);
return handler.RequestContext.RouteData.GetCurrentModel<T>();
}
}
I added an intermediate step and checked for a null handler since I didn't have one in my site. But this should get you the missing piece you needed.

Related

Interface with more implementation and Dependency Injection

I created a project with .net Core 2.
Now I have a List of classes from the same interface which I needed at runtime.
My problem is, I can't add this classes to the servicecollection (only one interface). So I don't have access to the other services in those classes. Also I think it wouldn't solve it.
I could create a singleton/static class with my servicecollection and use the IServiceProvider to get those other services from there, but I think that isn't the best practice.
Here is an example of my problem:
public class Manager : IManager
{
private IList<IMyService> _myService;
public Manager()
{
IList<Type> types = GetIMyServiceTypes();
foreach (Type type in types)
{
var instance = (IMyService)Activator.CreateInstance(type);
_myService.Add(instance)
}
}
public IList<bool> IsTrue()
{
return _myService
.Select(se => se.IsTrue())
.ToList();
}
public IList<Type> GetIMyServiceTypes()
{
var type = typeof(IMyService);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p))
.ToList();
return types;
}
}
public class ServiceType1: IMyService
{
public bool IsTrue()
{
//Need Access to IServiceCollection Services
}
}
public interface IMyService
{
bool IsTrue();
}
public class MyController : Controller
{
private IManager _amanager;
public MyController(IManager manager)
{
_manager = manager
}
public IActionResult IsTrue()
{
IList<bool> isTrue =_manager.IsTrue();
return new ObjectResult(isTrue);
}
}
Is there a pattern, which I could use to solve my problem? Is there a best practice to have access to the services without using them in the constructor?
I found the solution on another post in stackoverflow https://stackoverflow.com/a/44177920/5835745
But I will post my changes for other people with the same problem. I loaded the list of classes from the configuration, but it's also possible to add all classes.
public class Manager : IManager
{
private IList<IMyService> _myService;
private readonly Func<string, IService> _serviceAccessor;
public Manager (Func<string, IService> serviceAccessor)
{
IList<string> authentications = new List<string> {"value1", "value2"}
foreach (string authentication in authentications)
{
AddAuthentication(_serviceAccessor(authentication));
}
}
public IList<bool> IsTrue()
{
return _myService
.Select(se => se.IsTrue())
.ToList();
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<Value1>();
services.AddTransient<Value2>();
services.AddTransient(factory =>
{
Func<string, IService> accesor = key =>
{
switch (key)
{
case "value1":
return factory.GetService<Value1>();
case "value2":
return factory.GetService<Value2>();
default:
throw new KeyNotFoundException();
}
};
return accesor;
});
}
}

Implement dependency injection in background services in Xamarin Forms using Prism

I am making use of Prism in my xamarin forms project.I was able to use dependency injection(constructor injection) in my View Model without any problems.I am also making use of background services to push long running tasks in the background.How do I inject dependency in my Background services?When I try to pass the interface object as a paramater to the constructor(SyncingBackgroundingCode) ,the object(SqliteService) is null.I have registered and resolved the objects in the dependency injection container.
How to handle this case?Can anybody provide an example or link to implement this scenario?
This is the piece of code where im trying to implement dependency injection.
This is in Droid :-
public class AndroidSyncBackgroundService : Service
{
CancellationTokenSource _cts;
public override IBinder OnBind (Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand (Intent intent, StartCommandFlags flags, int startId)
{
_cts = new CancellationTokenSource ();
Task.Run (() => {
try {
//INVOKE THE SHARED CODE
var oBackground = new SyncingBackgroundingCode();
oBackground.RunBackgroundingCode(_cts.Token).Wait();
}
catch (OperationCanceledException)
{
}
finally {
if (_cts.IsCancellationRequested)
{
var message = new CancelledTask();
Device.BeginInvokeOnMainThread (
() => MessagingCenter.Send(message, "CancelledTask")
);
}
}
}, _cts.Token);
return StartCommandResult.Sticky;
}
public override void OnDestroy ()
{
if (_cts != null) {
_cts.Token.ThrowIfCancellationRequested ();
_cts.Cancel ();
}
base.OnDestroy ();
}
}
This is in PCL:-
public class SyncingBackgroundingCode
{
public SQLiteConnection _sqlconnection;
SqliteCalls oSQLite = new SqliteCalls();
ISqliteService _SqliteService;
public SyncingBackgroundingCode(ISqliteService SqliteService)
{
//object is null
}
public async Task RunBackgroundingCode(CancellationToken token)
{
DependencyService.Get<ISQLite>().GetConnection();
await Task.Run (async () => {
token.ThrowIfCancellationRequested();
if (App.oSqliteCallsMainLH != null)
{
App.bRunningBackgroundTask = true;
oSQLite = App.oSqliteCallsMainLH;
await Task.Run(async () =>
{
await Task.Delay(1);
oSQLite.ftnSaveOnlineModeXMLFormat("Offline", 0);
oSQLite.SyncEmployeeTableData();
oSQLite.SaveOfflineAppCommentData();
oSQLite.SaveOfflineAdditionToFlowData();
await Task.Delay(500);
var msgStopSyncBackgroundingTask = new StopSyncBackgroundingTask();
MessagingCenter.Send(msgStopSyncBackgroundingTask, "StopSyncBackgroundingTask");
});
}
}, token);
}
}
Unfortunately Xamarin and Xamarin Forms don't give frameworks like Prism anywhere to tie into to handle IoC scenarios. There are a couple of ways you can handle this though.
First the Container is a public property on the PrismApplication in your background service you could do something like:
public class FooBackgroundService
{
private App _app => (App)Xamarin.Forms.Application.Current;
private void DoFoo()
{
var sqlite = _app.Container.Resolve<ISQLite>();
}
}
Another slightly more involved way would be to use the ServiceLocator pattern. You might have something like the following:
public static class Locator
{
private static Func<Type, object> _resolver;
public static T ResolveService<T>() =>
(T)_resolver?.Invoke(typeof(T));
public static void SetResolver(Func<Type, object> resolver) =>
_resolver = resolver;
}
In your app you would then simply set the resolver. Prism actually does something similar to this with the ViewModel locator, which then allows it to inject the correct instance of the NavigationService.
public class App : PrismApplication
{
protected override void OnInitialized()
{
SetServiceLocator();
NavigationService.NavigateAsync("MainPage");
}
protected override void RegisterTypes()
{
// RegisterTypes
}
private void SetServiceLocator()
{
Locator.SetResolver(type => Container.Resolve(type, true));
}
}
Finally your service would simply reference the Service Locator like:
public class BarBackgroundService
{
public void DoBar()
{
var sqlite = Locator.ResolveService<ISQLite>();
// do foo
}
}

Web API, Light Inject and Passing a Static Dictionary to the data layer

We have a multi-database solution and are passing the connection string to a factory function like so:
container.Register<IDbContextFactory>(
f => new DynamicDbContextFactory(ClientConfig.GetConnectionString()),
new PerScopeLifetime());
ClientConfig contains a static dictionary that gets populated on app start that maps a sub domain to a connection string. It seems that this approach is causing a memory leak (not 100% sure about this causing the leak but there is a leak).
public class ClientConfig
{
private static ConcurrentDictionary<string, string> ConnectionStringManager
{
get;
set;
}
// etc.
}
My question is in MVC what is the best way to hold a list of connection strings that can be easily looked up on each request in order to pass that down the chain.
Edit : The question was initially tagged with Autofac
With Autofac you don't have to use a dictionary and something like that to do what you want. You can use a custom parameter :
public class ConnectionStringParameter : Parameter
{
public override Boolean CanSupplyValue(ParameterInfo pi,
IComponentContext context,
out Func<Object> valueProvider)
{
valueProvider = null;
if (pi.ParameterType == typeof(String)
&& String.Equals(pi.Name, "connectionString",
StringComparison.OrdinalIgnoreCase))
{
valueProvider = () =>
{
// get connectionstring based on HttpContext.Current.Request.Url.Host
return String.Empty;
};
}
return valueProvider != null;
}
}
Then register your Parameter using a Module
public class ConnectionStringModule : Autofac.Module
{
protected override void AttachToComponentRegistration(
IComponentRegistry componentRegistry, IComponentRegistration registration)
{
registration.Preparing += registration_Preparing;
}
private void registration_Preparing(Object sender, PreparingEventArgs e)
{
Parameter[] parameters = new Parameter[] { new ConnectionStringParameter() };
e.Parameters = e.Parameters.Concat(parameters);
}
}
Module you have to register inside your container using
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new ConnectionStringModule());
Each time Autofac have to resolve a parameter of type String named connectionString it will used the custom parameter and get your connectionstring based on what you want.
By the way this code sample use HttpContext.Current. In case of a multithreaded process it may return null. I don't recommend using HttpContext.Current for such things. You can use an intermediate class instead of accessing it, for example a IConnectionstringProvider interface.
public interface IConnectionstringProvider
{
String ConnectionString { get; }
}
public class ConnectionStringProvider : IConnectionstringProvider
{
public ConnectionStringProvider(Strong host)
{
// get connectionstring based on host
this._connectionString = String.Empty;
}
private readonly String _connectionString;
public String ConnectionString
{
get { return this._connectionString; }
}
}
Inside your Parameter you will have to change the valueProvider by
valueProvider = () =>
{
return context.Resolve<IConnectionstringProvider>().ConnectionString;
};
And finally you will have to register your IConnectionstringProvider at the beginning of the request lifetimescope :
class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new ConnectionStringModule());
IContainer container = builder.Build();
container.ChildLifetimeScopeBeginning += container_ChildLifetimeScopeBeginning;
}
private static void container_ChildLifetimeScopeBeginning(
Object sender, LifetimeScopeBeginningEventArgs e)
{
String host = HttpContext.Current.Request.Url.Host;
ContainerBuilder childLifetimeScopeBuilder = new ContainerBuilder();
childLifetimeScopeBuilder.RegisterInstance(new ConnectionStringProvider(host))
.As<IConnectionstringProvider>()
.SingleInstance();
childLifetimeScopeBuilder.Update(e.LifetimeScope.ComponentRegistry);
}
}
Of course there is many way to do it but you have the idea

Registering closed types using StructureMap's scanner

How do I register a closed type so that instances of the generic are created using HybridHttpOrThreadLocalScoped lifecycle?
My classes:
public interface IBaseService
{
}
public interface IAccountService
{
void Save(Account entry);
Account GetById(string id);
List<Account> GetList();
void Delete(string id);
bool Exists(string id);
}
public interface IClientService
{
void Save(Client entry);
Client GetById(string id);
List<Client> GetList();
void Delete(string id);
bool Exists(string id);
}
public class AccountService : IBaseService, IAccountService
{
Some code for managing accounts
}
public class ClientService : IBaseService, IClientService
{
Some code for managing clients
}
Dependency resolver:
public StructureMapContainer(IContainer container)
{
_container = container;
_container.Configure(x => x.Scan(y =>
{
y.AssembliesFromApplicationBaseDirectory();
y.WithDefaultConventions();
y.LookForRegistries();
y.ConnectImplementationsToTypesClosing(typeof(IService<>))
.OnAddedPluginTypes(t => t.HybridHttpOrThreadLocalScoped());
}));
}
What’s the syntax in the resolver for automatically creating instances of IBaseService? Using ConnectImplementationsToTypesClosing only works for open generics. Do I even need to use the resolver? Is there a better way to register the types?
For now, this is how I amhandling registering them:
container.Configure(x =>
{
x.For<IClientService>()
.HybridHttpOrThreadLocalScoped()
.Use(new ClientService());
x.For<IEmailAddressService>()
.HybridHttpOrThreadLocalScoped()
.Use(new EmailAddressService());
x.For<IAccountService>()
.HybridHttpOrThreadLocalScoped()
.Use(new AccountService());
});
Something like:
Scan(y =>
{
y.AssemblyContainingType<IService>();
y.Assembly(Assembly.GetExecutingAssembly().FullName);
y.With(new ServiceScanner());
});
Then you need the Customscanner:
/// <summary>
/// Custom scanner to create Service types based on custom convention
/// In this case any type that implements IService and follows the
/// naming convention of "Name"Service.
/// </summary>
public class ServiceScanner : IRegistrationConvention
{
public void Process(Type type, StructureMap.Configuration.DSL.Registry registry)
{
if (type.BaseType == null) return;
if (type.GetInterface(typeof(IService).Name) != null)
{
var name = type.Name;
var newtype = type.GetInterface(string.Format("I{0}", name));
registry
.For<IService>()
.AddInstances(y => y.Instance(new ConfiguredInstance(type).Named(name)))
.HybridHttpOrThreadLocalScoped();
registry.For(newtype)
.HybridHttpOrThreadLocalScoped().Use(c => c.GetInstance<IService>(name));
}
}
}

Castle Windsor Typed Factory Facility with generics

I'm trying to register a factory that could resolve an array of event handlers defined as follow:
public interface IEvent { }
public class EventA : IEvent { }
public class EventB : IEvent { }
public class EventC : IEvent { }
public interface IHandler<TEvent> where TEvent : IEvent
{
void Handle(TEvent ev);
}
public class HandlerX : IHandler<EventA>, IHandler<EventB>
{
public void Handle(EventA ev)
{
throw new NotImplementedException("handle EventA");
}
public void Handle(EventB ev)
{
throw new NotImplementedException("handle EventB");
}
}
public class HandlerY : IHandler<EventB>, IHandler<EventC>
{
public void Handle(EventB ev)
{
throw new NotImplementedException("handle EventB");
}
public void Handle(EventC ev)
{
throw new NotImplementedException("handle EventC");
}
}
public interface HandlerFactory
{
object[] GetHandlersForEvent(IEvent ev);
}
Basically for each event I can have more handlers and each handler can handle multiple events. I also want the factory to return object[] because at runtime I don't know what closed generic types would be returned.
I tried the approach descirbed by Krzysztof Koźmic http://kozmic.pl/2010/03/11/advanced-castle-windsor-ndash-generic-typed-factories-auto-release-and-more/
but still have problems.
Basically my question boils down to what types to return from my custom type deriving from DefaultTypedFactoryComponentSelector.
I tried many variations of the following:
public class HandlerSelector : DefaultTypedFactoryComponentSelector
{
protected override TypedFactoryComponent BuildFactoryComponent(MethodInfo method, string componentName, Type componentType, System.Collections.IDictionary additionalArguments)
{
Type eventType = null;
foreach (var k in additionalArguments.Values)
{
eventType = k.GetType();
}
var handlerType = typeof(IHandler<>).MakeGenericType(eventType);
var handlerArrayType = handlerType.MakeArrayType();
//return handlerArrayType;
return new TypedFactoryComponentCollection(handlerType, additionalArguments);
}
protected override Type GetComponentType(MethodInfo method, object[] arguments)
{
return typeof (object);
/*
var message = arguments[0];
var handlerType = typeof(IHandler<>).MakeGenericType(message.GetType());
var handlerArrayType = handlerType.MakeArrayType();
return handlerArrayType;
*/
}
/*
public TypedFactoryComponent SelectComponent(MethodInfo method, Type type, object[] arguments)
{
var message = arguments[0];
var handlerType = typeof(IHandler<>).MakeGenericType(message.GetType());
var result = new TypedFactoryComponentCollection(handlerType.MakeArrayType(), new Arguments(arguments));
return result;
}*/
}
with Windsor installer defined as:
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<TypedFactoryFacility>()
.Register(
Component.For<HandlerSelector>().ImplementedBy<HandlerSelector>(),
Component.For<AutoReleaseHandlerInterceptor>(),
AllTypes.FromAssemblyContaining<Program>()
.BasedOn(typeof(IHandler<>))
.WithService.Base()
.Configure(c => c.LifeStyle.Is(LifestyleType.Transient)
.Interceptors<AutoReleaseHandlerInterceptor>()),
Component.For<HandlerFactory>().AsFactory(c => c.SelectedWith<HandlerSelector>()));
}
}
When calling factory.GetHandlersForEvent(ev); I get an exception complaining about array type mismatch:
"Attempted to access an element as a type incompatible with the array."
Stack trace:
at System.Collections.Generic.Dictionary2.ValueCollection.CopyTo(TValue[] array, Int32 index)
at System.Collections.Generic.Dictionary2.ValueCollection.System.Collections.ICollection.CopyTo(Array array, Int32 index)
at Castle.MicroKernel.DefaultKernel.ResolveAll(Type service, IDictionary arguments) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\MicroKernel\DefaultKernel_Resolve.cs:line 285
at Castle.Facilities.TypedFactory.TypedFactoryComponentCollection.Resolve(IKernel kernel) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\Facilities\TypedFactory\TypedFactoryComponentCollection.cs:line 39
at Castle.Facilities.TypedFactory.Internal.TypedFactoryInterceptor.Resolve(IInvocation invocation) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\Facilities\TypedFactory\Internal\TypedFactoryInterceptor.cs:line 173
at Castle.Facilities.TypedFactory.Internal.TypedFactoryInterceptor.Intercept(IInvocation invocation) in e:\OSS.Code\Castle.Windsor\src\Castle.Windsor\Facilities\TypedFactory\Internal\TypedFactoryInterceptor.cs:line 83
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.HandlerFactoryProxy.GetHandlersForEvent(IEvent ev)
at CastleWindsorTests.Program.TryIt(HandlerFactory factory) in c:\users\user\documents\visual studio 2010\Projects
How to implement the HandlerSelector so that it works well with factory defined as returning object[] whereas the real objects at runtime are closed generic types?
I'll be happy to be pointed to some existing documentation with guidelines for implementors of ITypedFactoryComponentSelector / DefaultTypedFactoryComponentSelector. Yes, I tried the http://docs.castleproject.org/(S(kwaa14uzdj55gv55dzgf0vui))/Windsor.Typed-Factory-Facility-interface-based-factories.ashx but here's not much about the above types.
I really don't want to introduce a service locator (instead of factory) ;).
To answer my own question:
I must've been blind. After reading more closely the xmldoc of the methods I override, changing HandlerSelector to the following solved the problem:
public class HandlerSelector : DefaultTypedFactoryComponentSelector
{
protected override TypedFactoryComponent BuildFactoryComponent(MethodInfo method, string componentName, Type componentType, System.Collections.IDictionary additionalArguments)
{
return new TypedFactoryComponentCollection(componentType, additionalArguments);
}
protected override Type GetComponentType(MethodInfo method, object[] arguments)
{
var message = arguments[0];
var handlerType = typeof(IHandler<>).MakeGenericType(message.GetType());
return handlerType;
}
}
#workabyte
For Castle v3, GetComponentType method stays the same but the BuildFactoryComponent method looks like this for me:
protected override Func<IKernelInternal, IReleasePolicy, object> BuildFactoryComponent(MethodInfo method, string componentName, Type componentType, IDictionary additionalArguments)
{
return (kernel, rp) => kernel.ResolveAll(componentType);
}

Resources