WPF-Caliburn.Micro-NLog handle exception on App Domain - wpf

Hi I try log expcetion on App Domain with NLog. It is WPF app with Caliburn Micro.
In MEF bootstraper I have this code:
static readonly ILog Log = LogManager.GetLog(typeof(NLogLogger));
#region Constructors
public MefBootStrapper()
: base()
{
_msgBox = new MessageBoxes();
_doHandle = true;
}
static MefBootStrapper()
{
LogManager.GetLog = type => new NLogLogger(type);
}
#endregion
#region Exception handling on App Domain
protected override void OnUnhandledException(object sender,
System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
if (_doHandle)
{
Log.Error(e.Exception.InnerException);
_msgBox.ShowException(e.Exception.InnerException);
e.Handled = true;
}
else
{
Log.Error(e.Exception.InnerException);
_msgBox.ShowException(e.Exception);
e.Handled = false;
}
}
#endregion
When I run app and throw exception from view modle class it show message box that is ok but exception is not logged to file.
I try log exception in view model calls:
something like this: Log.Error(new Exception("4"));
This work, but If i try log exception in OnUnhandleException method it doesnt wokr. Why?

Your problem is that the static field Log gets initialized before your static constructor runs see (Static field initialization). So you will have your Log field with the default Caliburn Nulloger initialized instead of your NLogLogger. You should move the Log field initialization into your static constructor.
private static readonly ILog Log;
static MefBootStrapper()
{
LogManager.GetLog = type => new NLogLogger(type);
Log = LogManager.GetLog(typeof(NLogLogger));
}

Related

WPF, Prism, Unitybootstrapper, and Enterprise Library Logging setup throwing LogWriter exception

I'm just trying to get up off the ground and get used to working with Prism, in my bootstrapper I have:
public class Bootstrapper : UnityBootstrapper
{
private readonly EnterpriseLibraryLoggerAdapter _logger = new EnterpriseLibraryLoggerAdapter();
protected override void InitializeShell()
{
base.InitializeShell();
Application.Current.MainWindow = (Shell)this.Shell;
Application.Current.MainWindow.Show();
}
protected override DependencyObject CreateShell()
{
return this.Container.Resolve<Shell>();
}
protected override ILoggerFacade CreateLogger()
{
return _logger;
}
for my App OnStartup:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Bootstrapper bootstrapper = new Bootstrapper();
bootstrapper.Run();
}
}
And the logging adapter
public class EnterpriseLibraryLoggerAdapter : ILoggerFacade
{
#region ILoggerFacade Members
public void Log(string message, Category category, Priority priority)
{
Logger.Write(message, category.ToString(), (int)priority); // <--Blows up here
}
#endregion
}
When the bootstrapper Runs, it hits the Logger.Write and throws an exception:
The type LogWriter does not have an accessible constructor.
I'm following from the StockTraderRI sample app. Am I missing a registration somewhere?
moved the configuration to my bootstrapper constructor and things seem to be working
var builder = new ConfigurationSourceBuilder();
builder.ConfigureLogging()
.WithOptions
.DoNotRevertImpersonation()
.LogToCategoryNamed("Debug")
.SendTo.FlatFile("Basic Log File")
.FormatWith(new FormatterBuilder()
.TextFormatterNamed("Text Formatter")
.UsingTemplate(
"Timestamp: {timestamp}{newline}Message: {message}{newline}Category: {category}{newline}"))
.ToFile("core.log")
.SendTo.RollingFile("Rolling Log files")
.RollAfterSize(1024)
.ToFile("RollingTest.log")
.LogToCategoryNamed("General")
.WithOptions.SetAsDefaultCategory()
.SendTo.SharedListenerNamed("Basic Log File");
var configSource = new DictionaryConfigurationSource();
builder.UpdateConfigurationWithReplace(configSource);
EnterpriseLibraryContainer.Current = EnterpriseLibraryContainer.CreateDefaultContainer(configSource);

Frame ContentLoaded event

I'm new at Silverlight.
I've created a sort of master page using a Page with a frame where the content is loaded. As I handle multiple UserControls at the time (only one is shown, but I want to keep the state of the opened before) I'm setting Content property instead of Navigate method. That way I can assign a UserControl (already created, not a new one as it would be using Navigate with the Uri to the UserControl).
Now I want to take a picture as shown here from the frame when its content changes. If I do it immediately when the content set, the UserControl won't be shown in the picture because it takes a few secs. Frames have the event Navigated, but it doesn't fire with property Content (it just fires when the method Navigate is used, as it name says).
How can I know when new Content is loaded?
If it helps I'm using Silverligh 5.
I've a solution but I don't really like it, so I'm still looking for other ways.
public class CustomFrame : Frame
{
private readonly RoutedEventHandler loadedDelegate;
public static readonly DependencyProperty UseContentInsteadNavigationProperty =
DependencyProperty.Register("UseContentInsteadNavigation", typeof (bool), typeof (CustomFrame), new PropertyMetadata(true));
public bool UseContentInsteadNavigation
{
get { return (bool)GetValue(UseContentInsteadNavigationProperty); }
set { SetValue(UseContentInsteadNavigationProperty, value); }
}
public CustomFrame()
{
this.loadedDelegate = this.uc_Loaded;
}
public new object Content
{
get { return base.Content; }
set
{
if (UseContentInsteadNavigation)
{
FrameworkElement fe = (FrameworkElement)value;
fe.Loaded += loadedDelegate;
base.Content = fe;
}
else
{
base.Content = value;
}
}
}
void uc_Loaded(object sender, RoutedEventArgs e)
{
((UserControl)sender).Loaded -= loadedDelegate;
OnContentLoaded();
}
public delegate void ContentLoadedDelegate(Frame sender, EventArgs e);
public event ContentLoadedDelegate ContentLoaded;
private void OnContentLoaded()
{
if (ContentLoaded != null)
ContentLoaded(this, new EventArgs());
}
}

Unity: Problem with resolving RIA DomainContext

I am using PRISM 4 and got my head around almost all features, however as soon as I would like to inject my DomainContext class (RIA) into my view model, the hell breaks loose. :) It would be great if an experienced Unity/Prism developer could give me an advice how to proceed.
Within my bootstrapper, I am registering the required class in Unity Container like this:
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterType<SCMDomainContext>();
}
Within the NavigationModule, I have the following in the ctor to register the NavigationView with a particular region.
public NavigationModule(IUnityContainer container, IRegionManager regionManager)
{
_container = container;
_regionManager = regionManager;
_regionManager.RegisterViewWithRegion(Constants.NavRegion, () => _container.Resolve<NavigationView>());
}
The View takes the View Model as dependency:
public NavigationView(NavigationViewModel viewModel)
{
InitializeComponent();
Loaded += (s, e) =>
{
DataContext = viewModel;
};
}
The ViewModel has the following:
public NavigationViewModel(SCMDomainContext context)
{
_context = context;
ConstructCommon();
}
As soon as I comment this ctor out and put a en empty ctor, it is all fine, for some reason I can't resolve the SCMDomainContext class. Which is the one you add to have the Domain Context created for you provided by Ria Services.
Since I am using Silverlight, I can't see the stack trace to follow the exception, all I get is this message on a page. What am I missing please?
Microsoft JScript runtime error: Unhandled Error in Silverlight Application An exception occurred while initializing module 'NavigationModule'.
- The exception message was: Activation error occured while trying to get instance of type NavigationModule, key ''
Check the InnerException property of the exception for more information. If the exception occurred
while creating an object in a DI container, you can exception.GetRootException() to help locate the
root cause of the problem. at Microsoft.Practices.Prism.Modularity.ModuleInitializer.HandleModuleInitializationError(ModuleInfo moduleInfo, String assemblyName, Exception exception)
at Microsoft.Practices.Prism.Modularity.ModuleInitializer.Initialize(ModuleInfo moduleInfo)
at Microsoft.Practices.Prism.Modularity.ModuleManager.LoadModulesThatAreReadyForLoad()
at Microsoft.Practices.Prism.Modularity.ModuleManager.IModuleTypeLoader_LoadModuleCompleted(Object sender, LoadModuleCompletedEventArgs e)
at Microsoft.Practices.Prism.Modularity.XapModuleTypeLoader.RaiseLoadModuleCompleted(LoadModuleCompletedEventArgs e)
at Microsoft.Practices.Prism.Modularity.XapModuleTypeLoader.HandleModuleDownloaded(DownloadCompletedEventArgs e)
at Microsoft.Practices.Prism.Modularity.XapModuleTypeLoader.IFileDownloader_DownloadCompleted(Object sender, DownloadCompletedEventArgs e)
at Microsoft.Practices.Prism.Modularity.FileDownloader.WebClient_OpenReadCompleted(Object sender, OpenReadCompletedEventArgs e)
at System.Net.WebClient.OnOpenReadCompleted(OpenReadCompletedEventArgs e)
at System.Net.WebClient.OpenReadOperationCompleted(Object arg)
Your help on this is highly appreciated,
Kave
I can't see much wrong here. But having said that, I'm using the Initialize method from the interface in the following way to register types and views for regions:
#region properties
[Dependency]
public IUnityContainer Container { get; set; }
[Dependency]
public IRegionManager RegionManager { get; set; }
#endregion
public virtual void Initialize()
{
this.Container.RegisterType<NavigationViewModel>(new ContainerControlledLifetimeManager());
this.Container.RegisterType<NavigationView>(new ContainerControlledLifetimeManager());
this.RegionManager.RegisterViewWithRegion(Constants.NavRegion, () => this.Container.Resolve<NavigationView>());
}
Not sure whether it makes a difference if you don't explicitly register the ViewModel and the View type. Personally I prefer to have control over the way how a type gets resolved by the container.
In fact its best to create a layer for the DomainContext like this. Then its easily resolvable by an IoC:
public class ContactModuleService : IContactModuleService
{
readonly SCMDomainContext _context = new SCMDomainContext();
#region Implementation of IContactModuleService
public EntitySet<Contact> Contacts
{
get { return _context.Contacts; }
}
public EntityQuery<Contact> GetContactsQuery()
{
return _context.GetContactsQuery();
}
public SubmitOperation SubmitChanges(Action<SubmitOperation> callback, object userState)
{
return _context.SubmitChanges(callback, userState);
}
public SubmitOperation SubmitChanges()
{
return _context.SubmitChanges();
}
public LoadOperation<TEntity> Load<TEntity>(EntityQuery<TEntity> query, Action<LoadOperation<TEntity>> callback, object userState) where TEntity : Entity
{
return _context.Load(query, callback, userState);
}
public LoadOperation<TEntity> Load<TEntity>(EntityQuery<TEntity> query) where TEntity : Entity
{
return _context.Load(query);
}
#endregion
}

