C# How to catch an exception on generic abstract class constructor - c#

I am unable to catch an exception from a generic abstract class in the client app. The reason I want the exception to be thrown in the constructor is that the config file functionality needs to be the same in the derived classes and therefore I don't see a reason to implement this in every derived class. The exception should be handled in the overarching generic class AgentModule<T> however, this is not the case for a reason I am unaware.
I can catch the exception when I move the code to a method and invoke from the client class.
The abstract class:
public abstract class Importer
{
public abstract string Name { get; }
public abstract string Description { get; }
private System.Configuration.Configuration _customConfig;
public Importer()
{
string customConfigFile = this.GetType().Assembly.Location + ".config";
if (System.IO.File.Exists(customConfigFile))
{
System.Configuration.ExeConfigurationFileMap fileMap = new System.Configuration.ExeConfigurationFileMap();
fileMap.ExeConfigFilename = customConfigFile;
_customConfig = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(fileMap, System.Configuration.ConfigurationUserLevel.None);
}
else
{
throw new System.IO.FileNotFoundException("Could not load configuration file: " + customConfigFile);
}
}
public abstract void Load(ILogger logger);
}
The generic overarching class:
public class AgentModule<T> : ModuleBase where T : Importer, new()
{
private Importer _importer;
public override void Run()
{
try
{
_importer = (Importer)Activator.CreateInstance<T>();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
Derived class:
public class XLoad : Importer
{
public override string Name { get { return _name; } }
public override string Description { get { return _description; } }
private string _name;
private string _description;
public XLoad()
{
_name = "Load";
_description = "some desc";
}
public override void Load(ILogger logger)
{
Console.WriteLine("I am loading");
}
}

The Visual Studio debugger will not catch any exception for whatever happens within Activator.CreateInstance(). But if you execute the exe manually/programmatically, this exception will be handled. You can even get the exception thrown at the constructor of the Importer class from the InnerException at AgentModule.Run()
try
{
_importer = (Importer)Activator.CreateInstance<T>();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
if(e.InnerException != null)
Console.WriteLine(e.InnerException.Message );
}

Related

How to get generic type from one class to another c#

Is it possible to pass the generic type from one class to other class generic property.
For example:
Assembly Logger
namespace Logger
{
public class GenericLoger<T>
{
T _genericLog;
LogManager _logManager;
public GenericLoger(string logName)
{
_logManager = new LogManager(logName);
//Assigning the generic type to Log.GenerciLog, this is how I am
expecting or by some other possible way?.
Log.GenerciLog = _genericLog;
}
public static Write(string description)
{
_logManager.write(description);
}
}
public static class Log
{
LogManager _logManager;
static Log()
{
_logManager = new LogManager();
}
public static Write(string description)
{
_logManager.write(description);
}
//The generic type supplied in GenericLoger need to pass here,
//like this or by some other possible way?
public static T GenerciLog { get; internal set; }
//T is unrecognized here as type is available in GenericLoger
//I want to pass here from GenericLoger
}
}
Assembly Main Caller of Logger
using Logger;
namespace DataProcessor
{
internal class SpecialLogger
{
private static Lazy<GenericLog<SpecialLogger>> _passed;
public static GenericLog<SpecialLogger> Passed
{
get
{
if (_passed == null)
{
_passed = new Lazy<GenericLog<SpecialLogger>>(() => new GenericLog<SpecialLogger>("Passed"), true);
}
return _passed.Value;
}
}
private static Lazy<GenericLog<SpecialLogger>> _failed;
public static GenericLog<SpecialLogger> Failed
{
get
{
if (_failed == null)
{
_failed = new Lazy<GenericLog<SpecialLogger>>(() => new GenericLog<SpecialLogger>("Failed"), true);
}
return _failed.Value;
}
}
}
internal class Processor
{
public void ProcessRate()
{
var trans = dataManager.GetData();
//Will write the log in "Log.txt" file
Log.write(trans.Count + " transaction found");
foreach (var item in trans)
{
try
{
//transaction process code here
//This will write the text in "Passed.txt" file. 'Passed' property I want to access like this
Log.GenerciLog.Passed.Write(item);
}
catch (Exception ex)
{
//This will write the text in "Failed.txt" file. 'Failed' property I want to access like this
Log.GenerciLog.Failed.Write(item);
}
}
}
}
}
NOTE: In .NET you don't have a way for automatic type inference for use case like yours, also there is no automatic type substitution.
Not sure if this is what you are looking for
Your method definition should look like this
public static T GenerciLog<T> { get; internal set; }
and this is how to call it
try
{
//transaction process code here
//This will write the text in "Passed.txt" file. 'Passed' method I want to access like this
Log.GenerciLog<SpecialLogger>.Passed.Write(item);
}
catch (Exception ex)
{
//This will write the text in "Failed.txt" file. 'Failed' method I want to access like this
Log.GenerciLog<SpecialLogger>.Failed.Write(item);
}
This is a very simple log class. There is a lot more you could do with this sort of thing. Its all provided by log4net which I'd recommend using rather than trying to write your own logger. But the below is a start of how I'd implement a simple logger. It allows you to log to several different things at once. I appreciate the below doesn't answer exactly what you want but its an indication of how to start and you can adapt it to suit your needs.
public static class Logger
{
private static List<ILogger> _loggers = new List<ILogger>();
public static void Log(string message)
{
foreach (var logger in _loggers)
logger.Write(message);
}
public static void AddLogger(ILogger logger)
{
_loggers.Add(logger);
}
}
public interface ILogger
{
void Write(string message);
}
public class SpecialLogger : ILogger
{
public void Write(string message)
{
//special log code here eg
Console.WriteLine(message);
}
}
then somewhere do this
Logger.AddLogger(new SpecialLogger());
Logger.Log("A log message");

trigger OnExceptionAspect from MethodInterceptionAspect

I want to get to MyExceptionAspect.OnException when an exception is thrown from MyInterceptorAspect.OnInvoke so the following code will return "Much love":
public class MyClass
{
[MyInterceptorAspect]
[MyExceptionAspect]
public string Do()
{
return "LOVE";
}
}
[Serializable]
public sealed class MyInterceptorAspect : MethodInterceptionAspect
{
public override void OnInvoke(MethodInterceptionArgs args)
{
// ...
throw new Exception("Much love");
// ...
// base.OnInvoke(args) is NOT called.
}
}
[Serializable]
public sealed class MyExceptionAspect : OnExceptionAspect
{
public override void OnException(MethodExecutionArgs args)
{
args.ReturnValue = args.Exception.Message;
args.FlowBehavior = FlowBehavior.Return;
}
}
At runtime, when the exception is thrown from the interceptor, it's not caught by OnExceptionAspect.
Figured it out while writing the question :)
In compile-time, PostSharp uses OnExceptionAspect to wrap the Do method with try-catch, and insert a call for MethodInterceptionAspect.OnInvoke on the first line of it - so the order of the aspects matter to the fact if that call will be included in the try block.
So this change solved it nicely:
public class MyClass
{
[MyExceptionAspect(AspectPriority = 1)]
[MyInterceptorAspect(AspectPriority = 2)]
public string Do()
{
return "LOVE";
}
}

Ninject Factory Pattern and Bindings

I am trying to implement the Ninject.Extensions.Factory pattern and my program is telling me my bindings aren't right, but I can't figure out why. I keep getting an "Error activating IHashable. No matching bindings are available, and the type is not self-bindable" exception thrown. The relevant areas of my code are below:
public interface IHashable
{
FileInfo File { get; }
string ComputeHash();
}
public interface IHashableFactory
{
IHashable GetNew(FileInfo file);
}
public class MD5ChecksumProvider : IHashable
{
private FileInfo _file;
public FileInfo File
{
get { return _file; }
}
public MD5ChecksumProvider(FileInfo file)
{
if (file == null)
throw new ArgumentNullException("file");
_file = file;
}
public string ComputeHash()
{
// implementation
}
}
public class AppFileProvider : IAppFileProvider
{
private IHashableFactory _hashFactory;
public IHashableFactory HashProvider
{
get { return _hashFactory; }
}
public AppFileProvider(IHashableFactory hashProviderFactory)
{
_hashFactory = hashProviderFactory;
}
public string GetChecksum(FileInfo fileInfo)
{
var hasher = _hashFactory.GetNew(fileInfo);
return hasher.ComputeHash();
}
}
public class BindingProviders : NinjectModule
{
public override void Load()
{
Bind<IHashable>()
.To<MD5ChecksumProvider>();
}
}
public class BindingFactories : NinjectModule
{
public override void Load()
{
Bind<IHashableFactory>()
.ToFactory();
}
}
// my DI container
public sealed class Container : IDisposable
{
private bool _isDisposed;
private IKernel _kernel;
private BindingFactories _bindingFactories;
private BindingObjects _bindingObjects;
private BindingProviders _bindingProviders;
public Container()
{
_isDisposed = false;
_bindingFactories = new BindingFactories();
_bindingObjects = new BindingObjects();
_bindingProviders = new BindingProviders();
_kernel = new StandardKernel(_bindingObjects, _bindingProviders, _bindingFactories);
}
public T Get<T>()
{
return _kernel.Get<T>();
}
public void Dispose()
{
// nothing worth seeing
}
private void Dispose(bool disposing)
{
// nothing worth seeing
}
}
// the program (composition root)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
using (var container = new Container())
{
var fileProvider = container.Get<IAppFileProvider>();
foreach (var file in files)
{
string hash = fileProvider.GetChecksum(storePath, file); // this line throws "Error activating IHashable. No matching bindings are available, and the type is not self-bindable.""
}
}
}
}
I feel like my bindings are setup correctly but I must be missing something obvious. Any ideas why I'm getting the exception from the above code?
This is caused by a feature of Ninject.Extensions.Factory.
It treats methods which start with Get differently from those which don't.
If you rename IHashableFactory.GetNew to Create or Make everything works fine.
The "Get" feature is described here:
The default instace provider of the extension has the convention that it tries to return an instance using a named binding whenever a method starts with “Get”. E.g. IFoo GetMySpecialFoo() is equal to
resolutionRoot.Get<IFoo>("MySpecialFoo");
Since i think this is not obvious to the user and the exception isn't helpful at all in this regard, i have filed an issue report here

