{"id":16431478,"url":"https://github.com/dcastro/mementocontainer","last_synced_at":"2025-10-27T01:30:24.420Z","repository":{"id":10057766,"uuid":"12108139","full_name":"dcastro/MementoContainer","owner":"dcastro","description":null,"archived":false,"fork":false,"pushed_at":"2018-03-09T08:17:11.000Z","size":425,"stargazers_count":5,"open_issues_count":3,"forks_count":2,"subscribers_count":2,"default_branch":"dev","last_synced_at":"2025-02-01T01:23:12.447Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dcastro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-08-14T12:19:12.000Z","updated_at":"2020-12-07T19:16:01.000Z","dependencies_parsed_at":"2022-09-17T08:11:54.753Z","dependency_job_id":null,"html_url":"https://github.com/dcastro/MementoContainer","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcastro%2FMementoContainer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcastro%2FMementoContainer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcastro%2FMementoContainer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcastro%2FMementoContainer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dcastro","download_url":"https://codeload.github.com/dcastro/MementoContainer/tar.gz/refs/heads/dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238418207,"owners_count":19468864,"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":[],"created_at":"2024-10-11T08:30:27.130Z","updated_at":"2025-10-27T01:30:24.030Z","avatar_url":"https://github.com/dcastro.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MementoContainer\n\nMementoContainer is an alternative approach to the [Memento design pattern](http://paginas.fe.up.pt/~aaguiar/as/gof/hires/pat5ffso.htm).\n\nIt is a lightweight utility that takes a snapshot of your objects' state so that you can easily rollback to a previous state when recovering from errors.\n\nThis approach, like the original one, promotes highly decoupled systems and preserves encapsulation boundaries while leveraging C#'s awesomeness\n(e.g., reflection, attributes, lambda expression analysis, dynamic typing) to avoid polluting your code base with Memento types.\n\nBesides, taking a snapshot of an object's state isn't always a trivial task.\nIf you have a big dependency graph, then you will probably have to perform tedious deep cloning of your objects.\nMementoContainer does all that for you - and more.\n\n```csharp\nvar memento = Memento.Create()\n                        .Register(article);\n\ntry\n{\n   ArticleFormatter.Format(article);\n}\ncatch(FormattingException)\n{\n   memento.Rollback(); //Et voilà!\n}\n\n```\n\n## Getting started\n\n### Registering objects\n\nThe first step is to annotate your model's properties with the `MementoProperty` and/or `MementoCollection` attributes, so that the memento will know which properties it will need to watch.\n\n```csharp\npublic class Magazine\n{\n   [MementoProperty]\n   public string Title { get; set; }\n\n   [MementoCollection]\n   public IList\u003cArticle\u003e Articles { get; set; }\n}\n```\n\nIn order to preserve encapsulation, these properties can have any access modifiers (private, public, protected) and even be static.\nAnd if the class `Article` also happens to have annotated properties, those will be registered as well!\n\nAlternatively, you may also use the `MementoClass` attribute on your classes.\nThis way, all your object's properties/collections will be recorded.\n```csharp\n[MementoClass]\npublic class Article\n{\n   public string Title { get; set; }\n   public string Author { get; set; }\n}\n```\n\nThe Memento object exposes a [fluent interface](http://www.martinfowler.com/bliki/FluentInterface.html) so that you can easily register all your objects with the container.\n\n```csharp\nvar magazine1 = new Magazine\n    {\n        Title = \"Draft\",\n        Articles = new List\u003cArticle\u003e\n            {\n                new Article(\"Draft\", \"DCastro\")\n            }\n    };\n\nvar memento = Memento.Create()\n                        .Register(magazine1)\n                        .Register(magazine2)\n                        .Register(publisher);\n```\n\nNow you can freely act upon your objects and if anything goes wrong, just rollback!\n\n```csharp\ntry\n{\n   magazine1.Name = \"State of emergency declared\";\n   magazine1.Articles.Clear();\n   db.Save(magazine1);\n}\ncatch(DBException)\n{\n   //The magazine will be renamed back to \"Draft\"\n   //and the article authored by \"DCastro\" will be re-inserted.\n   memento.Rollback();\n}\n```\n\n### Registering single properties/collections\n\nYou can also register single properties/collections, without the need to add attributes to your classes.\n\n```csharp\nvar memento = Memento.Create()\n                        .RegisterProperty(publisher, p =\u003e p.Name) //simple property\n                        .RegisterProperty(publisher, p =\u003e p.ProfilePhoto.Description) //chain of properties\n                        .RegisterProperty(() =\u003e ArticleFactory.LastReleaseDate) //static property\n                        .RegisterCollection(articlesList);\n```\n\n\n\n## NuGet\nTo install MementoContainer, run the following command in the Package Manager Console\n\n```\nPM\u003e Install-Package MementoContainer\n```\n\n## Depency Injection and Mocking\nThe IMemento interface is available so that you can easily mock it with tools like [Moq](https://code.google.com/p/moq/) in your unit tests and inject it as a depency using your favourite IoC container (e.g., [Castle Windsor](http://docs.castleproject.org/Windsor.MainPage.ashx) or [Ninject](http://www.ninject.org/)).\n\n## Documentation\nFor more information and advanced usage, head on the [wiki].\n\n[wiki]: https://github.com/dcastro/MementoContainer/wiki\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdcastro%2Fmementocontainer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdcastro%2Fmementocontainer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdcastro%2Fmementocontainer/lists"}