Should I validate a route value in Controller? - c#

I am building a web app using ASP.NET MVC5. I have logic for validating the route value similar to the following.
[HttpGet]
public ActionResult Books(string name)
{
if(!CheckBook(name))
{
return RedirectToAction(Index);
}
return View(model:name);
}
private bool CheckBook(string name)
{
var exists = false;
var allBooks = Library.Books; // Library is a static class and Books returns a list with all the book names
foreach(var book in allBooks)
{
if(book == name)
{
exists = true;
}
}
return exists;
}
Is it a bad practice to validate the route value in the controller? Should I create a folder such as validators and add validation functions there? Or is this where I create services? I learned that I shouldn't add business logic in controllers, so I am unsure.

First off it's OK to put simple Business Logic directly in a controller, as you can test it with DI. Putting the Business Logic in a library with a Domain Specific Language is obviously better.
Let me help you out with a few things:
Because you need to return View(model:name); and the name is based on the Route Value you will need to validate it exists.
Because the Book lookup is related to the Book controller I'd keep the "simple" logic in the controller.
When we talk about Validators, we tend to be talking about parsing form inputs (and validating at both front and back-ends). See this example with a link to a dozen more examples: https://stackoverflow.com/a/51851312/495455
In this case where you need to interrogate routes, headers and query strings you can keep the logic in the controller, or if its called twice or more move it to a library class for polymorphic use.
The Lookup method:
OP:
private bool CheckBook(string name)
{
var exists = false;
var allBooks = Library.Books; // Library is a static class and Books returns a list with all the book names
foreach(var book in allBooks)
{
if(book == name)
{
exists = true;
}
}
return exists;
}
Better:
private bool CheckBook(string name)
{
var allBooks = Library.Books;
foreach(var book in allBooks)
{
if(book == name)
{
return true; //Don't keep iterating to the end when we know its true!
}
}
return false;
}
Better:
private bool CheckBookExists(string name)
{
var bookExists = Library.Books.Contains(name);
return bookExists;
}

Related

Typewriter ReturnType from IActionResult

I have started to play around with Typewriter to see if it would fit my requirements for generating both Models and an API layer.
So far, it is working for generating models, and I have it generating some sort of API Layer, however I have run into a snag when using the $ReturnType as demonstrated in the example Angular Web API Service. In the example code;
${
using Typewriter.Extensions.WebApi;
string ReturnType(Method m) => m.Type.Name == "IHttpActionResult" ? "void" : m.Type.Name;
string ServiceName(Class c) => c.Name.Replace("Controller", "Service");
}
module App { $Classes(:ApiController)[
export class $Name {
constructor(private $http: ng.IHttpService) {
} $Methods[
public $name = ($Parameters[$name: $Type][, ]) : ng.IHttpPromise<$ReturnType> => {
return this.$http<$ReturnType>({
url: `$Url`,
method: "$HttpMethod",
data: $RequestData
});
};]
}
angular.module("App").service("$ServiceName", ["$http", $Name]);]
}
It is using $ReturnType, however when you are calling a .net WebApi controller with the method;
public async Task<IActionResult> DoSomething(){
return Ok(MyModel);
}
The $ReturnType is IActionResult, which is not strongly typed enough for me. I want this to be of type MyModel.
Is there something I can do to get the type returned within Ok? Can I decorate the method with a Type which Typewriter can then read and use?
Ok, so I have had no answers on this question, so I will answer it with my current solution so it might help out others.
I have created a new Attribute;
public class ReturnTypeAttribute : Attribute
{
public ReturnTypeAttribute(Type t)
{
}
}
Which I then use to decorate my Api method;
[ReturnType(typeof(MyModel))]
public async Task<IActionResult> DoSomething(){
return Ok(MyModel);
}
Now in my TypeWriter file, I have the following code;
string ReturnType(Method m) {
if (m.Type.Name == "IActionResult"){
foreach (var a in m.Attributes){
// Checks to see if there is an attribute to match returnType
if (a.name == "returnType"){
// a.Value will be in the basic format "typeof(Project.Namespace.Object)" or "typeof(System.Collections.Generic.List<Project.Namespace.Object>)
// so we need to strip out all the unwanted info to get Object type
string type = string.Empty;
// check to see if it is an list, so we can append "[]" later
bool isArray = a.Value.Contains("<");
string formattedType = a.Value.Replace("<", "").Replace(">", "").Replace("typeof(", "").Replace(")", "");
string[] ar;
ar = formattedType.Split('.');
type = ar[ar.Length - 1];
if (isArray){
type += "[]";
}
// mismatch on bool vs boolean
if (type == "bool"){
type = "boolean";
}
return type;
}
}
return "void";
}
return m.Type.Name;
}
So as you can see, I am checking for an Attribute called "returnType", then getting the value of this attribute which is a string, removing some formatting to get to the raw object name, then returning this. So far it is working well for my needs. If anyone can think of a nicer solution, then please let me know!
It is not the best solution I was hoping for as you need to make sure you have ReturnType(typeof(Object)) if you want the correct type in the .ts file.
In my case I get the return type from the parameter in the method:
// Turn IActionResult into void
string ReturnType(Method objMethod)
{
if(objMethod.Type.Name == "IActionResult")
{
if((objMethod.Parameters.Where(x => !x.Type.IsPrimitive).FirstOrDefault() != null))
{
return objMethod.Parameters.Where(x => !x.Type.IsPrimitive).FirstOrDefault().Name;
}
else
{
return "void";
}
}
else
{
return objMethod.Type.Name;
}
}
See:
Turbocharging Your Angular 4+ Development Using Typewriter

