diff --git a/Source/Kernel/Concepts/Jobs/IJobTypes.cs b/Source/Kernel/Concepts/Jobs/IJobTypes.cs
index 1d2b44bf0..2b2c18240 100644
--- a/Source/Kernel/Concepts/Jobs/IJobTypes.cs
+++ b/Source/Kernel/Concepts/Jobs/IJobTypes.cs
@@ -55,4 +55,11 @@ enum GetForError
/// The .
/// or .
Result GetRequestClrTypeFor(JobType type);
+
+ ///
+ /// Gets the job request associated with the .
+ ///
+ /// The job request clr type.
+ /// or .
+ Result GetJobClrTypeFromRequestClrType(Type jobRequestClrType);
}
diff --git a/Source/Kernel/Grains/Jobs/JobTypes.cs b/Source/Kernel/Grains/Jobs/JobTypes.cs
index bd62ae88f..29db45b3e 100644
--- a/Source/Kernel/Grains/Jobs/JobTypes.cs
+++ b/Source/Kernel/Grains/Jobs/JobTypes.cs
@@ -17,6 +17,7 @@ public class JobTypes : IJobTypes
readonly Dictionary _jobTypes = [];
readonly Dictionary _jobTypePerType = [];
readonly Dictionary _jobRequestTypes = [];
+ readonly Dictionary _jobRequestTypeToJobType = [];
///
/// Initializes an instance of the class.
@@ -56,6 +57,14 @@ public class JobTypes : IJobTypes
: IJobTypes.GetRequestClrTypeForError.CouldNotFindType;
}
+ ///
+ public Result GetJobClrTypeFromRequestClrType(Type jobRequestClrType)
+ {
+ return _jobRequestTypeToJobType.TryGetValue(jobRequestClrType, out var jobClrType)
+ ? jobClrType
+ : IJobTypes.GetRequestClrTypeForError.CouldNotFindType;
+ }
+
void InitializeMap(ITypes types)
{
PopulateJobTypes(types);
@@ -64,7 +73,9 @@ void InitializeMap(ITypes types)
void PopulateJobTypes(ITypes types)
{
- foreach (var jobClrType in types.FindMultiple().Where(type => type is { IsClass: true, IsAbstract: false } && type != typeof(NullJob)))
+ foreach (var jobClrType in types.FindMultiple()
+ .Where(type => type is { IsClass: true, IsAbstract: false, IsInterface: false, IsGenericType: false }
+ && type != typeof(NullJob) && type.Assembly.FullName != typeof(IJob).Assembly.FullName))
{
var jobTypeAttribute = jobClrType.GetCustomAttribute();
var jobType = jobTypeAttribute?.JobType ?? jobClrType;
@@ -95,7 +106,9 @@ void PopulateJobRequestTypes()
throw new JobTypeMustHaveARequestType(jobType, jobClrType);
default:
// First generic argument of IJob is the type of the request
- _jobRequestTypes.Add(jobType, jobInterfaces[0].GetGenericArguments()[0]);
+ var requestType = jobInterfaces[0].GetGenericArguments()[0];
+ _jobRequestTypes.Add(jobType, requestType);
+ _jobRequestTypeToJobType.Add(requestType, jobClrType);
break;
}
}
diff --git a/Source/Kernel/Storage.MongoDB/Jobs/JobStateSerializer.cs b/Source/Kernel/Storage.MongoDB/Jobs/JobStateSerializer.cs
index 3a5199890..e6dba98c0 100644
--- a/Source/Kernel/Storage.MongoDB/Jobs/JobStateSerializer.cs
+++ b/Source/Kernel/Storage.MongoDB/Jobs/JobStateSerializer.cs
@@ -1,9 +1,11 @@
// Copyright (c) Cratis. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using Cratis.Applications.MongoDB;
using Cratis.Chronicle.Concepts.Jobs;
using Cratis.Chronicle.Storage.Jobs;
using Cratis.Strings;
+using Microsoft.Extensions.DependencyInjection;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
@@ -15,21 +17,67 @@ namespace Cratis.Chronicle.Storage.MongoDB.Jobs;
/// The .
public class JobStateSerializer(IJobTypes jobTypes) : SerializerBase
{
+ public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, JobState value)
+ {
+ var requestType = value.Request.GetType();
+ var requestSerializer = BsonSerializer.SerializerRegistry.GetSerializer(requestType);
+ }
///
public override JobState Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
+ var jobRequestElementName = nameof(JobState.Request).ToCamelCase();
var rawBsonDocument = context.Reader.ReadRawBsonDocument();
using var rawDocument = new RawBsonDocument(rawBsonDocument);
+ rawDocument.Remove(jobRequestElementName);
var bsonDocument = rawDocument.ToBsonDocument();
var jobTypeString = bsonDocument.GetValue(nameof(JobState.Type).ToCamelCase()).AsString;
var jobRequestType = jobTypes.GetRequestClrTypeFor(new(jobTypeString)).AsT0;
- var jobRequestElementName = nameof(JobState.Request).ToCamelCase();
var request = (IJobRequest)BsonSerializer.Deserialize(
bsonDocument.GetElement(jobRequestElementName).ToBsonDocument(),
jobRequestType);
- bsonDocument.Remove(jobRequestElementName);
+ // bsonDocument.Remove(jobRequestElementName);
var jobState = BsonSerializer.Deserialize(bsonDocument);
jobState.Request = request;
return jobState;
}
-}
\ No newline at end of file
+}
+
+public class JobRequestSerializer(IJobTypes jobTypes) : SerializerBase
+ where TJobRequest : IJobRequest
+{
+ ///
+ public override TJobRequest Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
+ {
+ var rawBsonDocument = context.Reader.ReadRawBsonDocument();
+ using var rawDocument = new RawBsonDocument(rawBsonDocument);
+ var bsonDocument = rawDocument.ToBsonDocument();
+ return BsonSerializer.Deserialize(bsonDocument);
+ }
+}
+
+///
+/// Represents a for concepts.
+///
+public class JobRequestSerializationProvider(IServiceProvider serviceProvider) : IBsonSerializationProvider
+{
+ ///
+ /// Creates an instance of a serializer of the concept of the given type param T.
+ ///
+ /// The Concept type.
+ /// for the specific type.
+ public static JobRequestSerializer CreateSerializer(IServiceProvider serviceProvider)
+ where T : class, IJobRequest
+ => ActivatorUtilities.CreateInstance>(serviceProvider);
+
+ ///
+ public IBsonSerializer GetSerializer(Type type)
+ {
+ if (type.IsAssignableTo(typeof(IJobRequest)))
+ {
+ var createSerializerMethod = GetType().GetMethod(nameof(CreateSerializer))!.MakeGenericMethod(type);
+ return (createSerializerMethod.Invoke(null, [serviceProvider]) as IBsonSerializer)!;
+ }
+
+ return null!;
+ }
+}