Controller Tests for Service Layer Logic - asp.net-mvc

I have a solution with the following architecture MVC app > Services > Repositories. Now lets say I have a Document Model and a Document has many Notes. I have a Notes controller with an AddNote(documentID) action. Now my business rules say that only the users associated with the document can add notes so I enforce this. I am currently going with the following method:
public ActionResult AddNote(int documentID)
{
try
{
NoteCreateEditViewModel viewModel = Mapper.Map<Note, NoteCreateEditViewModel>(noteService.GetNewNote(User.Identity, documentID));
return View(viewModel);
}
catch (BusinessLogicException validationException)
{
// Send user somewhere else.
}
}
noteService.GetNewNote(User.Identity, documentID) throws a BusinessLogicException should the user have no right on the Document. I am using an exception as this seems to be the best way to handle business/validation violations (although I personally feel this is bad use of exceptions!).
When testing the above from a controller test, should I just be testing that the correct redirect (or whatever) happens should the BusinessLogicException be thrown or should I be simulating an unauthorised user/non existent documentID etc? In my mind, the service test for GetNewNote(User.Identity, documentID) would be the place to simulate an unauthorised user as this ensures my tests are testing the core functionality of a particular piece of code.
However, if I dont write a controller test which simulates an unauthorised user generating an Exception, then how will someone who looks at my tests in the future understand that the desired functionality of AddNote is to prevent unauthorised users from adding notes. If they dont understand this they may be tempted to simply initialise a new Note directly in the controller, rather than through noteService.GetNewNote(User.Identity, documentID).
So should I be testing more in my controllers or is there a much simpler design in adding associated models?

In your unit test you should mock the noteService.GetNewNote method call so that it throws a BusinessLogicException. Then assert that the controller action returned a redirect result.

Related

ASP.Net MVC: Check if URL is Authorized

