IRegistrationConvention structuremap CtorDependency - c#

I need to send a custom instance in Ctor in scanner. Hear is my code:
public class RunnableScanner : IRegistrationConvention
{
private readonly List<Module> modules;
public RunnableScanner()
{
var config = RegisterModulesConfig.GetConfig();
modules = config.Modules.ToList();
}
public void Process(Type type, Registry registry)
{
if (!type.IsAbstract && typeof(IRunnable).IsAssignableFrom(type))
{
var module = modules.SingleOrDefault(c => c.Name == type.Name);
if (module != null)
{
registry.For(typeof (IRunnable)).Use(type).Named(type.Name).CtorDependency<Scheduler>("scheduler")
.IsNamedInstance(module.Scheduler + "Scheduler");
}
}
}
}
the line :
registry.For(typeof (IRunnable)).Use(type).Named(type.Name).CtorDependency<Scheduler>("scheduler") .IsNamedInstance(module.Scheduler + "Scheduler");
i need to set a value for Scheduler ("Interval" property).
I did try this:
var sch = ObjectFactory.GetNamedInstance<Scheduler>(module.Scheduler + "Scheduler");
sch.Interval = module.Interval;
registry.For(typeof (IRunnable)).Use(type).Named(type.Name).CtorDependency<Scheduler>("scheduler").Is(sch);
but this don't work because ObjectFactory i cant use in Registry.
Sorry for my English.

I'm not a structuremap expert so maybe this is not the best/most elegant/effective solution.
But the following registration using a LambdaInstance seems to work
registry.For(typeof (IRunnable)).Use(type).Named(type.Name)
.CtorDependency<Scheduler>("scheduler")
.Is(new LambdaInstance<Scheduler>(c =>
{
var sch = c.GetInstance<Scheduler>(module.Scheduler + "Scheduler");
sch.Interval = module.Interval;
return sch;
})
);

Related

Castle Windsor Resolving Mutiple Generic Implementations of 1 Inteface

Suppose I have the following:
public interface IFileHandler<TLocation,TRow> { ... }
//loads file in some location using record format defined in RowTypeA
//e.g. RowTypeA records exist in files that match string 'file_a.csv'
public class FileHandlerA<TLocation> : IFileHandler<TLocation, RowTypeA>{ ... }
//loads file in some location using record format defined in RowTypeB
//e.g. RowTypeB records exist in files that match string 'file_b.csv'
public class FileHandlerB<TLocation> : IFileHandler<TLocation, RowTypeB>{ ... }
public class MyCode {
...
public void MyMethod()
{
//here is how I would like to resolve file handlers
var fh1 = container.Resolve<IFileHandler<Location1, RowTypeA>>(); //resolves to FileHandlerA<Location1>
var fh2 = container.Resolve<IFileHandler<Location2, RowTypeA>>(); //resolves to FileHandlerA<Location2>
var fh3 = container.Resolve<IFileHandler<Location1, RowTypeB>>(); //resolves to FileHandlerB<Location1>
}
...
}
How do I do the registration in Castle Windsor for this? Or is there a better design for this problem?
P.S.
I tried:
Classes
.FromAssembly(thisAssembly)
.BasedOn(typeof(IFileHandler<,>)
.WithServiceAllInterfaces();
Also thought about this:
Component
.For<IFileHandler<,>()
.ImplementedBy<???>
I think this should work but haven't tested it:
var locationTypes = typeof(ILocation).Assembly.GetTypes()
.Where(t => !t.IsInterface && !t.IsGenericType).ToArray();
var fileHandlerTypes = typeof(IFileHandler<,>).Assembly.GetTypes()
.Where(t => !t.IsInterface && !t.IsGenericType && t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IFileHandler<,>))).ToArray();
foreach (var fh in fileHandlerTypes)
foreach(var locType in locationTypes)
{
var rowType = fh.BaseType.GenericTypeArguments[1];
var requestedType = typeof(IFileHandler<,>).MakeGenericType(locType).MakeGenericType(rowType);
container.Register(Component.For(requestedType, fh));
}

MVVM Command property stacktrace

