ASP.NET MVC 3 View Engine does not recognise PartialView with .cshtml - c#

The below image shows the Partial View GetMovieTypes.cshtml living in the Shared folder
I call the partial view using the line #Html.Partial("GetMovieTypes.cshtml") in the Index View of EmployeeController
Issue is I get Server Error when I call the Employee Controller with Index Action
The partial view '_GetMovieTypes.cshtml' was not found or no view
engine supports the searched locations. The following locations were
searched:
~/Areas/Staff/Views/Employee/GetMovieTypes.cshtml.cshtml
But when I rename the PartialView to GetMovieTypes.cshtml.cshtml it works fine
Why is the ViewEngine forcing me to add the .cshtml extension twice

Remove the .cshtml portion:
#Html.Partial("GetMovieTypes")

You simply need to call
#Html.Partial("GetMovieTypes")
Dot is not recognized as extension separator by MVC binding. So if you write
"GetMovieTypes.cshtml" it searches for exactly that name, plus cshtml extension.

you should change your code call into
#Html.Partial("_GetMovieTypes")
as that's the name of your View, I do that all the time.
there is no need to mention the extension, that's only if you are calling from your Controller.
my own example:

You need to remove the .chtml extension:
#Html.Partial("GetMovieTypes")
You can also pass the model you havbe in the "parent" view like this:
#Html.Partial("GetMovieTypes", MovieTypesModel)
With this method, your view and its partial have the same model and information
*Maybe I'm wrong but I think you have an underscore in the name of the view too, so you should call it like this:
#Html.Partial("_GetMovieTypes", MovieTypesModel)

Related

How to detect what is the model of the view and where its getting populated?

I'm learning a C# ASP.NET MVC application and I'm having a hard time walking backwards from the view to the code that executes a stored procedure that populates the model class. This is complicated (for me) by the fact that it uses Castle for IoC, so I can't just search for new [Classname].
Any help is appreciated.
I'll post a more in-depth example soon, but for now I'll simply explain it this way:
One has a View which refers to a #model. That model is a class that was populated via a Controller by calling a stored procedure (or executing inline SQL) and passed to the View.
In simplest terms, my question is:
When I see #model in a View, how do I figure out which class #model refers to,
How do I find the place where that class got populated with data before it got passed to the View?
How do I figure out which class #model refers to?
The same way that you can go to the definition of a code element in .cs files, you can do that in .cshtml files as well. Click on the name of the type in front of #model and press F12 or Right click → Go To Definition to see the definition of the type or choose Go To Implementation to see the implementation if available.
If you don't have #model the view class is deriving from WebViewPage<dynamic> the model for the view is dynamic. If you have #model Something the view class is deriving from WebViewPage<Something> and the model for the view is Something.
Assuming you have a SampleModel class in SampleProject.Models namespace, the following ways are some ways that you can declare #model for the Index.cshtml view which is located in Home folder, under Views folder:
Without any #model
<div> Hello! </div>
FullName in View
#model SampleProject.Models.SampleModel
<div> Hello! </div>
Using and Name in View:
#using SampleProject.Models
#model SampleModel
<div> Hello! </div>
Namespace in web.config and Name in View
Having a namespace entry inweb.config in root of the project, or in Views folder or in your view folder (in the example, Home folder):
<system.web.webPages.razor>
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
...
<add namespace="SampleProject.Models" />
...
</namespaces>
</pages>
</system.web.webPages.razor>
And the name in view file:
#model SampleModel
<div> Hello! </div>
How do I find the place where that class got populated with data before it got passed to the View?
In short, at design time, the view doesn't know where its data come from, while action knows which view is going to return. At run-time, view knows which action has returned it.
Design time
In MVC, the View doesn't belong to a controller and any action of a controller can return the view simply. So View at design time doesn't have a parent controller/action, while the action knows which view they are going to return.
However in simple cases, which you have a 1-1 relation between views and actions, a view in the following path Views\Home\Index usually is returned by Index action of HomeController class.
In simple cases, when you are coding in view, if you Right Click and choose Go To Controller, it goes to the controller class based on the folder name of the view. When you are coding in controller and Right Click in body of name of an Action and choose Go To View, it goes to the view having the same name as your action in a folder with the same name as your controller (without controller suffix) under views folder.
Run-time
At run-time, each view knows what controller/action has returned it:
#ViewContext.RouteData.Values["controller"]
#ViewContext.RouteData.Values["action"]
#ViewContext.Controller

Partial Pages in ASP.NET Core 2.0

