I got an issue with Unity interception when throw an Exception in my method. Please reference from my sample application as below:
class Program
{
static void Main(string[] args)
{
var container = new UnityContainer();
container.RegisterType<IInterface1, Implementation1>();
container.RegisterType<ICallHandler, AuditLoggingCallHandler>();
container.RegisterInstance(typeof(IUnityContainer), container);
container.AddNewExtension<Interception>();
container.Configure<Interception>()
.SetInterceptorFor<IInterface1>(new InterfaceInterceptor());
var service = container.Resolve<IInterface1>();
service.Method1("xyz");
Console.ReadLine();
}
}
The AuditLogging behavior implement following code below:
public class AuditLoggingAttribute : HandlerAttribute
{
public int RequestId { get; set; }
public override ICallHandler CreateHandler(IUnityContainer container)
{
return container.Resolve<ICallHandler>();
}
}
public class AuditLoggingCallHandler : ICallHandler
{
public IMethodReturn Invoke(IMethodInvocation input,
GetNextHandlerDelegate getNext)
{
LogEntry logEntry = new LogEntry();
logEntry.Message = "[BEGIN] " + input.MethodBase.Name + "()";
Logger.Write(logEntry);
IMethodReturn result = getNext()(input, getNext);
if (result.Exception != null)
{
logEntry = new LogEntry();
logEntry.Message = " [EXCEPTION] " + input.MethodBase.Name
+ "." + input.MethodBase.Name
+ "() ";
logEntry.ExtendedProperties
.Add("Exception Message", result.Exception.Message);
logEntry.ExtendedProperties
.Add("Exception StackTrace", result.Exception.StackTrace);
Logger.Write(logEntry);
}
logEntry = new LogEntry();
logEntry.Message = " [FINISH] " + input.MethodBase.Name + "()";
if (result.ReturnValue != null)
{
logEntry
.ExtendedProperties
.Add("Return value", result.ReturnValue.ToString());
}
Logger.Write(logEntry);
return result;
}
public int Order { get; set; }
}
And the Interface1.cs and Implementation1.cs are below:
public interface IInterface1
{
[AuditLogging]
IEnumerable<string> Method1(string name);
}
public class Implementation1 : IInterface1
{
public IEnumerable<string> Method1(string name)
{
if (name.Equals("xyz"))
{
throw new Exception("xyz are not allow");
}
yield return "ABC";
}
}
The logging file point out the Exception does not write down.There is some thing I am missing or the Unity interception cannot working as expected.
Here the log file below, it should have [EXCEPTION] but there is nothing like that:
----------------------------------------
Timestamp: 5/30/2013 9:29:07 AM
Message: [BEGIN] Method1()
Category: General
Priority: -1
EventId: 0
Severity: Information
Title:
Machine: XXXY
App Domain: ConsoleApplication10.vshost.exe
ProcessId: 8228
Thread Name:
Win32 ThreadId:1280
Extended Properties: Parameter values - [(String) name = 'xyz']
----------------------------------------
BTW, I using the Enterprise Library version 5 and Unity version 2.0.
The issue at here is yield return "ABC". When we apply yield return the method will be executed under lazy mode so the Exception still not raised. The exception only raise after the MethodReturn return by interceptor. You change the code as below will see [EXCEPTION] will be logged into the file:
public IEnumerable<string> Method1(string name)
{
if (name.Equals("xyz"))
{
throw new Exception("xyz are not allow");
}
var list = new List<string>();
list.Add("ABC");
return list;
//yield return "ABC";
}
Hope this help.
Related
I have a windows TCP service, which has many devices connecting to it, and a client can have one or more devices.
Requirement:
Separate Folder per client with separate log file for each device.
so something like this:
/MyService/25-04-2016/
Client 1/
Device1.txt
Device2.txt
Device3.txt
Client 2/
Device1.txt
Device2.txt
Device3.txt
Now I have not used a 3rd Party library like log4net or NLog, I have a class which handles this.
public class xPTLogger : IDisposable
{
private static object fileLocker = new object();
private readonly string _logFileName;
private readonly string _logFilesLocation;
private readonly int _clientId;
public xPTLogger() : this("General") { }
public xPTLogger(string logFileName)
{
_clientId = -1;
_logFileName = logFileName;
_logFilesLocation = SharedConstants.LogFilesLocation; // D:/LogFiles/
}
public xPTLogger(string logFileName, int companyId)
{
_clientId = companyId;
_logFileName = logFileName;
_logFilesLocation = SharedConstants.LogFilesLocation;
}
public void LogMessage(MessageType messageType, string message)
{
LogMessage(messageType, message, _logFileName);
}
public void LogExceptionMessage(string message, Exception innerException, string stackTrace)
{
var exceptionMessage = innerException != null
? string.Format("Exception: [{0}], Inner: [{1}], Stack Trace: [{2}]", message, innerException.Message, stackTrace)
: string.Format("Exception: [{0}], Stack Trace: [{1}]", message, stackTrace);
LogMessage(MessageType.Error, exceptionMessage, "Exceptions");
}
public void LogMessage(MessageType messageType, string message, string logFileName)
{
var dateTime = DateTime.UtcNow.ToString("dd-MMM-yyyy");
var logFilesLocation = string.Format("{0}{1}\\", _logFilesLocation, dateTime);
if (_clientId > -1) { logFilesLocation = string.Format("{0}{1}\\{2}\\", _logFilesLocation, dateTime, _clientId); }
var fullLogFile = string.IsNullOrEmpty(logFileName) ? "GeneralLog.txt" : string.Format("{0}.txt", logFileName);
var msg = string.Format("{0} | {1} | {2}\r\n", DateTime.UtcNow.ToString("dd-MMM-yyyy HH:mm:ss"), messageType, message);
fullLogFile = GenerateLogFilePath(logFilesLocation, fullLogFile);
LogToFile(fullLogFile, msg);
}
private string GenerateLogFilePath(string objectLogDirectory, string objectLogFileName)
{
if (string.IsNullOrEmpty(objectLogDirectory))
throw new ArgumentNullException(string.Format("{0} location cannot be null or empty", "objectLogDirectory"));
if (string.IsNullOrEmpty(objectLogFileName))
throw new ArgumentNullException(string.Format("{0} cannot be null or empty", "objectLogFileName"));
if (!Directory.Exists(objectLogDirectory))
Directory.CreateDirectory(objectLogDirectory);
string logFilePath = string.Format("{0}\\{1}", objectLogDirectory, objectLogFileName);
return logFilePath;
}
private void LogToFile(string logFilePath, string message)
{
if (!File.Exists(logFilePath))
{
File.WriteAllText(logFilePath, message);
}
else
{
lock (fileLocker)
{
File.AppendAllText(logFilePath, message);
}
}
}
public void Dispose()
{
fileLocker = new object();
}
}
And then I can use it like this:
var _logger = new xPTLogger("DeviceId", 12);
_logger.LogMessage(MessageType.Info, string.Format("Information Message = [{0}]", 1));
The problem with the above class is that, because the service is multi-threaded, some threads try to access the same log file at the same time causing an Exception to Throw.
25-Apr-2016 13:07:00 | Error | Exception: The process cannot access the file 'D:\LogFiles\25-Apr-2016\0\LogFile.txt' because it is being used by another process.
Which sometimes causes my service to crash.
How do I make my Logger class to work in multi-threaded services?
EDIT
Changes to the Logger Class
public class xPTLogger : IDisposable
{
private object fileLocker = new object();
private readonly string _logFileName;
private readonly string _logFilesLocation;
private readonly int _companyId;
public xPTLogger() : this("General") { }
public xPTLogger(string logFileName)
{
_companyId = -1;
_logFileName = logFileName;
_logFilesLocation = SharedConstants.LogFilesLocation; // "D:\\MyLogs";
}
public xPTLogger(string logFileName, int companyId)
{
_companyId = companyId;
_logFileName = logFileName;
_logFilesLocation = SharedConstants.LogFilesLocation;
}
public void LogMessage(MessageType messageType, string message)
{
LogMessage(messageType, message, _logFileName);
}
public void LogExceptionMessage(string message, Exception innerException, string stackTrace)
{
var exceptionMessage = innerException != null
? string.Format("Exception: [{0}], Inner: [{1}], Stack Trace: [{2}]", message, innerException.Message, stackTrace)
: string.Format("Exception: [{0}], Stack Trace: [{1}]", message, stackTrace);
LogMessage(MessageType.Error, exceptionMessage, "Exceptions");
}
public void LogMessage(MessageType messageType, string message, string logFileName)
{
if (messageType == MessageType.Debug)
{
if (!SharedConstants.EnableDebugLog)
return;
}
var dateTime = DateTime.UtcNow.ToString("dd-MMM-yyyy");
var logFilesLocation = string.Format("{0}{1}\\", _logFilesLocation, dateTime);
if (_companyId > -1) { logFilesLocation = string.Format("{0}{1}\\{2}\\", _logFilesLocation, dateTime, _companyId); }
var fullLogFile = string.IsNullOrEmpty(logFileName) ? "GeneralLog.txt" : string.Format("{0}.txt", logFileName);
var msg = string.Format("{0} | {1} | {2}\r\n", DateTime.UtcNow.ToString("dd-MMM-yyyy HH:mm:ss"), messageType, message);
fullLogFile = GenerateLogFilePath(logFilesLocation, fullLogFile);
LogToFile(fullLogFile, msg);
}
private string GenerateLogFilePath(string objectLogDirectory, string objectLogFileName)
{
if (string.IsNullOrEmpty(objectLogDirectory))
throw new ArgumentNullException(string.Format("{0} location cannot be null or empty", "objectLogDirectory"));
if (string.IsNullOrEmpty(objectLogFileName))
throw new ArgumentNullException(string.Format("{0} cannot be null or empty", "objectLogFileName"));
if (!Directory.Exists(objectLogDirectory))
Directory.CreateDirectory(objectLogDirectory);
string logFilePath = string.Format("{0}\\{1}", objectLogDirectory, objectLogFileName);
return logFilePath;
}
private void LogToFile(string logFilePath, string message)
{
lock (fileLocker)
{
try
{
if (!File.Exists(logFilePath))
{
File.WriteAllText(logFilePath, message);
}
else
{
File.AppendAllText(logFilePath, message);
}
}
catch (Exception ex)
{
var exceptionMessage = ex.InnerException != null
? string.Format("Exception: [{0}], Inner: [{1}], Stack Trace: [{2}]", ex.Message, ex.InnerException.Message, ex.StackTrace)
: string.Format("Exception: [{0}], Stack Trace: [{1}]", ex.Message, ex.StackTrace);
var logFilesLocation = string.Format("{0}{1}\\", _logFilesLocation, DateTime.UtcNow.ToString("dd-MMM-yyyy"));
var logFile = GenerateLogFilePath(logFilesLocation, "FileAccessExceptions.txt");
try
{
if (!File.Exists(logFile))
{
File.WriteAllText(logFile, exceptionMessage);
}
else
{
File.AppendAllText(logFile, exceptionMessage);
}
}
catch (Exception) { }
}
}
}
public void Dispose()
{
//fileLocker = new object();
//_logFileName = null;
//_logFilesLocation = null;
//_companyId = null;
}
}
If you don't want to use existing solutions, the reasonable approach to handle multithreaded writes in your logger is to use queue. Here is a sketch:
public class LogQueue : IDisposable {
private static readonly Lazy<LogQueue> _isntance = new Lazy<LogQueue>(CreateInstance, true);
private Thread _thread;
private readonly BlockingCollection<LogItem> _queue = new BlockingCollection<LogItem>(new ConcurrentQueue<LogItem>());
private static LogQueue CreateInstance() {
var queue = new LogQueue();
queue.Start();
return queue;
}
public static LogQueue Instance => _isntance.Value;
public void QueueItem(LogItem item) {
_queue.Add(item);
}
public void Dispose() {
_queue.CompleteAdding();
// wait here until all pending messages are written
_thread.Join();
}
private void Start() {
_thread = new Thread(ConsumeQueue) {
IsBackground = true
};
_thread.Start();
}
private void ConsumeQueue() {
foreach (var item in _queue.GetConsumingEnumerable()) {
try {
// append to your item.TargetFile here
}
catch (Exception ex) {
// do something or ignore
}
}
}
}
public class LogItem {
public string TargetFile { get; set; }
public string Message { get; set; }
public MessageType MessageType { get; set; }
}
Then in your logger class:
private void LogToFile(string logFilePath, string message) {
LogQueue.Instance.QueueItem(new LogItem() {
TargetFile = logFilePath,
Message = message
});
}
Here we delegate actual logging to separate class which writes log messages one by one, so cannot have any multithreading issues. Additional benefit of such approach is that logging happens asynchronously and as such does not slow down the real work.
Drawback is you can lose some messages in case of process crash (don't think that is really a problem but still mention it) and you consume separate thread to log asynchronously. When there is one thread it's not a problem but if you create one thread per device, that might be (though there is no need to - just use single queue, unless you really write A LOT of messages per second).
While it probably isn't the most elegant solution, you could have retry logic built in. For example:
int retries = 0;
while(retries <= 3){
try{
var _logger = new xPTLogger("DeviceId", 12);
_logger.LogMessage(MessageType.Info, string.Format("Information Message = [{0}]", 1));
break;
}
catch (Exception ex){
//Console.WriteLine(ex.Message);
retries++;
}
}
Also, I wrote that code just now without actually testing it so if there's some stupid error in it forgive me. But quite simply it'll try to write to the log as many times as you set in the "while" line. You can even add a sleep statement in the catch block if you think it'd be worth it.
I have no experience with Log4Net or NLog so no comment there. Maybe there's a sweet solution via one of those packages. Good luck!
The user of my Visual Studio application may click a button to restore the application to the factory defaults. At the factory we configure the application and then click another button to set that configuration as the factory defaults to the present configuration settings.
However, if we save the configuration settings (XML format) to settings.settings, they are stored in our own user folder (not in the Visual Studio project folder), and the user doesn't receive them.
(settings.settings uses the default values stored at design time.)
We need to store the factory defaults in a file that is included in the executable, or distributed with it. We can write the factory defaults in a factorydefaultconfig.xml file included with the distribution, but I thought you may know of a better way of doing that.
Right now I am studying Application configuration files to see if that's what I should be using.
Yep App Settings or rolling your own is the way we've handled this in the past. Add a reference to System.Configuration to your project, and then use the following:
ConfigurationManager.AppSettings.Set("lang", "English"); //Set
string getLang = ConfigurationManager.AppSettings["lang"]; //Get
For the App.config:
<configuration>
<appSettings>
<add key="lang" value="English"/>
</appSettings>
</configuration>
Just in case you want to try this out. Here is a class I wrote called ConfigHub for doing just what you are talking about. It makes use of locks as well, to ensure you don't end up with file in use errors:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
public static class ConfigHub
{
#region State
private static string WorkingDirectoryVar = null;
private static string ConfigFileNameVar = null;
private static bool AutoRefreshVar = true;
private static bool VerboseVar = true;
private static bool SetupExecutedVar = false;
private static XmlDocument ConfigDocVar = new XmlDocument();
private static Dictionary<string, string> ConfigLookupPair = new Dictionary<string, string>();
private static Object ConfigHubLock = new Object();
private const string CommentNameVar = "#comment";
#endregion
#region Property
public static bool Verbose
{
get { return VerboseVar; }
set { VerboseVar = value; }
}
public static bool AutoRefresh
{
get { return AutoRefreshVar; }
set { AutoRefreshVar = value; }
}
public static bool SetupExecuted
{
get { return SetupExecutedVar; }
}
public static string ConfigFilePath
{
get { return WorkingDirectoryVar + #"\" + ConfigFileNameVar; }
}
public static string ConfigFileName
{
get { return ConfigFileNameVar; }
}
public static string WorkingDirectory
{
get { return WorkingDirectoryVar; }
}
#endregion
#region Setup
public static void Setup()
{
lock (ConfigHubLock)
{
//Initialize config with default
WorkingDirectoryVar = Environment.CurrentDirectory;
ConfigFileNameVar = "SCW.Config.xml";
SetupExecutedVar = true;
RefreshConfiguration();
}
}
public static void Setup(string configFileName)
{
lock (ConfigHubLock)
{
//Initialize config with specified file
WorkingDirectoryVar = Environment.CurrentDirectory;
ConfigFileNameVar = configFileName.Trim().ToLower().Replace(".xml", "") + ".xml";
SetupExecutedVar = true;
RefreshConfiguration();
}
}
#endregion
#region Merchant
public static void SetValue(string key, string value)
{
//Fail if setup hasn't been called
if (!SetupExecutedVar) throw ConfigHubException.BuildException(ConfigHubExceptionType.NotSetup, "Setup must be called before using the ConfigHub", null);
try
{
lock (ConfigHubLock)
{
//Set the value
bool foundNode = false;
foreach (XmlNode configNode in ConfigDocVar.ChildNodes[0].ChildNodes)
{
if (configNode.Name.Trim().ToLower() == key.Trim().ToLower())
{
configNode.InnerXml = value.Trim();
foundNode = true;
}
}
if (!foundNode)
{
XmlNode newNode = ConfigDocVar.CreateNode("element", key.Trim(), "");
newNode.InnerXml = value.Trim();
ConfigDocVar.ChildNodes[0].AppendChild(newNode);
}
//Save the config file
ConfigDocVar.Save(WorkingDirectoryVar + #"\" + ConfigFileNameVar);
RefreshConfiguration();
}
}
catch (Exception err)
{
throw ConfigHubException.BuildException(ConfigHubExceptionType.SetValue, "Set value failed", err);
}
}
public static string GetValue(string key)
{
//Fail if setup hasn't been called
if (!SetupExecutedVar) throw ConfigHubException.BuildException(ConfigHubExceptionType.NotSetup, "Setup must be called before using the ConfigHub", null);
if (AutoRefreshVar) RefreshConfiguration();
try
{
lock (ConfigHubLock)
{
//Get and return the value
if (AutoRefreshVar) RefreshConfiguration();
if (ConfigLookupPair.ContainsKey(key.Trim().ToLower()))
{
return ConfigLookupPair[key.Trim().ToLower()];
}
else
{
throw ConfigHubException.BuildException(ConfigHubExceptionType.NoKeyFound, "The key " + key + " was not found", null);
}
}
}
catch (Exception err)
{
throw ConfigHubException.BuildException(ConfigHubExceptionType.GetValue, "Get value failed", err);
}
}
public static void RefreshConfiguration()
{
//Fail if setup hasn't been called
if (!SetupExecutedVar) throw ConfigHubException.BuildException(ConfigHubExceptionType.NotSetup, "Setup must be called before using the ConfigHub", null);
try
{
//Load configuration from file
ConfigDocVar.Load(WorkingDirectoryVar + #"\" + ConfigFileNameVar);
List<string> duplicateCheck = new List<string>();
foreach (XmlNode configNode in ConfigDocVar.ChildNodes[0].ChildNodes)
{
if (configNode.Name.Trim().ToLower() == CommentNameVar)
{
//Ignore the Comment
}
else
{
if (duplicateCheck.Contains(configNode.Name.Trim().ToLower()))
{
//Duplicate key failure
throw ConfigHubException.BuildException(ConfigHubExceptionType.DuplicateKey, "The key " + configNode.Name.Trim() + " appears multiple times", null);
}
else
{
//Add configuration key value pair
duplicateCheck.Add(configNode.Name.Trim().ToLower());
if (!ConfigLookupPair.ContainsKey(configNode.Name.Trim().ToLower()))
{
ConfigLookupPair.Add(configNode.Name.Trim().ToLower(), configNode.InnerXml.Trim());
}
else
{
ConfigLookupPair[configNode.Name.Trim().ToLower()] = configNode.InnerXml.Trim();
}
}
}
}
}
catch (Exception err)
{
//Look form root missing and multiple roots
if (err.ToString().ToLower().Contains("root element is missing"))
{
throw ConfigHubException.BuildException(ConfigHubExceptionType.NoRootFound, "No configuration root found", err);
}
else if (err.ToString().ToLower().Contains("multiple root elements"))
{
throw ConfigHubException.BuildException(ConfigHubExceptionType.MultipleRoots, "Multiple configuration roots found", err);
}
else
{
throw ConfigHubException.BuildException(ConfigHubExceptionType.Refresh, "Refresh failed", err);
}
}
}
#endregion
}
#region Exception
public enum ConfigHubExceptionType { NotSetup, Setup, Refresh, DuplicateKey, NoKeyFound, SetValue, GetValue, NoRootFound, MultipleRoots }
public class ConfigHubException : Exception
{
public ConfigHubException(ConfigHubExceptionType errType, string message) : base("#" + errType.ToString() + "-" + message + (ConfigHub.ConfigFilePath != #"\" ? " (" + ConfigHub.ConfigFilePath + ")" : "")) { }
public ConfigHubException(ConfigHubExceptionType errType, string message, Exception innerException) : base("#" + errType.ToString() + "-" + message + (ConfigHub.ConfigFilePath != #"\" ? " (" + ConfigHub.ConfigFilePath + ")" : ""), innerException) { }
public static ConfigHubException BuildException(ConfigHubExceptionType exceptionType, string message, Exception innerException)
{
if (!ConfigHub.Verbose || innerException == null) return new ConfigHubException(exceptionType, message);
else return new ConfigHubException(exceptionType, message, innerException);
}
}
#endregion
Note. You need to build the file in your project first and remove the XML header. Like the following (Ex: MyConfigFile.xml) - NO xml tag at the top like (). Finally, make sure you set your xml config file to copy always:
<Config>
<ValueName>Value</ValueName>
</Config>
I'm trying to use the code from this page, http://docs.castleproject.org/Windsor.Introduction-to-AOP-With-Castle.ashx and register an interceptor in a fluent manner.
But I get this error thrown. I've tried Castle Windsor versions from 2.5 to 3.3. So it must be something very basic in how interceptors are set up
Classes
public interface ISomething
{
Int32 Augment(Int32 input);
void DoSomething(String input);
Int32 Property { get; set; }
}
class Something : ISomething
{
public int Augment(int input) {
return input + 1;
}
public void DoSomething(string input) {
Console.WriteLine("I'm doing something: " + input);
}
public int Property { get; set; }
}
public class DumpInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation) {
Console.WriteLine("DumpInterceptorCalled on method " +
invocation.Method.Name);
invocation.Proceed();
if (invocation.Method.ReturnType == typeof(Int32)) {
invocation.ReturnValue = (Int32)invocation.ReturnValue + 1;
}
Console.WriteLine("DumpInterceptor returnvalue is " +
(invocation.ReturnValue ?? "NULL"));
}
}
Setup
Console.WriteLine("Run 2 - configuration fluent");
using (WindsorContainer container = new WindsorContainer())
{
container.Register(
Component.For<IInterceptor>()
.ImplementedBy<DumpInterceptor>()
.Named("myinterceptor"));
container.Register(
Component.For<ISomething>()
.ImplementedBy<Something>()
.Interceptors(InterceptorReference.ForKey("myinterceptor")).Anywhere);
ISomething something = container.Resolve<ISomething>(); //Offending row
something.DoSomething("");
Console.WriteLine("Augment 10 returns " + something.Augment(10));
}
Error
Type 'Castle.Proxies.ISomethingProxy' from
assembly'DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral,
PublicKeyToken=null' is attempting to implement an inaccessible
interface.
The answer
So I found why this was happening. Appearantly if you create inner classes and interfaces you can register and resolve them but attaching interceptors to them won't work
Example - where the error will be triggered
class Program
{
public static void Main(String [] args)
{
var container = new WindsorContainer();
container.Register(Component.For<TestInterceptor>().Named("test"));
container.Register(Component.For<InnerInterface>().ImplementedBy<InnerClass>().Interceptors(InterceptorReference.ForKey("test")).Anywhere);
// this row below will throw the exception
var innerClassInstance = container.Resolve<InnerInterface>();
}
class InnerClass : InnerInterface { }
interface InnerInterface { }
class TestInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
throw new NotImplementedException();
}
}
}
Conclusion
So to conclude my intention was not to create inner classes in the first place but rather put together a demo to showcase Castle Windsor. But maybe this can help someone if they run into the same error as me..
I have this code.
class Program
{
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.AddNewExtension<Interception>();
container.RegisterType<ITestInterception, TestInterception>(new TransientLifetimeManager(),
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<PolicyInjectionBehavior>());
container.Configure<Interception>()
.AddPolicy("MyPolicy")
.AddMatchingRule(new MemberNameMatchingRule("Test"))
.AddCallHandler<FaultHandler>();
try
{
var tester = container.Resolve<ITestInterception>();
tester.Test();
}
catch (Exception e)
{
Console.WriteLine(e.GetType() + "\n\n");
}
Console.ReadKey();
}
}
class AlwaysMatchingRule : IMatchingRule
{
public bool Matches(MethodBase member)
{
return true;
}
}
interface ITestInterception
{
void Test();
}
class TestInterception : ITestInterception
{
public void Test()
{
throw new ArgumentNullException("Null");
}
}
class FaultHandler : ICallHandler
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
Console.WriteLine("Invoke called");
IMethodReturn result = getNext()(input, getNext);
Exception e = result.Exception;
if (e == null)
return result;
return input.CreateExceptionMethodReturn(new InvalidOperationException("In interceptor", e));
}
public int Order { get; set; }
}
When it runs, I has ResolutionFailedException.
Resolution of the dependency failed, type =
"TestUnity.ITestInterception", name = "(none)". Exception occurred
while: while resolving. Exception is: TypeLoadException - Type
'DynamicModule.ns.Wrapped_ITestInterception_0e954c5db37c4c4ebf99acaee12e93f7'
from assembly 'Unity_ILEmit_InterfaceProxies, Version=0.0.0.0,
Can you explain me how to solve this problem?
The InnerException message says it all:
Type 'DynamicModule.ns.Wrapped_ITestInterception_c8a0c8bf8a3d48a5b7f85924fab5711f' from assembly 'Unity_ILEmit_InterfaceProxies, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is attempting to implement an inaccessible interface.
You need to make your interface public:
public interface ITestInterception
{
void Test();
}
An alternative to #Roelf's answer is to allow the calling assembly access to internal interfaces/objects:
In the project that has your Unity configuration, under Properties, add:
[assembly: InternalsVisibleTo("Unity_ILEmit_InterfaceProxies")]
I have 2 attributes:
SecuredOperationAttribute
ExceptionPolicyAttribute
If user doesn't has an access to the action on controller then I throw an custom NonAuthorizedException but I can't catch it on ExceptionPolicyAttribute
My code:
[LogMethod]
[ExceptionPolicy]
public ActionResult Edit(int id)
{
// some works on here
}
[Serializable]
public class ExceptionPolicyAttribute : OnExceptionAspect
{
private ILog logger;
private string methodName;
public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
{
this.methodName = method.DeclaringType.FullName + "." + method.Name;
}
public override void OnException(MethodExecutionArgs args)
{
Guid guid = Guid.NewGuid();
var stringBuilder = new StringBuilder(1024);
// Write the exit message.
stringBuilder.Append(this.methodName);
stringBuilder.Append('(');
// Write the current instance object, unless the method
// is static.
object instance = args.Instance;
if (instance != null)
{
stringBuilder.Append("this=");
stringBuilder.Append(instance);
if (args.Arguments.Count > 0)
stringBuilder.Append("; ");
}
// Write the list of all arguments.
for (int i = 0; i < args.Arguments.Count; i++)
{
if (i > 0)
stringBuilder.Append(", ");
stringBuilder.Append(args.Arguments.GetArgument(i) ?? "null");
}
// Write the exception message.
stringBuilder.AppendFormat("): Exception ");
stringBuilder.Append(args.Exception.GetType().Name);
stringBuilder.Append(": ");
stringBuilder.Append(args.Exception.Message);
logger.Error(stringBuilder.ToString(), args.Exception);
args.FlowBehavior = FlowBehavior.Continue;
}
public override Type GetExceptionType(System.Reflection.MethodBase targetMethod)
{
return typeof(NonAuthorizedException);
}
}
And the secure attribute is:
[Serializable]
public class SecuredOperationAttribute: OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
IUserManager userManager = new UserManager();
int userId = userManager.GetUserIdFromCookie;
AdminUser adminUser = GenericSessionHelper<AdminUser>.Get(userId.ToString(), State.Session);
if(!User.CanAccess)
{
args.ReturnValue = null;
throw new NonAuthorizedException(string.Format("{0} userId li kullanıcının {1} işlemini yapmak için yetkisi yoktur",userId,args.Method.Name));
}
return;
}
}
What could be a problem? Am I using postsharp in a wrong way?
I found the solution:
I was using attributes as like :
[SecuredOperation]
[ExceptionPolicy]
public ActionResult Edit(int id)
but ExceptionPolicy couldn't catch exception. so I moved the ExceptionPolicy to top of the Controller Class:
[ExceptionPolicy]
public class UserController : BaseAuthorizedUserController
now it works.