The MooVC library contains a collection of functionalities common to many applications, gathered to support the rapid development of a wide variety of applications targeting multiple platforms.
MooVC was originally created as a PHP based framework back in 2009, intended to support the rapid development of object-oriented web applications based on the Model-View-Controller design pattern that were to be rendered in well-formed XHTML. It is from this that MooVC gets its name - the Model-object-oriented-View-Controller.
While the original MooVC PHP based framework has long since been deprecated, many of the lessons learned from it have formed the basis of solutions the author has since developed. This library, and those related to it, are all intended to support the rapid development of high quality software that addresses a variety of use-cases.
Install the core package:
dotnet add package MooVCAdd optional infrastructure packages as needed; each capability below lists extensions that provide additional implementations.
MooVC packages a set of reusable building blocks.
Compression enhances your code by shrinking payloads and eliminating boilerplate through the ICompressor abstraction with built-in Brotli, GZip, and Deflate implementations.
Compress or decompress streams and byte arrays with a single call.
ICompressor provider = new GZipCompressor();
IEnumerable<byte> compressed = await provider.Compress(original, CancellationToken.None);
IEnumerable<byte> restored = await provider.Decompress(compressed, CancellationToken.None);MooVC.Infrastructure.Compression.LZ4– LZ4 compressor implementation for high throughput scenarios
Serialization and cloning streamline the persistence and duplication of complex objects through consistent ISerializer and ICloner interfaces. The core library includes a System.Text.Json implementation and supports optional compression.
Serialize or deserialize objects and create deep clones with a single call.
var serializer = new MooVC.Serialization.Json.Serializer();
IEnumerable<byte> serializedOrder = await serializer.Serialize(purchaseOrder, CancellationToken.None);
Order clonedOrder = await serializer.Deserialize<Order>(serializedOrder, CancellationToken.None);MooVC.Infrastructure.Serialization.Json.Newtonsoft– Newtonsoft.Json serializerMooVC.Infrastructure.Serialization.MessagePack– high performance binary serializerMooVC.Infrastructure.Serialization.Bson.Newtonsoft– BSON serializerMooVC.Infrastructure.Serialization.Apex– Apex binary serializer
Paging slices large data sets into predictable chunks using Directive and Page<T> types, preventing timeouts and lowering memory usage.
Construct a directive and turn queries into pages.
Directive request = new(limit: 25, page: 1);
Page<Customer> customerPage = customerQuery.ToPage(request);Provided in the core library; no additional packages required.
Threading helpers coordinate asynchronous initialization and exclusive access to shared resources, reducing concurrency errors.
Helpers include:
Initializer<T>for asynchronous lazy initializationCoordinator<T>for mutual exclusion by context
var initializer = new Initializer<Configuration>(_ => LoadConfigAsync());
Configuration configuration = await initializer.Initialize(CancellationToken.None);
var coordinator = new Coordinator<string>();
using IContext<string> context = await coordinator.Apply("orders", CancellationToken.None);
// exclusive workProvided in the core library; no additional packages required.
Hosting helpers safely start and stop long-running services across threads.
Helpers include:
ThreadSafeHostedServiceto coordinate multiple hosted services
var service = new ThreadSafeHostedService(example, logger);
await service.StartAsync(CancellationToken.None);
// ...
await service.StopAsync(CancellationToken.None);Provided in the core library; no additional packages required.
LINQ and collection extensions keep queries expressive and succinct. Each extension below targets a common scenario and includes an API-style summary for quick reference.
Conditionally apply a predicate only when a supplied condition is met.
public static IEnumerable<T>? WhereIf<T>(
this IEnumerable<T>? enumeration,
bool isApplicable,
Func<T, bool> predicate)
public static IEnumerable<T>? WhereIf<T>(
this IEnumerable<T>? enumeration,
Func<bool> condition,
Func<T, bool> predicate)enumeration– The sequence to filter.isApplicable/condition– Determines whether the filter is applied.predicate– The condition used to filter items.
- The filtered sequence if the condition is satisfied; otherwise, the original sequence.
IEnumerable<Order> activeOrders = allOrders.WhereIf(
includeOnlyActive,
order => order.IsActive);Execute an action for every element in the sequence, synchronously or asynchronously.
public static void ForAll<T>(this IEnumerable<T>? items, Action<T> action)
public static Task ForAll<T>(this IEnumerable<T>? items, Func<T, Task> operation)items– The sequence of items to iterate.action/operation– The delegate executed for each item.
- A
Taskrepresenting completion for the asynchronous overload; otherwise, nothing.
await activeOrders.ForAll(ProcessOrderAsync);Append additional items to an existing sequence without creating temporary collections.
public static IEnumerable<T> Combine<T>(this IEnumerable<T>? source, T instance)
public static IEnumerable<T> Combine<T>(this IEnumerable<T>? source, IEnumerable<T>? instances)source– The original sequence.instance/instances– Items to append to the sequence.
- A sequence containing the original elements followed by the appended items.
IEnumerable<int> combined = existing.Combine(new[] { 4, 5 });Create a dictionary keyed by values selected from each element.
public static IDictionary<TSubject, TValue> ToIndex<TSubject, TValue>(
this IEnumerable<TSubject>? source,
Func<TSubject, TValue> selector)
public static IDictionary<TSubject, TTransform> ToIndex<TSubject, TTransform, TValue>(
this IEnumerable<TSubject>? source,
Func<TSubject, TValue> selector,
Func<TValue, TTransform> transform)source– The sequence to index.selector– Projects each element into a key.transform– Converts the selected value before insertion.
- A dictionary containing keys and values generated from the sequence.
IDictionary<Guid, Order> orderLookup = allOrders
.ToIndex(order => order.Id);Insert multiple items into an ICollection<T> without manual loops.
public static void AddRange<T>(this ICollection<T> target, IEnumerable<T>? items)target– The collection receiving new items.items– The elements to add to the collection.
- Nothing. The
targetcollection is updated in place.
ICollection<Order> pending = new List<Order>();
pending.AddRange(@new);Clear an ICollection<T> and populate it with a replacement sequence.
public static void Replace<T>(this ICollection<T> target, IEnumerable<T>? replacements)target– The collection whose contents are to be replaced.replacements– The new elements for the collection.
- Nothing. The
targetcollection is overwritten withreplacements.
ICollection<Order> processed = GetExistingOrders();
processed.Replace(latest);Provided in the core library; no additional packages required.
Dynamic and I/O helpers reduce repetitive plumbing when working with dynamic objects, exceptions, and streams.
Utilities for cloning ExpandoObject, navigating exception trees, working with streams, and more.
dynamic cloned = original.Clone();Provided in the core library; no additional packages required.
These features can be adopted piecemeal – pick the utilities that help your project and ignore the rest.
- Accelerated Development – Reuse battle tested helpers instead of re‑implementing common infrastructure.
- Consistency – Uniform APIs for serialization, compression, and coordination keep code bases consistent across projects.
- Productivity – Extension methods and abstractions simplify code, letting software engineers focus on business logic.
Contributions and feedback are welcome.