I'd like to know which property command is executed using the following pattern in my ApplicationCommand, any idea ? Today the Log always show ApplicationCommand.Execute(), not very usefull to trace user actions.
Class declaration :
public class MyViewModel
{
public ICommand BlinkCommand { get; set; }
public ICommand CheckCommand { get; set; }
public MyViewModel()
{
BlinkCommand = new ApplicationCommand(() => DoBlink());
CheckCommand = new ApplicationCommand(() => DoCheck());
}
...
}
My application command implementation for all commands :
public class ApplicationCommand : RelayCommand
{
public void Execute()
{
// No try-catch, I never code bugs ;o)
Log.Info("Prepare to execute the command " + this);
base.Execute();
Log.Info("Finished to execute the command " + this);
}
}
Using 1 command = 1 class, it's fine. Using this way, which seems to be widely used on the WWW, I don't know how to proceed :(
Thanks by advance for your help
You should refactor your ApplicationCommand like this:
public class ApplicationCommand : RelayCommand
{
string commandName;
public void Execute()
{
// No try-catch, I never code bugs ;o)
Log.Info("Prepare to execute the command " + commandName);
base.Execute();
Log.Info("Finished to execute the command " + commandName);
}
public static void SetCommand(MyViewModel vm,
Expression<Func<MyViewModel,ICommand>> commandSelector,
Action action){
var me = commandSelector.Body as MemberExpression;
if(me == null) throw new ArgumentException("Invalid command selector!");
var newCommand = new ApplicationCommand(action);
newCommand.commandName = me.Member.Name;
vm.GetType()
.GetProperty(newCommand.commandName)
.SetValue(vm, newCommand, null);
}
}
//then use it like this
public MyViewModel()
{
ApplicationCommand.SetCommand(this, e => e.BlinkCommand, () => DoBlink());
ApplicationCommand.SetCommand(this, e => e.CheckCommand, () => DoCheck());
}
I understand that it's for debugging purpose, so we should print the property name and then using the approach above is better.
You could add an extra instance string to the ApplicationCommand that you pass when constructing an instance and log that when execute is called.
public class ApplicationCommand : RelayCommand
{
private string logName;
public ApplicationCommand(Action<T> execute, string logName = "")
{
// ...
this.logName = logName;
}
public void Execute()
{
// No try-catch, I never code bugs ;o)
Log.Info("Prepare to execute the command " + this.logName);
base.Execute();
Log.Info("Finished to execute the command " + this.logName);
}
}
Using it:
BlinkCommand = new ApplicationCommand(() => DoBlink(), "Blink");
Did you try call GetType()?
public class ApplicationCommand : RelayCommand
{
public ApplicationCommand(Expression<Func<ICommand>> property,Action<T> execute, string logName = "")
{
// ...
this.logName = logName;
}
public void Execute()
{
// No try-catch, I never code bugs ;o)
Log.Info("Prepare to execute the command " + GetTypeName(this.GetType()) + "." + GetPropertyPath(property));
base.Execute();
Log.Info("Finished to execute the command " + GetTypeName(this.GetType()) + "." + GetPropertyPath(property));
}
}
private string GetPropertyPath(LambdaExpression propertyPath, bool acceptsFields = false)
{
Stack<MemberInfo> properties = GetPropertyPathStack(propertyPath, acceptsFields);
return string.Join(".", properties.Select(p => p.Name));
}
private Stack<MemberInfo> GetPropertyPathStack(LambdaExpression propertyPath, bool acceptFields = false)
{
MemberExpression member = propertyPath.Body as MemberExpression;
Stack<MemberInfo> properties = new Stack<MemberInfo>();
while(member != null)
{
if (member.Member is PropertyInfo || (acceptFields && member.Member is FieldInfo))
{
properties.Push(member.Member);
if (member.Expression is MemberExpression)
{
member = member.Expression as MemberExpression;
}
else
{
ConstantExpression constant = member.Expression as ConstantExpression;
member = null;
}
}
else
{
member = null;
}
}
return properties;
}
private string GetTypeName(Type type)
{
if (type.IsGenericType)
{
return GetGenericTypeName(type);
}
else
{
return type.FullName;
}
}
private string GetGenericTypeName(Type type)
{
Type[] genericArguments = type.GetGenericArguments();
string argumentNames = string.Join(", ", genericArguments.Select(GetTypeName));
return string.Format("{0}<{1}>", type.GetBaseName(), argumentNames);
}
Hope, this will help you or inspire you for better solution.
Usage:
BlinkCommand = new ApplicationCommand(() => BlinkCommand, () => DoBlink());

Create a generic type to find implementations of in a Resharper plugin

I'm writing a plugin for resharper which I want to use to navigate from a ConcreteCommand -> ConcreteCommandHandler where those types look like this
public class ConcreteCommand : ICommand
public class ConcreteCommandHandler : ICommandHandler<ConcreteCommand>
I've got as far as adding my navigation menu option when the cursor is on a ICommand instance/definition (currently only by checking if the name contains 'Command' and not 'CommandHandler'), and I think I have the code necessary to actually search for a type which inherits something, but my issue is that the only thing I actually have a type for is my ConcereteCommand and I need to create (or get a reference to) the generic type ICommandHandler<T> with T being the type the cursor is currently on.
So I have 2 things I still want to know:
How can I check if my IDeclaredElement is an implementation of a particular interface (ideally by specifying the full name in a string from config)?
How can I create a ITypeElement which is a generic type of a specific interface where I can set the generic type from my existing IDeclaredElements type, so I can then find classes which inherit this?
My existing code looks like this:
[ContextNavigationProvider]
public class CommandHandlerNavigationProvider : INavigateFromHereProvider
{
public IEnumerable<ContextNavigation> CreateWorkflow(IDataContext dataContext)
{
ICollection<IDeclaredElement> declaredElements = dataContext.GetData(DataConstants.DECLARED_ELEMENTS);
if (declaredElements != null || declaredElements.Any())
{
IDeclaredElement declaredElement = declaredElements.First();
if (IsCommand(declaredElement))
{
var solution = dataContext.GetData(JetBrains.ProjectModel.DataContext.DataConstants.SOLUTION);
yield return new ContextNavigation("This Command's &handler", null, NavigationActionGroup.Other, () => { GotToInheritor(solution,declaredElement); });
}
}
}
private void GotToInheritor(ISolution solution, IDeclaredElement declaredElement)
{
var inheritorsConsumer = new InheritorsConsumer();
SearchDomainFactory searchDomainFactory = solution.GetComponent<SearchDomainFactory>();
//How can I create the ITypeElement MyNameSpace.ICommandHandler<(ITypeElement)declaredElement> here?
solution.GetPsiServices().Finder.FindInheritors((ITypeElement)declaredElement, searchDomainFactory.CreateSearchDomain(solution, true), inheritorsConsumer, NullProgressIndicator.Instance);
}
private bool IsCommand(IDeclaredElement declaredElement)
{
//How can I check if my declaredElement is an implementation of ICommand here?
string className = declaredElement.ShortName;
return className.Contains("Command")
&& !className.Contains("CommandHandler");
}
}
Ok managed to work this out with a fair bit of pushing in the right direction from #CitizenMatt.
basically my solution looks like this (still needs some tidying up)
private static readonly List<HandlerMapping> HandlerMappings = new List<HandlerMapping>
{
new HandlerMapping("HandlerNavigationTest.ICommand", "HandlerNavigationTest.ICommandHandler`1", "HandlerNavigationTest"),
new HandlerMapping("HandlerNavTest2.IEvent", "HandlerNavTest2.IEventHandler`1", "HandlerNavTest2")
};
public IEnumerable<ContextNavigation> CreateWorkflow(IDataContext dataContext)
{
ICollection<IDeclaredElement> declaredElements = dataContext.GetData(DataConstants.DECLARED_ELEMENTS);
if (declaredElements != null && declaredElements.Any())
{
IDeclaredElement declaredElement = declaredElements.First();
ISolution solution = dataContext.GetData(JetBrains.ProjectModel.DataContext.DataConstants.SOLUTION);
ITypeElement handlerType = GetHandlerType(declaredElement);
if (handlerType != null)
{
yield return new ContextNavigation("&Handler", null, NavigationActionGroup.Other, () => GoToInheritor(solution, declaredElement as IClass, dataContext, handlerType));
}
}
}
private static ITypeElement GetHandlerType(IDeclaredElement declaredElement)
{
var theClass = declaredElement as IClass;
if (theClass != null)
{
foreach (IPsiModule psiModule in declaredElement.GetPsiServices().Modules.GetModules())
{
foreach (var handlerMapping in HandlerMappings)
{
IDeclaredType commandInterfaceType = TypeFactory.CreateTypeByCLRName(handlerMapping.HandledType, psiModule, theClass.ResolveContext);
ITypeElement typeElement = commandInterfaceType.GetTypeElement();
if (typeElement != null)
{
if (theClass.IsDescendantOf(typeElement))
{
IDeclaredType genericType = TypeFactory.CreateTypeByCLRName(handlerMapping.HandlerType, psiModule, theClass.ResolveContext);
ITypeElement genericTypeElement = genericType.GetTypeElement();
return genericTypeElement;
}
}
}
}
}
return null;
}
private static void GoToInheritor(ISolution solution, IClass theClass, IDataContext dataContext, ITypeElement genericHandlerType)
{
var inheritorsConsumer = new InheritorsConsumer();
var searchDomainFactory = solution.GetComponent<SearchDomainFactory>();
IDeclaredType theType = TypeFactory.CreateType(theClass);
IDeclaredType commandHandlerType = TypeFactory.CreateType(genericHandlerType, theType);
ITypeElement handlerTypeelement = commandHandlerType.GetTypeElement();
solution.GetPsiServices().Finder.FindInheritors(handlerTypeelement, searchDomainFactory.CreateSearchDomain(solution, true),
inheritorsConsumer, NullProgressIndicator.Instance);
var potentialNavigationPoints = new List<INavigationPoint>();
foreach (ITypeElement inheritedInstance in inheritorsConsumer.FoundElements)
{
IDeclaredType[] baseClasses = inheritedInstance.GetAllSuperTypes();
foreach (IDeclaredType declaredType in baseClasses)
{
if (declaredType.IsInterfaceType())
{
if (declaredType.Equals(commandHandlerType))
{
var navigationPoint = new DeclaredElementNavigationPoint(inheritedInstance);
potentialNavigationPoints.Add(navigationPoint);
}
}
}
}
if (potentialNavigationPoints.Any())
{
NavigationOptions options = NavigationOptions.FromDataContext(dataContext, "Which handler do you want to navigate to?");
NavigationManager.GetInstance(solution).Navigate(potentialNavigationPoints, options);
}
}
public class InheritorsConsumer : IFindResultConsumer<ITypeElement>
{
private const int MaxInheritors = 50;
private readonly HashSet<ITypeElement> elements = new HashSet<ITypeElement>();
public IEnumerable<ITypeElement> FoundElements
{
get { return elements; }
}
public ITypeElement Build(FindResult result)
{
var inheritedElement = result as FindResultInheritedElement;
if (inheritedElement != null)
return (ITypeElement) inheritedElement.DeclaredElement;
return null;
}
public FindExecution Merge(ITypeElement data)
{
elements.Add(data);
return elements.Count < MaxInheritors ? FindExecution.Continue : FindExecution.Stop;
}
}
And this allows me no navigate to multiple handlers if they exist. This currently relies on the interfaces for the handled type and the handler type being in the same assembly. But this seems reasonable enough for me at the moment.

Entity framework error as"New transaction is not allowed because there are other threads running in the session

We are using entity framework codefirst approach
I am new to entity framework and I am facing error while trying to do "New transaction is not allowed because there are other threads running in the session.
public class DatabaseBackup : IDataBackup
{
private readonly IMonarchDbContext m_db;
public DatabaseBackup(IMonarchDbContext podb)
{
if (podb == null)
throw new ArgumentNullException("podb");
m_db = podb;
}
public DBBackupHistory GetLatestBackupHistory(DBBackupFrequency backupFrequency = DBBackupFrequency.Periodic)
{
DBBackupHistory result = null;
// get the backup history of the given backuptype and populate the objects
var configId = m_db.DBBackupConfigurations.Where(c => c.ScheduleType == (int)backupFrequency && c.BackupStatus == 1).Distinct().Select(c => c.ConfigurationId).DefaultIfEmpty(-1).First();
if (configId > 0)
{
result = m_db.DBBackupHistorys.Where(b => b.Status == 1 && b.ConfigurationId == configId).OrderByDescending(lb => lb.BackupDatetime).FirstOrDefault();
}
return result;
}
public IEnumerable<DBBackupConfiguration> GetAllConfiguration()
{
var result = m_db.DBBackupConfigurations.Where(c => c.BackupStatus == 1).OrderByDescending(c => c.ConfigurationId);
return result;
}
public void Backup(DBBackupConfiguration config, int fileIndex)
{
Console.WriteLine("Running DB Backup type {0} to device {1}", (DBBackupType)config.BackupType, fileIndex);
m_db.StoredProc.SPBackup(config, fileIndex);
}
I am calling the below methods in another class as follows
private readonly IDataBackup m_dataBackup;
public int PerformBackup(int defaultPollIntervalInMinutes = 15)
{
// polling interval in Minutes
int pollInterval = defaultPollIntervalInMinutes;
int fileIndex = getCurrentDumpFileIndex();
// check for the backup configuration
var configurations = m_dataBackup.GetAllConfiguration();
foreach (var config in configurations)
{
var lastBackup = m_dataBackup.GetLatestBackupHistory(DBBackupFrequency.Weekly);
if (lastBackup == null)
{
m_dataBackup.Backup(config, fileIndex + 1);
break;
}
Here is the Db Context class is as below
public class MonarchDbContext:DbContext,IMonarchDbContext
{
private IStoredProcedure m_storedProc;
private static object m_dbIntializerSet;
public MonarchDbContext(string nameOrConnectionString)
: base( nameOrConnectionString )
{
//-- Set the DB initializer only once.
System.Threading.LazyInitializer.EnsureInitialized( ref m_dbIntializerSet,()=>{
Database.SetInitializer<MonarchDbContext>(null);
//-- Give debug builds a chance to overwrite the above.
_SetInitializerForDebugBuilds();
return new object();
});
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
var csb = new SqlConnectionStringBuilder( this.Database.Connection.ConnectionString );
csb.MultipleActiveResultSets = true;
this.Database.Connection.ConnectionString = csb.ToString();
var objectContext = ( this as IObjectContextAdapter ).ObjectContext;
objectContext.CommandTimeout = 3600;
}
#region Public "Tables"
public IDbSet<DBBackupConfiguration> DBBackupConfigurations { get; set; }
public IDbSet<DBBackupHistory> DBBackupHistorys { get; set; }
public IStoredProcedure StoredProc
{
get
{
return System.Threading.LazyInitializer.EnsureInitialized(ref m_storedProc, () => new BackupStoredProc(this.Database));
}
}
#endregion
please let me know how can i solve the issue.
I found the issue
I need to add toList() at the end of the Linq code and it just worked for me.
public IEnumerable<DBBackupConfiguration> GetAllConfiguration()
{
var result = m_db.DBBackupConfigurations.Where(c => c.BackupStatus == 1).OrderByDescending(c => c.ConfigurationId).ToList();
return result;
}
Just add the List to Ienumerbale types

Returning a different provider (binding) based on an object (callcontext) with Ninject

I'm trying to return a different provider, depending on a custom context. Given the following
public interface IProvider
{
string WhoAreYou();
}
And two providers
namespace ProviderOne
{
public class Implementation : IProvider
{
public string WhoAreYou()
{
return "Provider One";
}
}
}
namespace ProviderTwo
{
public class Implementation : IProvider
{
public string WhoAreYou()
{
return "Provider Two";
}
}
}
And a context as follows
public class CallContext
{
public string SomeValue{ get; set; }
public int AnotherValue { get; set; }
}
My binding looks like this
CallContext context1 = new CallContext()
{
SomeValue = "one",
AnotherValue = 1
};
Bind<IProvider>().To<ProviderOne.Implementation>().WithMetadata("callcontext", context1);
CallContext context2 = new CallContext()
{
SomeValue = "two",
AnotherValue = 2
};
Bind<IProvider>().To<ProviderOne.Implementation>().WithMetadata("callcontext", context2);
I'm fairly certain it is correct up to here, though it's late, and I'm out of ideas.
My problem is getting to those bindings. I have tried various methods
var test1 = kernel.Get<IProvider>(b => b.Get<CallContext>("callcontext") == context1);
//var test1 = kernel.Get<IProvider>(m => m.Has("callcontext") && m.Get<CallContext>("callcontext").Equals(context1));
//var test1 = kernel.Get<IProvider>(m => m.Get<CallContext>("callcontext").Equals(context1));
//var test1 = kernel.Get<IProvider>().Equals(context1);
But they don't work, at best I get the "No binding" error, at worst I just get errors. I'm sure there must be something easy I am overlooking, or just no aware off.
Thank you
I found the problem, and if anyone runs up against this in the future, the solution above is fine, except you have to explicit override Equals for Ninject to resolve to the object. As follows.
public override bool Equals(object obj)
{
if (obj.GetType() == typeof(CallContext))
{
var context = (CallContext)obj;
if (Country != null)
{
if (Country.ToLower() != context.Country.ToLower())
return false;
}
if (Store != context.Store)
return false;
return true;
}
return false;
}
Then you can resolve it as proposed.
CallContext context1 = new CallContext()
{
SomeValue = "one",
AnotherValue = 1
};
var test1 = kernel.Get<IProvider>(b => b.Get<CallContext>("callcontext").Equals(context1));

Categories