Created
May 19, 2012 00:12
-
-
Save jpolvora/2728270 to your computer and use it in GitHub Desktop.
InterceptWithAttributeEntity
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.ComponentModel; | |
using System.Dynamic; | |
using System.Reflection; | |
using System.Linq.Expressions; | |
static void InterceptWithAttributeEntity() | |
{ | |
var myContext = new MyContext(); | |
//will look for an [Aspect] attribute on myContext and apply defined aspects | |
IMyContext proxyContext = ObjectProxyFactory.CreateUsingAttribute<IMyContext>(myContext); | |
var customer = proxyContext.Customers.FirstOrDefault(); | |
if (customer == null) | |
{ | |
System.Console.WriteLine("No customers in Db"); | |
System.Console.ReadKey(); | |
customer = new Customer { Name = "Jone" }; | |
proxyContext.Customers.Add(customer); | |
proxyContext.SaveChanges(); // intercepted | |
return; | |
} | |
//will look for an an [Aspect] attribute on customer type definition and apply defined aspects | |
ICustomer proxyCustomer = ObjectProxyFactory.CreateUsingAttribute<ICustomer>(customer); | |
//view notifications in console | |
proxyCustomer.PropertyChanged += (s, e) => | |
{ | |
System.Console.WriteLine("Property Changed: {0} on {1}", | |
e.PropertyName, s); | |
}; | |
System.Console.WriteLine(proxyCustomer.Id); | |
proxyCustomer.Id = 0; | |
System.Console.WriteLine(proxyCustomer.Id); | |
proxyCustomer.Id = 1; //property changed | |
System.Console.WriteLine(proxyCustomer.Id); | |
proxyCustomer.Id = 2; // changed | |
System.Console.WriteLine(proxyCustomer.Id); | |
proxyCustomer.Id = 2; //not changed | |
System.Console.WriteLine(proxyCustomer.Name); | |
proxyCustomer.Name = null; | |
System.Console.WriteLine(proxyCustomer.Name); | |
proxyCustomer.Name = "Teste"; | |
System.Console.WriteLine(proxyCustomer.Name); | |
} | |
public class DbContextBehavior : IAspectBehavior<IMyContext> | |
{ | |
public DbContextBehavior() | |
{ | |
MethodsToIntercept = Helpers.GetMethodNames<IUnitOfWork>(c => c.SaveChanges()); | |
} | |
#region Implementation of IAspectBehavior<IContext> | |
public string[] MethodsToIntercept { get; private set; } | |
public void PreAspect(AspectContext<IMyContext> ctx) | |
{ | |
Debug.WriteLine("Entering {0}", ctx.CallCtx.MethodName); | |
} | |
public void PostAspect(AspectContext<IMyContext> ctx) | |
{ | |
Debug.WriteLine("Exiting {0}", ctx.CallCtx.MethodName); | |
} | |
#endregion | |
} | |
//This aspect definition assumes that your POCO class implements INotifyPropertyChanged, but doesn't need to inherit | |
//from base classes or to create an invoke method for the event. | |
//All work is done here through reflection. | |
//The reflection ocurrs only in when property changes and it's cached. | |
public abstract class PropertyChangedBehavior<T> : IAspectBehavior<T> | |
where T : class, INotifyPropertyChanged | |
{ | |
//always call this function to refresh the invocation list of the event handler | |
private readonly Func<MulticastDelegate> _refreshSubscribers; | |
protected PropertyChangedBehavior(T visitInstance) | |
{ | |
if (visitInstance == null) | |
throw new ArgumentNullException("visitInstance"); | |
Func<FieldInfo> propertyChanged = () => visitInstance.GetType() | |
.GetField("PropertyChanged", BindingFlags.Instance | BindingFlags.NonPublic); | |
_refreshSubscribers = () => propertyChanged().GetValue(visitInstance) as MulticastDelegate; | |
MethodsToIntercept = Helpers.GetMethodNamesFromPropertyInfo(getters: false, setters: true, propertyInfos: typeof(T).GetProperties()); | |
} | |
static void NotifyToSubscribers(MulticastDelegate multicastDelegate, T sender, string propertyName) | |
{ | |
//multicastDelegate will come null if there are no subscribers to the propertychanged event | |
if (multicastDelegate == null) | |
return; | |
var eventArgs = new PropertyChangedEventArgs(propertyName); | |
var delegates = multicastDelegate.GetInvocationList(); | |
foreach (var @delegate in delegates) | |
{ | |
@delegate.Method.Invoke(@delegate.Target, new object[] { sender, eventArgs }); | |
} | |
} | |
#region Implementation of IAspectBehavior<T> | |
public string[] MethodsToIntercept { get; private set; } | |
public virtual void PreAspect(AspectContext<T> ctx) | |
{ | |
var currMethod = ctx.CallCtx.MethodName.Substring(4); | |
var propertyInfo = ctx.Target.GetType().GetProperty(currMethod); | |
ctx.Parameters = propertyInfo.GetValue(ctx.Target, null); | |
} | |
public virtual void PostAspect(AspectContext<T> ctx) | |
{ | |
if (Equals(ctx.Parameters, ctx.CallCtx.Args[0])) return; | |
var propertyName = ctx.CallCtx.MethodName.Substring(4); | |
NotifyToSubscribers(_refreshSubscribers(), ctx.Target, propertyName); | |
} | |
#endregion | |
} | |
public class CustomerBehavior : PropertyChangedBehavior<ICustomer> | |
{ | |
public CustomerBehavior(ICustomer visitInstance) | |
: base(visitInstance) | |
{ | |
} | |
} | |
public interface ICustomer : INotifyPropertyChanged | |
{ | |
int Id { get; set; } | |
string Name { get; set; } | |
} | |
[Aspect(typeof(CustomerBehavior))] | |
public class Customer : DynamicObject, ICustomer | |
{ | |
public int Id { get; set; } | |
public string Name { get; set; } | |
#region Implementation of INotifyPropertyChanged | |
//doesn't need to create an invocation handler. | |
//the aspect will invoke the event through reflection | |
public event PropertyChangedEventHandler PropertyChanged; | |
#endregion | |
} | |
public interface IUnitOfWork : IDisposable | |
{ | |
int SaveChanges(); | |
} | |
public interface IMyContext: IUnitOfWork | |
{ | |
IDbSet<Customer> Customers { get; set; } | |
} | |
[Aspect(typeof(DbContextBehavior))] | |
public class MyContext : DbContext, IMyContext | |
{ | |
public MyContext() | |
: base("MyContext") | |
{ | |
Configuration.AutoDetectChangesEnabled = false; | |
Configuration.LazyLoadingEnabled = false; | |
Configuration.ProxyCreationEnabled = false; | |
Configuration.ValidateOnSaveEnabled = false; | |
} | |
public IDbSet<Customer> Customers { get; set; } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment