Does a decision on what services to use and in which order consitute logic in an MVC controller method?
I am near the end of a new ASP.NET MVC application I have been developing, and I have realised that I am not 100% on what should be goning on in my controller methods.
Is it better for an action method to decide which services/methods are called and in what order like so:
AccountService _accountService;
BillingService _billingService;
InvoiceService _invoiceService;
...
public ActionResult UpgradeAccountPackage(PackageType packageType, int accountId)
{
_accountService.UpgradeAccountPackage(packageType, accountId);
_billingService.BillForAccountUpgrade(packageType, accountId);
_invoiceService.CreateAccountUpgradeInvoice(packageType, accountId);
}
Or is it better to stick to a single method call to one service and allow this method to call the other services/support method it needs?
public ActionResult UpgradeAccountPackage(PackageType packageType, int accountId)
{
// account service upgrades account then开发者_StackOverflow calls the BillingService and InvoicService
// methods called above within this method
_accountService.UpgradeAccountPackage(packageType, accountId);
}
I have tended to go for the second example here, as it seemed originally like the first method would constitute logic in some way, and means the acion method would have to intrinsically know about how the account upgrade process works within my application, which seems like a bad thing.
However, now my application is almost finished it has a large service layer and this approach has led to almost every service having a strong dependency on numerous other services, and there is no centralised place which decides the flow of business transactions such as the one mentioned above, you have to dig around a bit in service methods to discover the processes.
I am considering refactoring to more closesly resemble the second method above, or introducing a new layer in between the controller and service layer which controls the flow of processes.
Do people tend to use the first or second method? What are peoples opinions?
I prefer the second method - much easier to test (using mocks), and the logic is there for reuse. You end up with Facades to your actual business logic, but that's not bad thing.
I don't understand why your service layer is full of concrete dependencies though...
The thing to remember is that you want classes to rely on interfaces, not implementation. (and then string it all together with a Dependancy Injection tool)
In C#, we can have one class implement many interfaces. So your service implementations can implement many interface, and yet the caller need only know about the part they need.
For example, you might have an AccountTransactionService
that imlpements IDepositor
and IWithdrawer
. If you implement double-entry accounting, then that could depend on IDepositor
and IWithdrawer
, which, in actual fact, just uses the same instance of AccountTransactionService
, but it doesn't have to, and the implementation details could be changed afterwards.
In general, the less one class knows about the other classes in the system, the better.
I more closely use the first method. Let the controller control what happens. Let the services decide how that happens.
If you add a second layer to control the flow of processes would that leave your ActionMethods only making the one call? If so, it seems unnecessary at that point.
You could have a service layer which depends on multiple repositories (not other services) and which defines the business operations:
public class MyService: IMyService
{
private readonly IAccountRepository _accountRepository;
private readonly IInvoiceRepository _invoiceRepository;
private readonly IBillingRepository _billingRepository;
public MyService(IAccountRepository accountRepository, IInvoiceRepository invoiceRepository, IBillingRepository billingRepository)
{
_accountRepository = accountRepository;
_invoiceRepository = invoiceRepository;
_billingRepository = billingRepository;
}
public void UpgradeAccountPackage(PackageType packageType, int accountId)
{
...
}
}
and then have your controller take IMyService
as dependency:
public class HomeController: Controller
{
private readonly IMyService _service;
public HomeController(IMyService service)
{
_service = service;
}
public ActionResult UpgradeAccountPackage(PackageType packageType, int accountId)
{
_service.UpgradeAccountPackage(packageType, accountId);
...
}
}
I define simple CRUD operations with the entities on the repositories and the service aggregates those multiple operations into one business transaction.
精彩评论