I noticed that the MapRoute extension includes an overload that accepts a string[] parameter which is called 'namespaces'. I read what Google had for me on it, and supposedly this is to help the framework find controllers in places it wouldn't otherwise look.
I did some spiking, and tried putting controllers in weird locations. I put one in the Scripts folder; I even built one in a separate assembly with a separate root namespace.
Without putting anyting in the namespaces param, everything worked fine. If I put just one of the namespaces in the namespaces param, it still found all my controllers. I thought maybe it would use that array to disambiguate between similarly named controllers, but that didn't happen either. A HomeController in MyProj.Controllers and one in SomeOtherName.Stuff would collide still.
So my question is, is that parameter deprecated? Or is it still used somehow in a way that I have yet to discern?
Ok, so after further testing, I figured out that it is not a filter, exactly, but it kinda is also. I gave you 'answer' credit even though you're partially wrong.
So, it does, after all, act like I thought it should which is to say it disambiguates. Basically, the logical flow is something like this:
Look for a namespace in the _cache that matches one in the namespaces array
if that's found, look for a controller of the right name
-- if that's found, return it
-- if it's not found, return search everywhere else that it'd normally look
if it's not found, search everywhere lese
So, in short, my thought that the namespaces array would serve to disambiguate was correct. The reason my first test in that regard failed is that it only does a perfect match, and I made the mistake of using just the root n/s from the assembly (in other wordss, MyRoot instead of MyRoot.Controllers).
What this namespaces thing allows, then, is to have a HomeController in two different namespaces and match them differently depending on the url or params.
No, the value is not deprecated. It is used in DefaultControllerFactory.cs. Note that if the value is supplied, it completely replaces the standard name spaces searched. When the parameter is not supplied, the name spaces searched our determined by:
HashSet<string> nsDefaults = new HashSet<string>(ControllerBuilder.DefaultNamespaces, StringComparer.OrdinalIgnoreCase);
When the parameter is supplied, the list you supply replaces this value.
In either case, DefaultControllerFactory calls:
GetControllerTypeWithinNamespaces(controllerName, nsDefaults);
...with the list, either the one you supplied, or the default. So it is clear that the value is supported.
When you look at the source code there, and in ControllerTypeCache, you can see the real purpose of the namespaces value: It does not cause the controller factory to look in places that would not otherwise look; rather it is a filter. In other words, it prevents the default controller factory from looking and name spaces that it would otherwise search for controllers.
Related
The result of GetParent('c:\1\2\') is 'c:\1\2'.
And the result of GetParent('c:\1\2') is 'c:\1'.
Is this the normal/expected behavior? If yes, what is the logic behind it?
This behaviour might seem a little odd but it is by design. This class is modelled on the .net class Directory. The documentation for Directory.GetParent says:
The string returned by this method consists of all characters in the path up to, but not including, the last DirectorySeparatorChar or AltDirectorySeparatorChar. For example, passing the path "C:\Directory\SubDirectory\test.txt" to GetParent returns "C:\Directory\SubDirectory". Passing "C:\Directory\SubDirectory" returns "C:\Directory". However, passing "C:\Directory\SubDirectory\" returns "C:\Directory\SubDirectory", because the ending directory separator is after "SubDirectory".
I've found properties corresponding to each action named like this: MVC.<Controller>.<Action>Params, they contain parameter names for each action. What are they for and how they can be used?
There were some edge scenarios where it was interesting to pass the parameter name as a constant. I can't instantly recall what that person was doing, but I could see this being useful is calls to AddRouteValue. In the end, it's all about never to have to use a literal string that refers to a C# object, whether it's a class, method, or param.
I have a bit of a dilemma, which to be honest is a fringe case but still poses an issue.
Currently I am using Ninject MVC and bind all my controllers like so:
Kernel.Bind<SomeController>.ToSelf();
Which works a treat for 99% of things that I have needed to do, however at the moment I am doing some wacky stuff around dynamic routing and dynamic controllers which require me to manually write a method to get the type of a controller from ninject. Now initially I thought it would be easy, but its not... I was expecting that I could get the controller based on its name, but that didnt work.
Kernel.Get<IController>("SomeController");
That got me thinking that its probably because it only knows about a binding to SomeController, not IController. So I thought, I can just write all my bindings like so:
Kernel.Bind<IController>.To<SomeController>().Named("SomeController");
This way it should be easy to get the type of the controller from the name doing the previous code, however if I were to bind this way, I would have a problem when I come to unbind the controllers (as plugins can be loaded and unloaded at runtime). So the normal:
Kernel.Unbind<SomeController>()
Which was great, will no longer work, and I would have to do:
Kernel.Unbind<IController>();
However then I realised that I need to give it some constraint to tell it which binding for this type I want to unbind, and there seems to be no overloads or DSL available to do this...
So I am trapped between a rock and a hard place, as I need to satisfy the ControllerLookup method, but also need to keep it so I can add and remove bindings easily at runtime.
protected override Type GetControllerType(RequestContext requestContext, string controllerName) {
//... find and return type from ninject
}
Anyone have any ideas?
(Just incase anyone questions why I am doing this, its because of the way I am loading plugins, Ninject knows about the types and the namespaces, but within the context of creating a controller it doesn't know the namespace just the controller name, so I do this to satisfy the isolation of the plugin, and the location of the dynamic controller, it is a roundabout way of doing it, but it is what people have done with AutoFac before Example of similar thing with AutoFac)
In my opinion the bindings should be created once at application startup and not change anymore after the first resolve. Everything else can lead to strange issues. Unless you have proper isolation using an AppDomain for each plugin you can not really unload them anyway. Instead of unloading bindings you can make them conditional and disable them using some configuration.
If you really want to unload bindings then I suggest not to do it for single bindings but take advantage of modules. Load all bindings belonging to one plugin together in one or several modules and unload those modules instead of the single bindings.
Stephen Walther recommends that you should provide explicit view names when you want to unit-test them.
I definitely want to test them, but I'm curious whether or not this recommendation is still valid with the release of 1.0.
In the NerdDinner tutorial the tests just check if the viewResult is null. They don't explicitly specify the viewName, which is therefore empty.
I would like to remove the view-names provided as strings in the actual code, but these checks seems less useful to me though...
(I can't even think of a scenario where the viewResult does return null?!)
There are really two separate questions here. The first is whether or not anything has changed in the MVC framework since Stephen Walther wrote the recommendation which would change the recommendation. The answer to that question is "no."
The second question is whether or not the recommendation is a good practice. I'm going to disagree with Stephen Walther, here. His example is a bit strange. His unit test for the "Index" action attempts to assert that the action returns an explicit view name, when clearly it does not. If I wrote this unit tests, I would instead assert that the view name is equal to empty string. Then the unit test would pass. Instead of asserting that the action specifies a view of a certain name, a unit test would then effectively assert that the action specifies that the view have the same name as the action. This is a legitimate thing to test.
One of the guiding principles behind the MVC framework is convention over configuration. In other words, you should not be required to specify anything which is just the usual default value. The default value of the view name is the same as the action name. The documented behavior of the WebFormsViewEngine is to look for a view with the same name as the action unless a separate view name is specified. Not specifying a view name, therefore, is the same as specifying "use the default view name."
Therefore, I do not think it is a good idea to specify a view name which is the same as the default, and I do not think that using unit testing is a good reason to violate this convention.
Providing explicit view names matters if controller can return various views. Then you can unit test controller, that it returns one it's supposed to return by name. Otherwise - i don't see the point of using them.
I'm confused with how views are organized, and it is important to understand this as ASP.NET MVC uses conventions to get everything working right.
Under the views directory, there are subdirectories. Inside these subdirectories are views. I'm assuming that the subdirectories map to controllers, and the controllers act on the views contained within their subdirectories.
Is there an emerging expectation of what types of views are contained within these directories? For instance, should the default page for each directory be index.aspx? Should the pages follow a naming convention such as Create[controller].aspx, List[controller].aspx, etc? Or does it not matter?
View directory naming and file naming are important, because the ASP.NET MVC framework makes certain assumptions about them. If you do not conform to these assumptions, then you must write code to let the framework know what you are doing. Generally speaking, you should conform to these assumptions unless you have a good reason not to.
Let's look at the simplest possible controller action:
public ActionResult NotAuthorized()
{
return View();
}
Because no view name has been specified in the call to View(), the framework will presume that the view filename will be the same as the Action name. The framework has a type called ViewEngine which will supply the extension. The default ViewEngine is WebFormViewEngine, which will take that name and append an .aspx to it. So the full filename in this case would be NotAuthorized.aspx.
But in which folder will the file be found? Again, the ViewEngine supplies that information. With WebFormViewEngine, it will look in two folders: ~/Views/Shared and ~/Views/{controller}
So if your controller was called AccountController, it would look in ~/Views/Account
But there might be times when you don't want to follow these rules. For instance, two different actions might return the same view (with a different model, or something). In this case, if you specify the view name explicitly in your action:
public ActionResult NotAuthorized()
{
return View("Foo");
}
Note that with WebFormViewEngine, the "view name" is generally the same as the filename, less the extension, but the framework does not require that of other view engines.
Similarly, you might also have a reason to want your application to look for views and non-default folders. You can do that by creating your own ViewEngine. I show the technique in this blog post, but the type names are different, since it was written for an earlier version of the framework. The basic idea is still the same, however.
In regard to expected names for the views, I think that it's one of those things that each project or organization will try to standardize.
As you hinted to in your question, it's possible that some of these Views (or more precisely, the Actions that render them) become popular across the board, like for example the ones below that are common in RoR applications that adopt the REST paradigm:
/orders/ (i.e. index)
/orders/show/123
/orders/edit/123
/orders/update/123
/orders/new
/orders/create
/orders/destroy/123
The choice/standardization of the Views is largely dependent on how you model your application (to say the obvious) and how fine-grained you want to go. The closer you map your controllers to individual model classes (cough...resources...cough), the shorter your actions will tend to be and more easily you will be able to follow a standard set of actions (as in the above example).
I also believe that shorter actions help pushing more and more of the model business logic into the models themselves, where it belongs.