SeedPacket Illustration

SeedPacket 2.0

Created by Will Crowther


SeedPacket is for quickly seeding data in .net for graphic mockups, Rapid Application Development (RAD), unit testing, prototyping, data generation, database seeding, and unit testing. Written in C#, it is easy to use, with a customizable, and powerful rules engine that can pull data from an external source such as an Xml/Json file or string.

How It Works

Similar to a LINQ statement, SeedPacket adds a .seed() extension method onto IEnumerable that fills the list with fully populated elements. The rules engine keys off the datatype or interface, and name of an item's properties so that the instance is filled with data that is appropriate to that type. That is to say, "out-of-the-box", email properties will be filled with valid emails, phone numbers filled with phone numbers, and names are names etc.

By default, the rules engine loads up about 30 rules for common situations and will degrade to more generic rules if necessary. If you need to modify the default generated data, the rules are simple to create and modify, and come with a many examples, including using a data generator that pulls from an external source. The randomly generated data can be set to always be static across requests or to be random for each time.

The SeedPacket source code is available on GitHub.

Install SeedPacket using the Nuget Package Manager in Visual Studio.
From the Package Manager Console type: PM> Install-Package SeedPacket
For more details:

Simple Examples

Creating seed data is as simple as importing SeedPacket from Nuget, adding the SeedPacket.Extensions namespace, and calling .Seed() on an existing an IEnumerable such as List, etc. The table on the right was generated the code in the second example below.

Be sure to import the SeedPacket.Extensions namespace.
// Example 'User' Class public class User { public int UserId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } public DateTime Created { get; set; } } // Creates 10 rows (default) var users = new List<User>().Seed(); // Create 20 rows (shown to right) var users = new List<User>().Seed(20); // Create rows starting with 100 to 200 var users = new List<User>().Seed(100, 200);

You can change the number of rows generated by changing the "rows" number to the right and the page will use javascript to fetch a new list of users generated by SeedPacket on the server. Note that even though the seed records are "randomly" generated, the list begins with the same results on subsequent iterations. This is because we are passing in the same random "seed" integer by default. Now change the "seed" number to the right and you will see that the generated data is always the same for a particular number.

You will see how this can be easily customized when we update what data is generated with some custom rules in the Rules engine. The base data is taken from an embedded datasource, which can be easily overridden with an external XML / Json string or file.

Notice how the seed data generated are well-formed usernames and email addresses. The default rules finds that the property type is a "string" and property contains "email" and "username" and generates the appropriate data, including generating the username from the firstname and lastname. Other data types such as the DateTime "Created" or an Int Id are also be created. The rules match first on data-type, then on match on property name with a last-added prioritization.

What happens when you have a field name and/or datatype is not that common? Generally, the basic rules will catch common patterns and use a simple pattern such as the default of Property Name + the RowNumber for string. If there is not even a basic rule for a particular match, generally the type default is returned.

Of course, the real flexibility comes from being able to easily add your own custom rules. We will get to that in the next section, but lets first look at a more advanced example.

UserId FirstName LastName Email Created
1 Tiffany Robinson 07/26/2019
2 Robert Miller 07/06/2018
3 Nicholas Green 09/25/2020
4 Jacqueline Lopez 07/22/2020
5 Mary Davis 06/06/2018
6 Treymayne Hill 08/19/2020
7 Omar Roberts 06/05/2021
8 Courtney Carter 02/26/2021
9 Jesse Walker 12/13/2019
10 Naomi Parker 09/06/2021
11 Zoey Edwards 11/13/2021
12 --- Collins 12/26/2021
13 Denise Martin 03/15/2019
14 Janice Rodriguez 09/11/2019
15 Patricia Johnson 02/12/2018
16 Crystal Turner 06/15/2021
17 John Smith 01/17/2018
18 Jennifer Gonzalez 01/12/2021
19 Theresa Perez 04/26/2021
20 Gary Hernandez 04/25/2020
When to use SeedPacket?

You will find that SeedPacket is the most useful when you are in the initial stages of a project and want to rapidly change the structure of data classes without actually having to worry about the data contained in those classes.

A typical development workflow may be:

1. Stub out lists of data using the .Seed method to fill in the structure for your project

2. Create custom Rules to fill in and generate realistic data for mockups and presentations

3. Use SeedPacket for test doubles in your unit tests if desired

4. Migrate to an ORM (Object-Relational Mapping) framework, like Entity Framework, and seed the database using the rules you have created

Designers and UI/UX Developers can focus on designing without worrying about how changes to underlying models and data are affecting their prototypes!

