{"id":20683104,"url":"https://github.com/puresharper/puresharp","last_synced_at":"2025-04-22T12:21:15.451Z","repository":{"id":64548498,"uuid":"90499131","full_name":"Puresharper/Puresharp","owner":"Puresharper","description":"Puresharp is a Framework that provides the essential APIs (AOP, IOC, etc...) to productively build high quality (.NET 4.5.2+ \u0026 .NET Core 2.1+) applications through reliability, scalability and performance without no compromise","archived":false,"fork":false,"pushed_at":"2019-01-31T18:47:12.000Z","size":179,"stargazers_count":146,"open_issues_count":6,"forks_count":17,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-04-17T23:27:21.329Z","etag":null,"topics":["advice","aop","architecture","aspects","composition","csharp","framework","injection","interception","ioc","net","proxy"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Puresharper.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-05-07T00:26:20.000Z","updated_at":"2025-03-05T17:56:17.000Z","dependencies_parsed_at":"2022-12-10T18:28:29.002Z","dependency_job_id":null,"html_url":"https://github.com/Puresharper/Puresharp","commit_stats":null,"previous_names":["virtuoze/puresharp"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Puresharper%2FPuresharp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Puresharper%2FPuresharp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Puresharper%2FPuresharp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Puresharper%2FPuresharp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Puresharper","download_url":"https://codeload.github.com/Puresharper/Puresharp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250237851,"owners_count":21397403,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["advice","aop","architecture","aspects","composition","csharp","framework","injection","interception","ioc","net","proxy"],"created_at":"2024-11-16T22:15:30.299Z","updated_at":"2025-04-22T12:21:15.422Z","avatar_url":"https://github.com/Puresharper.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\n# Puresharp API .NET\nPuresharp is a set of features for .NET 4.5.2+ / .NET Core 2.1 to improve productivity by producing flexible and efficient applications.\n\n## Overview\nPuresharp mainly provides architectural tools to build the basics of professional applications :\n- Dependency Injection Container\n- Aspect Oriented Programming\n- Metadata Reflection API\n\nThis framework is divided into 2 parts :\n- **IPuresharp** \u0026nbsp;\u0026nbsp;[![NuGet](https://img.shields.io/nuget/v/IPuresharp.svg)](https://www.nuget.org/packages/IPuresharp)\n\nIPuresharp is a nuget package dedicated to rewrite assemblies (using **[Mono.Cecil](https://github.com/jbevain/cecil)**) to allow them to be highly customizable at runtime. IPuresharp won't add a new library reference to assmblies, but only include a post build process to automatically rewrite assemblies just after success build.\n\n    Install-Package IPuresharp -Version 5.0.5\n\nIt can be used manually with command line to manage third party assemblies\n\n    IPuresharp.exe \"FullnameToAssembly.dll\"\n\n- **Puresharp** \u0026nbsp;\u0026nbsp;[![NuGet](https://img.shields.io/nuget/v/Puresharp.svg)](https://www.nuget.org/packages/Puresharp)\n\nPuresharp is a nuget package offering various features useful for designing a healthy and productive architecture. This package also includes all the artillery to easily handle the elements that brings the IL writer IPuresharp. The nuget package add a library (Puresharp.dll) without any other depencies.\n\n    Install-Package Puresharp -Version 5.0.5\n\n_note : It is recommanded to install **IPuresharp** nuget package in all projects and install **Puresharp** nuget package only in project where you explicitly need it._\n\n### Dependency Injection Container\n\nThe global workflow of the DI Container is similar to others : setup a composition, create a container and instantiate from container some components.\n\n#### Preview\n\nExample of interfaces to configure\n\n    public interface IA\n    {\n    }\n\n    public interface IB\n    {\n    }\n\n    public interface IC\n    {\n    }\n    \nExample of implementations to bind to interfaces\n\n    public class A : IA\n    {\n        public A(IB b, IC c)\n        {\n        }\n    }\n\n    public class B : IB\n    {\n        public B(IC c, int constant)\n        {\n        }\n    }\n\n    public class C : IC\n    {\n    }\n\nCreate a composition\n\n    var _composition = new Composition();\n\nSetup composition for IA, IB, IC whith respectivily A, B, C\n\n    _composition.Setup\u003cIA\u003e(() =\u003e new A(Metadata\u003cIB\u003e.Value, Metadata\u003cIC\u003e.Value), Instantiation.Multiton);\n    _composition.Setup\u003cIB\u003e(() =\u003e new B(Metadata\u003cIC\u003e.Value, 28), Instantiation.Multiton);\n    _composition.Setup\u003cIC\u003e(() =\u003e new C(), Instantiation.Multiton);\n    \nCreate a container from composition setup\n\n    var _container = _composition.Materialize();\n\nInstantiate a module of IA from container\n\n    using (var _module = _container.Module\u003cIA\u003e())\n    {\n        var _ia = _module.Value;\n    }\n    \n_note : module is [IDisposable](https://msdn.microsoft.com/en-us/library/system.idisposable(v=vs.110).aspx) and crontrol lifecycle for all dependencies._\n\n#### FAQ\n\n- **How is managed lifecycle for dependencies?** \n_When a module is setup into composition, instantiation mode is required and can be **Singleton** (a single instance with a lifecycle related to container), **Multiton** (a new instance for each module with lifecycle related to module itself) or **Volatile** (always a new instance with lifecycle related to owner module). Container and Module are both IDisposable to release created components._\n\n- **Sould my interfaces implement IDisposable to match with lifecycle management?** \n_On the contrary, the interface of a component should never implement the IDisposable interface which is a purely infrastructure concern. Only implementations could possibly be. The container makes sure to dispose the implementations properly when it implements the IDisposable interface._\n\n- **Why using lambda expression to configure components instead of classic generic parameter?** \n_Lambda expression offer a way to target constructor to use, specify when to use dependencies and capture constant._\n\n- **How dependency is configured?** \n_Simply use **Metadata\u0026lt;T\u0026gt;.Value** in expression when you need to get back dependency from container._\n\n- **Is constructor injection prevent cyclic reference between component?** \n_No, cyclic references are a feature. When an instance is created, it is not really the case, a lazy proxy instance is prepared to minimize unused resources retention and allow cyclic references._\n\n- **In preview, only constructors are used to setup component, is it limited to constructor injection?** \n_No, expressions are totally open. You can inject static methods, constructors, members and even mix differents styles._\n\n### Aspect Oriented Programming\n\nWorkflow :\n- Identify group of methods by defining a **Pointcut**\n- Specify an **Aspect** by defining some **Advices**\n- Instantiate the **Aspect** and **Weave** it into **Pointcut**\n\n#### Preview\n\nExample of interface\n\n    [AttributeUsage(AttributeTargets.Method)]\n    public class Read : Attribute\n    {\n    }\n\n    [AttributeUsage(AttributeTargets.Method)]\n    public class Operation : Attribute\n    {\n    }\n\n    public interface IService\n    {\n        [Operation]\n        void SaveComment(int id, string text);\n\n        [Read]\n        [Operation]\n        string GetComment(int id);\n    }\n    \nExample of implementation\n\n    public class Service : IService\n    {\n        public void SaveComment(int id, string text)\n        {\n        }\n\n        public string GetComment(int id)\n        {\n            return null;\n        }\n    }\n    \nSupposed we want to log all readonly operations. For that, we have to define a **Pointcut** that represent all methods that are readonly operation (where Read attribute and Operation attribute are placed)\n\n    public class ReadonlyOperation : Pointcut.And\u003cPointcut\u003cOperation\u003e, Pointcut\u003cRead\u003e\u003e\n    {\n    }\n    \nDefine an **Advice** to log before whith Trace.WriteLine for exemple when calling methods\n\n    public class Log : IAdvice\n    {\n        private MethodBase m_Method;\n\n        public Log(MethodBase method)\n        {\n            this.m_Method = method;\n        }\n\n        public void Instance\u003cT\u003e(T instance)\n        {\n        }\n\n        public void Argument\u003cT\u003e(ref T value)\n        {\n        }\n\n        public void Begin()\n        {\n            Trace.WriteLine(this.m_Method);\n        }\n\n        public void Await(MethodInfo method, Task task)\n        {\n        }\n\n        public void Await\u003cT\u003e(MethodInfo method, Task\u003cT\u003e task)\n        {\n        }\n        \n        public void Continue()\n        {\n        }\n        \n        public void Throw(ref Exception exception)\n        {\n        }\n\n        public void Throw\u003cT\u003e(ref Exception exception, ref T value)\n        {\n        }\n\n        public void Return()\n        {\n        }\n\n        public void Return\u003cT\u003e(ref T value)\n        {\n        }\n        \n        public void Dispose()\n        {\n        }\n    }\n    \nDefine an **Aspect** that use log **Advice**\n\n    public class Logging : Aspect\n    {\n        override public IEnumerable\u003cAdvisor\u003e Manage(MethodBase method)\n        {\n            yield return Advice\n                .For(method)\n                .Around(() =\u003e new Log(method));\n        }\n    }\n    \nInstantiate **Aspect** and weave it to our ReadonlyOperation **Pointcut**\n\n    var _logging = new Logging();\n    _logging.Weave\u003cReadonlyOperation\u003e();\n\nCongratulation, the logging Aspect in now injected to all readonly operation contract.\n\n#### Sample\n    \nHere a set of sample to let see differents way to create and advisor.\n    \n    public class Logging : Aspect\n    {\n        override public IEnumerable\u003cAdvisor\u003e Manage(MethodBase method)\n        {\n            //Use classic interceptor to create an 'Around' advisor (place break points in interceptor methods to test interception).\n            yield return Advice\n                .For(method)\n                .Around(() =\u003e new Interceptor());\n\n            //Use linq expression to generate a 'Before' advisor.\n            yield return Advice\n                .For(method)\n                .Before(invocation =\u003e\n                {\n                    return Expression.Call\n                    (\n                        Metadata.Method(() =\u003e Console.WriteLine(Metadata\u003cstring\u003e.Value)), \n                        Expression.Constant($\"Expression : { method.Name }\")\n                    );\n                });\n\n            //Use linq expression to generate a 'Before' advisor.\n            yield return Advice\n                .For(method)\n                .Before\n                (\n                    Expression.Call\n                    (\n                        Metadata.Method(() =\u003e Console.WriteLine(Metadata\u003cstring\u003e.Value)),\n                        Expression.Constant($\"Expression2 : { method.Name }\")\n                    )\n                );\n\n            //Use ILGeneration from reflection emit API to generate a 'Before' advisor.\n            yield return Advice\n                .For(method)\n                .Before(advice =\u003e\n                {\n                    advice.Emit(OpCodes.Ldstr, $\"ILGenerator : { method.Name }\");\n                    advice.Emit(OpCodes.Call, Metadata.Method(() =\u003e Console.WriteLine(Metadata\u003cstring\u003e.Value)));\n                });\n\n            //Use simple Action to generate a 'Before' advisor.\n            yield return Advice\n                .For(method)\n                .Before(() =\u003e Console.WriteLine($\"Action : { method.Name }\"));\n\n            //Use an expression to generate an 'After-Returning-Value' Advisor\n            yield return Advice\n                .For(method)\n                .After()\n                .Returning()\n                .Value(_Execution =\u003e\n                {\n                    return Expression.Call\n                    (\n                        Metadata.Method(() =\u003e Console.WriteLine(Metadata\u003cstring\u003e.Value)),\n                        Expression.Call\n                        (\n                            Metadata.Method(() =\u003e string.Concat(Metadata\u003cstring\u003e.Value, Metadata\u003cstring\u003e.Value)),\n                            Expression.Constant(\"Returned Value : \"),\n                            Expression.Call(_Execution.Return, Metadata\u003cobject\u003e.Method(_Object =\u003e _Object.ToString()))\n                        )\n                    );\n                });\n            \n            //Validate an email parameter value.\n            yield return Advice\n                .For(method)\n                .Parameter\u003cEmailAddressAttribute\u003e()\n                .Validate((_Parameter, _Attribute, _Value) =\u003e\n                {\n                    if (_Value == null) { throw new ArgumentNullException(_Parameter.Name); }\n                    try { new MailAddress(_Value.ToString()); }\n                    catch (Exception exception) { throw new ArgumentException(_Parameter.Name, exception); }\n                });\n        }\n    }\n    \n#### FAQ\n\n- **Can I weave multiple Aspects into the same Pointcut?** \n_Yes, just be carefull about weaving order._\n\n- **How can I remove an Aspect from a Pointcut?** \n_There is a **Release** method defined in **Aspect** to get rid of **Aspect** from **Pointcut**._\n\n- **Are attributes required to define Pointcut?** \n_No, **Pointcut** can be defined by directly inherits from **Pointcut** and implement the abstract method **Match** that take a **MethodBase** as single argument and return a boolean to indicate if a method is in **Pointcut** scope._\n\n- **Why I have to use IPuresharp?** \n_Interception is based on IPuresharp. Indeed IPuresharp add a build action to rewrite CIL to make assembly \"Architect Friendly\" by injecting transparents and hidden features to to grant full execution control at runtime._\n\n- **Can I intercept constructor? If yes, how do I implement it?**\n_Constructor interception is supported and is treated like another method with declaring type as first argument and void for return type._\n\n- **Is generic types and methods supported?**\n_Generic types and methods ares fully supported by injection._\n\n- **Can I intercept async methods?**\n_Async methods ares fully supported by injection and offer a way to intercept each asynchronous steps._\n\n## More\n- [https://en.m.wikipedia.org/wiki/Aspect-oriented_programming](https://en.m.wikipedia.org/wiki/Aspect-oriented_programming)\n- [https://en.m.wikipedia.org/wiki/Dependency_injection](https://en.m.wikipedia.org/wiki/Dependency_injection)\n- [https://en.m.wikipedia.org/wiki/SOLID](https://en.m.wikipedia.org/wiki/SOLID)\n- [https://en.m.wikipedia.org/wiki/Domain-driven_design](https://en.m.wikipedia.org/wiki/Domain-driven_design)\n\n## Contribution\n- Feedbacks are wellcome, don't hesitate to tell me if any improvements seems to be cool\n- Any pull requests for patching or correct my bad english are wellcome too\n- You can also donate to help financially maintain the project : **3D8txm4gMJDtti7tpcYnndLDfxpADkLggn**\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpuresharper%2Fpuresharp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpuresharper%2Fpuresharp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpuresharper%2Fpuresharp/lists"}