I'd like to simply check from a Controller whether another URL is authorized.
So for example, I'd like to call into a Controller like so:
[HttpPost]
public ActionResult IsUrlAuthorized(string url)
{
bool isAuthorized = // What do I put here?
return Json(isAuthorized);
}
So I'd like to know what I could call to check on whether the current user is authorized for the passed-in URL or not. I'm guessing the answer has something to do with Routes, which sit a little bit outside MVC?
This is a somewhat similar question but not quite the same thing:
ASP.NET MVC. Check if user is authorized from JavaScript
Since the user may or may not be authorized in general, but may not have the right permissions or role assignments to see a specific URL.
Ideas?
Update: I use standard MVC authorization attributes to lock down my app, so I'll just give an example of what that looks like here. In MVC Routes map to Controllers. A single method on a Controller can be restricted to one or more Roles:
public class HomeController : Controller
{
[Authorize(Roles = "User, Moderator")]
public ActionResult ListRecentPosts()
{
. . .
}
}
Or, an entire Controller can be restricted to one or more roles:
[Authorize(Roles = "Admin")]
public class AdminController : Controller
. . .
The actual URL that any of these controller methods responds to is based on a default mapping in a standard MVC app:
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
But, you can be nice to your users and make URLs guessable by adding a lot more Routes - as a result, a Controller method can have many names that point to it. You can't just assume and infer the controller name from the URL (even if it maps out that way for half the URLs in the site).
So presumably I either need a way to ask the Routing engine directly whether a URL is authorized for the current user, or a 2-step of asking the Routing engine for which Controller and Method, then ask if those are authorized - hopefully not by using Reflection and matching Roles directly as that again would appear to assume too much.
Update 2: The way this came up is I have an Account strip at the top of my app. Its state can change by selecting one of several accounts you're authorized as. Depending on where you are in the app, the account you chose might have authorization to view this page - and you might be in the middle of filling out a form you don't want to lose. So the naive approach - just refresh when they pick another account - is harmful, and a waste of the user's time even if there is no form and they're just reading a page that's all text.
While that convenience to the user is nice, the user is going to fairly assume that pages they can't see as a user who shouldn't have permission really are denied (and, it would be harmful to leave them on a page that's forbidden - actions taken from it will fail). So I need to know whether to redirect away based on their new permissions.
One of the things I love about .Net is the way many of its best libraries decompose so well, so you can easily recompose things that are part of its normal functionality, or a new twist. Both the Routing module and MVC appear to be very well constructed, so I have to suspect this can be done.
The cheap hack is to ensure that my authorization module returns a consistent redirect status code when a user isn't authorized, and when the user changes their account in the account strip, fire 2 AJAX calls: One to change account, and then a second to the current page over AJAX just to check the HTTP Status Code. 200 OK means leave the page as is, Redirect means follow the redirect. Obviously this is a little ugly, involves an extra HTTP call, creates a false hit in the logs, and makes an assumption about how authorization is handled across the app.
There could be a secondary concern - the page might be authorized, but just change how it works or looks. This particular app has no change in look based on account (besides the account strip itself), and I can handle functionality changes by just providing a custom event that forms listen to - they can reload any relevant data from the server in response to it.
Using UrlAuthorization.CheckUrlAccessForPrincipal only works if you're only using URL authorization. But for MVC using Routing, we highly recommend that you don't use URL authorization to secure an app.
Instead, we recommend using Authorization attributes on the controller class. The reason is there could be multiple URLs that call the same controller action. It's always better to secure the resource at the the resource and not just at the entry ways.
In this particular case, you'd have to get an instance of the controller given the URL. THat's a little tricky as you'll basically have to run the MVC pipeline from the point where you have the URL to the point where you have the controller. It's possible, but seems heavyweight.
I wonder if there isn't a better and simpler way to accomplish your goals. What is it you're really trying to do?
UPDATE: Based on your scenario, it sounds like this is an initial check just for UI purposes. Perhaps all you need to do is make an asynchronous Ajax request to the URL and check the HTTP Status code. If it's a 401 status code, you know the user is not authorized. That seems like the safest bet.
How about UrlAuthorizationModule.CheckUrlAccessForPrincipal method.
UrlAuthorizationModule.CheckUrlAccessForPrincipal Method (System.Web.Security)

What's the recommended place to perform validation: ViewModel, Model or Controller?

I have a registration page and would like to perform some validation (in addition to the StringLength and Required annotations on my ViewModel) for duplicate usernames and email addresses. Currently I perform this validation in my controller when the registration form is posted back. I'm not sure if this is the right place to do it though.
I can't imagine the ViewModel to be the right place as it would require the ViewModel to have a reference to my UserRepository. Does it make sense to have this kind of validation in the model classes?
If so, how do I implement this on the model so I can check if the information is valid before I sent it into my repository?
Update
Code of my controller action:
if (ModelState.IsValid)
{
if (!_userRepository.Exists(registerViewModel.Username))
{
if (!_userRepository.EmailExists(registerViewModel.Email))
{
_userRepository.Add(
new User
{
Created = DateTime.Now,
Email = registerViewModel.Email,
Password = registerViewModel.Password,
Username = registerViewModel.Username
});
_userRepository.SaveChanges();
TempData["registrationDetails"] = registerViewModel;
return RedirectToAction("Confirm");
}
else
{
ModelState.AddModelError(string.Empty, "This email address is already in use.");
}
}
else
{
ModelState.AddModelError(string.Empty, "This username is already taken.");
}
}
return View(registerViewModel);
}
Update 2
Should the domain model care about such constraints as duplicate user names or email addresses or is this something that the controller layer should worry about?
Update 3
It seems that putting the validation logic in the controller makes the most sense as it can be reused in remote validation and in model validation on submit. Is something like checking for duplicates generally a thing that should be done in controllers or does it make sense to have these kind of checks in a domain model?
Thanks,
I would perform it both on the frontend (ajax perhaps) and backend - which depends on your solutions architecture.
I like to let users know immediately if there's going to be a registration issues.
In my typical setup of a data layer / business layer and presentation layer, I would perform the dup checks in the business logic and have the controller call that piece of code (in addition to an ajax lookup on the front end for users).
As a bit of a side note: I generally prefer to only use MVVM (with view models) in windows applications. Combining MVC with MVVM can make things unnecessarily complicated
I would suggest that you do this in Controllers.
The main reason is that whatever the structure of the app be, you would definitely need to use Ajax to notify the user whether the username has already been taken or not. Otherwise it's just bad usability which doesn't justify your code structure.
And for that you would like to have a action method which could ajax-ly see if the username exists or not.
Overall, it does mean you may end up with two sets of validation method (UI and model) but its all for a good cause.
Also to make a good usable site you would definitely be using a Javascript framework like knockoutjs or backbone. Thats true MVVM and in that case having your ViewModels being the Model layer classes (as Chris mentioned) is not a good idea. So basically you'll end up with two sets of validation anyways.
As Rob said in the comments, it does depend on the structure of your application. I tend to have a double validation (Validation on my ViewModels as well as validation on my service layer) to ensure that the data that hits the service is valid. This helps because my services get used by multiple clients, but the views and ViewModels are client specific. Front end validations have the advantage of instant feedback, and the backend validations help keep your data clean.
My suggestion is - For validation, such as duplicate email address and user name- to keep your validation methods in controller.
Or in your Validation Layer - which will be used in between view model and data layer
for MVC3 you will be able to add methods in controller as a actions using Remote attribute to your property in view model for instant results
You should validate in both the View (client-side) and Controller (server-side). If you have MVC 3, you can use the new RemoteAttribute. It uses jQuery to make a server-side call, in which you could check for the existence of a user or email address.