generic action method mvc with database call

I am searching for a way to make generic action methods that can be inherited by multiple controllers, so I don't have to repeat the same method in MVC for different controllers and tables. I think this would be applicable to a lot of the CRUD stuff I have to frequently do for multiple classes.
For example, here's the code I'd like to duplicate:
public ActionResult ToggleQC(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
BACTERIA_EVW bacteria = db.BACTERIA_EVW.Find(id);
if (bacteria == null)
{
return HttpNotFound();
}
//add/remove QC status (switch to whichever one it isn't right now)
if (bacteria.QCOn == null) //if it hasn't been QCed
{
bacteria.QCOn = DateTime.Now;
bacteria.QCBy = User.Identity.Name;
}
else //if it has been QCed and they are undoing it
{
bacteria.QCBy = null;
bacteria.QCOn = null;
}
//save changes
db.Entry(bacteria).State = EntityState.Modified;
db.SaveChanges();
//return updated QC status partial
return PartialView("_QCStatus", bacteria);
}
I need to do the same thing in a chemistry controller, but I'd rather not repeat the whole thing and just change one part. Is it possible to pass the model type into the method as a parameter, to replace BACTERIA_EVW? How would I do that?
I apologize if this is something really basic; I may not know the right terms to look for. I've searched for generic action methods but I haven't found any answers, although there was something about generic controllers - do I need to make a generic controller class somehow to include a method like this?
Thanks very much.
If you just care about removing code redundancy you can create a generic controller with that method and inherit other controllers from that:
namespace BaseControllers
{
public class CoolController
{
public virtual ViewResult Get()
{
var awesomeModel = new object();
return View(awesomeModel);
}
}
}
And in your child controller:
public class CoolController : BaseControllers.CoolController
{
public override ViewResult Get()
{
var ignoredResult = base.Get();
// ViewData.Model now refers to awesomeModel
return View("NotGet");
}
}
Same can happen for other CRUD operations.

Web API Action Filter to handle empty sets & 404's

