asp.net mvc - Views and Controllers - asp.net

How do controllers know which views to return? I thought it was by naming convention, but I have seen instances, for example in the Nerd Dinner application, where the names don't match. Where or how do I see this mapping? Thanks.

public class EmployeesController
{
public ViewResult Index()
{
return View("CustomerName");
}
}
Will search for:
Views/Employees/CustomerName.aspx
Views/Employees/CustomerName.ascx
Views/Shared/CustomerName.aspx
Views/Shared/CustomerName.ascx
That's pretty much it..
When you just return View(); without specifying a name, it searched for the view with the same name as the controlleraction. In this case, Index.aspx

There are three ways to specify a view name.
By Convention
public ActionResult MyAction {
return View()
}
That will look for a view with the name of the action method, aka "MyAction.ascx" or "MyAction.aspx"
** By Name **
public ActionResult MyAction {
return View("MyViewName")
}
This will look for a view named "MyViewName.ascx" or "MyViewName.aspx".
** By application path **
public ActionResult MyAction {
return View("~/AnyFolder/MyViewName.ascx")
}
This last one only looks in this one place, the place you specified.

It is based on the name of the Action in the Controller. Here's an example:
I have a controller named UserController.
One of my actions on that controller is named Index.
When I say return View();
It will look in the Views directory, in the User folder, for Index.aspx or Index.ascx
It will also look in the Shared folder.

Related

Unit testing if methods find and return a view in ASP.NET

I'm new to ASP.NET and I'm refactoring some functionalities in my MVC-structured ASP.NET application into area's. This has already lead to controller-methods not able to find their views anymore, which results in the following page:
To test if all controllers can find their views, I'd like to write some automated unit tests for this.
I have came up with the following:
[TestMethod]
public void AboutTest()
{
var controller = new HomeController();
var result = controller.About() as ViewResult;
Assert.IsNotNull(result);
}
which tests the About-method in the following code:
public class HomeController : Controller
{
public ActionResult About()
{
return View();
}
public ActionResult Contact()
{
return View("~/Views/SomeFolder/Contact.cshtml");
}
}
But even when the HomeControllers About-method can not find a view, this assert succeeds, so this does not work for me.
I have found a solution online to use use ViewEngine.FindView() here. I don't think I can use this, since in some controllers the views are referenced by a hardcoded string (see the contact method in the example controller above) instead of just returning the default view (simularly named as its method). The ViewEngine.FindView(controller.ControllerContext, "about", "about"); will then fail, but the controller-method would not.
Another solution states to use Assert.IsEqual() and check if the result.ViewName is equal to a hardcoded string (for example: "About"). Since I do not set or know the title of the views I'm expecting to get returned, this would not be a solution either.
(How) would I be able to test my application for this?
You shouldn't check for null, it will return a ViewResult even when it doesn't render.
To test whether it actually renders use AssertViewRendered from mvccontrib.
[TestMethod]
public void AboutTest()
{
var controller = new HomeController();
var result = controller.About().AssertViewRendered();
}
You can even check for a specific view like so:
result.AssertViewRendered().ForView(MVC.Your.Views.AboutView);
Or supply data like so:
controller.page().AssertViewRendered().ForView("page").WithViewData<SomeModel>();
For an interactive tutorial with lots of pictures I can recommend: http://toreaurstad.blogspot.nl/2011/09/adventures-with-mvccontrib-testhelper.html
Edit:
You might also check out Selenium to test your entire app (incl. rendering of 200 routes).

Multiple actions matched when i start controller in asp core

I have asp core Project and Modules project into them
and when i started i cath them - error message
Structure of my solution there:
how to make it work?
You can't have two controllers with the same name, change one of them to another name.
You can't have two Actions methods in one controller with the same name, so you need to change the name of one of them . However you can do this if they have different HTTP verbs such as "GET" and "POST"; and in doing so, because they are C# methods, they need to be slightly different. For instance, they could have different parameters.
For example
[HttpGet]
public IActionResult Subscribe()
{
return View();
}
[HttpPost, ValidateAntiForgeryToken]
public IActionResult Subscribe(Subscriber _subscriber)
{
ViewData["Title"] = "Subscribe";
_subscriber.Created = DateTime.Now;
_subscriber.name= "John Doe";
_subscriber.email= "JohnDoe#email.com";
_dataContext.Add(_subscriber);
_dataContext.SaveChanges();
return RedirectToAction("Index", "Home");
}
That should solve the problem.

asp.net mvc 4 custom urls for action method

I am creating a asp.net mvc 4 application
public class AspNetController : Controller
{
//
// GET: /AspNet/
public ActionResult Index()
{
return View();
}
public ActionResult Introduction()
{
return View();
}
}
as Shown Above There is AspNet Controller and Introduction Action Method
Default Url for Introduction Action Method is
localhost:55134/aspnet/introduction
But I Want Url Like
localhost:55134/aspnet/introduction-To-AspNet
Same for
/localhost:55134/aspnet/NetFrameWork To
/localhost:55134/aspnet/What-is-.Net-Framework
How to do that
You should be able to use the ActionName attribute to decorate your routes.
[ActionName("Introduction-To-AspNet")]
public ActionResult Introduction()
{
return View();
}
You really want to use AttributeRouting, either via a 3rd party package or natively if you can.
Technically this concept comes under Routing in ASP.NET MVC.
For this you need to do an entry for route in App_Start->RouteConfig.cs file under RegisterRoutes(RouteCollection routes)
For Example:
routes.MapRoute(
"customRouteName",
"aspnet/introduction-To-AspNet",
new { controller = "AspNet", action = "Introduction" });
here aspnet/introduction-To-AspNet will append after your base url i.e. localhost:55134/
The quick and dirty answer is to add a route to your ~/AppStart/RouteConfig.cs file and it will be taken care of:
routes.MapRoute(
name: "CustomRoute",
url: "Aspnet/Introduction-To-AspNet",
defaults: new { controller = "Home", action = "AspNet", id = UrlParameter.Optional }
);
However, I'm assuming this is for some type of blog? I would reccomend that you have an action method called view, and then use your name as a parameter for the article. That way, you don't have to go in and edit the code every time you add a new article or other content:
public class ArticlesController : Controller
{
public ActionResult ViewArticle(string? title)
{
ViewBag.Article = title;
return View();
}
}
that way, your URL would be www.yoursite.com/Articles/ViewArticle/Introduction-To-AspNet. In general, you don't want to add tons of specific routes to your route config if you can avoid it. That being said, if this is a legacy system, the route table may be the only way.
EDIT
Ok, so what you can do is pass the string into the ViewBag and use a case statement to determine which partial view to show (I think this just might be your ideal solution):
<!--cshtml view-->
#switch(ViewBag.Article)
{
case 'Introduction-To-AspNet':
#Html.Partial('pathToPartialView.cshtml')
break;
case 'Some-Other-Article'
#Html.Partial('pathToAnotherPartialView.cshtml')
break;
...
...
default:
#Html.Partial('invalidArticleName.cshtml')
break;
}
The controller will pass the article name through the ViewBagand then you can use the case statement to figure out which article to render... and of course, the real secret sauce you've been looking for: #Html.Partial('URL') - this will take your partial and render it right were you put that in the page. You can also pass objects to that just as an FYI.
In addition, make sure that you have a default action on the switch statement that will show some sort of 404 page that indicates that the name in the URL was invalid. You ALWAYS want to have this anytime you're taking user input from the URL because people monkey with URLs all the time (and more innocently, copy+paste them wrong/incompletely all the time)

Error 404 creating a view in mvc5

I am linking a SQL database to my MVC ASP.Net. I have created the model, context class, web config and controller.
However for some reason when I create a view by right clicking on the 'views' folder I get a 404 error when I debug. If I create my view by right clicking next to:
public ActionResult Index()
in the Controller class i don't get this error. Is there any reason for this?
From your question, it seems like you might be creating the View in the wrong folder.
When you add a view for a Controller/Action, you must create subdirectory in ~/Views that matches your controller's name.
For example,
public ProductController : Controller
{
public ActionResult Index()
{
return View();
}
}
You would add your Index.cshtml to Views/Product:
~/Views/Product/Index.cshtml
If you wanted to return another view called "Other.cshtml",
return View("Other");

Using Html.Action with a controller in a subfolder

I am building a webapge using asp.net mvc4. For organization, I would like to put some of the controllers inside a subfolder in the Controllers folder. For example:
Controllers
AccountController
BlahController
Dashboard (Folder)
ChickenController
BeefController
To use BeefController (which returns a partial view), it seems as though I should use:
#Html.Action("Index", "Dashboard/BeefDashboard")
However this gets me the following error:
The controller for path '/' was not found or does not implement IController.
How would I be able to use BeefController?
There no physical sub folder concepts in the ASP.NET MVC world. What you should do is to have an action method in Dashboard controller, which accepts a parameter and then return specific views according to that.
public class DashBoardController: Controller
{
public ActionMethod Index(string id)
{
if(id=="chicken")
{
return PartialView("Chicken");
}
else if(id=="beef")
{
return PartialView("beef");
}
return View("NotFound");
}
}
Now you can access those like
Dashboard/beef
Dashboard/chicken

Resources