TL; DR Are "partial Pages" possible in ASP.NET Core 2.0? If so, why am I getting the error described below?
I've been messing with the new Razor Page feature of ASP.NET 2.0 and having some trouble with partials. The documentation linked above refers to "partials" in several places, but only to the extent of saying mystical things like "The layouts, templates, and partials you're using with MVC controllers and conventional Razor views just work." Do they mean partial Views, like what we're used to, or some new kind of partial Page also? They show that files with the conventional Partial suffix in the name can be placed in the Pages/ folder, but the files that they mention (e.g., _ValidationScriptsPartial.cshtml) don't have the #page declaration. If "partial Pages" are indeed a new thing, then I would expect the following minimal scenario to work:
A Page file named Derp.cshtml:
#page
#namespace MyApp.Pages
#model DerpModel
<p>Member 1: #Model.Member1</p>
<p>Member 2: #Model.Member2</p>
A class file named Derp.cshtml.cs in the same directory (nested under the first in VS 2017's Solution Explorer), containing the following class:
namespace MyApp.Pages {
public class DerpModel : PageModel {
public void OnGet() {
Member1 = "Derp Member1";
Member2 = "Derp Member2";
}
public string Member1 { get; set; }
public string Member2 { get; set; }
}
}
A second Page file named DerpWrapper.cshtml in the same directory, with the following code:
#page "{id}"
#namespace MyApp.Pages
#model DerpModel
<p>Outer Member 1: #Model.Member1</p>
<p>Outer Member 2: #Model.Member2</p>
#Html.Partial("Derp", Model)
And of course a _ViewImports file that declares #namespace MyApp.Pages
Note that both Razor Pages have the same #model type, and the second Page basically wraps up the first one with a call to Html.Partial() and passes its Model. This should all be pretty standard stuff, but upon navigating to http://localhost:xxx/DerpWrapper, I get a 500 response due to a NullReferenceException with the following stack trace.
MyApp.Pages.Derp_Page.get_Model()
MyApp.Pages.Derp_Page+<ExecuteAsync>d__0.MoveNext() in Derp.cshtml
+
<p>Inner Member1: #Model.Member1</p>
...
MyApp.Pages.DerpWrapper_Page+<ExecuteAsync>d__0.MoveNext() in DerpWrapper.cshtml
+
#Html.Partial("Derp", Model)
...
Why does the "wrapper" Page's Model equal null? Is there no way to define a Razor Page and display it from another Page or View with Html.Partial()?
Razor’s partial views are basically .cshtml views that are transcluded into another view, that is a razor view or a razor page. They are rendered within that view and as such inherit some of the view’s properties, e.g. its ViewData. They however do not have a controller, a page model or some other kind of “code behind” that gives you a way to run code for the partial.
As such, the primary use for partials is to extract common components that do not contain logic on their own into separate and reusable files.
The other kind of reusable components that exist in Razor are view components. View components are similar to partials but they do have an actual class that backs them and that allows you to add your own logic to the view component.
At the moment, view components follow the MVC layout for views, meaning the view component is actually a class and you return a view from its Invoke method which causes the view engine to locate that .cshtml in the Views folder. David Fowler confirmed to me though, that they are working on a Razor page like experience for view components too, so in a later version of ASP.NET Core, you will eventually be able to write a .cshtml view component and add some code-behind to it (just like Razor pages).
Coming back to your question though, at the moment there are two kinds of entry points for an MVC route: An MVC controller, possibly returning a view, and a Razor page. Neither of these can invoke one or the other inside of them though. If you are rendering a view, you can load partials or view components but not other “full” views or Razor pages. And if you’re rending a Razor page, you also can load partials or view components, but still no other “full” views or Razor pages.
So what you want to do is simply not possible because a Razor page is supposed to be an entry point to the route, and while invoking any view as a partial may work (in some situations), you will certainly neither get the controller for that view nor the page model running for it. If you want to invoke something that has complex logic, you should use view components instead.
Answers on Stack overflow remain for ages so it's important that we ensure that they are improved.
To add onto Poke's Answer or rather to correct it. Partial views separate common sections between pages. These sections can include logic. But that logic should not involve any field(variables, or objects) contained or defined within any specific page. They can apply logic though dependency injection... by injecting them into the partial view.

How to go to a View in Shared folder from a View in Home folder in MVC using C#

I am trying to access a PartialView in Shared folder by clicking an Html.ActionLink HelperMethod present on a view in Home Folder as:
#Html.ActionLink("Create New", "~/Views/Shared/_AddBranch.cshtml");
with fail. I dont want to add a new controller to achieve this but I don't mind replacing Html.ActionLink with another tool if I need to. Anyone knows how to do it?
You should not be generating an anchor tag which points to the view file directly without an action method. Ideally you should create an action method throuh which you will render the view.
If you are trying to render some re-usable view. You should use Html.Partial method in your main page
#Html.Partial("~/Views/Shared/_AddBranch.cshtml")
Razor will include the HTML markup for the _AddBranch.cshtml when it renders your main page
If you want to pass a model/viewmodel to the partial, you can use this overload
#Html.Partial("~/Views/Shared/_AddBranch.cshtml",Model.YourModelYouWantToPass)
Assuming YourModelYouWantToPass is a property of the model of your main page and your partial view is strongly typed to the type of YourModelYouWantToPass property.

How to create reusable control in ASP.NET MVC

How can/should I create some "custom control" in ASP.NET MVC 3? I have red about partial views, ViewUsersControl, Html.RenderAction, but I still don't know, which way is the proper MVC way for razor views.
If I need to render some ajax component to view, I can imagine to do it by partial view, but what if I want to render section with custom logic?
1) PartialViews
2) Custom Html helpers
3) Child Actions
Update ASP.NET Core:
2) Tag Helpers are preferred way over Custom Html helpers
3) View Components are used instead of Child Actions
You may use
#{Html.RenderPartial("YourCustomView",YourModel);}
For instance, In your Shared folder create a new View and name it "_MyCustomControl"
Then in the code write :
#model YourNameSpace.Models.YourModel
#{
Layout = null;
}
#*Here write your control's markup*#
Then in your Views where you want to use this "control" you add:
#{Html.RenderPartial("_MyCustomControl",new YourModel { args });}
If you get into trouble with RenderPartial check this out
In addition to all the other answers for this post, I can offer you the use of EditorFor and DisplayFor templates. These are useful when you want to easily render or edit a custom type. It'll handle validation nicely (which can get weird when using partials) and you can nest them recursively (again another feature that isn't obviously handy until you need it).
You can also use Html.RenderAction() or Html.Action() to call another controller action within a view and display the results in-line in the page. This is probably the closest to what you need as it allows you to render a partial, include code in the controller and it also allows for the passing of parameters.
Links to:
DisplayFor and EditorFor Templates
Action and RenderAction
As you have mentioned that you can use Partial Views.
Yes you can use Partial Views, which is the most effective and efficient way.
For Ajax rendering you can always use
#using (Ajax.BeginForm("Details", new { id = Model.Post.PostId }, new AjaxOptions
{
Few of the links you would like to see
Rendering partial view in ASP.Net MVC3 Razor using Ajax
Render Partial Views using JQuery in MVC3

Re-using a partial view (ascx) across different Controllers and Views

Let's assume I have 2 Controllers, TopicsController and PostsController.
For each controller, I have a couple of views (Index & Details).
The Topic (Index) view inherits System.Web.Mvc.ViewPage<IEnumerable<MessageBoard.Models.Topic>>
The Topic (Details) view inherits System.Web.Mvc.ViewPage<MessageBoard.Models.TopicFormViewModel>
I'm using a TopicFormViewModel because I'm sending additional data along with the Model.
The Post (Details) view just inherits System.Web.Mvc.ViewPage<MessageBoard.Models.Post>
Now, I've created a partial view (CreatePost.ascx) which is (obviously :p) used to create a new Post. I want to be able to re-use this control on all of the views you see above.
Update
I've tried rendering the partial view using <% Html.RenderPartial("New"); %> from my Topics/Index.aspx View, but that results in an exception
The model item passed into the dictionary is of type 'System.Data.Linq.Table`1[MessageBoard.Models.Topic]', but this dictionary requires a model item of type 'MessageBoard.Models.Post'.
Now the problem is that my partial view (CreatePost.ascx) accepts a System.Web.Mvc.ViewUserControl<MessageBoard.Models.Post> and I'm not sure how to pass that from all my views above.
I'm also unsure know how to submit the .ascx values to a certain URL (i.e. /Topics/1/CreatePost), how do I tell the submit button to post to that URL?
Thanks in advance,
Marko
Ciao Marko,
Now the problem is that my partial
view (CreatePost.ascx) accepts a
System.Web.Mvc.ViewUserControl
and I'm not sure how to pass that from
all my views above.
I am not sure I understand what do you mean by "how to pass that from all my views above" but I am sure that you dont have to pass an instance of Post from your views. What is going on is that from your views you will invoke a controller action that creates the Post model object and then bind it to the CreatePost.ascx partial.
I'm also unsure know how to submit the
.ascx values to a certain URL (i.e.
/Topics/1/CreatePost), how do I tell
the submit button to post to that URL?
You have two options:
Inside your CreatePost.ascx partial you are probably using a form.
<% using (Html.BeginForm("action", "controller", FormMethod.Post, new {} )) { %>
If you use in the way I am showing you can change the first and the second params respectively to the names of the Action and the Controller that would habndle your submit.
The second option is using jQuery. Simply set an ID for your form and then
$("#myForm").submit(function(event) {
//post an ajax request to the server
});
Hope this helps!
P.S. To be able to reuse your CreatePost.ascx partial place it inside the shared view folder (where your master page is).
In regards to reusing a partial view which is not in the same view folder, use the following and pass in the model required, alternatively you can define a custom route for it.
<% html.RenderPartial("~/Views/<ControllerName>/<PartialViewName>.ascx", <model>);
#Marko
Another way would be to have in the PostController an Action like the following:
[HttpGet]
public ActionResult CreatePost( int topicId ) {
PostModel pm = _manager.CreateDefaultPost();
pm.TopicID = id;
return PartialView( "CreatePost", pm );
}
Then wherever you want to create a Post you can simply call this action that returns the strong-typed view for your new post.
Even if you have a supplementary http call over the network IMO this solution has the advantage to keep the initialization code of a new Post centralized to a single place.
From the View "point-of-view" the call to the action can be done when the user press the "New Post" button and then inject the received markup inside a modal dialog or in a place of your pleasure in the current page.
Hope it helps!

Categories

Resources