This example passes in 5 additional custom rules into the Rules engine
var generator = new MultiGenerator("~/SourceFiles/xmlSeedSourcePlus.xml") { Rules = { new Rule(typeof(string), "ItemName", g => Funcs.GetNextElement(g, "ProductName"), "ItemName"), new Rule(typeof(int), "SelectedProduct", g => g.RowRandom.Next(0, 11), "Random product id"), new Rule(typeof(string), "Ceo", g => Funcs.GetNextElement(g, "FirstName") + " " + func.NextElement(g, "LastName"), "Random CEO Name"), new Rule(typeof(string),"Description%", g => Funcs.GetRandomElement(g, "Description"), "Description", "Gets Description from custom XML file" ), new Rule(typeof(List<Item>), "", g => Funcs.GetCacheItemsNext<Item>(g, g.Cache.Items, 10, 10, false), "ItemList"), }, BaseDateTime = DateTime.Today, BaseRandom = new Random(1234567) }; generator.Cache.Items = new List<Item>().Seed(1, 10, generator); var examples = new List<Example>().Seed(100, 115, generator);

Advanced Example

For more advanced situations, you can pass in a generator class that contains a customizable rules engine. By default, the "Advanced" ruleset is used which contains about thirty common rules and the data is loaded from an internal resource. In the example below a "MultiGenerator" is injected into the Seed method. We are adding five new rules to modify how the data is created.

The first rule applies to the "ItemName" field uses a built-in seedpacket function (Func) that gets the next element from the datasource list "ProductName". It actually overrides a rule that gets random (fake) products and replaces it with one that gets the next item in the sequence. This insures the values will all be unique, if the number of items requested is less than in the source.

The second rule, randomly picks a selected value for the dropdown from 0 to 10 (the C# Random() method picks values less than the max value).

The third rule, randomly picks a first and last name for any string fields matching "CEO"

The fourth rule, matches any string starting with "Description" and gets a random value from the datasoure called "Description". This is not in the default lists that are "built-in" in SeedPacket. In the constructor for the MultiGenerator, you will see that we are now passing in a custom xml file that has all the source data for our lists. Now we have complete control of our source data and Funcs.RandomElement() can pull from any named element.

The fifth custom rule is the most interesting and makes sure that any List<Item> fields are filled from a generated list that has been saved in the generator's Cache. We can populate this generated list from another .Seed call and this allows us to have complex, hierarchical data when needed. Note how we can initially declare the rules, but then need to make sure we fill the cached data before the rules are actually run.

Lastly, notice how we are setting the BaseDateTime value. This can be used as the starting point for all DateTimes that we generate. We are also setting the BaseRandom value. This is the base of the "Random Tree" that all the other randoms such as the RowRandom property use as theire starting point. If we pass in a Random without a seed value, every call will generate different values. If we pass in a Random with a seed value, the data generated will always be the same. We can always pass in a different number seed number if we do not like the data that we get...

Id Company City State CEO NetWorth Products Description CompanyGuid
100 Next Ind Franklin TN Collins $831.29M Bumpy 69985f02-f418-e67d-a3ec-6fcefd2001ab
101 Primo Industries WestLake OK John Smith $701.28M Square, man e8416547-6668-e2e1-152e-046a52ed3b2d
102 Tyrell York IN Patricia Johnson $264.05M Smelly but good 754e3baf-9fca-5f4c-9981-b8759aca2769
103 Oscorp Co London IA Michael Williams $286.25M Awful cb01bfae-ebd2-a1e3-2765-abf23b5ebe8d
104 Acme Greenville AL Susan Jones $11.40M Rich! c080c8f8-82a6-20b0-9160-ed0afce0df14
105 More Co Peachtree LA William Brown $341.35M Who knows 05f29e93-e410-3238-1d7f-2841653cac9b
106 City Inc Westmoor WI Mary Davis $969.97M It was kinda big 0cd0e348-25bd-1aea-3180-cc870fbdd105
107 Stark Pinetown GA Robert Miller $190.00M Yellow, definitely yellow 56732497-2fcb-78b1-821f-356ec4a825bf
108 Umbrella Co HillTown MI Sarah Wilson $431.56M Hairy and green 249b6cce-887a-bbf2-3462-34330f274e33
109 More Co Peachtree KY Peter Moore $332.15M Midnight blue 89e44f94-082d-fae0-349e-b3b7fbf997f2
110 Wonka Lincolnton CT Ann Taylor $120.69M Itty bitty 4f0868d4-296f-f759-4c4e-66b846e278c2
111 Umbrella Co HillTown MA Roger Anderson $417.13M Funny to look at 11d6c9f1-64c6-f536-45c0-95cf3ea0098c
112 Stark Pinetown FL Theresa Thomas $176.89M Pointy 413e0a09-9e91-7c81-6dff-46fe88f4a9c0
113 CyberGlobe Industries Sierra ND Ethan Jackson $668.54M Fresh 15b91e2e-ba75-c48c-8473-c6eafac60f6b
114 Nakatomi Co Brighton ME Crystal White $372.35M Arkward bbc86352-6e94-6467-5da1-07b76243e0a7
115 Stark Pinetown GA Phillip Harris $198.34M Bumpy e4f77a4d-639d-822a-35b8-8c1b450efb5c

© 2018 Will Crowther - SeedPacket