Post sharp using instance member

I am attempting to create an aspect to manage security on a few properties of a class. However, the security aspect for one member relies on the data in another property of the class. I've read some tutorials on the IntroduceAspect, but I'm not sure it's what I need.
public class ClassWithThingsIWantToSecure
{
[SecurityAspectHere(inherits from LocationInterceptionAspect)]
public int ThingIWantToSecure;
public string ThingINeedToKnowAboutInSecurityAspect;
}
Can someone point me in the right direction for making the runtime value of ThingINeedToKnowAboutInSecurityAspect available in the SecurityAspect?
I have done something a bit like this before, I've knocked up a test on a machine with postsharp installed and just tried it out, here is the code...
class Program
{
static void Main(string[] args)
{
Baldrick baldrick = new Baldrick();
baldrick.ThingINeedToKnowAboutInSecurityAspect = "Bob";
Console.WriteLine("There are {0} beans", baldrick.ThingIWantToSecure);
baldrick.ThingINeedToKnowAboutInSecurityAspect = "Kate";
try
{
//This should fail
Console.WriteLine("There are {0} beans", baldrick.ThingIWantToSecure);
}
catch (Exception ex)
{
//Expect the message from my invalid operation exception to be written out (Use your own exception if you prefer)
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
}
[Serializable]
public class SecurityAspect : LocationInterceptionAspect
{
public override void OnGetValue(LocationInterceptionArgs args)
{
ISecurityProvider securityProvider = args.Instance as ISecurityProvider;
if (securityProvider != null && securityProvider.ThingINeedToKnowAboutInSecurityAspect != "Bob")
throw new InvalidOperationException("Access denied (or a better message would be nice!)");
base.OnGetValue(args);
}
}
public interface ISecurityProvider
{
string ThingINeedToKnowAboutInSecurityAspect { get; }
}
public class Baldrick : ISecurityProvider
{
public string ThingINeedToKnowAboutInSecurityAspect { get; set; }
[SecurityAspect]
public int ThingIWantToSecure{get { return 3; }}
}
So, the idea here is to interrogate the args.Instance property for the instace of the object that is being decorated.

mySQL error with plugin loaded into appDomain

I am struggling to get dynamic loading working with my plugin. I'm loading the plugin into an appdomain but I get the following exception when my plugin tries to execute any mySQL code:
MySql.Data.MySqlClient.MySqlException
was unhandled
Message=Access denied
for user ''#'localhost' (using
password: NO)
Here is the code on Plugins.cs:
public class Plugins {
private static List<PluginContainer> PluginList;
public static bool PluginsAreLoaded {
get {
if(PluginList==null) {
return false;
}
else {
return true;
}
}
}
public static void LoadAllPlugins(Form host) {
//add assemblies in OD folder to appDomain
Assembly[] list = AppDomain.CurrentDomain.GetAssemblies();
AppDomain appDomainAnesthesia AppDomain.CreateDomain("appDomainAnesthesia");
for(int i=0;i<ProgramC.Listt.Count;i++) {
string dllPathWithVersion = String.Empty;
if(!ProgramC.Listt[i].Enabled) {
continue;
}
if(ProgramC.Listt[i].PluginDllName=="") {
continue;
}
string dllPath=ODFileUtils.CombinePaths(Application.StartupPath,ProgramC.Listt[i].PluginDllName);
if(dllPath.Contains("[VersionMajMin]")) {
Version vers=new Version(Application.ProductVersion);
dllPathWithVersion=dllPath.Replace("[VersionMajMin]",vers.Major.ToString()+"."+vers.Minor.ToString());
dllPath=dllPath.Replace("[VersionMajMin]","");//now stripped clean
if(File.Exists(dllPathWithVersion)){
File.Copy(dllPathWithVersion,dllPath,true);
}
}
if(!File.Exists(dllPath)) {
continue;
}
//add our plugin to the appDomain
try {
string typeName = Path.GetFileNameWithoutExtension(dllPath) + ".Plugin";
PluginBase plugin = (PluginBase)appDomainAnesthesia.CreateInstanceAndUnwrap(Path.GetFileNameWithoutExtension(dllPathWithVersion), typeName);
appDomainAnesthesia.Load(Path.GetFileNameWithoutExtension(dllPathWithVersion));
plugin.Host=host;
}
catch(Exception ex) {
MessageBox.Show(ex.Message);
continue;//don't add it to plugin list.
}
PluginContainer container=new PluginContainer();
container.Plugin=plugin;
container.ProgramNum=ProgramC.Listt[i].ProgramNum;
PluginList.Add(container);
}
}
Here is PluginBase:
public abstract class PluginBase : MarshalByRefObject {
private Form host;
///<summary>This will be a refrence to the main FormOpenDental so that it can be used by the plugin if needed. It is set once on startup, so it's a good place to put startup code.</summary>
public virtual Form Host {
get {
return host;
}
set {
host=value;
}
}
///<summary>These types of hooks are designed to completely replace the existing functionality of specific methods. They always belong at the top of a method.</summary>
public virtual bool HookMethod(object sender,string methodName,params object[] parameters) {
return false;//by default, no hooks are implemented.
}
///<summary>These types of hooks allow adding extra code in at some point without disturbing the existing code.</summary>
public virtual bool HookAddCode(object sender,string hookName,params object[] parameters) {
return false;
}
public virtual void LaunchToolbarButton(long patNum) {
}
}
PluginContainer:
class PluginContainer {
public PluginBase Plugin;
public long ProgramNum;
and finally, Plugin:
public class Plugin : PluginBase {
private Form host;
public AnestheticData AnesthDataCur;
public AnestheticRecord AnestheticRecordCur;
public Patient PatCur;
public string SourceDirectory;
public string DestDirectory;
public System.ComponentModel.IContainer components;
public long patNum;
public static Procedure procCur;
public static List<Procedure> ProcList;
public static ODtextBox textNotes;
public override Form Host {
get {
return host;
}
set {
host=value;
ConvertAnesthDatabase.Begin();//if this crashes, it will bubble up and result in the plugin not loading. }
}
It bombs at the
plugin.Host=host;
line on Plugins.cs which comes from the ConverAnesthDatabase.Begin() method as there are multiple mySQL statements there.
I have access to the mySQL database, so that is not the issue.
How do I resolve this error?
Try not to "extend" your PluginBase and use an Interface instead:
public interface IPlugin
{
Form Host {get; set; }
bool HookMethod(object sender,string methodName,params object[] parameters);
bool HookAddCode(object sender,string hookName,params object[] parameters);
void LaunchToolbarButton(long patNum);
}
and then
public class Plugin : IPlugin
{
...
}

Categories