I have a controller method which returns a list of resources like this:
[HttpGet, Route("events/{id:int}/rosters")]
public RosterExternalList List(int id, int page = 1, int pageSize = 50) {
return Repository.GetRosters(id).ToExternal(page, pageSize);
}
And the repository method is:
public IQueryable<EventRoster> GetRosters(int id) {
return EventDBContext.EventRosters.Where(x => x.eventID == id).OrderBy(x => x.EventRosterID).AsQueryable();
}
This is the same pattern for multiple list methods. The problem is that when no items are retrieved from the db, the api sends a 200 with an empty response body even if the id passed in is invalid.
What I want is if id = invalid, send appropriate response (404?). Otherwise, if the id is valid, and there are no records, send the 200 with empty body.
My question is - is this the right way to handle this? Can this be done via an Action Filter so it will be implemented across all the methods like this? How?
It is possible with an action filter like this:
public class EventsFilter : ActionFilterAttribute
{
public EventDBContext EventDBContext { get; set; }
public override void OnActionExecuting(HttpActionContext actionContext)
{
bool exists = false;
var routeData = actionContext.Request.GetRouteData();
object value;
if (routeData.Values.TryGetValue("id", out value))
{
int id;
if (int.TryParse(value, out id))
{
exists = EventDBContext.EventRosters.Where(x => x.eventID == id).Any();
}
}
if (exists == false)
{
var response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, "Event not found");
throw new HttpResponseException(response);
}
}
}
You would also need to configure a dependency resolver to set EventDBContext property.
Is it the right way?
It depends on your solution design:
If your business layer is integrated and depends on the Web API (as it appears from your example), then yes it is the way to go.
If Web API (service layer) is not the only one who uses your business layer, then you would want to avoid duplication of event checking in other places and move it to a more generic class than Web API action filter and call this class from your business layer instead of Web API to make sure that regardless of the caller, you would always check if event exists. In that class you would throw something like BusinessLogicNotFoundException with information about event. And on the Web API, you would need to create an ExceptionFilterAttribute that handles BusinessLogicNotFoundException and creates an appropriate 404 response.

How to use hashed IDs within Entity Framework in ASP .NET MVC 5.1 web application to avoid predictible links to records in database

I have model class:
public class Person {
public int Id { get; set; }
...
}
and to see details about a person user can guess its' id
http://localhost:17697/Person/Details/2
they're just consecutive integers.
How can I tell Entity Framework to shuffle those ID to make them harder to guess?
If you don't want predictable IDs then you could use a Guid instead of int. "Shuffling" would over-complicate the process and it's not going to give you any protection.
Remember that if you're trying to secure a url, write proper security using authorization and filters. Security through obscurity does not actually secure anything
Personally, I utilize slugs in my URLs, rather than ids. Something like:
http://localhost:17697/Person/Details/john-doe
You then pull the object based on the slug:
db.People.SingleOrDefault(m => m.Slug == slug);
However, "security by obscurity" is not a good game plan. Making the ids "harder to guess", doesn't solve the problem of people accessing it who shouldn't. If the details should be protected, then implement authentication and specify an authorization policy for the action.
Late to the party, but since there isn't much about using HashIds within ASP.NET MVC I'll share my solution using a custom ModelBinder and a BaseModel class. The end route looks something like /example/voQ/details.
First you need a model, that your existing models can extend from and generate a HashId;
public class abstract BaseModel
{
private static readonly Hashids __hashId = new Hashids("seed", 2);
public Id { get; set; }
[NotMapped]
public HashId
{
get { return BaseModel.__hashId.Encode(this.Id); }
}
}
The binder needs registering in Global.asax for each model:
ModelBinders.Binders.Add(typeof(ExampleModel), new ControllerModelBinder<ExampleModel>());
Then the action can use the model directly without worrying about the hash id:
public ActionResult Details(ExampleModel model)
{
return View(model);
}
Setting up a link is the same, but rather than passing the Id, you need to use the HashId property from the BaseModel.
#Url.Action("Details", new { id = item.HashId })
Finally the the model binder:
public class ControllerModelBinder<T> : DefaultModelBinder
where T : BaseModel
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
if (bindingContext.ModelType == typeof(T))
{
string hash = bindingContext.ValueProvider.GetValue("id").RawValue.ToString();
if (!string.IsNullOrWhiteSpace(hash))
{
int id = HashIdHelper.ToInt(hash);
if (id > 0)
{
using (ApplicationContext context = new ApplicationContext())
{
DbRawSqlQuery<T> query = context.Database.SqlQuery<T>(string.Format("SELECT * FROM {0} WHERE id = #Id LIMIT 1", EntityHelper.GetTableName<T>(context)), new MySqlParameter("#Id", id));
try
{
T model = query.Cast<T>().FirstOrDefault();
if (model != null)
{
return model;
}
}
catch (Exception ex)
{
if (ex is ArgumentNullException || ex is InvalidCastException)
{
return base.BindModel(controllerContext, bindingContext);
}
throw;
}
}
}
}
}
return base.BindModel(controllerContext, bindingContext);
}
}
You can use HttpServerUtility.UrlTokenEncode and HttpServerUtility.UrlTokenDecode
Encode uses base64 encoding, but replaces URL unfriendly characters.
There's a similar answer in a previous SO question. See the accepted answer.
MSDN Reference

Why controllers run first in the ASP.NET MVC?

I want to improve current implementation of the ASP.NET MVC Framework.
Current code:
routes.MapRoute(null, "I-want-to-fly", new { controller = "Airport", action = "Fly" });
public class AirportModel
{
public List<Plane> Planes { get; private set; }
public List<Pilot> Pilots { get; private set; }
public void AddFly(Plane plane, Pilot pilot, Passenger passenger)
{
// . . .
}
}
public class AirportController
{
private AirportModel model;
[HttpGet]
public ViewResult Fly(string from, string to)
{
var planes = return (from p in model.Planes
where p.CityFrom == from && p.CityTo == to
select p).ToList();
return View(planes);
}
[HttpPost]
public ActionResult Fly(Plane plane, Passenger passenger, DateTime time)
{
if (!(ModelState.IsValid && plane.TimeOfDeparture == time))
return View();
var pilot = (from p in model.Pilots
where p.Free && p.CanAviate(plane.Id)
select p).First();
model.AddFly(plane, pilot, passenger);
return RedirectToAction("Succeed");
}
}
My proposal:
routes.MapRoute(null, "I-want-to-fly", new { model = "Airport", action = "Fly" });
public class AirportModel
{
private List<Plane> planes;
private List<Pilot> pilots;
private void AddFly(Plane plane, Pilot pilot, Passenger passenger)
{
// . . .
}
[HttpGet]
public ViewResult Fly(string from, string to)
{
var planes = return (from p in model.Planes
where p.CityFrom == from && p.CityTo == to
select p).ToList();
return View(suitablePlanes);
}
[HttpPost]
public ActionResult Fly(Plane plane, Passenger passenger, DateTime time)
{
if (!(ModelState.IsValid && new PlaneController().CanFly(plane, time)))
return View();
var pilot = (from p in pilots
where p.Free && p.CanAviate(plane.Id)
select p).First();
AddFly(plane, pilot, passenger);
return RedirectToAction("Succeed");
}
}
public static class PlaneController
{
public static bool CanFly(Plane plane, DateTime time)
{
return plane.TimeOfDeparture == time; // it will be more complex
}
}
You see, in such way we don't need excessive count of controllers and their methods. Model would create controller only by perforce: mostly to verify user input (not input validation, business validation).
What do you think, can this idea have a continuation? Or, what is wrong with it?
Thanks for your replies!
UPDATE: I noticed, that we need to replace implementations of controller and view as a result of changing the model's state (mostly). So, if model causes to change the implementation, why model cannot do it?
UPDATE 2: It seems to me I explained incorrectly. I don't want model to do all work, of course no! I try to say, that not controller should decide what to do with model and what view is the most suitable for this user request.
Doesn't it strange, that model doesn't know how to visualize itself, but some controller knows?
Doesn't it strange, than we need controller for the GET request, where there is nothing to control?
I try to remove those strangenesses.
UPDATE 3: I understand that it cannot be applied anywhere. The main question is: can it improve some part of current implementations of MVC ? Mostly I'm interested in ASP.NET MVC -- can we
remove redundant controllers or some its methods
work directly with models
using this idea? Is it possible and what are the problems of this idea?
Found problems:
More strong connection between model and view/controller -- but currently I don't think it's a problem. Actually it shows that views and controllers were created in help for the major element -- model.
UPDATE 4: I changed the code, showing "before/after". Maybe this example will be better.
Doesn't this just violate the whole idea of MVC? Your model is separated from your controller and your view. In this way (the way you propose) you would not be able to replace your model by another implementation, or your controller for that matter.
updated I:
You could of course let your model do the part of the controller as well, but from that moment on you're not talking about the MVC design pattern anymore. For MVC, the model does and should not now about the view. That's the controllers job.
The controller receives user input and initiates a response by making calls on model objects. A controller accepts input from the user and instructs the model and viewport to perform actions based on that input.
In the MVC pattern, the Model isn't just fixed to your database model, it could be a combination of your database model and a repository pattern as well, where you implement your business logic.
The biggest problem I see with your proposal is that it makes code non-reusable. I get a model that is tightly coupled with it's views which I really don't want if I want to reuse the model in whatever way I might want to.
Update II
I think your are being mislead by the actual word Controller, I had that thought for a while and your latest comment sort of confirms this for me
Controllers are some objects, that check correspondence of user input to business-logic.
Controllers act upon user input, they might check the user input but their responsibility for checking validity stops there. Business logic goes in the Model (again, the Model as defined by the MVC pattern, not the model as in datamodel). Their main purpose is deciding what View to display.
Also from one of your latest comments:
How do you think, if [asp.net mvc] would be developed in my way, would it solve problem of redundant controllers?
Asp.Net MVC follows the MVC design pattern. Your proposal does not. It seem more like a ModelControlled View pattern, just to coin a name. Also, there are no redundant controllers, the controllers are no problem, they are an integral part of the solution.
And an effort to simplistically clarify what I mean with a code example:
namespace DataProject.Model
{
public class AirportModel
{
public List<Plane> Planes { get; set; }
public List<Pilot> Pilots { get; set; }
public List<Passenger> Passengers { get; set; }
public List<Flight> Flights { get; set; }
}
}
namespace SomeProject.Repository
{
public class AirportRepository
{
private DataProject.Model.AirportModel model;
//constructor sets the model somehow
public bool AddFlight(Plane plane, List<Passenger> passengers, DateTime time)
{
//Business logic
if (plane.TimeOfDeparture != time) return false;
var pilot = (from p in model.Pilots
where p.Free &&
p.CanAviate(plane.Id)
select p).FirstOrDefault();
//More Business logic
if (pilot == null) return false;
//Add plane, pilot and passenger to database
model.Flights.add(new Flight{Pilot = pilot, Plane = plane, Passengers = passengers});
//Even here you could decide to do some error handling, since you could get errors from database restrictions
model.Save();
return true;
}
public List<Planes> GetPlanes(string from, string to)
{
return (from p in model.Planes
where p.CityFrom == from && p.CityTo == to
select p).ToList();
}
}
}
namespace MVCApp.Controllers
{
public class AirportController
{
private SomeProject.Repository.AirportRepository repository;
[HttpGet]
public ViewResult Fly(string from, string to)
{
var viewModel = repository.GetPlanes(from, to);
return View(viewModel);
}
[HttpPost]
public ActionResult Fly(Plane plane, List<Passenger> passengers, DateTime time)
{
if (!ModelState.IsValid) return View();
if (!repository.AddFlight(plane, pilot, passenger)) return View();
return RedirectToAction("Succeed");
}
}
}
No offense intended but how exactly is this an improvement?
So you've made a class called a PersonModel that isn't really doing "model things" at all - it is doing the work that Controllers do - you've got it handling gets and posts and calling out for the display of Views and then you've got a static "Controller" that really controlling nothing and is concerning itself with business logic. Honestly, I don't get how this is an improvement.
A concrete example of is you've got a controller checking whether Age >= 18, which is a very "business rules" thing for a controller to be doing. That's not the purpose of a controller. That's the job of a model object - to concern itself with things like business logic. Controllers, as one person put it, are more of an electronic curator. In your example, you've relegated it to something far less than a curator.
There are distinct roles that objects play in an MVC application. Views show us stuff and provide us with ways to interact with the application. Controllers handle the input coming from the View and serve up views that are needed. Models provides a place to put data and the logic and business rules that the model encompasses. Services handle things like persisting data to some store, like a DB.
You can do everything in one class without controllers at all but you want "separte of concerns"
So the controller is responsible for the http request and validation and the model is responsible only for the data.
You are the programmer then you could agree or disagree with MVC pattern.
But the pattern which you described doesn't support the separation of concern and it breaks out the whole idea about MVC
This has nothing to do with MVC.
This is 'MVNothing'
:)
Just kidding *_^

Categories