I'm trying to find the best approach for a logic that is supposed to retrieve data from different sources and combine them into a JSON object.
I was able to make it work by serializing the results of each source and return strings.
Here's a quick example of my solution. Consider that Orders can be retrieved from one system, and Users from another.
public interface IProcessor<IData> {
public string GetData(IData source);
}
public interface IData {
public string Name { get; }
public string ApiUrl { get; }
}
public class OrdersDataProcessor: IProcessor<IData> {
public string GetData(IData source) {
//request data from source
var results = source.ApiUrl;
var data = new object { };
return JsonConvert.SerializeObject(data);
}
}
public class UsersDataProcessor : IProcessor<IData> {
public string GetData(IData source) {
//request data from source
var results = source.ApiUrl;
var data = new object { };
return JsonConvert.SerializeObject(data);
}
}
I can then register these processors with something like
Container.RegisterType<IProcessor<IData>,OrdersDataProcessor>("orders");
Container.RegisterType<IProcessor<IData>,UsersDataProcessor>("users");
There could be many sources of data, so I store a configuration in the database for each combination I want. The last step is to create a service, resolve the dependencies and call the GetData method.
public interface IDataAgreggator {
public IEnumerable<IData> Sources { get; set; }
}
public class ProcessDataService {
private readonly IUnityContainer unity;
public ProcessDataService(IUnityContainer unity) {
this.unity = unity;
}
public void ProcessData(IDataAgreggator agreggator) {
foreach (var source in agreggator.Sources) {
var processor = unity.Resolve<IProcessor>(source.Name);
var data = processor.GetData();
// combine all data and return
}
}
}
The big problem of this strategy is that the DataProcessors are returning strings, and it makes the results very limited. For instance, I want to create json schemas for each return type of GetData. Therefore it would be a lot helpful if there was a way to keep these data processors generic but at the same time with specific types defined in the return type.
I was thinking of something like this
public interface IProcessorWithType<TReturn> {
public TReturn GetData();
}
public class OrderResult { }
public class OrdersDataProcessorWithType : IProcessorWithType<OrderResult> {
public OrderResult GetData() {
//request data from source
var data = new OrderResult { };
return data;
}
}
public class UsersResult { }
public class UsersDataProcessorWithType : IProcessorWithType<UsersResult> {
public UsersResult GetData() {
//request data from source
var data = new UsersResult { };
return data;
}
}
I am struggling to find a way to resolve these dependencies at runtime though. Does anyone have any better idea to solve this problem?
My last attempt was this, but I would still need provide a return type to resolve the dependency here.
public class ResolveTest {
private readonly IUnityContainer unity;
public ResolveTest(IUnityContainer unity) {
this.unity = unity;
}
public void Test() {
var type = typeof(UsersResult);
var processorType = typeof(IProcessorWithType<>).MakeGenericType(type);
var registrations = unity.Registrations.Where(r => r.RegisteredType == processorType);
foreach (var registration in registrations) {
// this does not work
var processor = unity.Resolve(processorType, registration.Name) as IProcessorWithType;
}
}
}