Global handling exception in WPF app with Caliburn.Micro

Hi I try implement solution from this site im my WPF app for global exception handling.
http://www.codeproject.com/Articles/90866/Unhandled-Exception-Handler-For-WPF-Applications.aspx
I use Caliburn Micro as MVVM framework. Service I have in external assembly and it is injected in view model class with MEF.
Here is my implementation for global exception handling in WPF app.
App.xaml
DispatcherUnhandledException="Application_DispatcherUnhandledException"
Startup="Application_Startup"
App class:
public partial class App : Application
{
private IMessageBox _msgBox = new MessageBoxes.MessageBoxes();
public bool DoHandle { get; set; }
private void Application_Startup(object sender, StartupEventArgs e)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
private void Application_DispatcherUnhandledException(object sender,
System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
if (DoHandle)
{
_msgBox.ShowException(e.Exception);
e.Handled = true;
}
else
{
_msgBox.ShowException(e.Exception);
e.Handled = false;
}
}
void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var ex = e.ExceptionObject as Exception;
_msgBox.ShowException(ex);
}
}
Service method from external assembly:
public void ServiceLogOn()
{
try
{
}
catch (Exception ex)
{
throw ex;
}
}
This service method is call in view model class for example on button click event:
[Export(typeof(ILogOnViewModel))]
public class LogOnViewModel : Screen, ILogOnViewModel
{
public void LogOn()
{
_service.ServiceLogOn();
}
}
I run WPF app in Visual Studio and produce exception with message "Bad credentials" in ServiceLogOn method.
I expect that I see the message box with the exception.
But Visual Studio stop debuging app and show exception in service method in service project.
So I try run WPF from exe file and produce same exception in ServiceLogOn method.
I get this error:
Exception has been throw by target of an invocation.
Any exception from view model class is not handled in methods:
Application_DispatcherUnhandledException
or CurrentDomain_UnhandledException.
in App class.
What I do bad?
EDITED with Simon Fox’s answer.
I try implement in MEF bootstraper advice of Simon Fox’s, but I still something do wrong.
I move handle logic for exception to OnUnhandledException method in bootstraper class.
Here is my code from bootstraper class:
public class MefBootStrapper : Bootstrapper<IShellViewModel>
{
//...
private IMessageBox _msgBox = new MessageBoxes.MessageBoxes();
public bool DoHandle { get; set; }
protected override void OnUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
if (DoHandle)
{
_msgBox.ShowException(e.Exception);
e.Handled = true;
}
else
{
_msgBox.ShowException(e.Exception);
e.Handled = false;
}
}
//...
}
I bind some method from view model on button and throw new exception. Something like this:
public void LogOn()
{
throw new ArgumentException("Bad argument");
}
But result is sam, I test app out of Visual Studio and get this exception.
Exception has been throw by target of an invocation.
Caliburn.Micro has built in support for hooking unhandled exceptions. The Bootstrapper class (which every Caliburn project requires) sets this up for you and provides the virtual OnUnhandledException method.
In your custom BootStrapper you must override OnUnhandledException to perform any custom actions for unhandled exceptions in your app. Note that you will most likely have to marshal actions such as displaying a message box to the UI thread (Caliburn enables this easily via Execute.OnUIThread).
You may also have an issue in the way your service moves exceptions to the client, but without any details of how the service is implemented/hosted/etc I cannot help. Are you using WCF to do SOAP? Are you using FaultContracts?

