diff --git a/docs/site/Writerside/hi.tree b/docs/site/Writerside/hi.tree
index 06da2666e6..c368d48fd6 100644
--- a/docs/site/Writerside/hi.tree
+++ b/docs/site/Writerside/hi.tree
@@ -16,6 +16,8 @@
+
+
@@ -28,6 +30,7 @@
+
diff --git a/docs/site/Writerside/images/return-from-web-api.png b/docs/site/Writerside/images/return-from-web-api.png
new file mode 100644
index 0000000000..9d6a438e03
Binary files /dev/null and b/docs/site/Writerside/images/return-from-web-api.png differ
diff --git a/docs/site/Writerside/images/swagger-json-parameter.png b/docs/site/Writerside/images/swagger-json-parameter.png
new file mode 100644
index 0000000000..7ab56fa7bd
Binary files /dev/null and b/docs/site/Writerside/images/swagger-json-parameter.png differ
diff --git a/docs/site/Writerside/redirection-rules.xml b/docs/site/Writerside/redirection-rules.xml
index 68d0d79f6a..a892e386b4 100644
--- a/docs/site/Writerside/redirection-rules.xml
+++ b/docs/site/Writerside/redirection-rules.xml
@@ -50,4 +50,8 @@
Created after removal of "How to create Value Objects" from Vogen
Basics.html
+
+ Created after removal of "Working with protobuf" from Vogen
+ Working-with-protobuf.html
+
\ No newline at end of file
diff --git a/docs/site/Writerside/topics/Use-in-Swagger.md b/docs/site/Writerside/topics/Use-in-Swagger.md
new file mode 100644
index 0000000000..1f3e4ce887
--- /dev/null
+++ b/docs/site/Writerside/topics/Use-in-Swagger.md
@@ -0,0 +1,82 @@
+# Use in Swagger
+
+You can use Vogen types as parameters in ASP.NET Core Web API endpoints.
+That is because the .NET runtime will notice the `TypeConverter` that is generated by default, and use that to try
+to convert the underlying type (e.g. `string` or `int`) to the value object.
+
+However, Swagger treats value object fields as JSON, e.g. given this method:
+
+```C#
+[HttpGet("/WeatherForecast/{cityName}")]
+public IEnumerable Get(CityName cityName)
+{
+ ...
+}
+```
+
+... You can use it (e.g. at `http://localhost:5053/WeatherForecast/London`) without having to do anything else,
+but Swagger will show the field as JSON instead of the underlying type:
+
+
+
+To fix this, add this to your project:
+
+```C#
+public class VogenSchemaFilter : ISchemaFilter
+{
+ public void Apply(OpenApiSchema schema, SchemaFilterContext context)
+ {
+ if (context.Type.GetCustomAttribute() is not { } attribute)
+ return;
+
+ // Since we don't hold the actual type, we ca only use the generic attribute
+ var type = attribute.GetType();
+
+ if (!type.IsGenericType || type.GenericTypeArguments.Length != 1)
+ {
+ return;
+ }
+
+ var schemaValueObject = context.SchemaGenerator.GenerateSchema(
+ type.GenericTypeArguments[0],
+ context.SchemaRepository,
+ context.MemberInfo, context.ParameterInfo);
+
+ CopyPublicProperties(schemaValueObject, schema);
+ }
+
+ private static void CopyPublicProperties(T oldObject, T newObject) where T : class
+ {
+ const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
+
+ if (ReferenceEquals(oldObject, newObject))
+ {
+ return;
+ }
+
+ var type = typeof(T);
+ var propertyList = type.GetProperties(flags);
+ if (propertyList.Length <= 0) return;
+
+ foreach (var newObjProp in propertyList)
+ {
+ var oldProp = type.GetProperty(newObjProp.Name, flags)!;
+ if (!oldProp.CanRead || !newObjProp.CanWrite) continue;
+
+ var value = oldProp.GetValue(oldObject);
+ newObjProp.SetValue(newObject, value);
+ }
+ }
+}
+```
+
+... and then, when you register Swagger, tell it to use this new filter:
+
+```C#
+builder.Services.AddSwaggerGen(opt => opt.SchemaFilter());
+```
+Many thanks to [Vitalii Mikhailov](https://github.com/Aragas) for this contribution.
+
+
+Although this is currently a manual step, it is intended for this to be put into a NuGet package at some point.
+
\ No newline at end of file
diff --git a/docs/site/Writerside/topics/Using-with-JSON.md b/docs/site/Writerside/topics/Using-with-JSON.md
new file mode 100644
index 0000000000..b240fdcbb9
--- /dev/null
+++ b/docs/site/Writerside/topics/Using-with-JSON.md
@@ -0,0 +1,16 @@
+# Working with JSON
+
+
+This documentation is currency incomplete and is being improved.
+
+
+As well as System.Text.Json (STJ), Vogen also generates the code to work with Newtonsoft.Json (NSJ)
+
+They are controlled by the `Conversions` enum. The following has serializers for NSJ and STJ:
+
+```c#
+[ValueObject(conversions: Conversions.NewtonsoftJson | Conversions.SystemTextJson)]
+public readonly partial struct Celsius { }
+```
+
+See the examples folder for more information.
diff --git a/docs/site/Writerside/topics/Working-with-databases.md b/docs/site/Writerside/topics/Working-with-databases.md
new file mode 100644
index 0000000000..3ebb581ab0
--- /dev/null
+++ b/docs/site/Writerside/topics/Working-with-databases.md
@@ -0,0 +1,30 @@
+# Working with databases
+
+
+This documentation is currency incomplete and is being improved.
+
+
+There are other converters/serializer for:
+
+* Dapper
+* EFCore
+* [LINQ to DB](https://github.com/linq2db/linq2db)
+
+They are controlled by the `Conversions` enum. The following has serializers for NSJ and STJ:
+
+```c#
+[ValueObject(conversions: Conversions.NewtonsoftJson | Conversions.SystemTextJson, underlyingType: typeof(float))]
+public readonly partial struct Celsius { }
+```
+
+If you don't want any conversions, then specify `Conversions.None`.
+
+If you want your own conversion, then again specify none, and implement them yourself, just like any other type. But be aware that even serializers will get the same compilation errors for `new` and `default` when trying to create VOs.
+
+If you want to use Dapper, remember to register it—something like this:
+
+```c#
+SqlMapper.AddTypeHandler(new Customer.DapperTypeHandler());
+```
+
+See the examples folder for more information.
diff --git a/docs/site/Writerside/topics/reference/Integration.md b/docs/site/Writerside/topics/reference/Integration.md
index df2ed83b07..3acbf95d5d 100644
--- a/docs/site/Writerside/topics/reference/Integration.md
+++ b/docs/site/Writerside/topics/reference/Integration.md
@@ -68,3 +68,33 @@ public enum Conversions
```
The default, as specified above in the `Defaults` property, is `TypeConverter` and `SystemTextJson`.
+
+
+-- todo: merge this in:
+
+There are other converters/serializer for:
+
+* Newtonsoft.Json (NSJ)
+* Dapper
+* EFCore
+* [LINQ to DB](https://github.com/linq2db/linq2db)
+* protobuf-net (see the FAQ section below)
+
+They are controlled by the `Conversions` enum. The following has serializers for NSJ and STJ:
+
+```c#
+[ValueObject(conversions: Conversions.NewtonsoftJson | Conversions.SystemTextJson, underlyingType: typeof(float))]
+public readonly partial struct Celsius { }
+```
+
+If you don't want any conversions, then specify `Conversions.None`.
+
+If you want your own conversion, then again specify none, and implement them yourself, just like any other type. But be aware that even serializers will get the same compilation errors for `new` and `default` when trying to create VOs.
+
+If you want to use Dapper, remember to register it—something like this:
+
+```c#
+SqlMapper.AddTypeHandler(new Customer.DapperTypeHandler());
+```
+
+See the examples folder for more information.
diff --git a/docs/site/Writerside/topics/tutorials/Serialization.md b/docs/site/Writerside/topics/tutorials/Serialization.md
index 64d9047616..d3c23a4de7 100644
--- a/docs/site/Writerside/topics/tutorials/Serialization.md
+++ b/docs/site/Writerside/topics/tutorials/Serialization.md
@@ -1,28 +1,100 @@
-# Serializing and persisting
+# Working with ASP.NET Core
-By default, each VO is decorated with a `TypeConverter` and `System.Text.Json` (STJ) serializer. There are other converters/serializer for:
+In this tutorial, we'll create a type and see how to serialize and deserialize it.
-* Newtonsoft.Json (NSJ)
-* Dapper
-* EFCore
-* [LINQ to DB](https://github.com/linq2db/linq2db)
-* protobuf-net (see the FAQ section below)
+First, create a value object:
-They are controlled by the `Conversions` enum. The following has serializers for NSJ and STJ:
+```C#
+[ValueObject]
+public partial struct CustomerId { }
+```
+
+In the `ValueObject`, we don't specify any additional configuration other than the underlying primitive that is
+being wrapped.
+We'll see shortly how to add this configuration, but for now, we'll look at the default configuration
+and what it allows us to do.
+
+By default, each value object generates a `TypeConverter` and `System.Text.Json` (STJ) serializer.
+We can see this from the following snippet of generated code:
+
+```C#
+[global::System.Text.Json.Serialization.JsonConverter(typeof(CustomerIdSystemTextJsonConverter))]
+[global::System.ComponentModel.TypeConverter(typeof(CustomerIdTypeConverter))]
+public partial struct CustomerId
+{
+}
+```
+
+'Type Converters' are used by the .NET runtime in things like ASP.NET Core Web Applications, grids, and WPF bindings.
+Let's see how that works in a web API project.
+
+Create a new ASP.NET Core Web API targeting .NET 7.0. In the project, look at the endpoint named `GetWeatherForecast` in
+the `WeatherForecastController` type. It looks like this:
+
+```C#
+[HttpGet(Name = "GetWeatherForecast")]
+public IEnumerable Get()
+{
+ ...
+}
+```
+
+To demonstrate how we can use Value Objects, we'll add a `CityName` value object and use it as part of the request.
+
+Create a `CityName` type:
```c#
-[ValueObject(conversions: Conversions.NewtonsoftJson | Conversions.SystemTextJson, underlyingType: typeof(float))]
-public readonly partial struct Celsius { }
+[ValueObject]
+public partial struct CityName { }
```
-If you don't want any conversions, then specify `Conversions.None`.
+... now, add this as a parameter to the endpoint:
+```C#
+ [HttpGet("/WeatherForecast/{cityName}")]
+ public IEnumerable Get(CityName cityName)
+ {
+ }
+```
+
+Add a `CityName` property to the `WeatherForecast` type:
+
+```C#
+public class WeatherForecast
+{
+ public CityName CityName { get; set; }
+
+ public DateOnly Date { get; set; }
-If you want your own conversion, then again specify none, and implement them yourself, just like any other type. But be aware that even serializers will get the same compilation errors for `new` and `default` when trying to create VOs.
+ ...
+```
-If you want to use Dapper, remember to register it—something like this:
+Now, change the code in the endpoint to populate the new `CityName` property.
+We're keeping things simple and just returning what we were provided:
```c#
-SqlMapper.AddTypeHandler(new Customer.DapperTypeHandler());
+return Enumerable.Range(1, 5).Select(index => new WeatherForecast
+ {
+ + CityName = cityName,
+ Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
+ TemperatureC = Random.Shared.Next(-20, 55),
+ Summary = Summaries[Random.Shared.Next(Summaries.Length)]
+ })
+ .ToArray();
```
-See the examples folder for more information.
+You can now access that via the URL and treat the value object as a string,
+e.g. `http://localhost:5053/WeatherForecast/London`
+
+You should see the City returned, something like this:
+
+
+
+
+
+You'll need to replace for 5053 to whatever is specified in the project just created, which can be
+found in launchSettings.json.
+
+Also, you'll see that Swagger treats cityName as a JSON field. This can be changed as detailed in [this How-to article](Use-in-Swagger.md).
+
+
+