TDD'ing MVC Controllers to drive design

I am starting out on a new project (well, restarting an existing one), and trying to adopt TDD (for the nth time) for all the benefits that it should bring.
I believe that TDD will result in my tests driving me to write only the code that I need to write, but it will drive me to write the code that I NEED and not leave some out.
This is where my current state of uncertainty comes in.
Consider the story:
"A user must be able to add a widget, doing so they are taken to view the details of the newly added widget."
OK, so working from the UI (as that's where a user will add their widget from, and not using Visual Studio and a set of assemblies that I write)... I begin with the following test, writing the very minimal so that the test passes.
So I started out with the controller throwing a NotImplementedException, then returning a View()... the following was the first point that I had written the fewest lines I could to make the test pass.
[TestFixture]
public class WidgetControllerTester
{
[Test]
public void Create_IfBusinessModelIsValid_ReturnRedirectToRouteResultToDetailsAction()
{
// Arrange
var currentUser = new User
{
DisplayName = "Fred",
Email = "fred#widgets.com",
Password = "pass",
Status = UserStatus.Active
};
var model = new WidgetModel();
var controller = new WidgetController();
// Act
var actionResult = controller.Create(currentUser, model);
// Assert
actionResult.AssertActionRedirect().ToAction("Details");
}
}
public class WidgetModel
{
}
public class WidgetController: Controller
{
public ActionResult Create()
{
return View("Create");
}
[HttpPost]
public ActionResult Create(User currentUser, Widget model)
{
return RedirectToAction("Details");
}
}
Now I realise that additional tests for invalid models and checking of model state will evolve from additional stories.
However I can't see a clear path of how I would leverage additional tests to drive further code within the controller.
For instance, I know at some point I will want to make a WidgetService call from the Create action. Am I missing something obvious (not being able to see the wood for the trees kind of stuff) how I can progress the controller code with additional tests?
Talking about the WidgetService, I expect that I will write a WidgetServiceTester and for th e time being references within the controller will most likely be mocked.
Some thoughts I have had...
Create a new test called Create_IfModelIsValid_WidgetIsAddedToRepository, but how does this clearly lead onto service calls in the controller action?
I need to write a more detailed story stating that the model needs to be inserted into the repository/database, etc?
Am I muddling up elements of TDD and XP?
Thanks for reading, I would appreciate any feedback and insights to the best practice for progressing.
Joe.
EDIT 27 Feb 2010
I found the following article Iteration #6 – Use Test-Driven Development (on asp.net) (http://www.asp.net/%28S%28ywiyuluxr3qb2dfva1z5lgeg%29%29/learn/mvc/tutorial-31-cs.aspx) which demonstrates the sort of thing I was after, however they seem to consider addition of repository/service to the controller as re-factoring... I personally don't agree, am I wrong? :)
I'm going to think about writing a test that checks the ViewData of the Details action and update this question once I have.
Joe. I feel a lot of the same uncertainty, sometimes. But I also think that most of what you're missing is those up-front stories. First, you should decompose your story just a tad to create the actual developer requirements. Here's what I mean:
"A user must be able to add a widget, doing so they are taken to view the details of the newly added widget."
Ok, so to me, that breaks out questions as follows, which can help you think of tests:
"A user" -- where did the user come from? How are they logged in? (if you're using the default AccountController and tests, then this is already there, if not, you'll want tests for getting the login form, logging in, validating both successful and failed logins, etc)
"add a widget" -- to what (I don't mean implementation, I just am pointing out that this implies that you're either going to hit a repository or a service, unless 'add' just means add it to the running instance and you don't need persistence)? does the widget have to be valid at this point, or can invalid widdgets be saved and made valid later? This implies to me tests that a repository or service has a method hit (save(), insert(), add(), whatever (not the internals of the method, until you get to testing your service/repo, just that the controller does its job by calling it), check what happens on a valid/invalid widget (you need to expand your story a bit or add a story to cover what should happen on valid/invalid widgets)
"doing so they are taken to view the newly added widget's details" -- reworded slightly, but basically what you said. Always? or only on success? Is this view editable or read-only (i.e. Edit action or Details action)? Is there a message to the user that tells them that they've been successful, or should they infer from the fact that they're viewing their widget that they were successful? This should drive tests that do things like check properties on the returned actionresult and check the values stored in TempData (status message) as well as checking what happens in both paths (success or failure).
that's just a quick shot, but basically that's the thought process. you can also do the same w/ other stories, and for that matter generate new stories to cover more application behavior.
A couple thoughts on your design going forward.
Your next test should look at what I wrote above first, which is the fact that the controller's create POST action should 1) receive needed data (your params), 2) call that service/repository to "add" the widget, 3) possibly do something if that add fails (this is in your design; I've gotten to where my controllers assume all will go well and I handle failures through attributes, but thats' a personal design decision), 4) redirect to details.
So, your next test would be using a mock (I prefer the moq library on google code, but whatever you have will work). You'll need some interface to describe the service your controller will call, and you pass in a mocked implementation of that to your controller under test in order to ensure that it's calling the correct method. In Moq, that'd look something like this:
[Test]
public void Create_CallsRepository()
{
// Arrange
var currentUser = new User
{
DisplayName = "Fred",
Email = "fred#widgets.com",
Password = "pass",
Status = UserStatus.Active
};
var model = new WidgetModel();
var mockService = new Mock<IService<WidgetModel>();
mockService.Setup(s=>s.Add(model)); //.Returns(whatever) if it returns something
var controller = new WidgetController(mockService.Object);
// Act
var actionResult = controller.Create(currentUser, model);
// Assert
mockService.Verify(s=>s.Add(model));
}
That makes some design assumptions, of course, but the tension of how to write your tests vs how your objects should be called / handle things is part of what makes TDD so valuable.

ASP.NET MVC: Authorization inside an Action - Suggested Patterns or this is a smell?

I have an ASP.NET MVC application using Authorization Attributes on Controllers and Actions. This has been working well but a new wrinkle has shown up.
Object: Shipment
Roles: Shipping, Accounting, General User
The Shipment moves through a workflow. In state A it can be edited by Shipping only. In state B it can be edited by Accounting only.
I have a ShipmentController, and an Edit Action. I can put an Authorization attribute to limit the Edit action to only those two roles, but this doesn't distinguish between which state the Shipment is in. I would need to do some Authorization inside the action before the service call to determine if the user is really authorized to execute the edit action.
So I'm left with two questions:
1) Whats a good way to have authorization inside an Action. The Controller Action calls to a service, and the service then makes appropriate calls to the Shipment object (update quantity, update date, etc). I know for sure I want the Shipment object to be agnostic of any authorization requirements. On the other hand, I don't have a real grasp if I would want the service object to know about authorization or not. Are there any good patterns for this?
2) Is my problem actually a symptom of bad design? Instead of ShipmentController should I have a StateAShipmentController and StateBShipmentController? I don't have any polymorphism built into the Shipment object (the state is just an enum), but maybe I should and maybe the Controllers should reflect that.
I guess I'm after more general solutions, not a specific one for my case. I just wanted to provide an example to illustrate the question.
Thanks!
I don't see a problem with an Action method doing further authorization checks within it. You can leverage the Roles provider for the fine-grained authorization you're looking for. Please excuse my syntax here - it's likely rough and I haven't tested this.
[Authorize(Roles="Shipping, Accounting")]
public ActionResult Edit(int id)
{
Shipment shipment = repos.GetShipment(id);
switch (shipment.State)
{
case ShipmentState.A:
if (Roles.IsUserInRole("Shipping"))
return View(shipment);
else
return View("NotAuthorized");
break;
case ShipmentState.B:
if (Roles.IsUserInRole("Accounting"))
return View(shipment);
else
return View("NotAuthorized");
break;
default:
return View("NotAuthorized");
}
}
Your authorization attribute could get the Shipment from action parameters or route data and then make a decision.
For number 1, there are a number of patterns that enable rich behavior in domain objects. In double-dispatch, you pass a reference to a service abstraction (interface) to a method on the object. Then it can do its thing. You can also write an application service that takes the Shipment and does the work.
On number 2, not necessarily. You may need to abstract the concept of a "contextual Shipment" into a service that figures out which Shipment context you're in. But I'd YAGNI that until you need it again.
You could take a look at Rhino.Security, it could be used to implement user authorization in these kinds of scenarios.
In addition to the answer above, you can return a HttpUnauthorizedResult instead of creating your own view for NotAuthorized. This will redirect to the login page and behave just like the usual [Authorize] attribute

