{"id":13686508,"url":"https://github.com/DevrexLabs/memstate-tutorial","last_synced_at":"2025-05-01T09:31:54.419Z","repository":{"id":147174151,"uuid":"148650170","full_name":"DevrexLabs/memstate-tutorial","owner":"DevrexLabs","description":"Course material for learning memstate","archived":false,"fork":false,"pushed_at":"2018-11-18T23:08:28.000Z","size":610,"stargazers_count":5,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-08-03T15:05:21.978Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://github.com/devrexlabs/memstate","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/DevrexLabs.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,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-09-13T14:27:57.000Z","updated_at":"2023-07-28T12:36:29.000Z","dependencies_parsed_at":"2024-01-14T15:26:42.556Z","dependency_job_id":"79b11c07-c838-42b6-b1bb-3c934fcb4194","html_url":"https://github.com/DevrexLabs/memstate-tutorial","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevrexLabs%2Fmemstate-tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevrexLabs%2Fmemstate-tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevrexLabs%2Fmemstate-tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevrexLabs%2Fmemstate-tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DevrexLabs","download_url":"https://codeload.github.com/DevrexLabs/memstate-tutorial/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224250217,"owners_count":17280522,"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-08-02T15:00:33.940Z","updated_at":"2024-11-12T09:30:56.830Z","avatar_url":"https://github.com/DevrexLabs.png","language":"C#","funding_links":[],"categories":["C# #"],"sub_categories":[],"readme":"# Memstate tutorial\n\nThis is material for a 2-day course. If you are doing a 3 hour workshop jump in at task 3, examine what's already there and run the unit tests.\n\n## Prerequisites\n* Development environment for .NET Core such as VS2017 on Windows, VS for mac or VS Code on any platform\n* Docker for some of the later modules\n* Experienced C# developer with an open mind\n\n\n## Task 0 : Clone the repository\nClone this repository, or even better fork it to your own GH account and clone from there. If you don't have an account create one now!\n```\ngit clone  https://github.com/DevrexLabs/memstate-tutorial\n```\n\nEach step of the tutorial is tagged so that you can easily jump around and look at the code. To start working on a task checkout a new branch from the tag associated with that task. \n\n```\ngit checkout -b dev-1 task-1\n```\n\nThis will create and a switch to a branch named dev-1. Go ahead and do this now then you are all set for task 1.\n\n\n## Task 1 : Creating the domain model\nTime required: 40-60 minutes\n\nIn the Twitter.Core library, add a `Tweet` class, a `User` class and a `Twitter` class.\n\nThe Twitter class should have \n* an ordered collection of tweets\n* a collection of users keyed by id (string)\n\nand methods to:\n* post a tweet: `int PostTweet(string user, string message)`\n* retrieve a range of users tweets\n* retrieve a range of all tweets\n* Follow a user: `void Follow(string follower, string followee)`\n\nKeep it simple and just do the bare minimum at this point, you will add more state and behavior later. Try to use the ubiquitous language of the domain. Some additional rules:\n \n* The User entity is created when posting the first tweet of the account.\n* The user entity should have an ordered collection of tweets\n* The user entity should have ordered collections of followers and followees\n* Prefer passing basic arguments instead of entities, example: `PostTweet(string user, string message, Datetime when)` instead of `PostTweet(Tweet tweet)`\n\n## Task 2 : Testing the domain model\nTime required: 10-20 minutes\n\nAdd a unit test project using your preferred unit testing library.\nWrite some of the tests below, you might need to add behavior to your domain model to make them pass. Don't get carried away with details, this is just to demonstrate how you would do TDD if you're into that kind of thing.\n\n * Tweets are assigned unique int ids in an ever increasing sequence\n * Tweets are added to the users list of tweets\n * Tweets are added to the all tweets collection\n \n\n## Task 3 : Adding command and queries\nTime required: 10-20 minutes\n\nAdd the `Memstate.All` package to the `Twitter.Core` project. Create command and query classes:\n* `class PostTweet : Command\u003cTwitter, long\u003e` (returns the assigned id\n* `class ReadTimeLine : Query\u003cTwitter, Tweet[]\u003e` (retrieve a range of tweets for a specific user)\n* `class AllTweets : Query\u003cTwitter, Tweet[]\u003e`\n* `class Follow : Command\u003cTwitter\u003e`\n\noverride the `Execute(Twitter state)` method adding the correct behavior.\n\n## Task 4 : Testing commands and queries\nTime required: 15-30 minutes\n\nAdd some tests for the commands and queries by creating an instance of Twitter, executing the command/query then verifying return values and possible state changes.\n\n\n## Task 5: Integration tests\nTime required: 15-30 minutes\n\nRepeat the tests from task 4 but running through the Memstate engine. The test setup should:\n```\nvar cfg = Config.Current;cfg.UseInMemoryFileSystem();\nvar settings = cfg.GetSettings\u003cEngineSettings\u003e();\nsettings.WithRandomSuffixAppendedToStreamName();\nvar engine = Engine.Start\u003cTwitter\u003e();\n```\n\nand then in your test methods\n`engine.Execute(command or query)`\n\n## Task 6: Implementing ASP.NET Controllers\nTime required: 10-20 minutes\n\nIn the web project, add a reference to the domain model project and the `Memstate.All` nuget package.\nAdd a controller named `TwitterController` \nIn the constructor create a client using `Client.For\u003cTwitter\u003e()` or if you have the skills configure it for dependency injection as a singleton.\n\nCreate action methods for the following operations:\n* `GET UserTweets(userName, skip, take)`\n* `GET AllTweets(skip, take)`\n* `POST Tweet(userName, message)`\n* `POST Follow(userName, followee)`\n\nThe UI is a single page and already hooked up. It uses jquery ajax to talk to the backend, examine the `Twitter.cshtml` view for details. Test manually that you can tweet, follow, refresh to see all.\n\n## Task 7: Reactive\nTime: \nDefine the events `Tweeted` and `Followed`. They should inherit from the `Event` base class. Publish events from within the commands `Execute()` by calling `RaiseEvent()` on the `Command` base class. \nNote: The tests from Task 4 might fail when you raise events. This bug is fixed with memstate version 0.6.6\n\n(Optional) Add tests to verify that the correct events are published. The events are passed as an argument to the `Engine.CommandExecuted` event.\n\nTo subscribe to events use `Client.Subscribe\u003cTEvent\u003e(Action\u003cTEvent\u003e handler)` or `Client.Subscribe\u003cTEvent\u003e(Action\u003cTEvent\u003e handler, IEventFilter filter)`\n\nThis tutorial on SignalR should \nhttps://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr\n\nAdd a SignalR hub that keeps track of connected users, subscribes to events and relays them to clients. Note that Hubs are stateless so have a look at `IHubContext\u003cT\u003e`\n\n## Task 8: Running a standalone server\nRun a standalone Memstate server by adding a .NET Core console application named `Twitter.Server`, add a reference to the `Memstate.Host` nuget package. In the main method, build and `Start()` a `Host\u003cTwitterModel\u003e` by using the `Memstate.Host.HostBuilder` class.\n\nNow configure the web application to connect to the external server instead of the locally embedded engine. Change the `Type` from Local to Remote on the object returned by calling `Config.Current.GetSettings\u003cClientSettings\u003e()`. `Client.For\u003cTwitter\u003e()` will now return a `RemoteClient\u003cTwitter\u003e` instead of a `LocalClient\u003cTwitter`.\n\nNote: The reactive bits from Task 7 do not work with a remote memstate server.\n\n## Task 9: Using Event Store\nInstall and launch eventstore or run it in a docker container.\nConfigure the server to use the eventstore storageprovider.\n \n## Task 10: Create a docker image\nDockerize the web and/or host app created in task 8.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDevrexLabs%2Fmemstate-tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDevrexLabs%2Fmemstate-tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDevrexLabs%2Fmemstate-tutorial/lists"}