MVVM Command property stacktrace - c#

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());

Related

C# Return a Copy of ConcurrentBag

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Concurrent;
namespace Crystal_Message
{
class Message
{
private int messageID;
private string message;
private ConcurrentBag <Employee> messageFor;
private Person messageFrom;
private string calltype;
public Message(int iden,string message, Person messageFrom, string calltype, string telephone)
{
this.messageID = iden;
this.messageFor = new ConcurrentBag<Employee>();
this.Note = message;
this.MessageFrom = messageFrom;
this.CallType = calltype;
}
public ConcurrentBag<Employee> ReturnMessageFor
{
get
{
return messageFor;
}
}
public int MessageIdentification
{
get { return this.messageID; }
private set
{
if(value == 0)
{
throw new ArgumentNullException("Must have Message ID");
}
this.messageID = value;
}
}
public string Note
{
get { return message; }
private set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("Must Have a Message");
}
this.message = value;
}
}
public Person MessageFrom
{
get { return messageFrom; }
private set
{
this.messageFrom = value;
}
}
public string CallType
{
get { return this.calltype; }
private set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentNullException("Please specify call type");
}
this.calltype = value;
}
}
public void addEmployee(Employee add)
{
messageFor.Add(add);
}
public override string ToString()
{
return "Message: " + this.message + " From: " + this.messageFrom + " Call Type: " + this.calltype + " For: " + this.returnMessagefor();
}
private string returnMessagefor()
{
string generate="";
foreach(Employee view in messageFor)
{
generate += view.ToString() + " ";
}
return generate;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
Message testEquals = obj as Message;
if((System.Object)testEquals == null)
{
return false;
}
return (this.messageID == testEquals.messageID) && (this.message == testEquals.message) && (this.messageFor == testEquals.messageFor) && (this.messageFrom == testEquals.messageFrom) && (this.calltype == testEquals.calltype);
}
public bool Equals(Message p)
{
if ((Object)p == null)
{
return false;
}
return (this.messageID == p.messageID) && (this.message == p.message) && (this.messageFor == p.messageFor) && (this.messageFrom == p.messageFrom) && (this.calltype == p.calltype);
}
public override int GetHashCode()
{
unchecked
{
return this.messageID.GetHashCode() * 33 ^ this.message.GetHashCode() * 33 ^ this.messageFor.GetHashCode() * 33 ^ this.messageFrom.GetHashCode() * 33 ^ this.calltype.GetHashCode();
}
}
}
}
I have a Message class where a user could leave a message for more than one person. I have a getter for it, however, is returning a ConcurrentBag<> the way I've done proper practice? If not, how do i return the ConcurrentBag<> so I can loop through it and display it?
ConcurrentBag<T> is an IEnumerable<T>. You can loop through it as usual. However, as this is a thread safe collection, there are performance concerns to using it.
If you want to get rid of the performance impact while looping, call ToArray on it and return the new array instead.
public IEnumerable<Employee> ReturnMessageFor
{
get
{
return messageFor.ToArray();
}
}
It's not clear to me what you are trying to accomplish.
Are you trying to externalize the Bag for all operations? Because that's what you did...
If you want to externalize something you can iterate over you should either return the Bag as IEnumerable or return an array or a list copied from the Bag.
Either way it's safe to iterate over. Might not be the best in terms of performance, but that's another question.
// Option 1
public IEnumerable<Employee> ReturnMessageFor
{
get
{
return messageFor;
}
}
// Option 2
public Employee[] ReturnMessageFor
{
get
{
return messageFor.ToArray();
}
}
Notes:
You might want to make messageFor readonly (in the code you posted it is readonly).
Remember that a ConcurrentBag allows you to safely iterate over a snapshot of the collection in a thread safe manner, but it does not lock the items in the collection.

Give out parameter on event in C#

I want to give an out parameter on event but it doesn't work
like this
error :Cannot use parameter out in anonyme method or lambda expression
public void CallMyMethod()
{
//{... code here`removed...just for initialize object}
int? count = null;
MyMethod(myObject,count);
}
public static void MyMethod(AnObject myObject,out int?count)
{
//{... code removed...}
IEnumerable<AnAnotherObject> objects = myObject.GetAllObjects();//... get objects
count = (count == null) ? objects.Count() : count;
MyPopup popup = CreateMypopup();
popup.Show();
popup.OnPopupClosed += (o, e) =>//RoutedEventHandler
{
if (--count <= 0)
{
Finished();//method to finish the reccursive method;
}
else
{
MyMethod(myObject, out count);
}
};
}
The standard way to pass parameters to event handler is to define your own class
public class MyObjectArgs: EventArgs
{
MyObject myObj {get;set}
int? Count {get; set;}
}
and then pass the same instance of this class down the recursive calls
public void CallMyMethod()
{
//{... code here`removed...just for initialize object}
MyObjectArgs args = new MyObjectArgs();
args.Count = null;
args.myOby = myObject;
MyMethod(args);
}
public static void MyMethod(MyObjectArgs args)
{
//{... code removed...}
IEnumerable<AnAnotherObject> objects = args.myObj.GetAllObjects();//... get objects
args.Count = (args.Count == null) ? objects.Count() : args.Count;
MyPopup popup = CreateMypopup();
popup.Show();
popup.OnPopupClosed += (o, e) =>//RoutedEventHandler
{
if (--args.Count <= 0)
{
Finished();//method to finish the reccursive method;
}
else
{
MyMethod(args);
}
};
}
Also the line where you count the objects seems to be incorrect, perhaps you want this ?
args.Count = (args.Count == null) ? objects.Count() : args.Count + objects.Count();

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

IRegistrationConvention structuremap CtorDependency

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;
})
);

c# gettype of object from class

How could I make this work?:
public class myClass
{
public string first;
public int second;
public string third;
}
public string tester(object param)
{
//Catch the name of what was passed not the value and return it
}
//So:
myClass mC = new myClass();
mC.first = "ok";
mC.second = 12;
mC.third = "ko";
//then would return its type from definition :
tester(mC.first) // would return : "mc.first" or "myClass.first" or "first"
//and
tester(mC.second) // would return : "mc.second" or "myClass.second" or "second"
In the absence of infoof, the best you can do is Tester(() => mC.first) via expression trees...
using System;
using System.Linq.Expressions;
public static class Test
{
static void Main()
{
//So:
myClass mC = new myClass();
mC.first = "ok";
mC.second = 12;
mC.third = "ko";
//then would return its type from definition :
Tester(() => mC.first); // writes "mC.first = ok"
//and
Tester(() => mC.second); // writes "mC.second = 12"
}
static string GetName(Expression expr)
{
if (expr.NodeType == ExpressionType.MemberAccess)
{
var me = (MemberExpression)expr;
string name = me.Member.Name, subExpr = GetName(me.Expression);
return string.IsNullOrEmpty(subExpr)
? name : (subExpr + "." + name);
}
return "";
}
public static void Tester<TValue>(
Expression<Func<TValue>> selector)
{
TValue value = selector.Compile()();
string name = GetName(selector.Body);
Console.WriteLine(name + " = " + value);
}
}
This is not possible. Variable names don't exist in compiled code, so there's no way you can retrieve a variable name at runtime
That's not possible. "param" will have no information on where the value came from.
When calling tester(), a copy of the value in one of the properties is made, so the "link" to the property is lost.

Categories