Specify ASP.NET MVC 3 Routes symbolically - asp.net-mvc-3

I really like the ASP.NET MVC 3 framework. Or at least, it sure is incomparably better than trying to fool with ASP.NET 3.5 or 4.0. However, I am just really confused about something. Why did they choose to specify routes with strings?
IOW, I am told to specify my routes like this (for instance):
... new { controller = "Products", action = "List", id = UrlParameter.Optional }
This route matches a ProductsController.List() method. Let's say I'm in a refactoring mood and I want to rename my ProductsController to InventoryController. After using my renaming tool of choice, I have open up Global.aspx and go through all my routes and change all these stupid strings to "Inventory". You might respond that I can do a find and replace... but come on! I feel like that is such a last-generation answer.
I love refactoring my code as I come to understand my domain better. I don't want to use stupid (I say stupid because they have no significance to the compiler) strings to refer to symbolic/semantic code constructs that correspond exactly to type and method names that are ultimately stored in a symbol table. What is the point? Why bother with types at all? Let's just go back to writing scripts using associative arrays and dictionaries to represent our domain model... it seems to me that the benefit of strong typing is greatly lessened when we mix it with string references.
Seriously, though, an option would be reflection. Would there be a performance hit for this? I suppose the MVC framework must be using reflection on that "Products" string to get my ProductsController, so... But also, you would have to remove the "Controller" portion of the type name, as follows:
= typeof(ProductsController).Name.Replace("Controller", string.Empty)
I could use the following helper function to make it a little DRYer:
public string GetControllerName(Type controller)
{
return controller.Name.Replace("Controller", string.Empty);
}
Benchmarking is in order, if this is the only way to avoid those strings... Still, this is stupid. I'm using reflection on a type to get a string that MVC is going to use in conjunction with reflection to get the type I originally had in the first place.
Is there some reason not take the next (logical?) step and have the controller and action properties expect Types and Delegates directly? Wouldn't this simply be cleaner and clearer? So far as I understand, a fundamental aspect of MVC is convention over configuration, but routing with those strings just seems to be a furtive form of configuration to me.
Is there another way around this? I am still new to MVC. I've read that we can replace these routing components. Does anyone know if it is possible to do what I'm talking about? And if it's not possible, well... am I alone here? Am I missing something? Some overriding reason why it is essential that these routes be set by dumb strings? If not, could this maybe be something to lobby for?
Am I alone in hating it when strings are used in this way? I still think C# needs something akin to Ruby's symbols and Lisp's keywords that our refactoring tools could take advantage of. Sort of like "string enumerations" where the enumeration value name is at the same time the value.
I understand that parts of this question are subjective, but I am also looking for the objective answer on whether it is possible to directly use types and delegates to specify these routing configurations.
Thank you,
Jeromeyers

Personally I never had problems with the way routes are defined because I always unit test them. So if I am in a refactoring mood, my unit tests always guarantee me that the routes will behave as I want.
Of course if you are still not satisfied with the way the ASP.NET MVC team designed the framework (don't hesitate to open a ticket and vote for improvement in future versions) you could always write a custom route:
public class IHateMagicStringsRoute<T> : Route where T : Controller
{
public IHateMagicStringsRoute(
string url,
Expression<Func<T, ActionResult>> expression
) : base(url, Parse(expression), new MvcRouteHandler())
{ }
private static RouteValueDictionary Parse(Expression<Func<T, ActionResult>> expression)
{
var mce = expression.Body as MethodCallExpression;
if (mce != null)
{
return new RouteValueDictionary(new
{
controller = typeof(T).Name.Replace("Controller", ""),
action = mce.Method.Name
});
}
return null;
}
}
and then instead of:
routes.MapRoute(
"Default",
"{controller}/{action}",
new { controller = "Home", action = "Index" }
);
you could:
routes.Add(
new IHateMagicStringsRoute<HomeController>(
"{controller}/{action}",
x => x.Index()
)
);
Now you can rename your controllers and actions as much as you like.

Related

Handling multiple classes in a generic controller, some pointers please

I am using MVC3.
I have a pretty complex document class that contains many sub classes, lets call them "dog", "cat", "sheep", "cow", "goat".
I would like to use a generic controller to list, add and edit each of these classes.
Listing: I can list the relevant entity by passing in document model and iterating through the relevant class.
Edit: I need to get the id and identify the class of interest ie "dog" and then passing this as the model for editing. However next time round I may be editing a "cat" instance. Typically in MVC, as I understand it, one would ideally create a "DogController" and a "CatController". However since this document class is meant to be flexible I do not wish to hard code controllers. It may be necessary to add 2 more classes ie "horse" and "donkey".
At the moment I am using some if/else logic to ensure that the correct View is setup and called with the correct class. However this does feel as if I am breaking some MVC rules here.
Perhaps the answer lies in the use of a more formal ViewModel. Perhaps I can then have one of the properties as the subclass ("Dog"). Perhaps this can be swapped out at runtime using IOC?
Thoughts and pointers appreciated?
Thanks.
EDIT: I have tried to create 2 version of the "edit" action with different input models
[HttpPost]
public ActionResult Edit(Dog DogModel){}
[HttpPost]
public ActionResult Edit(Cat CatModel){}
I thought that due to method overloading MVC would be able to pick the correct one when the View posted, and then applied modelbinding.
Perhaps I am expecting too much or my understanding is lacking.
routes.MapRoute("Route", "{controller}/{action}/{name}/{id}", new { controller = "Animal", action = "search", name = "Home", id = 0 });

Should controller methods take arguments?

Given that there is file selection widget on the view and controller need to handle event of selecting file, should I rather write controller method:
public void fileSelected(String filePath){
//process filePath
}
or
public void fileSelected(){
String filePath = view.getSelectedFilePath();
//process filePath
}
The first approach seems to introduce less coupling between C and V: C don't know what exactly data does C need while handling given event.
But it requires creating a lot of verbose methods similar to getSelectedFile on V side.
On the other hand, second approach may lead to cluttered controller methods in more complex cases than in example (much more data to pass than just filePath).
From your own experience, which approach do you prefer?
The first approach is my favourite. The only difference is I would rather use an object (like Mario suggested) to pass arguments to the method. This way method's signature will not change when you add or remove some of the arguments. Less coupling is always good :)
One more thing:
If You want to try the second solution I recommend using a ViewFactory to remove view logic from the controller.
The first approach is the way to go;
public void fileSelected(String filePath){
//process filePath
}
The Controller should not care about how the View looks like or how it's implemented. It gets much clearer for the developer as well, when creating/updating the view, to know what an action in the controller wants. Also it makes it easier for method overloading.
Though, I don't know really how String filePath = view.getSelectedFilePath(); would work. Are we talking about parsing the View code/markup?
On the other hand, second approach may lead to cluttered controller methods in more complex cases than in example (much more data to pass than just filePath).
That's when you would create a View Model class (let's say we name it MyViewModel) to store all the properties that you need to send (may it be 10 properties) and then pass that in the action: fileSelected(MyViewModel model). That's how it's intended to be used and what the *ModelBinder's in asp.net mvc are there to help you with.
I think you need to look at this from a step back.
Worry less about how it gets in, and be more concerned with validation and error raising.
Tomorrow, your requirements could change and demand that you source the information via a different architectural approach. You could refactor the setup of [inputs / an input object] into a base controller class - or one of several classes for different controller domains.
If you focus on proper validation, whether within the controller (scrubbing) or outside of it (unit tests), then you perform more thorough decoupling though duck typing.
I would go with the first approach. It's reusable and separates concerns. Even if the method of getting the filePath in the future were to change, it won't affect your method's functionality.

Strongly typed Razor Views as an Email Template engine

I do know there are several similar questions out there that address this topic, but I am not happy with the answers.
What I'd like is to take full advantage of the Razor View engine that can use strongly typed views with layout pages and partial views. I'd like to declare the model at the top of my views and just pass in that model. So simple! No dynamic models that need to be constructed explicitly just before passing them into the view. EDIT: I'd like to do this outside of a Web application, inside a class library that can construct email bodies. That's the real issue here is making use of the Razor View Engine that is not a web app.
The idea behind this is if I have a User object with 20 properties on it and my first version of the Welcome email only uses the Name, but later I want to edit the template to use their City, State or Email address, then I want to be able to update the Razor view without having to add code and recompile and redeploy.
I see RazorEngine and I love the idea and simplicity, but everything is a dynamic type. My issue here is that I'll be pulling data as models from the database. By having to shove things into a dynamic type, I don't get all my properties on the View.
I also see MvcMailer, which is also nice in theory but it suffers from the same issue which is that all data models passed into the view are dynamic and not strongly typed.
I've begun to build out my own version of this, which will require several web namespaces like System.Web.Mvc, System.Web.Razor and System.Web.WebPages - and I'm okay with that. The issue is the lack of HttpContext and ControllerContext and RouteData .... which I'm trying to mock/stub so the. I'm currently trying to investigate DisplayModes and figure out how to mock these outside a real Web context.
Is there a better way? If you're going to suggest one of the two previously mentioned frameworks, please note my issues and let me know if there are workarounds.
EDIT 2: After playing a bit more with the RazorEngine, the strongly typed models is not necessarily as much of an issue as I thought. What I'm left wishing for now is the ability to use a Layout page and partial views as well. I can hack around this with string placeholders that get replaced, but probably not very efficient AND not very flexible.
Assuming you are trying to achieve this from within an action method of a controller, here's a simple way to do it.
This method will give you the output of a strongly typed view :
public static string RenderViewToString(this Controller controller, string viewName, object model)
{
controller.ViewData.Model = model;
try
{
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindView(controller.ControllerContext, viewName, null);
ViewContext viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(controller.ControllerContext, viewResult.View);
return sw.ToString();
}
}
catch(Exception ex)
{
return ex.ToString();
}
}
Then from within a controller method, all you need to do is call this method with the name of the view and the model.
public ActionResult Mail()
{
// whatever you use to get your User object
var model = new User();
var output = this.RenderViewToString("~/Views/User/Email.cshtml", model)
}
This will allow you to simulate the rendering of a strongly typed view, including its associated layout, and gather the output as a string which you can then use to send via email.
The answer is that it doesn't seem to matter whether the object passed in is dynamic or not. I can pass my strongly typed object, and it will be accepted as is without needing to make it dynamic or rebuild a dynamic object.
My prelim tests show that this should be fine and works well.
Try out Actionmailer.net: https://bitbucket.org/swaj/actionmailer.net/wiki/Home
I've been using it quite successfully.
Check out RazorMachine. It's like RazorEngine, but works with layouts.

Command Pattern in .NET MVC 3 (removing junk from the controller)

I am trying to implement this Command Pattern on my .NET MVC 3 application, specifically for saving edits to a Thing. I am undecided on how to proceed. Before I get to the actual question, here is the simplified code:
public class ThingController
{
private readonly ICommandHandler<EditThingCommand> handler;
public ThingController(ICommandHandler<EditThingCommand> handler)
{
this.handler = handler;
}
public ActionMethod EditThing(int id)
{
...build EditThingViewModel and return with View...
}
[HttpPost]
public ActionMethod EditThing(int id, EditThingViewModel vm)
{
var command = new EditThingCommand
{
...not sure yet...
};
this.handler.Handle(command);
...redirect somewhere...
}
}
My EditThingViewModel is wholly disconnected from my domain, which consists of POCO classes. It seems like my EditThingCommand should look like this:
public class EditThingCommand
{
Thing ModifiedThing;
}
However, building ModifiedThing would then still be happening in my controller. That's the majority of the work in this case. By the time ModifiedThing is built (and the "old" timestamp applied to it for optimistic concurrency checking), all that's left is for command to call Update on my data context.
Clearly there is value in being able to easily decorate it with other commands, but I'd also like to be able to move the construction of ModifiedThing outside of my controller. (Perhaps this question is really just about that.) EditThingCommand is in my domain and doesn't have a reference to EditThingViewModel, so it can't go there. Does it make sense to have another command in my presentation layer for mapping my viewmodel to my poco entity?
I created an EditThingPostCommand outside of my domain, which takes the EditThingViewModel as a parameter. The EditThingPostCommandHandler is responsible for creating the EditThingCommand and calling its handler.
It works, but I'm not going to assume that's the best answer to my question. Arguably most of what the EditThingPostCommandHandler is doing could be done in a custom AutoMapper configuration, which would still serve the purpose of cleaning up the controller action method.
After several months of using this pattern on other projects, it is apparent to me that the commands on this particular project were simply too general and therefore too complex, requiring too much setup. It would have been better to create, for example, an EditThingTitleCommand and a MoveThingPiecesCommand and so on, and call them from their own ActionMethods.
In other words, when using the command pattern, don't just use the commands as replacements for typical CRUD operations. With more specificity comes more benefit.

MVC Security problems in my application - Best strategy for separating logic?

I feel like the biggest idiot - I thought only ActionResults were sent back to the client. For this reason, I had a load of "helper" methods in my controller.
I just tried accessing them via a URL and I swear I almost went crazy when I saw they can be reached! ... Luckily, no one else has discovered this yet.
One such method I have, that I call over and over again is :
public User GetCurrentUser()
{
User user = db.Users.SingleOrDefault(x => x.UserName == User.Identity.Name);
return user;
}
I have just created a folder called "Logic" inside my Models folder and I am attempting to separate the code - I was just wondering what the best strategy is for calling code, namespaces and more?
In the above example, I am using User.Identity.Name which only inherits from Controller. If I add this, I am back to stage one!
Thanks to Darin Dimitrov, I now know about the [NonAction] Attribute - which, adding to these methods does exactly what I need/fixes the security problem, however, many of these Methods are used in different controllers and I know it would be best if I can separate the logic from the controllers. I am just not sure what the best way to go about it is.
Can anyone point me in the right direction before I start pulling all my hair out!?
You may take a look at the [Authorize] attribute.
UPDATE:
Or you could use the [NonAction] attribute or make the method private. But the best practice in this case would be to simply move this logic out of your controller. A controller should contain only controller actions. Other logic should be placed in its respective layers.

Resources