.Net resolving dependency at runtime for return type of method in generic interface

73 Views Asked by At

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;
            }
        }
    }
0

There are 0 best solutions below