ASP.NET MVC - User Input and Service/Repository - Where to do Validation?

This might be too opinionated a question, but looking for help!
I have been trying to refine my ASP.NET MVC program structure. I just started using it at preview 5 and it is my first foray into business application development -- so everyting is new!
At the controller level, I have a service object responsible for talking to the repository and taking care of all business logic. At the action level, I have an object that holds all view data -- user input and generated output -- that I'll call view object (is there a general term for this?). Unlike most examples I see, this object is not a database object, but an object specific to the view.
So now I want to add user validation. The problem is, I'm not sure where to put it. It makes the most sense to me to do it in the Service layer. The Service layer is responsible for all the business logic and validation is business logic. On the other hand, most validation frameworks that I see are for validating an object, which makes me think the view object should be validation aware. Finally, there are some validation methods that would require a database connection (checking if a user input field has a corresponding database record for example), and the view object has no concept of a database, only the Service.
So some options I see are:
Do validation in the Service.Method on the parameters passed to the method.
Do validation in the view object before calling Service.Method.
Do validation in the view object but make the Service.Method require a view object reference so it is initiating the validation on the object.
I'm sure there are more. I'm curious of how other people handle user input validation in the MVC sense. I've previously used the Enterprise Validation Block and liked being able to use stock validators for everything, but I'm not sure how to make it fit into a seperate view object and service layer. It would be easy if they (view object / service) were the same object, which is maybe what people do? Like I said, its all new to me and I'm looking for best practice / patterns.
I typically do basic validation (required fields, email format, etc.) in the controller action when the form is submitted. I then let the business layer handle validation that requires business knowledge. I usually double check the basic stuff in the business layer as well, so if I expose that logic through web services or use it in another application later, I still have validation where it is most important (IMO).
There are some interesting links on this
MVC & MS Validation Application Block
MVC & Data Annotation Validators
Form Validation video
Personally, i've added validation to my Service layer objects (first two links). This way, if any method in any controller decides to call my service method .. the logic is all checked and boxed in one location. DRY.
That said, i also have some UI validation (3rd link) .. to reduce the roundtrip time.
Lastly, the current MVC dll's have the ability to pass error messages back to the UI .. so the view can display them nicely. Check out :-
ViewData.ModelState.AddModelError(key, message)
hth!
Check the following blog posts
http://blog.codeville.net/2008/09/08/thoughts-on-validation-in-aspnet-mvc-applications/
http://www.emadibrahim.com/2008/09/08/client-server-side-validation-in-aspnet-mvc/
Take a look at the S#arp Architecture project. Validation is handled on the model to ensure that no entity is persisted to the database in an invalid state. It does this by using NHibernate.Validator and attaching it to NHibernate's save and update events.
Personally, this approach makes the most sense to me since you don't have to duplicate your validation logic in multiple controllers.
I was afraid I'd get no replies for my post, happy to be wrong!
I've read those links before, but probably a month or more ago, and re-reading them with what I understand now has been very helpful. I really like Steve Sanderson's post with the sliding scale, but wish he would show an example of validating something at the right-end of the spectrum.
As an example in his blog he gives: " 'usernames must be unique' will probably be enforced in your database". So would this be something like:
public static void SavePerson(Person person)
{
// make sure it meets some format requirement
// in this case the object is responsible for validation and the service layer is the caller
person.EnsureValid();
// todo: action to verify username is unique by checking database
// in this case the service layer is responsible for calling and implementing validation
// todo: action to save to database
}
This makes sense, and would show my trouble grasping where to put validation as it is inside both the service layer (very unique name) and view-object (verify formats).
Another concern I have is the service layer starts to balloon with validation logic. Maybe split it out to a different class or something? In my case some validation logic might be shared between services, so I would like to think of a DRY way to implement this. Fun stuff to think about!
Emad Ibrahim's link is great in that once I start to understand this process a bit more I was going to look for a way to generate javascript client-side validation using the same set of rules without having to repeat code. He already has that :)
I have heard about S#arp but not sat down and seen how it works (I'm not sure if there is much in the way of demos on it, or if downloading the code is the demo!). I'm not sure if doing validation on the database model only would be sufficient. It seems to me there would be plenty of valid model states with regards to the database that business logic would say are invalid (such as date ranges / must be before / after / etc). Those are the cases that are wracking my brain :)
Also, a link I liked (googled it after I saw Emad reply to Steves post with BLL and no idea what it meant... duh):
http://en.wikipedia.org/wiki/Business_logic_layer
So I didn't know it, but I think this is the model I'm writing to: Business Process object that handles data interactions, and Business Entities that are logical models rather than database models. I think I need to start reading some more fundamental patterns and practices with this stuff to better understand the concepts (it seems like a lot of this is stuff Java people write vs. .NET people). It might be time to take a step back :)
I have come across this same issue in a recent project. First, to restate the problem, I am trying to follow the domain-centric approach of DDD. I have entities composed into aggregates that can validate themselves, and the repositories verify validity on save. The UI can also get validity information from an aggregate in order to display error feedback to the client. The general approach is to leverage as much as possible ASP.NET MVC's model binding, and validation/form UI helpers. This creates the simple UI flow: 1) bind, 2) validate, 3) if valid, save, else re-populate view.
However, it is not directly obvious how to do leverage ASP.NET MVC and this simple flow when DDD services are involved. Originally, I developed my services as such:
public class SomeProcessService
{
public Result Execute(int anAggregateID, int anotherAggregateID, string someData)
{
// validate input
// if invalid, return failures
// else
// modify aggregates
// using (transaction)
// {
// save aggregates
// commit
// }
// return success
}
}
The problem is that the validation and the save are inextricably linked in the method. To leverage the MVC model binding, we need something that serves as a model to bind to. I am refactoring to this:
public class SomeProcessService
{
public class Request : IValidateable
{
public int AggregateID {get;set;}
public int AnotherAggregateID {get;set;}
public string SomeData {get;set;}
public Result Validate()
{
// validation
}
}
public void Execute(Request request)
{
// validate input by calling request.Validate()
// if invalid, throw new ValidationException(request)
// else
// modify aggregates
// using (transaction)
// {
// save aggregates
// commit
// }
// return success
}
}
This repurposes the Parameter Object pattern to separate method input validation. I can bind to a SomeProcessService.Request object in my controller, as well as get validation information there. If all is well, from my controller I initiate the service call using the Request object as the parameter. This approach seems to happily marry DDD services with ASP.NET MVC validation requirements.

Resources