Structuring projects in a solution for interfaces

I had this idea that I would achieve some good automation and separation of concerns as follows:

  1. Define an interface, IDataProvider, in a class in a DataMuncher project that needs to both consume and output data.
  2. In separate projects, have different implementations of that interface, e.g., in LunarData.csproj would be LunarDataProvider : IDataProvider, and in SolarData.csproj would be SolarDataProvider : IDataProvider.
  3. In DataMuncher, reflect over the assembly and linked assemblies and find all classes implementing IDataProvider.
  4. Create instances of the IDataProvider-implementing classes that were found, ask them what data they can provide, and if their data matches up with what was similarly learned from IDataConsumer classes, request the appropriate data, and send it onward to the consumers.

The idea is that if I need to add a new data provider, I can do so with only the barest touch on any other projects. I just create a new project, add a class that implements IDataProvider, and whether I’m manufacturing the data (as might occur in a unit test), reading from a text file, connecting to a database, or calling a web API, or any other means of getting the data, as long as I return it in the form required by the interface, it can be consumed. Thus, the quirks of the data are not exposed to the rest of the system and no proper nouns are propagated to other parts when they shouldn’t be.

However, I’ve run into a wee bit of a problem where the provider classes need to depend on the DataMuncher, but the DataMuncher needs to depend on the provider classes (in order to do what ultimately amounts to self dependency-injection).

So for this scenario to work I need at least 3 projects: one where the interface is defined, one where it’s implemented (dependent), and one that is dependent on both of them that does what amounts to dependency injection, call this the DataHub project. But that seems like a lot of complexity.

One suggestion was made to just put the interface definition and the data source implementations all in the same project. This would enable the implementing project to have no outside dependencies, and would avoid the need for another coordinating project to which many projects must refer. It also reduces the number of projects in the solution, which is also a possible benefit. (E.g., DataProviders.cs would have all three: IDataProvider plus LunarDataProvider and SolarDataProvider.

What would you do in this scenario? I saw value in having one project per implementation, but I have to admit that I don’t have a plethora of experience with various project structures that would have given me an idea of what works best. I also saw value in the division between projects forcing the separation of implementation internals from other projects, so that no one implementation would ever, even by mistake, use code or classes from another implementation. With one project each, a review of the project reference dependency graph could easily establish that the separate implementations are properly isolated from each other. This makes sure the code is truly modular and properly encapsulated.

Another benefit of separate projects is that if the data source doesn’t need to access, say, a database, there are no references to database libraries. Perhaps it’s file-based, and doesn’t need any dependencies. Then, the reference graph can be examined for correctness and anything strange will stick out much better: rather than “hmmm, I guess one of the 10 implementations uses that library”, “why is X using Y!?!”

I also considered, still with three projects, defining the interface in the DataHub, but this would prevent it, due to circular reference problems, from doing the reflection to find data sources—the recipient of the benefit of the interface, DataMuncher, would have to perform that task, and instead of LunarData having a reference to DataMuncher, it would be the other way around. This is now more references, and the DataHub class now also has to have a lot of projects referencing it (again, instead of the other way around). All these extra references suggest that perhaps the single project with interface and implementations is better.

Some guidance or ideas would be appreciated.

Hmmmm … it just occurred to me, 20 minutes after posting, that perhaps I should simply use a dependency injection library. That would use a pattern that is well established, and would remove some of the questions by reducing the number of reasonable ways to structure things. Still thinking on this …

For Reference

First we go fetch all the types available in all referenced assemblies that implement IDataProvider:

var types = GetType()
   .Assembly
   .GetReferencedAssemblies()
   .SelectMany(assemblyName => Assembly.Load(assemblyName).GetTypes())
   .Where(type => (typeof (IDataProvider)).IsAssignableFrom(type))
   .ToList();

Then we can create instances of these:

var instantiatedTypes = types
   .Select(Activator.CreateInstance)
   .ToList()
   .AsReadOnly();

This list of instantiated types then need to be passed to the core of the system, as a parameter to the DataMuncher class (or perhaps a method).

public sealed class DataMuncher {
   public DataMuncher(
      IEnumerable<IDataProvider> dataProviders,
      IEnumerable<IDataConsumer> dataConsumers
   ) {
      var consumersAndData = dataConsumers
         .Select(consumer => new { consumer, dataspec = consumer.GetDesiredDataSpecification() })
         .Select(cas => new {
            cas.consumer,
            cas.dataspec,
            data = dataProviders
               .Select(provider => provider.RetrieveData(cas.dataspec))
         })
         .ToList();
      consumersAndData.ForEach(cas => cas.consumer.ReceiveData(cas.data));
   }
}

This is very rough, just to show the idea. Don’t bother code reviewing this particular code, it is only here to show the basic idea and get assistance in how to structure the interfaces.

Note: I have been reading .Net solution structure of an enterprise application and it is possibly helping, but I don’t have a conclusion yet.

3

You can have one project holding the DataMuncher and the IDataProvider. Reference it from one or more Data Provider projects, implement the IDataProvider there.

From your application’s composite root have the concrete Data Provider injected into your DataMuncher before use.

What is not clear from your post is why DataMuncher was/is dependant on the Data Providers. If you invert this dependency properly things would get simple. DataMuncher defines the contract, the Data Provider project(s) provide an implementation.

Your app’s composition root configures when to use which implementation.

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật