I have been given to develop a web application that can have multiple presentation layers, currently its on the web but soon to be on desktops and other platforms. So I searched around on how to do it best. I have found that its better to use a layered approach.
I am thinking to have BLL as a web-service which could be accessed by different PLs. The BLL will be accessing DAL for data specific operations.
So far so good, but I was thinking of using ASP.NET MVC for the web app. Now I am a bit confused because the "controllers" essentially contain the business logic, right.
Is it a good option ? If i do follow the same path, using MVC and the above mentioned layers, my controllers wont necessarily contain the BLL but will only be, kinda dummies.
Is it the right way to do it?
These are the recommended layers:
Presentation (MVC, WPF, Whatever):
contains only presentation logic (never includes business logic) the controller only handle communication with application/services layer to co-ordinate communication.
Distributed Services (Remote Facade):
as you will have many clients, some of them would be windows apps and others are web apps, it is recommended to create a remote service layer (WCF services or web services) which exposes business layer to consumers (preferable send and receive DTOs).
Application Layer:
a layer which handles the communication with domain layer, and co-ordinate transaction logic and technical services, and if you are using DTOs it translates domain objects into DTOs and vice versa
Domain Layer:
contains entities and value objects, this is the core of business logic designed in terms of object oriented domain objects encapsulating data and logic. it also could contains repository interfaces if using repository pattern. and domain services for logic that does not fit into a single entity.
Data Access:
using ORM like NHibernate or EF or whatever data access techniques to map entities into database tables.
Infrastructure / Common:
infrastructure code and cross cutting technical services like logging
I will try to give a tiny example about each layer:
a hypothetical incomplete example say you want to activate a purchase order
Presentation Layer (MVC):
public class PurchaseOrderController
{
public ActionResult ActivateOrder(int id)
{
var response = _orderManagementService.ActivateOrder(id); // Call distributed service (Web Service)
if(response.Succeed)
return new SuccessActionResult();
else
return new FailedActionResult(response.Reason);
}
}
Distributed Service Layer (Web Service):
public class OrderManagementWebService : IOrderManagementService
{
private readonly IOrderExecutionService _orderService;
public OrderManagementWebService(IOrderExecutionService orderService)
{
_orderService = orderService; // Order Service from application service
}
public ActivationResult ActivateOrder(int id)
{
var response = _orderService.ActivateOrder(id); // Call the application layer to execute the logic
if(
}
}
Application Layer:
public class OrderExecutionService : IOrderExecutionService
{
private IOrderRepository _orderRepository;
public OrderExecutionService(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
}
public ActivationResult ActivateOrder(int id)
{
var order = _orderRepository.GetById(id); // Get the order from repository
try
{
order.Activate(); // Call business logic inside the order entity
return new ActivationResult { Success = true } ;
}
catch(ActivationException ex)
{
LogFactory.GetLog().Exception(ex); // Call log from infrastructure layer
return new ActivationResult { Success = false, Reason = ex.Message } ;
}
}
}
Domain Layer:
public class PurchaseOrder : Entity
{
// Properties and fields (Data)
public int Id { get; private set; }
public Customer Customer { get; private set; }
// Methods (contains business logic)
public void Activate()
{
if(Customer.IsBlacklisted)
throw new InvalidCustomerException(...);
if(_lineItems.Count == 0)
throw new NoItemsException(...);
this.SetStatus(OrderStatus.Active);
.....
}
}
Repositories (Data Access Layer):
public class OrderRepository : IOrderRepository
{
public PurchaseOrder GetById(int id)
{
// data access code to access ORM or any data access framework.
}
}
Infrastrucute:
public class Logger : ILogger
{
public void Exception(Exception ex)
{
// write exception to whatever
}
}
Related
In my onion architecture I've my PresentationLayer who contains a class named LogRabbitMQFilters with differents properties to filter search.
I pass LogRabbitMQFilters in ApplicationLayer by mapper :
public RabbitMQController(IELKService iELKService, IMapper mapper)
{
_iELKService = iELKService;
_mapper = mapper;
}
public async Task<IActionResult> Index(int? id, LogRabbitMQFilters filters)
{
var filtersMapped = _mapper.Map<LogRabbitMQFilters>(filters);
var response = await _iELKService.GetLog(filtersMapped);
/*some code.....*/
}
In ApplicationLayer I map my logRabbitMQFilters to RabbitMQFilters which is declare in Persistance layer and I call my repository like this :
public ELKService(IELKRepository iELKRepository, IMapper mapper)
{
_iELKRepository = iELKRepository;
_mapper = mapper;
}
public async Task<LogResult> GetLog(LogRabbitMQFilters logRabbitMQFilters)
{
var filterMapped = _mapper.Map<RabbitMQFilters>(logRabbitMQFilters);
return await _iELKRepository.GetLogs(filterMapped);
}
It's best approch to do this ? Is there another way to pass my filters class to the repository ? I thought of specification pattern but I don't now if it's a good solution.
DDD and onion architecture share common principles (e.g. domain isolation), however they also draw some different aspects regarding development techniques. It should be pointed out that architectures and designs should serve our goals rather than be the goals themselves.
From your description it seems you have a CRUD-style system. I see no business rules, no domain concepts, no specifications. And that is, of course, not a bad thing.
Isolating domain from other layers (presentation, infrastructure) is beneficial in particular when sophisticated validations are to be applied and business rules are to be enforced within complex entity objects. In your case, however, you map plain object LogRabbitMQFilters (presentation layer) to "itself" (application layer) then to plain object RabbitMQFilters (infrastructure layer). Passing an object as is from presentation layer to application layer is OK in cases like yours (even from a DDD/onion perspective), however:
The second mapping should not exist, since infrastructure layer knows domain and therefore should receive your (presumably) domain entity LogRabbitMQFilters.
LogRabbitMQFilters is actually not a true domain entity since, as mentioned before, it does not apply any business rule.
Flatly mapping objects from one layer to another seems pointless.
I thought of specification pattern but I don't now if it's a good solution
Specification pattern is very useful when we want to pack expressions as business invariants, e.g. having a class named ShortMessage (business invariant) encapsulating an expression such as Message.Length < 42. But with your case I see no use for that, due to the CRUD nature of your application: you simply receive some user properties to function as operands in the context of an ORM object representing a database table, in order to do something like that:
myORMManager
.FetchAll<MyTableObject>()
.Filter(record =>
record.DateDebut == filter.DateDebut &&
record.DateFin == filter.DateFin &&
.
.
record.Message == filter.Message
.
.
.
);
Each of the predicates separated by 'and' operator can be considered as specification, however such specifications are just technical, as they do not convey any business invariant. The object filter can actually be a client request.
To conclude, it is acceptable to develop a single-layer application directly using client properties as operands for database filter expressions, as long as business invariants are out of picture (or at least with low complexity). If you would still like to have a DDD framework, i.e. having an application service (where you may apply simple validations such as DateFin > DateDebut) and a repository object together with the controller object, then I would recommend to have a single class "walking through" all three objects
In regards of complexity it always great to break up the application
according to its responsibilities or concerns.
Considering your code, it seems you are following the industry specified standard. For better clarity I am also adding here a sample code snippet of a standard project architecture.
Controller:
[Route("api/User")]
[ApiController]
public class UserController : ControllerBase
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
[HttpGet]
[Authorize]
[Route("users")]
public async Task<ActionResult> Users()
{
var users = await _userService.GetAllUsers();
return Ok(new ResponseViewModel { output = "success", msg = "request successful", returnvalue = users });
}
}
Service Interface:
public interface IUserService
{
Task<List<UserViewModel>> GetAllUsers();
}
Service Implementation:
public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public async Task<List<UserViewModel>> GetAllUsers()
{
return await _userRepository.GetAllUsers();
}
}
Repository Interface:
public interface IUserRepository
{
Task<List<UserViewModel>> GetAllUsers();
}
Repository Implementation:
public class UserRepository : IUserRepository
{
private readonly AppDbContext _dbContext;
private readonly IMapper _mapper;
public UserRepository(AppDbContext dbContext, IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
}
public async Task<List<UserViewModel>> GetAllUsers()
{
var users = await _dbContext.Users.ToListAsync();
var userViewModel = _mapper.Map<List<UserViewModel>>(users);
return userViewModel;
}
}
Model:
public class UserViewModel
{
public long user_id { get; set; }
public string full_name { get; set; }
}
Note: Hope above steps guided you accordingly. Additionally, you could also have a look our official document for more information
regarding industry practices.
I've not worked with .Net Core before but have a lot of experience with MVC and Entity Framework. My project has four distinct folders, API, DTO, Repository and WEB. The DTO folder has many model files which fits the data model. The API folder has a Controller file called ReferenceDataController and looks like this
[Route("api/[controller]")]
[ApiController]
public class ReferenceDataController : ControllerBase
{
private readonly IReferenceDataRepository _repository;
public ReferenceDataController(IReferenceDataRepository repository)
{
_repository = repository;
}
// GET api/values
[HttpGet]
public ActionResult<ReferenceData> GetReferenceData()
{
return _repository.GetReferenceData();
}
I'm told that if I call this GET method it will return a data object. How do I call this method in the API folder from my HomeController in my WEB folder?
First, in your web project, you need to do a little setup. Add a class like the following:
public class ReferenceDataService
{
private readonly HttpClient _httpClient;
public ReferenceDataService(HttpClient httpClient)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
}
public async Task<List<ReferenceData>> GetReferenceDataAsync(CancellationToken cancellationToken = default)
{
using (var response = await _httpClient.GetAsync("/api/referencedata", cancellationToken))
{
if (response.IsSuccessStatusCode())
{
return await response.Content.ReadAsAsync<List<ReferenceData>>();
}
return null;
}
}
}
Then, in ConfigureServices in Startup.cs:
services.AddHttpClient<ReferenceDataService>(c =>
{
c.BaseAddress = new Uri("https://api.example.com");
// Use the actual URL for your API here. You also probably want to get this
// from `Configuration` rather than hard-coding it.
});
Finally, inject ReferenceDataService into your HomeController:
public class HomeController : Controller
{
private readonly ReferenceDataService _referenceDataService;
public HomeController(ReferenceDataService referenceDataService)
{
_referenceDataService = referenceDataService ?? throw new ArgumentNullException(nameof(referenceDataService));
}
// In your action(s):
// var data = await _referenceDataService.GetReferenceDataAsync(HttpContext.RequestAborted);
}
This is the quick and dirty code here. Things you should consider for improvement:
Use an interface for your service class(es), i.e. IReferenceDataService. That will make testing easier. In ConfigureServices:
services.AddHttpClient<IReferenceDataService, ReferenceDataService>(...);
Then, inject IReferenceDataService instead.
You can and should use the Polly extensions with AddHttpClient to support retry and exception handling polices. At the very least, you'd definitely want to add AddTransientHttpErrorPolicy:
services.AddHttpClient<ReferenceDataService>(...)
.AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10)
}));
That will handle transient errors like temporarily being unable to connect to the API because it was restarted or something. You can find more info and more advanced configuration possibilities at the docs.
You should be using separate DTO classes. For brevity, I just used your (presumed) entity class ReferenceData. Instead, you should always use customized DTO classes that hold just the pieces of the data that you need to be available via the API. This way, you can control things like serialization as well as custom validation schemes, without conflicting with what's going on with your entity class. Additionally, the web project would only need to know about ReferenceDataDTO (or whatever), meaning you can share a library with your DTOs between the API and web projects and keep your DAL completely out of your web project.
I'm trying to implement an N-tier architecture using repositories and service layer in asp.net mvc application.
A Service object can own multiple repositories to collect all data it needs using the same unit of work.
Controllers call only Service objects and don't know anything about repositories.
Repository example:
public class UsersRepository : IUsersRepository
{
public IEnumerable<User> GetUsers(UsersQuery query)
{
...
}
}
UsersQuery objects incapsulates several options for querying Users, e.g:
public class UsersQuery
{
public bool IncludeDeleted { get; set; }
public Expression<Func<User, object>> OrderBy { get; set; }
//Ans so on...
}
How should I for example pass dynamic OrderBy clause (and other options) to my repository? Of course, it is possible just to pass Query object through the service, but it seems to me not to be the true way, as producing overhead and violating the DRY principle.
Any suggestions? Thanks in advance.
I have an MVC application that accesses SQL and Windows Azure. The logical flow looks like this:
Person <--> View <--> Controller.ConvertPersonHere(x) <--> StorageContext.DoDataAction <--> AzurePersonTableEntity
ConvertPersonHere is the answer to this Stack Overflow question and it converts the Model entity to the Storage entity
public class Person
{
public string Name {get;set;}
public int ID {get;set;}
}
public class PersonEntity : TableServiceEntity
{
public string Name {get;set;}
public int ID {get;set;}
// Code to set PartitionKey
// Code to set RowKey
}
Now that I'm adding WCF to the mix, how should I go about accessing data functions? Assume I have currently have a method to .Save(Person) in the controller and want to Save(Person) from my WCF call.
Do I need to abstract out the data actions in the controller?
I would refactor the code like this - move the functionality to convert from Person to PersonEntity and vice versa to a separate mapper, move saving functionality to separate repository as well, and move controller's code for invoking mapper and repository to separate service too.
So methods in your controller will look similar to:
public ActionResult SomeMethod(Person person)
{
if (ModelState.IsValid)
{
_personService.Save(person)
return View("Success");
}
return View();
}
And in your WCF service you'll be able to reuse the code. In order to validate the classes in WCF using DataAnnotations attributes, you can use the approach similar to the following - http://blog.jorgef.net/2011/01/odata-dataannotations.html
From this example, if your Mvc project was gone and replaced by a Wpf project, your other functionality is still available. If you have both projects they can reference core functionality. Have the implementation which has no relation to UI (MVC or WPF) in other projects. This way those UI projects can reference this functionality.
public interface IConverter<TDataModel, TModel> { TModel MapToDomain(TDataModel source);}
public interface IPersonConverter : IConverter<PersonEntity, Person> { }
public interface IPersonRepository { Person GetById(int id); }
public class PersonConverter : IPersonConverter
{
public Person MapToDomain(PersonEntity source)
{
return new Person { ID = source.ID, Name = source.Name };
//or use an AutoMapper implementation
}
}
public class PersonRepository : IPersonRepository
{
private readonly IPersonConverter _personConverter;
public PersonRepository(IPersonConverter personConverter)
{
_personConverter = personConverter;
}
public Person GetById(int id)
{
PersonEntity personEntity = new PersonEntity(); //get from storage
return _personConverter.MapToDomain(personEntity);
}
}
public class MvcController
{
private readonly IPersonRepository _personRepository;
public MvcController(PersonRepository personRepository)
{
_personRepository = personRepository;
}
public ActionResult SomeMethod(int id)
{
Person person = _personRepository.GetById(id);
//make your view model based on the person domain model
//with another convert / map, to fit view as personForm
//(if this is overkill you can use person).
return View(personForm);
}
}
Mvc or Wpf project
PersonForm (ui model)
Controller or Wpf Class
Person -> PersonForm converter
List item
Core project
Person
IPersonRepository
Infrastructure project
Person Repository
Person Entity
Azure Person Table Entity
Storage Context
I know it's a tangent, but if you're mixing WCF and ASP.NET MVC, you should at least be aware of OpenRasta. A good start is this Herding Code podcast with the main contributor.
(No, this is not even intended to answer your actual question!)
I was looking at the differences between POCO and DTO (It appears that POCO's are dto's with behaviour (methods?))and came across this article by Martin Fowler on the anaemic domain model.
Through lack of understanding, I think I have created one of these anaemic domain models.
In one of my applications I have my business domain entities defined in a 'dto' dll. They have a lot of properties with getter's and setter's and not much else. My business logic code (populate, calculate) is in another 'bll' dll, and my data access code is in a 'dal' dll. 'Best practice' I thought.
So typically I create a dto like so:
dto.BusinessObject bo = new dto.BusinessObject(...)
and pass it to the bll layer like so:
bll.BusinessObject.Populate(bo);
which in turn, performs some logic and passes it to the dal layer like so:
dal.BusinessObject.Populate(bo);
From my understanding, to make my dto's into POCO's I need to make the business logic and behaviour (methods) part of the object. So instead of the code above it is more like:
poco.BusinessObject bo = new poco.BusinessObject(...)
bo.Populate();
ie. I am calling the method on the object rather than passing the object to the method.
My question is - how can I do this and still retain the 'best practice' layering of concerns (separate dll's etc...). Doesn't calling the method on the object mean that the method must be defined in the object?
Please help my confusion.
Typically, you don't want to introduce persistence into your domain objects, since it is not part of that business model (an airplane does not construct itself, it flies passengers/cargo from one location to another). You should use the repository pattern, an ORM framework, or some other data access pattern to manage the persistent storage and retreival of an object's state.
Where the anemic domain model comes in to play is when you're doing things like this:
IAirplaneService service = ...;
Airplane plane = ...;
service.FlyAirplaneToAirport(plane, "IAD");
In this case, the management of the airplane's state (whether it's flying, where it's at, what's the departure time/airport, what's the arrival time/airport, what's the flight plan, etc) is delegated to something external to the plane... the AirplaneService instance.
A POCO way of implementing this would be to design your interface this way:
Airplane plane = ...;
plane.FlyToAirport("IAD");
This is more discoverable, since developers know where to look to make an airplane fly (just tell the airplane to do it). It also allows you to ensure that state is only managed internally. You can then make things like current location read-only, and ensure that it's only changed in one place. With an anemic domain object, since state is set externally, discovering where state is changed becomes increasingly difficult as the scale of your domain increases.
I think the best way to clarify this is by definition:
DTO: Data Transfer Objects:
They only serve for data transportation typically between presentation layer and service layer. Nothing less or more. Generally it is implemented as class with gets and sets.
public class ClientDTO
{
public long Id {get;set;}
public string Name {get;set;}
}
BO: Business Objects:
Business objects represents the business elements and naturally the best practice says they should contain business logic also. As said by Michael Meadows, it is also good practice to isolate data access from this objects.
public class Client
{
private long _id;
public long Id
{
get { return _id; }
protected set { _id = value; }
}
protected Client() { }
public Client(string name)
{
this.Name = name;
}
private string _name;
public string Name
{
get { return _name; }
set
{ // Notice that there is business logic inside (name existence checking)
// Persistence is isolated through the IClientDAO interface and a factory
IClientDAO clientDAO = DAOFactory.Instance.Get<IClientDAO>();
if (clientDAO.ExistsClientByName(value))
{
throw new ApplicationException("Another client with same name exists.");
}
_name = value;
}
}
public void CheckIfCanBeRemoved()
{
// Check if there are sales associated to client
if ( DAOFactory.Instance.GetDAO<ISaleDAO>().ExistsSalesFor(this) )
{
string msg = "Client can not be removed, there are sales associated to him/her.";
throw new ApplicationException(msg);
}
}
}
Service or Application Class
These classes represent the interaction between User and the System and they will make use of both ClientDTO and Client.
public class ClientRegistration
{
public void Insert(ClientDTO dto)
{
Client client = new Client(dto.Id,dto.Name); /// <-- Business logic inside the constructor
DAOFactory.Instance.Save(client);
}
public void Modify(ClientDTO dto)
{
Client client = DAOFactory.Instance.Get<Client>(dto.Id);
client.Name = dto.Name; // <--- Business logic inside the Name property
DAOFactory.Instance.Save(client);
}
public void Remove(ClientDTO dto)
{
Client client = DAOFactory.Instance.Get<Client>(dto.Id);
client.CheckIfCanBeRemoved() // <--- Business logic here
DAOFactory.Instance.Remove(client);
}
public ClientDTO Retrieve(string name)
{
Client client = DAOFactory.Instance.Get<IClientDAO>().FindByName(name);
if (client == null) { throw new ApplicationException("Client not found."); }
ClientDTO dto = new ClientDTO()
{
Id = client.Id,
Name = client.Name
}
}
}
Personally I don't find those Anaemic Domain Models so bad; I really like the idea of having domain objects that represent only data, not behaviour. I think the major downside with this approach is discoverability of the code; you need to know which actions that are available to use them. One way to get around that and still keep the behaviour code decoupled from the model is to introduce interfaces for the behaviour:
interface ISomeDomainObjectBehaviour
{
SomeDomainObject Get(int Id);
void Save(SomeDomainObject data);
void Delete(int Id);
}
class SomeDomainObjectSqlBehaviour : ISomeDomainObjectBehaviour
{
SomeDomainObject ISomeDomainObjectBehaviour.Get(int Id)
{
// code to get object from database
}
void ISomeDomainObjectBehaviour.Save(SomeDomainObject data)
{
// code to store object in database
}
void ISomeDomainObjectBehaviour.Delete(int Id)
{
// code to remove object from database
}
}
class SomeDomainObject
{
private ISomeDomainObjectBehaviour _behaviour = null;
public SomeDomainObject(ISomeDomainObjectBehaviour behaviour)
{
}
public int Id { get; set; }
public string Name { get; set; }
public int Size { get; set; }
public void Save()
{
if (_behaviour != null)
{
_behaviour.Save(this);
}
}
// add methods for getting, deleting, ...
}
That way you can keep the behaviour implementation separated from the model. The use of interface implementations that are injected into the model also makes the code rather easy to test, since you can easily mock the behaviour.