12

Assume an application with a layered architecture, i.e. presentation, business/domain/logic, data access: it makes sense to plug access to external APIs in at the data layer if what they do resembles data operations. For instance, a DLL that simply performs CRUD operations against a particular data repository would go in the data access layer.

What I'm a little confused about is where to incorporate actions that don't perform data operations in the strict sense, i.e. they perform operations that somewhat resemble "data" in a more-loose sense because they work on remote or networked resources. Here are a few examples:

  • a web service that downloads a PDF of a SQL Server Reporting Services (SSRS) report.
  • a library that sends email via SMTP or connects to a Microsoft Exchange mailbox and downloads messages in a folder structure
  • direct interactions with the file system, such as writing to a log file, using built-in programming language functionality

I'm tempted to put these in the data layer since a lot of resources I've read indicate this. For instance, this MSDN article about "Data Layer Guidelines" has both "Data Sources" and "Services" hanging off the data layer, and it states about "Services":

When a business component must access data provided by an external service, you might need to implement code to manage the semantics of communicating with that particular service. Service agents implement data access components that isolate the varying requirements for calling services from your application, and may provide additional services such as caching, offline support, and basic mapping between the format of the data exposed by the service and the format your application requires.

However, this is talking about external services which are specifically performing data operations and makes no mention of the other types of somewhat-data-like operations like I have listed above.

The alternative is to put the them into the business or domain logic layer, but it doesn't feel right to be accessing external network or server resources like this from the business or domain logic layer.

Can someone please offer guidance or some of their experiences on this topic?

4 Answers 4

11
+50

It sounds like you're describing the onion architecture, a form of n-tier architecture -- which is just a fancy way of saying it has components broken out into layers.

The layer you're focusing on is the Infrastructure layer. Data is the most common component of infrastructure. But other functions can be contained in separate libraries in the same layer.

Architecture is a subjective thing. The best I can do is offer you how I would set up the project.

If you want to be really explicit about your layers, you can use solution folders to separate things out.

enter image description here

Notice I didn't include the solution folder in the namespace -- it's Whatever.Web, not Whatever.Client.Web. That's another subjective call, but I've found it cleaner this way. Solution folders aren't mandated to be part of the namespace like project folders are.

And in the end, once I had an intuition for what concerns belong in which layer, I found I didn't even really need the solution folders:

enter image description here

Just by glancing at that, it's clear to me that the shared models are in the Core, the client is the Web, and everything else is there to support as infrastructure. But if I started getting many more projects in each layer, then I could switch back to organizing with solution folders.

For extra credit, I might mention that personally my Core/Domain layer would have interfaces for the Infrastructure services:

enter image description here

And the infrastructure library would then implement that interface, so you can always 'swap out' the dependency, to whatever other library implementation.

4
  • Thank you. The "onion architecture" actualizes very well the abstraction notion that I've been grasping at.
    – rory.ap
    Jul 12, 2016 at 13:54
  • What is the reason to place 'Whatever' solution name prefix into project names ?
    – Muflix
    May 1, 2019 at 13:31
  • Putting the solution name as part of the project namespace leads to a nice clean assembly reference: Whatever.Core.dll, instead of just Core.dll
    – RJB
    May 1, 2019 at 22:36
  • I have a question here which is always confusing me, In Whatever.Core I have Contracts.IEmailSender and in Whatever.Infra.Emails I have SendGridEmailSender that implements IEmailSender .. Is i allowed to use any dependencies inside Whatever.Core.Services for example if i have another implementation of IEmailSender but in my services and called EmailSender and use SendGrid for example, so can i add a sendgrid package to Whatever.Core.Services?? or my Core.Domain and Core.Services should be totally clean form any 3rd parties??
    – Marzouk
    Feb 24, 2020 at 12:04
4

I think you are extrapolating from rather old terminology of 'Data Layer' and 'Data Access Layer'

The implicit assumption of these terms is that you have some large database which your app runs off and you want to separate and abstract that from your applications or 'Business Layer'. You want to avoid polluting your 'should be available for all uses, past present and future, data' with your 'business logic of the day'

But you example cases are a bit more modern in their thinking, connecting to various 'Services' which provide random functionality to the caller.

The answer is that Your 'Business Layer' is still king. It should consume services, some of which are your traditional 'Data Access Layer' but the very fact that you abstract that layer means the Business layer doesn't know that that service is in the Data Layer.

It could be just some encapsulated in memory logic which is also part of your business layer, it could be an external third party or it could be a local file system.

2
  • That's probably why the onion architecture (per RJB's answer) or Domain Driven Design prefer to call the lowest layer an infrastructure rather than data layer.
    – kamilk
    Jul 7, 2016 at 21:31
  • also we should really be talking about 'Data Layers' plural when we talk about this kind of service orientated architecture
    – Ewan
    Jul 8, 2016 at 9:44
2

Okay... a simple answer. When I'm building a project that has 'perpendicular' behavior (connecting to external systems, writing to log files, etc) I do it through a library and generally make the calls to it in the business layer. The business layer typically is where the action requiring external access is taking place, and by building the capability into a library I can reuse it in other projects. Libraries are Good. Keep your controllers in the business layer simple and push the weird stuff into libraries or else you'll get tripped up later.

When I need to make something that's not-data-layer look like data-layer it's usually either a code smell indicating I really should to be putting the code in a library, or it's just something I'm hacking temporarily.

2

Well there is no generic answer, for some it's a matter of opinion so i won't answer in a generic way but i'll take your points one by one. I'm answering considering that all of those will be designed as simple interface. Not implementation.

a web service that downloads a PDF of a SQL Server Reporting Services (SSRS) report.

This could be just part of a Util class called in business layer. Or if you consider a bit wider, it's about reading files, whether they're remote or not. It's just a data access IMO. Only the true (not test :)) implementation will make it remote.

a library that sends email via SMTP or connects to a Microsoft Exchange mailbox and downloads messages in a folder structure

So it's about read or write in a mailbox ? What is the difference with a read/write to a database ? The answer is the implementation. So raw reading /Writing is just data access. Of course parsing the file to generate some data or choosing what to put in the file to sent belong to the business layer.

And since you have both SMTP/Micrisoft exchange, you would have 2 different implementations. Business will say which one he wants to use.

direct interactions with the file system, such as writing to a log file, using built-in programming language functionality

Again this is about storage, still reading/writing data access. In my case i have FileService that can save any file to the system and returns a FileInfo objects stored in database, so object can be linked to the file.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.