diff --git a/2014.02.February/AOP/Demo/.nuget/NuGet.Config b/2014.02.February/AOP/Demo/.nuget/NuGet.Config new file mode 100644 index 0000000..67f8ea0 --- /dev/null +++ b/2014.02.February/AOP/Demo/.nuget/NuGet.Config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/2014.02.February/AOP/Demo/.nuget/NuGet.exe b/2014.02.February/AOP/Demo/.nuget/NuGet.exe new file mode 100644 index 0000000..9cba6ed Binary files /dev/null and b/2014.02.February/AOP/Demo/.nuget/NuGet.exe differ diff --git a/2014.02.February/AOP/Demo/.nuget/NuGet.targets b/2014.02.February/AOP/Demo/.nuget/NuGet.targets new file mode 100644 index 0000000..2c3545b --- /dev/null +++ b/2014.02.February/AOP/Demo/.nuget/NuGet.targets @@ -0,0 +1,151 @@ + + + + $(MSBuildProjectDirectory)\..\ + + + false + + + false + + + true + + + false + + + + + + + + + + + $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) + + + + + $(SolutionDir).nuget + + + + packages.$(MSBuildProjectName.Replace(' ', '_')).config + + + + + + $(PackagesProjectConfig) + + + + + packages.config + + + + + + + $(NuGetToolsPath)\NuGet.exe + @(PackageSource) + + "$(NuGetExePath)" + mono --runtime=v4.0.30319 $(NuGetExePath) + + $(TargetDir.Trim('\\')) + + -RequireConsent + -NonInteractive + + "$(SolutionDir) " + "$(SolutionDir)" + + + $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) + $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols + + + + RestorePackages; + $(BuildDependsOn); + + + + + $(BuildDependsOn); + BuildPackage; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2014.02.February/AOP/Demo/Aop.sln b/2014.02.February/AOP/Demo/Aop.sln new file mode 100644 index 0000000..efa1248 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop.sln @@ -0,0 +1,27 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aop", "Aop\Aop.csproj", "{79BC310C-CD80-4B6D-B965-38A6207186F7}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6AAFDAC4-6347-4EF9-AAAD-1A791A7BD33C}" + ProjectSection(SolutionItems) = preProject + .nuget\NuGet.Config = .nuget\NuGet.Config + .nuget\NuGet.exe = .nuget\NuGet.exe + .nuget\NuGet.targets = .nuget\NuGet.targets + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {79BC310C-CD80-4B6D-B965-38A6207186F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79BC310C-CD80-4B6D-B965-38A6207186F7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79BC310C-CD80-4B6D-B965-38A6207186F7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79BC310C-CD80-4B6D-B965-38A6207186F7}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/2014.02.February/AOP/Demo/Aop/Advantage/Exceptions.cs b/2014.02.February/AOP/Demo/Aop/Advantage/Exceptions.cs new file mode 100644 index 0000000..4b8a2dd --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Advantage/Exceptions.cs @@ -0,0 +1,19 @@ +using System; + +namespace Aop.Advantage +{ + public static class Exceptions + { + public static bool Handle(Exception ex) + { + // exception handling + if (ex.GetType() == typeof(ArithmeticException)) + return false; + if (ex.GetType() == typeof(TimeoutException)) + return true; + + // etc... + return false; + } + } +} \ No newline at end of file diff --git a/2014.02.February/AOP/Demo/Aop/Advantage/FakeAdvantageWebCapsule.cs b/2014.02.February/AOP/Demo/Aop/Advantage/FakeAdvantageWebCapsule.cs new file mode 100644 index 0000000..afa645a --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Advantage/FakeAdvantageWebCapsule.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; + +namespace Aop.Advantage +{ + public class FakeAdvantageWebCapsule : IAdvantageWebCapsule + { + public void AddSubscription(int customerId, string pubCode) + { + throw new Exception(); + Console.WriteLine("Adding '{0}' subscription for customer with id: '{1}'", pubCode, customerId); + } + + public IList GetSubscriptions(int customerId) + { + return new List + { + "ABC", + "DEF", + "GHI" + }; + } + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Advantage/IAdvantageWebCapsule.cs b/2014.02.February/AOP/Demo/Aop/Advantage/IAdvantageWebCapsule.cs new file mode 100644 index 0000000..cdd9382 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Advantage/IAdvantageWebCapsule.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Aop.Advantage +{ + public interface IAdvantageWebCapsule + { + void AddSubscription(int customerId, string pubCode); + IList GetSubscriptions(int customerId); + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Aop.csproj b/2014.02.February/AOP/Demo/Aop/Aop.csproj new file mode 100644 index 0000000..0325016 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Aop.csproj @@ -0,0 +1,128 @@ + + + + + Debug + AnyCPU + {79BC310C-CD80-4B6D-B965-38A6207186F7} + Exe + Properties + Aop + Aop + v4.5 + 512 + True + ..\ + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Autofac.3.3.0\lib\net40\Autofac.dll + + + ..\packages\Autofac.Extras.DynamicProxy2.3.0.3\lib\net40\Autofac.Extras.DynamicProxy2.dll + + + ..\packages\Castle.Core.3.2.2\lib\net45\Castle.Core.dll + + + ..\packages\EnyimMemcached.2.12\lib\net35\Enyim.Caching.dll + + + + ..\packages\Moq.4.2.1402.2112\lib\net40\Moq.dll + + + ..\packages\NLog.2.1.0\lib\net45\NLog.dll + + + True + ..\packages\PostSharp.3.1.31\lib\net20\PostSharp.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/2014.02.February/AOP/Demo/Aop/App.config b/2014.02.February/AOP/Demo/Aop/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/2014.02.February/AOP/Demo/Aop/Business/Domain/ILoggable.cs b/2014.02.February/AOP/Demo/Aop/Business/Domain/ILoggable.cs new file mode 100644 index 0000000..5de962f --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/Domain/ILoggable.cs @@ -0,0 +1,7 @@ +namespace Aop.Business.Domain +{ + public interface ILoggable + { + string LogInformation(); + } +} \ No newline at end of file diff --git a/2014.02.February/AOP/Demo/Aop/Business/Domain/Subscription.cs b/2014.02.February/AOP/Demo/Aop/Business/Domain/Subscription.cs new file mode 100644 index 0000000..94215b2 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/Domain/Subscription.cs @@ -0,0 +1,15 @@ +namespace Aop.Business.Domain +{ + public class Subscription : ILoggable + { + public int CustomerId { get; set; } + public string PubCode { get; set; } + + public string LogInformation() + { + return "Customer Id: " + CustomerId + + "\n" + + "Pub Code: " + PubCode; + } + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Business/Services/AdvantageService.cs b/2014.02.February/AOP/Demo/Aop/Business/Services/AdvantageService.cs new file mode 100644 index 0000000..ebad0be --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/Services/AdvantageService.cs @@ -0,0 +1,155 @@ +using System; +using System.Transactions; +using Aop.Advantage; +using Aop.Business.Domain; + +namespace Aop.Business.Services +{ + public class AdvantageService : IAdvantageService + { + private readonly IAdvantageWebCapsule _advantageWebCapsule; + + public AdvantageService(IAdvantageWebCapsule advantageWebCapsule) + { + _advantageWebCapsule = advantageWebCapsule; + } + + #region V1 No Cross Cutting + + public void AddSubscriptionV1(Subscription subscription) + { + _advantageWebCapsule.AddSubscription(subscription.CustomerId, subscription.PubCode); + } + + #endregion V1 + + #region V2 With Logging + + public void AddSubscriptionV2(Subscription subscription) + { + // logging + Console.WriteLine("AddSubscription: {0}", DateTime.Now); + Console.WriteLine("Customer Id: {0}", subscription.CustomerId); + Console.WriteLine("Pub Code: {0}", subscription.PubCode); + + _advantageWebCapsule.AddSubscription(subscription.CustomerId, subscription.PubCode); + + // logging + Console.WriteLine("AddSubscription complete: {0}", DateTime.Now); + } + + #endregion V2 With Logging + + #region V3 With Logging, Defensive Programming + + public void AddSubscriptionV3(Subscription subscription) + { + // defensive programming + if (subscription == null) throw new ArgumentNullException("subscription"); + + // logging + Console.WriteLine("AddSubscription: {0}", DateTime.Now); + Console.WriteLine("Customer Id: {0}", subscription.CustomerId); + Console.WriteLine("Pub Code: {0}", subscription.PubCode); + + _advantageWebCapsule.AddSubscription(subscription.CustomerId, subscription.PubCode); + + // logging + Console.WriteLine("AddSubscription complete: {0}", DateTime.Now); + } + + #endregion V3 With Logging, Defensive Programming + + #region V4 With Logging, Defensive Programming, Transactions + + public void AddSubscriptionV4(Subscription subscription) + { + // defensive programming + if (subscription == null) throw new ArgumentNullException("subscription"); + + // logging + Console.WriteLine("AddSubscription: {0}", DateTime.Now); + Console.WriteLine("Customer Id: {0}", subscription.CustomerId); + Console.WriteLine("Pub Code: {0}", subscription.PubCode); + + // start new transaction + using (var scope = new TransactionScope()) + { + try + { + _advantageWebCapsule.AddSubscription(subscription.CustomerId, subscription.PubCode); + + // complete transaction + scope.Complete(); + } + catch + { + throw; + } + } + + // logging + Console.WriteLine("AddSubscription complete: {0}", DateTime.Now); + } + + #endregion V4 With Logging, Defensive Programming, Transactions + + #region V5 With Logging, Defensive Programming, Transactions, Retries And Exception Handling + + public void AddSubscriptionV5(Subscription subscription) + { + // defensive programming + if (subscription == null) throw new ArgumentNullException("subscription"); + + // logging + Console.WriteLine("AddSubscription: {0}", DateTime.Now); + Console.WriteLine("Customer Id: {0}", subscription.CustomerId); + Console.WriteLine("Pub Code: {0}", subscription.PubCode); + + // exception handling + try + { + // start new transaction + using (var scope = new TransactionScope()) + { + // retry up to three times + var retries = 3; + var succeeded = false; + while (!succeeded) + { + try + { + _advantageWebCapsule.AddSubscription(subscription.CustomerId, subscription.PubCode); + + // complete transaction + scope.Complete(); + succeeded = true; + } + catch + { + // don't re-throw until the + // retry limit is reached + if (retries >= 0) + retries--; + else + throw; + } + } + } + } + catch (Exception ex) + { + // exception handling + if (!Exceptions.Handle(ex)) + { + throw; + } + } + + // logging + Console.WriteLine("AddSubscription complete: {0}", DateTime.Now); + } + + #endregion V5 With Logging, Defensive Programming, Transactions, Retries And Exception Handling + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Business/Services/IAdvantageService.cs b/2014.02.February/AOP/Demo/Aop/Business/Services/IAdvantageService.cs new file mode 100644 index 0000000..2038f11 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/Services/IAdvantageService.cs @@ -0,0 +1,13 @@ +using Aop.Business.Domain; + +namespace Aop.Business.Services +{ + public interface IAdvantageService + { + void AddSubscriptionV1(Subscription subscription); + void AddSubscriptionV2(Subscription subscription); + void AddSubscriptionV3(Subscription subscription); + void AddSubscriptionV4(Subscription subscription); + void AddSubscriptionV5(Subscription subscription); + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/AdvantageServiceDynamicProxy.cs b/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/AdvantageServiceDynamicProxy.cs new file mode 100644 index 0000000..bbfc027 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/AdvantageServiceDynamicProxy.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Linq; +using Aop.Advantage; +using Aop.Business.Domain; +using Aop.Business.ServicesDynamicProxy.Aspects; + +namespace Aop.Business.ServicesDynamicProxy +{ + public class AdvantageServiceDynamicProxy : IAdvantageServiceDynamicProxy + { + private readonly IAdvantageWebCapsule _advantageWebCapsule; + + public AdvantageServiceDynamicProxy(IAdvantageWebCapsule advantageWebCapsule) + { + _advantageWebCapsule = advantageWebCapsule; + } + + [DefensiveProgramming] + [Logging] + [TransactionManagement] + [ExceptionHandling] + public virtual void AddSubscription(Subscription subscription) + { + _advantageWebCapsule.AddSubscription(subscription.CustomerId, subscription.PubCode); + } + + public virtual IList GetSubscriptions(int customerId) + { + return + _advantageWebCapsule.GetSubscriptions(customerId) + .Select(s => new Subscription {CustomerId = customerId, PubCode = s}) + .ToList(); + } + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/Aspects/DefensiveProgramming.cs b/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/Aspects/DefensiveProgramming.cs new file mode 100644 index 0000000..7c4a545 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/Aspects/DefensiveProgramming.cs @@ -0,0 +1,30 @@ +using System; +using System.Linq; +using Castle.DynamicProxy; + +namespace Aop.Business.ServicesDynamicProxy.Aspects +{ + public class DefensiveProgramming : IInterceptor + { + public void Intercept(IInvocation invocation) + { + if (!invocation.MethodInvocationTarget.GetCustomAttributes(typeof(DefensiveProgrammingAttribute), false).Any()) + { + invocation.Proceed(); + return; + } + + foreach (var argument in invocation.Arguments) + { + if (argument == null) + throw new ArgumentNullException(); + if (argument is int && (int)argument <= 0) + throw new ArgumentException(); + } + + invocation.Proceed(); + } + } + + public class DefensiveProgrammingAttribute : Attribute { } +} \ No newline at end of file diff --git a/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/Aspects/ExceptionHandling.cs b/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/Aspects/ExceptionHandling.cs new file mode 100644 index 0000000..1156258 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/Aspects/ExceptionHandling.cs @@ -0,0 +1,26 @@ +using System; +using Aop.Advantage; +using Castle.DynamicProxy; + +namespace Aop.Business.ServicesDynamicProxy.Aspects +{ + public class ExceptionHandling : IInterceptor + { + public void Intercept(IInvocation invocation) + { + try + { + invocation.Proceed(); + } + catch (Exception ex) + { + if (!Exceptions.Handle(ex)) + { + throw; + } + } + } + } + + public class ExceptionHandlingAttribute : Attribute { } +} \ No newline at end of file diff --git a/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/Aspects/Logging.cs b/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/Aspects/Logging.cs new file mode 100644 index 0000000..b0bb853 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/Aspects/Logging.cs @@ -0,0 +1,36 @@ +using System; +using System.Linq; +using Aop.Business.Domain; +using Castle.DynamicProxy; + +namespace Aop.Business.ServicesDynamicProxy.Aspects +{ + public class Logging : IInterceptor + { + public void Intercept(IInvocation invocation) + { + if (!invocation.MethodInvocationTarget.GetCustomAttributes(typeof(LoggingAttribute), false).Any()) + { + invocation.Proceed(); + return; + } + + Console.WriteLine("{0}: {1}", invocation.Method.Name, DateTime.Now); + + foreach (var argument in invocation.Arguments) + { + var loggable = argument as ILoggable; + if (loggable != null) + { + Console.WriteLine(loggable.LogInformation()); + } + } + + invocation.Proceed(); + + Console.WriteLine("{0} complete: {1}", invocation.Method.Name, DateTime.Now); + } + } + + public class LoggingAttribute : Attribute { } +} diff --git a/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/Aspects/TransactionManagement.cs b/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/Aspects/TransactionManagement.cs new file mode 100644 index 0000000..07d087c --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/Aspects/TransactionManagement.cs @@ -0,0 +1,51 @@ +using System; +using System.Linq; +using System.Transactions; +using Castle.DynamicProxy; + +namespace Aop.Business.ServicesDynamicProxy.Aspects +{ + public class TransactionManagement :IInterceptor + { + public void Intercept(IInvocation invocation) + { + if (!invocation.MethodInvocationTarget.GetCustomAttributes(typeof(TransactionManagementAttribute), false).Any()) + { + invocation.Proceed(); + return; + } + + Console.WriteLine("Starting transaction"); + // start new transaction + using (var scope = new TransactionScope()) + { + // retry up to three times + var retries = 3; + var succeeded = false; + while (!succeeded) + { + try + { + invocation.Proceed(); + + // complete transaction + scope.Complete(); + succeeded = true; + } + catch + { + // don't re-throw until the + // retry limit is reached + if (retries >= 0) + retries--; + else + throw; + } + } + } + Console.WriteLine("Transaction complete"); + } + } + + public class TransactionManagementAttribute : Attribute { } +} \ No newline at end of file diff --git a/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/IAdvantageServiceDynamicProxy.cs b/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/IAdvantageServiceDynamicProxy.cs new file mode 100644 index 0000000..d3c6c14 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/ServicesDynamicProxy/IAdvantageServiceDynamicProxy.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Aop.Business.Domain; + +namespace Aop.Business.ServicesDynamicProxy +{ + public interface IAdvantageServiceDynamicProxy + { + void AddSubscription(Subscription subscription); + IList GetSubscriptions(int customerId); + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/AdvantageServicePostSharp.cs b/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/AdvantageServicePostSharp.cs new file mode 100644 index 0000000..e848bc3 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/AdvantageServicePostSharp.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.Linq; +using Aop.Advantage; +using Aop.Business.Domain; +using Aop.Business.ServicesPostSharp.Aspects; +using Aop.Caching; + +namespace Aop.Business.ServicesPostSharp +{ + public class AdvantageServicePostSharp : IAdvantageServicePostSharp + { + private readonly IAdvantageWebCapsule _advantageWebCapsule; + + public AdvantageServicePostSharp(IAdvantageWebCapsule advantageWebCapsule) + { + _advantageWebCapsule = advantageWebCapsule; + } + + [Logging(AspectPriority = 1)] + [DefensiveProgramming(AspectPriority = 2)] + [ExceptionHandling(AspectPriority = 3)] + [TransactionManagement(AspectPriority = 4)] + public void AddSubscription(Subscription subscription) + { + _advantageWebCapsule.AddSubscription(subscription.CustomerId, subscription.PubCode); + } + + [Cache(CacheStore = CacheStore.Memory, Minutes = 60)] + public IList GetSubscriptions(int customerId) + { + return + _advantageWebCapsule.GetSubscriptions(customerId) + .Select(s => new Subscription {CustomerId = customerId, PubCode = s}) + .ToList(); + } + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/Aspects/DefensiveProgramming.cs b/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/Aspects/DefensiveProgramming.cs new file mode 100644 index 0000000..e61e77d --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/Aspects/DefensiveProgramming.cs @@ -0,0 +1,22 @@ +using System; +using PostSharp.Aspects; + +namespace Aop.Business.ServicesPostSharp.Aspects +{ + [Serializable] + public class DefensiveProgramming : OnMethodBoundaryAspect + { + public override void OnEntry(MethodExecutionArgs args) + { + var parameters = args.Method.GetParameters(); + var arguments = args.Arguments; + for (int i = 0; i < arguments.Count; i++) + { + if (arguments[i] == null) + throw new ArgumentNullException(parameters[i].Name); + if (arguments[i] is int && (int)arguments[i] <= 0) + throw new ArgumentException("", parameters[i].Name); + } + } + } +} \ No newline at end of file diff --git a/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/Aspects/ExceptionHandling.cs b/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/Aspects/ExceptionHandling.cs new file mode 100644 index 0000000..a125e4a --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/Aspects/ExceptionHandling.cs @@ -0,0 +1,18 @@ +using System; +using Aop.Advantage; +using PostSharp.Aspects; + +namespace Aop.Business.ServicesPostSharp.Aspects +{ + [Serializable] + public class ExceptionHandling : OnExceptionAspect + { + public override void OnException(MethodExecutionArgs args) + { + if (Exceptions.Handle(args.Exception)) + { + args.FlowBehavior = FlowBehavior.Continue; + } + } + } +} \ No newline at end of file diff --git a/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/Aspects/Logging.cs b/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/Aspects/Logging.cs new file mode 100644 index 0000000..d410b6e --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/Aspects/Logging.cs @@ -0,0 +1,29 @@ +using System; +using Aop.Business.Domain; +using PostSharp.Aspects; + +namespace Aop.Business.ServicesPostSharp.Aspects +{ + [Serializable] + public class Logging : OnMethodBoundaryAspect + { + public override void OnEntry(MethodExecutionArgs args) + { + Console.WriteLine("{0}: {1}", args.Method.Name, DateTime.Now); + + foreach (var argument in args.Arguments) + { + var loggable = argument as ILoggable; + if (loggable != null) + { + Console.WriteLine(loggable.LogInformation()); + } + } + } + + public override void OnSuccess(MethodExecutionArgs args) + { + Console.WriteLine("{0} complete: {1}", args.Method.Name, DateTime.Now); + } + } +} \ No newline at end of file diff --git a/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/Aspects/TransactionManagement.cs b/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/Aspects/TransactionManagement.cs new file mode 100644 index 0000000..a8e5f8b --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/Aspects/TransactionManagement.cs @@ -0,0 +1,43 @@ +using System; +using System.Transactions; +using PostSharp.Aspects; + +namespace Aop.Business.ServicesPostSharp.Aspects +{ + [Serializable] + public class TransactionManagement : MethodInterceptionAspect + { + public override void OnInvoke(MethodInterceptionArgs args) + { + Console.WriteLine("Starting transaction"); + // start new transaction + using (var scope = new TransactionScope()) + { + // retry up to three times + var retries = 3; + var succeeded = false; + while (!succeeded) + { + try + { + args.Proceed(); + + // complete transaction + scope.Complete(); + succeeded = true; + } + catch + { + // don't re-throw until the + // retry limit is reached + if (retries >= 0) + retries--; + else + throw; + } + } + } + Console.WriteLine("Transaction complete"); + } + } +} \ No newline at end of file diff --git a/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/IAdvantageServicePostSharp.cs b/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/IAdvantageServicePostSharp.cs new file mode 100644 index 0000000..1d46595 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Business/ServicesPostSharp/IAdvantageServicePostSharp.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Aop.Business.Domain; + +namespace Aop.Business.ServicesPostSharp +{ + public interface IAdvantageServicePostSharp + { + void AddSubscription(Subscription subscription); + IList GetSubscriptions(int customerId); + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Caching/CacheAttribute.cs b/2014.02.February/AOP/Demo/Aop/Caching/CacheAttribute.cs new file mode 100644 index 0000000..565d432 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Caching/CacheAttribute.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using Aop.PostSharpTestsWithIoC; +using Autofac; +using PostSharp.Aspects; + +namespace Aop.Caching +{ + [Serializable] + public class CacheAttribute : MethodInterceptionAspect + { + [NonSerialized] + private ICache _cache; + + #region Properties + + /// + /// Type of cache store to use + /// + public CacheStore CacheStore { get; set; } + + /// + /// Days the element to be cached should live in the cache + /// + public int Days { get; set; } + + /// + /// Hours the element to be cached should live in the cache + /// + public int Hours { get; set; } + + /// + /// Minutes the element to be cached should live in the cache + /// + public int Minutes { get; set; } + + /// + /// Seconds the items should live in the cache + /// + public int Seconds { get; set; } + + /// + /// Lifespan of the response in the cache + /// + public TimeSpan LifeSpan + { + get + { + // Default 1 hour + if (Days == 0 && Hours == 0 && Minutes == 0 && Seconds == 0) + { + return new TimeSpan(1, 0, 0); + } + return new TimeSpan(Days, Hours, Minutes, Seconds); + } + } + + public static Func GetInstanceStore { get; set; } + + #endregion + + public override void OnInvoke(MethodInterceptionArgs args) + { + if (!AspectSettings.On) + { + args.ReturnValue = args.Invoke(args.Arguments); + return; + } + + var key = CacheKeyBuilder.BuildCacheKey(args.Arguments, _methodName); + + var container = new CacheContainer(); + _cache = container.GetCache(CacheStore); + + var value = _cache.Get(key, ((MethodInfo) args.Method).ReturnType); + if (value == null) + { + lock (_syncRoot) + { + value = _cache.Get(key, ((MethodInfo) args.Method).ReturnType); + if (value == null) + { + value = args.Invoke(args.Arguments); + _cache.Set(key, value, LifeSpan); + } + } + } + + args.ReturnValue = value; + } + + #region Initialization Logic + + [NonSerialized] + private object _syncRoot; + private string _methodName; + + public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo) + { + _methodName = method.Name; + } + + public override void RuntimeInitialize(MethodBase method) + { + _syncRoot = new object(); + } + + #endregion + + #region Type Validation Logic + + public override bool CompileTimeValidate(MethodBase method) + { + var methodInfo = method as MethodInfo; + if (methodInfo != null) + { + var returnType = methodInfo.ReturnType; + if (IsDisallowedCacheReturnType(returnType)) + { + return false; + } + } + return true; + } + + private static readonly IList DisallowedTypes = new List + { + typeof (Stream), + typeof (IEnumerable), + typeof (IQueryable) + }; + + private static bool IsDisallowedCacheReturnType(Type returnType) + { + return DisallowedTypes.Any(t => t == returnType); + } + + #endregion + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Caching/CacheContainer.cs b/2014.02.February/AOP/Demo/Aop/Caching/CacheContainer.cs new file mode 100644 index 0000000..a5550ce --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Caching/CacheContainer.cs @@ -0,0 +1,37 @@ +using System; +using Aop.Caching.CacheStores; +using Autofac; +using Enyim.Caching; + +namespace Aop.Caching +{ + public class CacheContainer + { + public static Func GetScope { get; set; } + + public ICache GetCache(CacheStore type) + { + ICache cache; + switch (type) + { + case CacheStore.Memcached: + { + cache = GetScope().Resolve(new NamedParameter("cache", GetScope().Resolve())); + break; + } + case CacheStore.Null: + { + cache = GetScope().Resolve(); + break; + } + default: + { + cache = GetScope().Resolve(); + break; + } + } + + return cache; + } + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Caching/CacheKeyManager.cs b/2014.02.February/AOP/Demo/Aop/Caching/CacheKeyManager.cs new file mode 100644 index 0000000..957465c --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Caching/CacheKeyManager.cs @@ -0,0 +1,19 @@ +using System.Text; +using PostSharp.Aspects; + +namespace Aop.Caching +{ + public static class CacheKeyBuilder + { + public static string BuildCacheKey(Arguments arguments, string methodName) + { + var sb = new StringBuilder(); + sb.Append(methodName); + foreach (var argument in arguments.ToArray()) + { + sb.Append(argument == null ? "_" : argument.ToString()); + } + return sb.ToString(); + } + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Caching/CacheStores/MemcachedCache.cs b/2014.02.February/AOP/Demo/Aop/Caching/CacheStores/MemcachedCache.cs new file mode 100644 index 0000000..cafa568 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Caching/CacheStores/MemcachedCache.cs @@ -0,0 +1,55 @@ +using System; +using Enyim.Caching; +using Enyim.Caching.Memcached; + +namespace Aop.Caching.CacheStores +{ + public class MemcachedCache : ICache + { + #region Private Variables + + private readonly IMemcachedClient _cache; + + #endregion + + #region Constructor + + public MemcachedCache(IMemcachedClient cache) + { + if (cache == null) throw new ArgumentNullException("cache"); + + _cache = cache; + } + + #endregion + + #region Interface Members + + public void Set(string key, object value, DateTime expiresAt) + { + _cache.Store(StoreMode.Set, key, value, expiresAt); + } + + public void Set(string key, object value, TimeSpan validFor) + { + _cache.Store(StoreMode.Set, key, value, validFor); + } + + public object Get(string key, Type type) + { + return _cache.Get(key); + } + + public void Remove(string key) + { + _cache.Remove(key); + } + + public void Clear() + { + _cache.FlushAll(); + } + + #endregion + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Caching/CacheStores/MemoryCache.cs b/2014.02.February/AOP/Demo/Aop/Caching/CacheStores/MemoryCache.cs new file mode 100644 index 0000000..6d46507 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Caching/CacheStores/MemoryCache.cs @@ -0,0 +1,76 @@ +using System; +using System.Runtime.Caching; + +namespace Aop.Caching.CacheStores +{ + public class MemoryCache : ICache + { + #region Private Variables + + private readonly System.Runtime.Caching.MemoryCache _cache; + + #endregion + + #region Constructor + + public MemoryCache() + { + _cache = System.Runtime.Caching.MemoryCache.Default; + } + + #endregion + + #region Interface Members + + public object Get(string key, Type type) + { + return _cache[key]; + } + + public void Set(string key, object data, TimeSpan lifespan) + { + if (data == null) + { + return; + } + + var expiresAt = DateTime.UtcNow.Add(lifespan); + Set(key, data, expiresAt); + } + + public void Set(string key, object data, DateTime expiresAt) + { + if (data == null) + { + return; + } + + var policy = new CacheItemPolicy { AbsoluteExpiration = expiresAt }; + Set(key, data, policy); + } + + public void Remove(string key) + { + _cache.Remove(key); + } + + public void Clear() + { + foreach (var item in _cache) + { + Remove(item.Key); + } + } + + #endregion + + #region Private Methods + + private void Set(string key, object value, CacheItemPolicy policy) + { + _cache.Set(key, value, policy); + } + + #endregion + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Caching/CacheStores/NullCache.cs b/2014.02.February/AOP/Demo/Aop/Caching/CacheStores/NullCache.cs new file mode 100644 index 0000000..1b670c8 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Caching/CacheStores/NullCache.cs @@ -0,0 +1,43 @@ +using System; + +namespace Aop.Caching.CacheStores +{ + /// + /// implementation which does nothing + /// + /// + /// Used when real caches are unavailable or disabled + /// + public class NullCache : ICache + { + public void InitialiseInternal() + { + } + + public void Set(string key, object value, DateTime expiresAt) + { + } + + public void Set(string key, object value, TimeSpan validFor) + { + } + + public object Get(string key, Type type) + { + return null; + } + + public void Remove(string key) + { + } + + public bool IsSet(string key) + { + return false; + } + + public void Clear() + { + } + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Caching/CachedObject.cs b/2014.02.February/AOP/Demo/Aop/Caching/CachedObject.cs new file mode 100644 index 0000000..3074e8f --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Caching/CachedObject.cs @@ -0,0 +1,11 @@ +using System; + +namespace Aop.Caching +{ + public class CachedObject + { + public string Key { get; set; } + public object Value { get; set; } + public DateTime CachedDate { get; set; } + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Caching/ICache.cs b/2014.02.February/AOP/Demo/Aop/Caching/ICache.cs new file mode 100644 index 0000000..13f6f33 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Caching/ICache.cs @@ -0,0 +1,42 @@ +using System; + +namespace Aop.Caching +{ + public interface ICache + { + /// + /// Gets the value associated with the specified key. + /// + /// The key of the value to get. + /// Type of returned value. + /// The value associated with the specified key. + object Get(string key, Type type); + + /// + /// Adds the specified key and object to the cache. + /// + /// key + /// Data + /// Cache time + void Set(string key, object data, TimeSpan lifespan); + + /// + /// Adds the specified key and object to the cache. + /// + /// key + /// Data + /// Cache expiry date and time + void Set(string key, object data, DateTime expiresAt); + + /// + /// Removes the value with the specified key from the cache + /// + /// /key + void Remove(string key); + + /// + /// Clear all cache data + /// + void Clear(); + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Caching/_Enumerations.cs b/2014.02.February/AOP/Demo/Aop/Caching/_Enumerations.cs new file mode 100644 index 0000000..b65bd14 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Caching/_Enumerations.cs @@ -0,0 +1,9 @@ +namespace Aop.Caching +{ + public enum CacheStore + { + Memcached = 0, // Default Cache + Memory = 1, + Null = 2 + } +} diff --git a/2014.02.February/AOP/Demo/Aop/DynamicProxyTests/DynamicProxyLoggingAspectTests.cs b/2014.02.February/AOP/Demo/Aop/DynamicProxyTests/DynamicProxyLoggingAspectTests.cs new file mode 100644 index 0000000..133d75b --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/DynamicProxyTests/DynamicProxyLoggingAspectTests.cs @@ -0,0 +1,71 @@ +using System; +using Castle.DynamicProxy; +using Moq; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Aop.DynamicProxyTests +{ + #region Logging Service + + public interface ILoggingService + { + void Write(string message); + } + + public class LoggingService : ILoggingService + { + public void Write(string message) + { + Console.WriteLine("Logging: " + message); + } + } + + #endregion Logging Service + + #region Logging Aspect + + public class LoggingAspect : IInterceptor + { + readonly ILoggingService _loggingService; + + public LoggingAspect(ILoggingService loggingService) + { + _loggingService = loggingService; + } + + public void Intercept(IInvocation invocation) + { + _loggingService.Write("Log start"); + invocation.Proceed(); + var returnValue = (int)invocation.ReturnValue; + _loggingService.Write(string.Format("Log {0} end", returnValue)); + } + } + + #endregion Logging Aspect + + #region Unit Test + + [TestClass] + public class LoggingAspectTests + { + [TestMethod] + public void LoggingAspectTest() + { + // Arrange + var mockLoggingService = new Mock(); + var loggingAspect = new LoggingAspect(mockLoggingService.Object); + var mockInvocation = new Mock(); + mockInvocation.Setup(x => x.ReturnValue).Returns(3); + + // Act + loggingAspect.Intercept(mockInvocation.Object); + + // Assert + mockLoggingService.Verify(x => x.Write("Log start")); + mockLoggingService.Verify(x => x.Write(string.Format("Log 3 end"))); + } + } + + #endregion Unit Test +} diff --git a/2014.02.February/AOP/Demo/Aop/PostSharpTestsNoIoC/PostSharpLoggingAspectTestsNoIoC.cs b/2014.02.February/AOP/Demo/Aop/PostSharpTestsNoIoC/PostSharpLoggingAspectTestsNoIoC.cs new file mode 100644 index 0000000..86c9034 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/PostSharpTestsNoIoC/PostSharpLoggingAspectTestsNoIoC.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Reflection.Emit; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PostSharp.Aspects; + +namespace Aop.PostSharpTestsNoIoC +{ + public static class LoggingService + { + public static List _messages = new List(); + + public static List Messages + { + get { return _messages; } + } + + public static void Write(string message) + { + _messages.Add(message); + } + } + + [Serializable] + public class LoggingAspect : OnMethodBoundaryAspect + { + public override void OnEntry(MethodExecutionArgs args) + { + LoggingService.Write("Before: " + args.Method.Name); + } + public override void OnSuccess(MethodExecutionArgs args) + { + LoggingService.Write("After: " + args.Method.Name); + } + } + + [TestClass] + public class LoggingAspectTests + { + [TestMethod] + public void LoggingAspectTest() + { + // Arrange + var args = new MethodExecutionArgs(null, Arguments.Empty) + { + Method = new DynamicMethod("AddSubscription", null, null) + }; + + var aspect = new LoggingAspect(); + + // Act + aspect.OnEntry(args); + aspect.OnSuccess(args); + + // Assert + Assert.IsTrue(LoggingService.Messages.Contains("Before: " + args.Method.Name)); + Assert.IsTrue(LoggingService.Messages.Contains("After: " + args.Method.Name)); + } + } +} diff --git a/2014.02.February/AOP/Demo/Aop/PostSharpTestsWithIoC/PostSharpLoggingAspectTestsWithIoC.cs b/2014.02.February/AOP/Demo/Aop/PostSharpTestsWithIoC/PostSharpLoggingAspectTestsWithIoC.cs new file mode 100644 index 0000000..b003718 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/PostSharpTestsWithIoC/PostSharpLoggingAspectTestsWithIoC.cs @@ -0,0 +1,98 @@ +using System; +using System.Linq; +using System.Reflection; +using Autofac; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using PostSharp.Aspects; + +namespace Aop.PostSharpTestsWithIoC +{ + public class StringHelpers + { + [LoggingAspect] + public string Reverse(string str) + { + return new string(str.Reverse().ToArray()); + } + } + + [Serializable] + public class LoggingAspect : OnMethodBoundaryAspect + { + ILoggingService _loggingService; + + public static Func GetScope { get; set; } + + public override void RuntimeInitialize(MethodBase method) + { + if (!AspectSettings.On) return; + _loggingService = GetScope().Resolve(); + } + + public override void OnEntry(MethodExecutionArgs args) + { + if (!AspectSettings.On) return; + _loggingService.Log("before"); + } + + public override void OnSuccess(MethodExecutionArgs args) + { + if (!AspectSettings.On) return; + _loggingService.Log("after"); + } + } + + public interface ILoggingService + { + void Log(string logMessage); + } + + public static class AspectSettings + { + public static bool On = true; + } + + [TestClass] + public class MyNormalCodeTest + { + public void SetupIoC(ILoggingService loggingService) + { + var builder = new ContainerBuilder(); + builder.RegisterInstance(loggingService).As(); + var container = builder.Build(); + LoggingAspect.GetScope = container.Resolve; + } + + [TestMethod] + public void ReverseTest() + { + // Arrange + var loggingService = new Mock(); + SetupIoC(loggingService.Object); + var stringHelpers = new StringHelpers(); + + // Act + var result = stringHelpers.Reverse("hello"); + + // Assert + Assert.AreEqual("olleh", result); + loggingService.Verify(x => x.Log("before")); + loggingService.Verify(x => x.Log("after")); + } + + [TestMethod] + public void ReverseTestAlternative() + { + // Arrange + AspectSettings.On = false; + var myCode = new StringHelpers(); + + // Act + var result = myCode.Reverse("hello"); + + // Assert + Assert.AreEqual("olleh", result); + } + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Program.cs b/2014.02.February/AOP/Demo/Aop/Program.cs new file mode 100644 index 0000000..7e537ff --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Program.cs @@ -0,0 +1,115 @@ +using Aop.Advantage; +using Aop.Business.Domain; +using Aop.Business.Services; +using Aop.Business.ServicesDynamicProxy; +using Aop.Business.ServicesDynamicProxy.Aspects; +using Aop.Business.ServicesPostSharp; +using Aop.Caching.CacheStores; +using Autofac; +using Autofac.Extras.DynamicProxy2; +using Enyim.Caching; +using Aop.Caching; + +namespace Aop +{ + class Program + { + private static IContainer Container { get; set; } + + static void Main() + { + SetupIoC(); + + var subscription = new Subscription + { + CustomerId = 1, + PubCode = "ABC" + }; + + using (var scope = Container.BeginLifetimeScope()) + { + //#region Add Subscription No AOP + + //var advantageService = scope.Resolve(); + + //advantageService.AddSubscriptionV5(subscription); + + //#endregion Add Subscription No AOP + + #region Add Subscription PostSharp AOP + + var advantageServicePostSharp = scope.Resolve(); + + //advantageServicePostSharp.AddSubscription(subscription); + + #endregion Add Subscription PostSharp AOP + + //#region Add Subscription DynamicProxy AOP + + //var advantageServiceDynamicProxy = scope.Resolve(); + + //advantageServiceDynamicProxy.AddSubscription(subscription); + + //#endregion + + #region Get Subscriptions PostSharp AOP + + CacheContainer.GetScope = () => scope; + + advantageServicePostSharp.GetSubscriptions(1); + + advantageServicePostSharp.GetSubscriptions(1); + + #endregion Get Subscriptions PostSharp AOP + + //#region Get Subscriptions DynamicProxy AOP + + //advantageServiceDynamicProxy.GetSubscriptions(1); + + //#endregion + } + } + + private static void SetupIoC() + { + var builder = new ContainerBuilder(); + + builder.RegisterType().As(); + builder.RegisterType().As(); + + #region PostSharp + + builder.RegisterType().As(); + + #endregion PostSharp + + #region Dynamic Proxy + + builder.Register(c => new DefensiveProgramming()); + builder.Register(c => new Logging()); + builder.Register(c => new TransactionManagement()); + builder.Register(c => new ExceptionHandling()); + + builder.RegisterType() + .As() + .EnableInterfaceInterceptors() + .InterceptedBy(typeof (Logging)) + .InterceptedBy(typeof (DefensiveProgramming)) + .InterceptedBy(typeof (ExceptionHandling)) + .InterceptedBy(typeof (TransactionManagement)); + + #endregion Dynamic Proxy + + #region Caching + + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().SingleInstance(); + builder.RegisterType().SingleInstance(); + builder.RegisterType().SingleInstance(); + + #endregion Caching + + Container = builder.Build(); + } + } +} diff --git a/2014.02.February/AOP/Demo/Aop/Properties/AssemblyInfo.cs b/2014.02.February/AOP/Demo/Aop/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7db95eb --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PostSharpAop")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PostSharpAop")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f397875b-29a8-43a5-bbbb-eb8b7e824ee8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/2014.02.February/AOP/Demo/Aop/packages.config b/2014.02.February/AOP/Demo/Aop/packages.config new file mode 100644 index 0000000..61a0a62 --- /dev/null +++ b/2014.02.February/AOP/Demo/Aop/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/2014.02.February/AOP/Demo/packages/repositories.config b/2014.02.February/AOP/Demo/packages/repositories.config new file mode 100644 index 0000000..9e9dcff --- /dev/null +++ b/2014.02.February/AOP/Demo/packages/repositories.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/2014.02.February/AOP/Presentation/AOP.pptx b/2014.02.February/AOP/Presentation/AOP.pptx new file mode 100644 index 0000000..a00e87c Binary files /dev/null and b/2014.02.February/AOP/Presentation/AOP.pptx differ