Just started with MVC and I have a problem.
Below is the hierarchy of my files:
1.WebJltNZ\JWebJltNZ.Presentation.Web.Mvc\Controllers : LbpProfessionalController
2.WebJltNZ.Presentation.Web.Mvc\ViewModels : LbpProfessional
3.WebJltNZ.Presentation.Web.Mvc\Views\Home\RiskAndInsuranceServices\JltAffinityPartnerships :LbpProfessionalProtectionApplication
The method below:
public ActionResult Index()
{
return View(); // it's cannot be found.
}
is unable to find the view.
Am I missing something here. Please help.
You're getting the names wrong. The way it works is that the controller name matches a subfolder inside the view folder; and the action method matches a file inside that subfolder.
This means that the LbpProfessionalController in the Controllers folder should match a folder named LbpProfessional inside the Views folder.
And the Index method inside the LbpProfessionalController should match a Index.cshtml file inside the \Views\LbpProfessional folder.
The structure would then look like this
\Controllers\LbpProfessionalController.cs
\Views\LbpProfessional\Index.cshtml
Note that the name of the controller ends with ...Controller but the folder name doesn't get that part.
This is the standard way of linking Controllers and Views, and when you follow these rules you can use an action method as simple as this:
public ActionResult Index()
{
// This view will be found if you have given the view the right name
// ("Index.cshtml") and put it in the right place (folder named
// after controller).
return View();
}
But if you want to have a view that differs from the default way of linking then you need to specify the path to that other view. It could look like this:
public ActionResult Index()
{
return View("anotherViewName");
}
Inherit Controller class to the class in which you have placed public ActionResult Index()
Related
I have ported an mvc 3 app from vs 2010 to vs2012.
The ported app is using .NET 4.
All the old bits work, but with a new view, created in vs 2012, the view engine is not looking for .cshtml files for the view.
For example, when the user requests the index action on the Welcome controller in the Solicitors area, the url is:
mysite.com/solicitors/welcome/gg
(where gg is the user name). In that case, the error that comes back is:
The view 'Index' or its master was not found or no view engine
supports the searched locations. The following locations were
searched: ~/Areas/Solicitors/Views/Welcome/Index.aspx
~/Areas/Solicitors/Views/Welcome/Index.ascx
~/Areas/Solicitors/Views/Shared/Index.aspx
~/Areas/Solicitors/Views/Shared/Index.ascx ~/Views/Welcome/Index.aspx
~/Views/Welcome/Index.ascx ~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx ~/Areas/Solicitors/Views/Welcome/gg.master
~/Areas/Solicitors/Views/Shared/gg.master ~/Views/Welcome/gg.master
~/Views/Shared/gg.master ~/Areas/Solicitors/Views/Welcome/gg.cshtml
~/Areas/Solicitors/Views/Welcome/gg.vbhtml
~/Areas/Solicitors/Views/Shared/gg.cshtml
~/Areas/Solicitors/Views/Shared/gg.vbhtml ~/Views/Welcome/gg.cshtml
~/Views/Welcome/gg.vbhtml ~/Views/Shared/gg.cshtml
~/Views/Shared/gg.vbhtml
I have already added the following key to appsettings in web.config, but it makes no difference.
<add key="webpages:Version" value="1.0" />
EDIT:
Route in SolictorAreaRegistration.cs:
context.MapRoute(
"Solicitors_Welcome",
"Solicitors/Welcome/{nameUser}",
new { controller = "Welcome", action = "Index", nameUser = UrlParameter.Optional }
);
EDIT 2:
Using RouteDebug, I can see that the correct controller and action are found.
Route Data
Key Value
nameUser: gg
controller: Welcome
action: Index
Data Tokens
Key Value
Namespaces: System.String[]
area: Solicitors
UseNamespaceFallback: False
EDIT 3:
The route is found correctly, as I can see from debugging: the Index action is hit.
The problem happens when the line call the view is called:
namespace MyApp.Areas.Solicitors.Controllers
{
[Authorize]
public partial class WelcomeController : Controller
{
//
// GET: /Solicitors/Welcome/
public virtual ActionResult Index(string nameUser)
{
return View("Index", nameUser);
}
}
}
OK, got to the bottom of it:
The Problem:
The problem is that the model of my view is of type string. In my action, I was passing in a string as the model parameter:
public virtual ActionResult Index(string nameUser)
{
return View("Index", nameUser);
}
This will clash with one of the overloads of Controller.View(...):
View(string, string)
The second parameter expects the name of a layout file. When you do this, MVC goes off looking for a layout file with a name of the value of your string, which could be, for example:
"Hello, World. I'm an idiot, but if you give me a decent error message, I might be able to fix the bug."
Obviously, a layout file with that name doesn't exist. Nor does a layout file called "gg" either (my (test) solicitor's username).
The Solution:
The solution is simple:
Specify that the second parameter is the model, not the layout.
public virtual ActionResult Index(string nameUser)
{
return View("Index", model: nameUser);
}
Useful Article:
To view an extended discussion of this very issue, see the following article:
MVC Gotcha: Beware when using your view's model is a string
Many thanks to heartysoft.com for the enlightenment.
It is looking as you can see from the error message:
~/Areas/Solicitors/Views/Welcome/gg.cshtml
If you need to look for the Index view then you need to specify it:
http://mysite.com/solicitors/welcome/index/gg
I have a cshtml under Shared folder. I am doing a RedirectToAction() to this page but its not looking for this file in Shared folder. Its only looking in the appropriate folder under views. It uses to look into Shared folder before and I have no idea what I could have changed that breaking lookup. Any ideas?
You cannot do a RedirectToAction to a view. You are doing (as it name suggests) a redirect to an action. It is this action that returns a view. By default it will look for views in the ~/Views/ControllerName and ~/Views/Shared. So let's suppose that you have the following action which performs a redirect:
public class HomeController: Controller
{
public ActionResult Index()
{
return RedirectToAction("Index", "Products");
}
}
which would redirect to the Index action on the Products controller:
public class ProductsController: Controller
{
public ActionResult Index()
{
return View();
}
}
Now the Index.cshtml view could be in ~/Views/Products/Index.cshtml or in ~/Views/Shared/Index.cshtml.
I have a View - _Edit which lives in News M/V/C.
I reuse the V/M via the CategoryController as:
return PartialView("/Views/News/_Edit.cshtml", model);
How from within the View - _Edit can I alert the controller name?
When I:
alert('#ViewContext. RouteData.Values["controller"].ToString()');
The Value is: News
However, the URL is: /Category/foobar
Is there a way to get the value 'Category' to alert? thanks
I have put this in my partial view:
#HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString()
in the same kind of situation you describe, and it shows the controller described in the URL (Category for you, Product for me), instead of the actual location of the partial view.
So use this alert instead:
alert('#HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString()');
I do it like this:
#ViewContext.RouteData.Values["controller"]
Create base class for all controllers and put here name attribute:
public abstract class MyBaseController : Controller
{
public abstract string Name { get; }
}
In view
#{
var controller = ViewContext.Controller as MyBaseController;
if (controller != null)
{
#controller.Name
}
}
Controller example
public class SampleController: MyBaseController
{
public override string Name { get { return "Sample"; }
}
Other way to get current Controller name in View
#ViewContext.Controller.ValueProvider.GetValue("controller").RawValue
Just use:
ViewContext.Controller.GetType().Name
This will give you the whole Controller's Name
You are still in the context of your CategoryController even though you're loading a PartialView from your Views/News folder.
You can use any of the below code to get the controller name
#HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString();
If you are using MVC 3 you can use
#ViewContext.Controller.ValueProvider.GetValue("controller").RawValue
For anyone looking for this nowadays (latest versions) of ASP.NET Core MVC, you can use:
#Context.Request.RouteValues["controller"].ToString()
I'm trying to implement a common controller in MVC3 to return various JSON feeds, example -
public class AjaxController : Controller
{
public ActionResult Feed1()
{
ViewBag.Json = LogicFacade.GetFeed1Json();
return View();
}
public ActionResult Feed2()
{
ViewBag.Json = LogicFacade.GetFeed2Json();
return View();
}
}
This class has 30+ methods in it, the problem is this requires implementing an IDENTICAL View for each of the Controller's methods (sigh) that writes out ViewBag.Json.
I'm assuming this is a routing issue but I'm struggling with that. The following didn't work -
Tried setting ViewBag.Json then using RedirectToAction() but that seems to reset ViewBag.Json.
Note JsonResult is not appropriate for my needs, I'm using a different JSON serialiser.
So the objective here is to maintain one View file but keep this class with seperate methods that are called by routing, and not a crappy switch statement implementation.
Any help appreciated.
Use the same view and just specify the name. You can store in the controller's view folder, if only used by one controller, or in the Shared view folder if used by more than one.
return View("SharedJsonView");
Another, perhaps better, solution would be to create your own result -- maybe deriving from JsonResult, maybe directly from ActionResult -- that creates the JSON response that you need. Look at the source code for JsonResult on http://www.codeplex.com/aspnet for ideas on how to do it.
I am working on a project which adopted ASP.NET MVC3(Razor) tech.
Now, I have a controller below:
public class Home: Controller
{
public ActionResult Result(string id)
{
return View(id);
}
}
and I have set MapRoute as below:
context.MapRoute(
"Home_result",
"Home/Result/{id}",
new { controller="Home", action = "Result"}
);
and it was suposed to display a View which named "Result" when I typed the url http://domain.com/Home/Result/abc123 in the browser. However it didn't.
Instead it gave me an exception below:
The view 'Result' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/Home/abc123.cshtml
~/Views/Home/abc123.vbhtml
~/Views/Shared/abc123.cshtml
~/Views/Shared/abc123.vbhtml
It is strange isn't it?
Can anyone help me to figure out what mistakes I've made?
return View(id);
Returns a view with the name of ID's value (.cshtml), not the view with the name result.cshtml. I think this is because Id is a string. Are you trying to pass the id to the view?
To return the view matching the name of your controller's action simply use
return View();
If you want to pass that value to the view, for what ever crazy reason, using the viewbag is the easiest way since the string id is being used to declare a view name.
ViewBag.ID = id;
return View();
Then in the view just use the value you stored. And yes Razor HTML encodes by default.
#ViewBag.ID