Binding where value changes are directly stored in the DB

I'm currently struggling with one of the bindings I'm trying to add to my WPF project.
In the app I have a model with a bool property that cannot be used for databinding. Behind that property is a .NET remoting object that does some validation and writes the new value into the DB.
The requirement ist that the property should be displayed as checkbox, and as the user changes the value the new value should be immediatly provided to the .NET remoting object.
My approach so far:
I've created in my ViewModel with a DependencyProperty that is bound to my checkbox.
In the propertychanged handler of the DP, I'm writting the value to the property of the remoting object.
The problems I have with this approach:
if the validation within the .net remoting object raises an exception, this exception is swallowed. In addition the checkbox state and what's in the DB is not in sync. I tried to reset the value of the DP in case of an exception, but the checkbox doesn't reflect that.
What makes the situation even worse is the fact, that this WPF controls is integrated into an existing WinForms app.
So I would like to have the same behavior for these exceptions as I have implemented in my Application.ThreadException handler.
any ideas how to approach this?
The problem is that I heard only solutions for .NET 4.0 so far, but I'm working with 3.5SP1.
tia
Martin
Short demo code:
class TestVM : DependencyObject
{
private Model _m;
public TestVM()
{
_m = new Model();
}
public bool Value
{
get { return (bool)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
// Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value",
typeof(bool),
typeof(TestVM),
new FrameworkPropertyMetadata(
false,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
((sender, e) => ((TestVM)sender).Apply(e))));
private bool _suppress = false;
private void Apply(DependencyPropertyChangedEventArgs e)
{
if (_suppress) return;
try
{
_m.Value = this.Value;
}
catch
{
_suppress = true;
this.Value = _m.Value;
this.OnPropertyChanged(e);
}
finally
{
_suppress = false;
}
}
}
You don't need to use a DependencyObject as your ViewModel. You just need to implement INotifyPropertyChanged to get data binding support:
class TestVM
: INotifyPropertyChanged
{
private Model _m;
public TestVM()
{
_m = new Model();
}
public bool Value
{
get { return _m.Value; }
set
{
_m.Value = this.Value;
OnPropertyChanged("Value");
}
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Note that if you expect the setter to throw exceptions, you may want to use an ExceptionValidationRule on the binding in your view.
Update: It sounds like your problem is that the Binding won't respond to PropertyChanged events within the call to set the source. One way to get around this is to use an asynchronous binding by setting IsAsync=True in the XAML for your binding. WPF will process the PropertyChanged event after it has finished updating the source value and won't think it is a reentrant call.
You can also get around this by using a Converter and turning off updates on PropertyChanged by doing UpdateSourceTrigger=LostFocus, but I don't think you would want that behavior.
I found a solution for my problem. I'm now deriving my own binding class that does the job.
public class ExceptionBinding : Binding
{
public ExceptionBinding(string name)
: base(name)
{
Construct();
}
public ExceptionBinding()
: base()
{
Construct();
}
private void Construct()
{
this.ValidatesOnExceptions = true;
this.UpdateSourceExceptionFilter = new UpdateSourceExceptionFilterCallback(OnException);
}
private object OnException(object bindExpression, Exception exception)
{
// ... custom error display ...
var exp = (BindingExpressionBase)bindExpression;
exp.UpdateTarget();
return null; // null needed to avoid display of the default error template
}
}

Resources