How to see all the views in mvc application - asp.net-mvc

I added a default MvcApplication (MVC 4) (its name is MvcApplication3 matching the name of my solution's) width Home views (About, Index, Contact) and that will be my startup (bold in VS solution explorer's interface) project. Then I added another project (MvcApplication, but this time an empty one) called MvcApplication2 to the solution. Then I added the latter project as a reference to the first. I also added a controller called TestController (green line) to the referenced project and generated a view for its Index (red arrow) method. However, when I go to a link /Test or /Test/Index, the view I am expecting (red arrow) is not shown. Then I added the same folder Test with Index.cshtml (blue arrow) to the main project and now I am seeing its contents rather than the project's where my controller sits in.
Is it possible to make the application look for the views in the other project rather than the startup one?
I am adding the image of the structure to make it easier to follow.
P.S.: probably related: the breakpoint IS being hit in the Index method of TestController.
tldr; blue view is used instead of a red one

I think your problema is that you have set MvcApplication3 as startup Project and is causing you to open the view off that Project.
Is it possible to make the application look for the views in the other
project rather than the startup one?
Yes its posible, you can redirect your application the url. Think this your application have a url http://localhost:(someport) you can set redirect to the port of the second application.
I put a link to for better understanding a routing system of MVC: Documentation of routing system

As far as I know, you can't link to projects together like that. Each project becomes its own website with its own address. The reason you might put multiple projects together in one solution is to share things like classes, services, etc. I think what you're needing is areas:
http://www.codeproject.com/Articles/714356/Areas-in-ASP-NET-MVC

With some ideas from me and a friend of mine and a link about overriding RazorViewEngine I finally got what I wanted working exactly how I was expecting it to:
I created a folder named ViewsBase in the main project.
I rewrote RazorViewEngine this way: I only changed the place that was needed for me, leaving everything else like I found in the constructor of RazorViewEngine:
public class MyCustomViewEngine : RazorViewEngine
{
public MyCustomViewEngine()
{
...
ViewLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/{1}/{0}.vbhtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/Shared/{0}.vbhtml",
"~/ViewsBase/{1}/{0}.cshtml",
"~/ViewsBase/{1}/{0}.vbhtml"
};
...
(I find it rather disturbing how I am unable to format the code properly. Can someone give me a hand please?)
and in Global.asax of the main project I added:
ViewEngines.Engines.Clear();
var ourViewEngine = new
ViewEngines.Engines.Add(ourViewEngine);
AreaRegistration.RegisterAllAreas();
...
I added a post-build event command:
xcopy /s "$(ProjectDir)Views\*.*" /Y "$(SolutionDir)$(SolutionName)\ViewsBase\"
It started looking for the views in the expected order
I added a ViewStart file to the base project to make it render the Layout too.

Related

Controller cannot find view

I made a project where I have a basic DemoController:
<Export(GetType(IController))> _
<ExportMetadata("controllerName", "Demo")> _
<PartCreationPolicy(CreationPolicy.NonShared)> _
Public Class DemoController Inherits Controller
Public Function Index() As ActionResult
Return View("~/Views/Demo/Index.aspx")
End Function
End Class
In my "plugin" project that has this controller, it has the path /View/Demo/Index.aspx. When I run my main web app, I can get to the return View line but then it says the file cannot be found.
Why would this be?
I hope this all makes sense and sorry for the poor formatting.
I should probably mention that my .aspx file is in another project than the web app. I build everything into a dll then put that into a folder in my web app project. The error I am getting is "The view '~/Views/Demo/Index.aspx' or its master was not found or no view engine supports the searched locations. The following locations were searched: ~/Views/Demo/Index.aspx"
You said that you have all the views embedded in a separate project. Using the built-in view engine won't work. Either you have to specify the view locations in the built-in view engine as specified in this thread or create a custom view engine.
you must register the views for your plugins
the flow with asp.net mvc
so if you're developing plugins with DI you must keep in mind a few things
-custom View Engine
-custom Controller Factory
the default ControllerFactory can't resolve the controllers of your plug-ins, it's the same with the viewEngine, you must tell to the viewEngine where is that view
here is a example http://blog.maartenballiauw.be/post/2008/05/20/Creating-a-custom-ViewEngine-for-the-ASPNET-MVC-framework.aspx
~/Demo/Index
Should be right route
Also, please fix the return like that
Return View()
or
Return View("Index")

MVCContrib portable areas not working from HtmlExtensions, MVC 3

I just implemented MVCContrib's Portable Area feature and it works fine. I can open it using:
http://localhost/projectname/portableAreaName, but this portable area is not working if i render it using the HtmlHelper extension method like this:
public static void RenderHtmlWidget(this HtmlHelper Html)
{
Html.RenderAction("Index", "HtmlWidget", new {area = "HtmlWidget"});
}
And calling the helper method in the view as such:
#using Project.Widgets.HtmlWidget;
#{Html.RenderHtmlWidget();}
I'm getting an error: The view 'Index' or its master was not found or no view engine supports the searched locations. In the possible location list there are no ~/areas/... defined.
But I can render my HtmlWidget successfully with this the same line of code in the view:
#{Html.RenderAction("Index", "HtmlWidget", new { area = "HtmlWidget" });}
What am I doing wrong and how should I use the HtmlHelper extensions correctly with the MVCContrib portable areas feature?
There are a few things that may be causing this.
In the calling/parent project where you use the helper method to invoke your portable area, do you have a Web.config file in the /Areas/ folder? If not, you must copy the Web.config found in the /Views/ folder of the same project, and simply place the new copy in the /Areas/ folder as well.
In the Registration class file in your portable area project, after you call MapRoute in the "RegisterArea" method, are you calling "RegisterAreaEmbeddedResources();"?
Is each view in your portable area project made to be an embedded resource as opposed to content? Select a View in the Solution Explorer and hit F4, "Build Action" should be set to "Embedded Resource", but it defaults to "Content"
You also need to make sure that both the Portable project and the consuming project reference the same version of MvcContrib, but that they also utilize the same version of ASP.NET MVC. If your area is referenced in multiple projects, each based off of a different version of MVC (not likely, but possible depending on the situation), your area must use whatever version of MVC the consuming project uses.
I'd also suggest using Phil Haack's .NET Routing Debugger - its a single DLL file that you reference in the consuming application and add a single line to your ApplicationStart() in your Global.asax.cs. This becomes incredibly helpful in determining if your portable area is being correctly registered with the base project - and helps you cut to the chase.

Does ASP.NET MVC create default routes for areas

I have a couple of areas in my MVC 3 application Auth and Users. I am using Phil Haacks Route Debugging tool to view a list of my routes and see which one gets selected based on my url.
However there are a couple of routes present that I have not created in either my AreaRegistration file or Globalasax and I don’t know where they have come from or how to get rid of them. The routes are highlighted in yellow below.
You can also see that I have created a default route in my Auth area (highlighted in green) which simply points to the Login action of my Auth controller. I have debugged the RouteTable and it gets added when the AreaRegistration.RegisterAllAreas(); method is called. However it does not get added in the AreaRegistration as have stepped through this also.
Does ASP.NET MVC add this as a default and if so can I remove it somehow?
I don’t like to answer my own question but after a day of trying to solve this problem I thought I would post the answer in case anyone else has the same issue.
In the end I got rid of all my areas from my application and just had the basic Global.asax routing. When I ran the app I could see in the route debugger that the routing collection was still being populated with the routes from now non existing areas. After trying many things including deleting everything from my ASP.NET temp files, messing around with IIS AppPools and cleaning out browser data I finally came across the answer.
I deleted everything from the websites bin folder, did a rebuild and low and behold, the routes were gone. I reinstated my areas with the config described and everything is working as it should.
I have no idea why my MVC app was holding onto and populating the old routes but as soon as my bin was cleared and new dll’s created everything worked as it should. If anybody out there knows why this may be then I would be very interested.
Yes, each area has it's own AreaRegistration file that defines area routes. Look for it in your area root folder.
For your User area, look in Areas -> User -> UserAreaRegistration.cs
It should contain something like this:
public class UserAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "User";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"User_default",
"User/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
Did you rename your project? It loads the routes by reflection, probably by scanning everything in the bin folder. So if you refactored your code and changed the assembly name, you could have easily had old code being picked up and registering those routes.
JB

Changing ASP.Net MVC directory structure

I've been working with ASP.Net MVC (3) for some time now and i like it a lot. But one thing i find a bit annoying is having to browse between the controllers / views / model / script directory all the time. So i'm wondering if there's a way to tell MVC to look for the files in a different location?
Maybe someone can tell me how to simply group the files together by controller like:
Directory: /Membership
MembershipController
LogOnView
LogOnModel
RegisterView
RegisterModel
Kind regards
Olav
I know exactly what you're talking about. Here are the conditions where I find the default MVC folder structure to be onerous:
I'm using a model-per-view approach
My controller basically only works with that one particular view
I have some javascript that only pertains to that view
Why do I want to put each of these pieces in a different folder?
I create a folder for the view in the Views folder, so you have a folder ~/Views/MyEntityList (just like the traditional MVC approach), but I put everything that pertains to that component there:
~/Views/MyEntityList/
MyEntityListController.cs
MyEntityListModel.cs
MyEntityList.js
MyEntityList.aspx
I find this structure leads all the developers to keep views decoupled from one another. No special MVC configuration is required, except for allowing browsers to access the .js resources directly.
There are some architectural patterns where this might not be a good way to go. For a model-per-view approach (see Los Techies for more description) I really like this structure.
I think you need to get the Solution Navigator extensions via Power Tools update for VS 2010.
That way, you can display in the Solution Navigator, as opposed to the solution explorer, only the open files, for example. Makes it easier.
By the way, delete all the model folders and create a separate model project, eg:
MyApp.Domain
Any solution that is beyond basic will benefit from this.
As stated in the comments to your question, Areas will also reduce your navigation requirements.
The only "looking of files" going on is with views, everything else is just a convention, so if you want you could have:
Directory: /Membership
MembershipController
LogOnView
LogOnModel
RegisterView
RegisterModel
... but the views must be in ~/Views/Membership
It looks like you have to override some behavior in the view engine. You can See this question to get a better idea.
One way I can think of to achieve this is by writing your custom view engine. You can place all these below files in Controllers/Membership
MembershipController
LogOnView
LogOnModel
RegisterView
RegisterModel
Models will not be a problem you can simply change the namespace for the models, the only problem is with the views. For this write your custom view engine so that your mvc application knows the physical location of the view files as follows.
public class CustomViewEngine : RazorViewEngine
{
public CustomViewEngine()
{
ViewLocationFormats = new[]
{
"~/Controllers/{1}/{0}.cshtml",
};
}
}
In global.asax.cs add the ViewEngine in Application_Start() by including the following code
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomViewEngine());
You may also have to take care of various other factors like updating the Layout attribute depending on where you place the _Layout.cshtml.
In case you are using areas, add the AreaViewLocationFormats string array as well.
You can do further customization by overriding some of the methods like FileExists, CreateView, CreatePartialView.
Note: Do not forget to copy web.config in the views folder to the Membership controller. Otherwise application does not find the required mvc namespaces and it does not find the symbols like viewbag, model etc.

The view 'Index' or its master was not found.

The view 'Index' or its master was not found. The following locations were searched:
~/Views/ControllerName/Index.aspx
~/Views/ControllerName/Index.ascx
~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx
I got this error when using ASP.Net mvc area. The area controller action are invoked, but it seems to look for the view in the 'base' project views instead of in the area views folder.
What you need to do is set a token to your area name:
for instance:
context.MapRoute(
"SomeArea_default",
"SomeArea/{controller}/{action}/{id}",
new { controller = "SomeController", action = "Index", id = UrlParameter.Optional }
).DataTokens.Add("area", "YOURAREANAME");
This error was raised because your Controller method name is not same as the View's name.
If you right click on your controller method and select Go To View (Ctrl+M,Ctrl+G), it will either open a View (success) or complain that it couldn't find one (what you're seeing).
Corresponding Controllers and View folders name have the same names.
Corresponding Controller methods & Views pages should same have the same names.
If your method name is different than view name, return view("viewName") in the method.
Global.asax file contain the URL Route.
Default URL route like this.
"{controller}/{action}/{id}"
So,Try this.
1. Right click your controller method as below.
Example: let say we call Index() method.Right click on it.
2. Click Add View.. and give appropriate name.In this example name should be Index.
Then it will add correct View by creating with relevant folder structure.
Check the generated code at MyAreaAreaRegistration.cs and make sure that the controller parameter is set to your default controller, otherwise the controller will be called bot for some reason ASP.NET MVC won't search for the views at the area folder
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"SomeArea_default",
"SomeArea/{controller}/{action}/{id}",
new { controller = "SomeController", action = "Index", id = UrlParameter.Optional }
);
}
Where this error only occurs when deployed to a web server then the issue could be because the views are not being deployed correctly.
An example of how this can happen is if the build action for the views is set to None rather than Content.
A way to check that the views are deployed correctly is to navigate to the physical path for the site on the web server and confirm that the views are present.
The problem was that I used MvcRoute.MappUrl from MvcContrib to route the context.Routes.
It seems that MvcContrib routing mapper was uncomfortable with area routing.
You most likely did not create your own view engine.
The default view engine looks for the views in ~/Views/[Controller]/ and ~/Views/Shared/.
You need to create your own view engine to make sure the views are searched in area views folder.
Take a look this post by Phil Haack.
I had this problem today with a simple out of the box VS 2013 MVC 5 project deployed manually to my local instance of IIS on Windows 8. It turned out that the App Pool being used did not have the proper access to the application (folders, etc.). After resetting my App Pool identity, it worked fine.
right click in index() method from your controller
then click on goto view
if this action open index.cshtml?
Your problem is the IIS pool is not have permission to access the physical path of the view.
you can test it by giving permission. for example :- go to c:\inetpub\wwwroot\yourweb then right click on yourweb folder -> property ->security and add group name everyone and allow full control to your site . hope this fix your problem.
It´s still a problem on the Final release.. .when you create the Area from context menu/Add/Area, visual studio dont put the Controller inside de last argument of the MapRoute method. You need to take care of it, and in my case, I have to put it manually every time I create a new Area.
You can get this error even with all the correct MapRoutes in your area registration. Try adding this line to your controller action:
If Not ControllerContext.RouteData.DataTokens.ContainsKey("area") Then
ControllerContext.RouteData.DataTokens.Add("area", "MyAreaName")
End If
If You can get this error even with all the correct MapRoutes in your area registration and all other basic configurations are fine.
This is the situation:
I have used below mentioned code from Jquery file to post back data and then load a view from controller action method.
$.post("/Customers/ReturnRetailOnlySales", {petKey: '<%: Model.PetKey %>'});
Above jQuery code I didn't mentioned success callback function.
What was happened there is after finishing a post back scenario on action method, without routing to my expected view it came back to Jquery side and gave view not found error as above.
Then I gave a solution like below and its working without any problem.
$.post("/Customers/ReturnRetailOnlySales", {petKey: '<%: Model.PetKey %>'},
function (data) {
var url = Sys.Url.route('PetDetail', { action: "ReturnRetailOnlySalesItems", controller: "Customers",petKey: '<%: Model.PetKey %>'});
window.location = url;});
Note: I sent my request inside the success callback function to my expected views action method.Then view engine found a relevant area's view file and load correctly.
I have had this problem too; I noticed that I missed to include the view page inside the folder that's name is same with the controller.
Controller: adminController
View->Admin->view1.cshtml
(It was View->view1.cshtml)(there was no folder: Admin)
This error can also surface if your MSI installer failed to actually deploy the file.
In my case this happened because I converted the .aspx files to .cshtml files and visual studio thought these were brand new files and set the build action to none instead of content.
I got the same problem in here, and guess what.... looking at the csproj's xml' structure, I noticed the Content node (inside ItemGroup node) was as "none"... not sure why but that was the reason I was getting the same error, just edited that to "Content" as the others, and it's working.
Hope that helps
Add the following code in the Application_Start() method inside your project:
ViewEngines.Engines.Add(new RazorViewEngine());
I added viewlocationformat to RazorViewEngine and worked for me.
ViewLocationFormats = new[] {
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml",
"~/Areas/Admin/Views/{1}/{0}.cshtml",
"~/Areas/Admin/Views/Shared/{0}.cshtml"
};

Resources