Skip to content

Instantly share code, notes, and snippets.

@sakapon
Last active July 20, 2017 06:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sakapon/5d61eedc9580f6dba2bbefcb4373839e to your computer and use it in GitHub Desktop.
Save sakapon/5d61eedc9580f6dba2bbefcb4373839e to your computer and use it in GitHub Desktop.
ProxySample/CrossCuttingConsole/CrossCuttingProxy
using System;
using System.Runtime.Remoting.Messaging;
using System.Transactions;
namespace CrossCuttingConsole
{
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public abstract class AspectAttribute : Attribute
{
public abstract IMethodReturnMessage Invoke(Func<IMethodReturnMessage> baseInvoke, MarshalByRefObject target, IMethodCallMessage methodCall);
}
public class TraceLogAttribute : AspectAttribute
{
public override IMethodReturnMessage Invoke(Func<IMethodReturnMessage> baseInvoke, MarshalByRefObject target, IMethodCallMessage methodCall)
{
var methodInfo = $"{methodCall.MethodBase.DeclaringType.Name}.{methodCall.MethodName}({string.Join(", ", methodCall.InArgs)})";
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: Begin: {methodInfo}");
var result = baseInvoke();
if (result.Exception == null)
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: Success: {methodInfo}");
else
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: Error: {methodInfo}");
Console.WriteLine(result.Exception);
}
return result;
}
}
public class TransactionScopeAttribute : AspectAttribute
{
public TransactionOptions TransactionOptions { get; }
public TransactionScopeOption TransactionScopeOption { get; }
public TransactionScopeAttribute(
IsolationLevel isolationLevel = IsolationLevel.ReadCommitted,
double timeoutInSeconds = 30,
TransactionScopeOption scopeOption = TransactionScopeOption.Required)
{
TransactionOptions = new TransactionOptions
{
IsolationLevel = isolationLevel,
Timeout = TimeSpan.FromSeconds(timeoutInSeconds),
};
TransactionScopeOption = scopeOption;
}
public override IMethodReturnMessage Invoke(Func<IMethodReturnMessage> baseInvoke, MarshalByRefObject target, IMethodCallMessage methodCall)
{
using (var scope = new TransactionScope(TransactionScopeOption, TransactionOptions))
{
var result = baseInvoke();
scope.Complete();
return result;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
namespace CrossCuttingConsole
{
public class CrossCuttingProxy : RealProxy
{
public static T CreateProxy<T>() where T : MarshalByRefObject, new()
{
return (T)new CrossCuttingProxy(new T()).GetTransparentProxy();
}
public MarshalByRefObject Target { get; private set; }
// For non-ContextBoundObject.
internal CrossCuttingProxy(MarshalByRefObject target) : base(target.GetType())
{
Target = target;
}
// For ContextBoundObject.
internal CrossCuttingProxy(Type classToProxy) : base(classToProxy)
{
}
public override IMessage Invoke(IMessage msg)
{
if (msg is IConstructionCallMessage constructionCall)
return InvokeConstructor(constructionCall);
if (msg is IMethodCallMessage methodCall)
return InvokeMethod(methodCall);
throw new InvalidOperationException();
}
IConstructionReturnMessage InvokeConstructor(IConstructionCallMessage constructionCall)
{
var constructionReturn = InitializeServerObject(constructionCall);
Target = GetUnwrappedServer();
SetStubData(this, Target);
return constructionReturn;
}
IMethodReturnMessage InvokeMethod(IMethodCallMessage methodCall)
{
Func<IMethodReturnMessage> baseInvoke = () => RemotingServices.ExecuteMessage(Target, methodCall);
var newInvoke = methodCall.MethodBase.GetCustomAttributes<AspectAttribute>(true)
.Reverse()
.Aggregate(baseInvoke, (f, a) => () => a.Invoke(f, Target, methodCall));
return newInvoke();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment