AKlaus / DomainResult

Tiny package for decoupling domain operation results from IActionResult and IResult types of ASP.NET Web API
Apache License 2.0
53 stars 3 forks source link

Serialization Support #74

Open reactmanju opened 3 weeks ago

reactmanju commented 3 weeks ago

How can we Deserialize DomainResults.Common.DomainResult as it does not contain default constructor. Can serialization will be supported?

reactmanju commented 3 weeks ago

I am developing a Caching Behavior using mediatR as below to intercept (Pre-Processor) the call to a request Handler

public class CachingBehaviour <TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : MediatR.IRequest where TResponse : IDomainResultBase

My Request object is below

public class GetAllEmploymentTypesQuery : IRequest<IDomainResult<IEnumerable< EmploymentType >>>, ICachable

Definition of Request Handler is as below

public class GetAllEmploymentTypesQueryHandler : IRequestHandler<GetAllEmploymentTypesQuery, IDomainResult<IEnumerable< EmploymentType >>>

In the request handler I return return DomainResult.Success<IEnumerable< EmploymentType >> (result.ToList());

Within the CachingBehaviour I would like to serialize and deserialize the DomainResult<IEnumerable< EmploymentType >>, I am having issues while Deserializing. Any suggestions on how to achieve this will help a lot.

AKlaus commented 3 weeks ago

Hey, As I understand, you're using the MediatR.Extensions.Caching extension and the distributed cache (as the MemoryCache doesn't require serialisation). As the IDistributedCache relies on binary serialisation (with classes marked by the [Serializable] attribute), the topic here is "Implementing binary serialisation for the MediatR caching integration". Correct me here if I'm wrong.

1. Potential implementation

The main obstacle here is that the IDomainResult<T> type is essentially a wrapper on the object, the IEnumerable<EmploymentType> in your case, which caries

Hence, to serialise the IDomainResult<T>, all the nested T's must also be serializable. I'm hesitant to enforce this constraint, as it'd over-complicate the primary use case, but it can be left unenforced (if the T can't be serialised, then the operation would just fail).

So, the solution you're after would be a special IDistributedCache implementation for all the domain result types (IDomainResult, IDomainResult<T> along with tuples (T, IDomainResult)) and an extension method to register it.
Perhaps IMemoryCache and HybridCache should also be added to the pot.

Does it sound about right?

2. Potential alternative options for your case

Perhaps the fastest (and independent) option for IDomainResult<T> caching in MediatR would be implementing a bespoke CachingBehavior class that caches/serialises the T, IDomainResult.Status and IDomainResult.Errors. On resolving the value from the cache, it could form the IDomainResult<T> instance by calling something like

IDomainResult<T> ResolveFromCache<T>()
{
   // 1. Get the `value` (type of T), `status` (type of IDomainResult.Status) and the `errors` (type of IDomainResult.Errors)
   ....
   // 2. Form the required type by leveraging the implicit operator https://github.com/AKlaus/DomainResult/blob/7d82bc63d46871522882e3b457d0a0caf109b382/src/Common/DomainResultOfT.cs#L75
   return (value, new DomainResult(status, errors))
}

A more straightforward option could be caching just the T for successful requests only, as the failure can have intermittent and circumstantial causes.

Let me know if these are viable directions.