How to remove the child action in asp.net mvc3 - c#

how can i remove the child action in asp.net mvc3. I mean i am having partial views and main views. In the url bar when i entered the child page then it should not load.
for suppose my main page is
localhost:5820/Home/Index
Then when i enter
localhost:5820/Home/Index
then it should work and the child item is
localhost:5820/Home/About
Then when i enter
localhost:5820/Home/About
then it should not open. How can i do that in asp.net mvc. I have several pages like that i have displayed the pages in how can
i rectify this issue

Looks like you are looking for ChildActionOnly attribute:
[ChildActionOnly]
public ActionResult About()
{
return View();
}
It disables direct calls to localhost:5820/Home/About - only rendering as partial view will be available.
UPDATE according to what you need - mark all actions which should return partial views with ChildActionOnly attribute:
public ActionResult Index()
{
return View();
}
[ChildActionOnly]
public ActionResult About()
{
var model = ...
return PartialView("_About", model);
}
And in index view call those actions (from Home controller and other controllers) via:
#Html.Action("About", "Home")

The fact that your ABOUT page is a link inside your HOME page does not mean it is a child action, in fact, from the point of view of MVC they are in the same level, is YOU as a programmer that give the ilussion of hiereachies by providing an order of navigation.
Now, what you can do is:
simply remove the Action Methods from your controller, or
write a simple ignore route like:
routes.IgnoreRoute("YourRuleToIgnoreActions");
this rules should be at the beginning of your RegisterRoutes method in RegisterRoutes to avoid other rules to be triggered
To build up your ignore rules, here is a nice discussion on the topic: http://ardalis.com/IgnoreRoute-in-ASP.NET-Routing-is-Order-Dependent
UPDATE:
Probably too much thinking on this one, but in my opinion, the Models CAN have properties that modify the behaviour of the View, this is because from an architectural point of view, when you are already in the View, your concern is exclusively on the presentation layer, so I think it is perfectly valid to have something like:
public class MyReportsModel{
public bool displaySection1 { get; set;}
//other data
}
and in your views, you can change the presentation in the following way:
#{
if(#Model.displaySection1){
//display as normal
}
}
Of course, when you populate the model you should set that property in each controller according to your needs:
MyReporstModel thisView = new MyReportsModel();
thisView.displaySection1 = true;
// set all properties necessary to display
// if the controller knows that this partial view won't be displayed then
thisView.displaySection1 = false;
But that is no longer a technical issue but an architectural one.
hope it helps,

Related

ASP.Net MVC Using AddModelError with multiple ValidationSummary for querystring validation

I have a view with two forms each containing their own
#Html.ValidationSummary()
When the page is loaded, a querystring parameter is checked and if it exists I call:
ModelState.AddModelError("", "Querystring error");
However, this results in the error message appearing in both #Html.ValidationSummary() even if I specify a property in the form model.
I have a work around which is to have a seperate error message property in the model for the form and populate that and then display it if it exists in a label, but wondered if it is possible to specify one individual #Html.ValidationSummary() within a form to allow me to use ModelState.AddModelError?
Following the helpful information I was given by #GSerg, I thought I'd share my resolution.
So instead of having two forms within the same view, I split each form into two separate partial views and called each from within the main view...
#Html.Action("_RequestPartial")
#Html.Action("_LoginPartial")
Each partial view would contain the model to pass to it and a Html.BeginForm with a Html.ValidationSummary() inside.
Then within the Controller, set up the code to return the view as normal (in this case for the Index view)...
[HttpGet]
public ActionResult Index()
{
return View();
}
Then for the partial views, set up a PartialViewResult for each partial view annotated with ChildActionOnly...
[ChildActionOnly]
public PartialViewResult _RequestPartial()
{
... code that populates model you want to pass ...
return PartialView(model);
}
[ChildActionOnly]
public PartialViewResult _LoginPartial()
{
... code that populates model you want to pass ...
return PartialView(model);
}
Hope this helps someone.
To show the specific validation message, please see the snippet code below.
Controller :
[HttpGet]
public ActionResult Index()
{
ModelState.AddModelError("Error1", "Querystring error");
return View(new SampleViewModel());
}
View :
#Html.ValidationMessage("Error1")
Just tried to create a fiddle to get a complete picture. https://dotnetfiddle.net/GoMMhy

ASP.NET MVC Base Controller with Initialize() gets executed multiple times with HTml.Action()

This is a question about best-practices in ASP.NET MVC
I've created a website in MVC. Because every page has a menu, I thought I'd create a base controller class which all MVC Controllers in the project inherit from. In The Initialize() function of the base controller class I would then load my Menu.
In that way, I could keep my logic for loading the menu in one place and have it executed automatically.
Code (C#):
public abstract class BaseController : System.Web.Mvc.Controller
{
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
//Load the menu:
ViewBag.HeaderModel = LoadMenu();
}
}
public class HomeController : BaseController
{
public ActionResult Index()
{
//the menu is loaded by the base controller, so we can just return the view here
return View();
}
}
That works like a charm. Now here's the problem.
In my View, I present a list of the five latest Articles on the website. Since the Articles have their own logic and their own section on the website, I've created an ArticleController, which inherits from BaseController as well, with an action that displays a PartialResult with my five latest Articles.
public class ArticlesController : BaseController
{
public ActionResult DisplayLatestArticles()
{
var model = ... //abbreviated, this loads the latest articles
return PartialView("LatestArticles", model);
}
}
And the method is called like this in the View:
#Html.Action("Index", new { controller = "Articles" })
But this has one drawback: namely the Initialize() function on my Base Controller is executed twice, which loads the menu two times, which is undesirable (for performance reasons). So far I haven't been able to find a way to avoid this behavior.
What do you suggest in so far as refactoring this code? I want to make sure my logic to load my menu stays somewhere so it gets called automatically, without me or any other developers on the project having to worry about it. I prefer keeping my logic to display the latest Articles in the ArticlesController so everything to do with Articles is kept in its own Controller.
So, how best to proceed?
What you're trying to do is more suited to calling your header menu from a _Layout.cshtml page.
_Layout.cshtml:
<html>
...
<body>
...
#Html.Action("Header", "SharedStuff")
...
SharedStuffController.cs
public ActionResult Header()
{
// logic to create header, also create a view
return this.View();
}
Base controllers, I feel, are normally the wrong way to go. The above means that you keep all logic for the header nicely contained in something that describes it.
I am not expert on the MVC and landed on this page while searching for my own answer. I completely agree that Base contoller should not be used for generating menu items. However, for what so ever reason, if you wanted to continue using base controller, I would suggest the controller that returns partial views (i.e ArticlesController) should not inherit from base controller and it should inherit from Controller class.

MVC - Submit button not working with multiple partial views

I'm new to MVC, so please go easy on me. I was handed a project that was started in MVC and have been told to add to it. I was fine until I got to a section that needed data from two different models. Now I'm stuck and my boss wants this done yesterday. Please help if you can.
I have a view with two partial views and a submit button. Each of the partial views use a different model. The views display information on the screen which the user can change. The submit button is then clicked. In the controller, I would like to access the data from both models (the values that the user entered on the screen). Right now, I can't even get the submit button to call the controller. That is the part I need immediate help with, but I will eventually need to know how to access both model's data from the controller.
Here's the basic idea of what I want to do:
This is my view: CreateContract.cshtml
<div class="container-fluid">
#using (Html.BeginForm("CreateContract", "CreateContract", FormMethod.Post, new { #class = "form-horizontal " }))
{
<div id="PartialDiv">
#{
Html.RenderPartial("ApplicationPartialView", new CarmelFinancialWeb.Models.ModelApplication());
Html.RenderPartial("ContractPartialView");
}
</div>
<input id="btnCreateContract" type="submit" class="btn btn-primary" value="Save" name="CreateContract" />
}
</div>
This is part of the controller CreateContractController.cs. This method is hit when the view opens and is working correctly.
[AuthorizeAdmin]
public ActionResult CreateContract(string ID)
{
ModelContract obj_Contract = new ModelContract();
obj_Contract.BuyerName = "MOCS";
return View(#"~/Views/CreateContract/CreateContract.cshtml", obj_Contract);
}
This is part of the controller CreateContractController.cs. This method is not being hit when the submit button is clicked. I've tried including the string ID variable from the other method and both ModelContract and ModelApplication (and various combinations thereof), but I cannot get this method to be called.
[AuthorizeAdmin]
[HttpPost]
public ActionResult CreateContract()
{
ModelApplication obj_App = new ModelApplication();
return View(#"~/Views/CreateContract/CreateContract.cshtml", obj_App);
}
These are the methods in the controller for the partial views. These aren't getting called either.
public PartialViewResult ApplicationPartialView(string ID)
{
ModelApplication obj_App = new ModelApplication();
if (ID != null && ID != "0" && ID != null && ID != "")
{
obj_App = objBllApplication.GetApplicationByID(int.Parse(ID));
}
return PartialView("CreateContractApplicationPartialView");
}
public PartialViewResult ContractContractPartialView()
{
ModelContract obj_Contract = new ModelContract();
obj_Contract.DealerID = "MOCS";
return PartialView("CreateContractContractPartialView");
}
There's a lot going on under the hood here which is beneficial for you to know, especially since you're new to this. First, a view can only have one model. The high-level reason is that it's actually rendered via a generic class that the chosen model fills in as it's type. You can somewhat cheat, as you are here, by using partial views, but you still have to get a model instance into those. It's seems you're trying to do that by creating actions in your controller to represent those partials, but these are effectively useless. They are never being called. Html.Partial or Html.RenderPartial will just render the specified view, either with the same model as the calling view, by default, or the object passed in to those methods as the model (second parameter). It does not go back to the controller.
In MVC, there is something called "child actions" which work as you seem to want partials to here. By using Html.Action or Html.RenderAction instead, you can call this actions on your controller that return partial views. Two things there, though:
If you're going to return a partial view (instead of a full-fledged view), then you should decorate the action with [ChildActionOnly]. Otherwise, the actions are exposed to direct URL access from the browser, which would render the partial view alone, without any layout.
Child actions can only be used for GET-style requests. You can't POST to a child action.
It's actually best for things like this, to only use child actions to render separate areas of a form if those individual areas of the form will be posted to separate locations. Take for example a combo page where you have both a login or signup concept. You can use child actions to render each individual group of fields, but the login portion should POST to a login action and the signup portion should posted to a signup action. You wouldn't POST everything from both forms to the same action.
In your particular scenario, partial views are actually the way to go, but you just need to tweak the model of your main view to be a view model that contains both sub-models. For example:
public class MyAwesomeViewModel // name doesn't matter
{
public ModelApplication Application { get; set; }
public ModelContract Contract { get; set; }
}
Then, in your main view:
#model Namespace.To.MyAwesomeViewModel
...
#Html.Partial("ApplicationPartialView", Model.Application)
#Html.Partial("ContractPartialView", Model.Contract)
Finally, your POST action would take this view model as a parameter:
[HttpPost]
public ActionResult CreateContract(MyAwesomeViewModel model)
{
...
}

What's the correct code to use View like a redirect?

One of the View methods on the Controller class (in System.Web.Mvc) allows you pass a model to a different view. However, it does not update the url to the name of the new view because this method works more like Server.Tranfer than Response.Redirect. The point is that this behaviour can be confusing to anyone picking-up MVC. So, after the View method has been called, I would like the url path to be rewritten to reflect the name of the new view. I have tried the following, which does not work, on a class that implements the Controller class:
public ViewResult ViewAsRedirect(string viewName, object model)
{
var baseView = base.View(viewName, model);
ControllerContext.HttpContext.RewritePath(baseView.ViewName);
return baseView;
}
What's the correct code to implement what I have described?
EDIT
Any RedirectToAction method does not allow you to send you model to another action. There is a dirty workaround where you store it in TempData before you exit one action and retrieve it at the beginning of another action. I don't want to use this pattern. This is why I am using View(...) instead.
You simply cannot "update the URL" (i.e. redirect) and return content.
If you want the new URL to show the same content as you anticipated, then you'll need to (temporarily) store the results and include an identifier for the resource that you wish to display on the redirected URL.
There you can pull the resource in from the controller for the redirected URL again, and display it on the appropriate view.
So if you POST your object model to /Foo/Create, you can for example store model in a database, which yields an ID: 42. Then you can redirect to /Foo/View/42, and display it.
If you can explain what you are actually trying to do, a more concrete answer can be given.
RedirectToAction is very intuitive in my opinion... you should use one of the redirecting methods of MVC controller: Redirect(url), RedirectToAction(acion), RedirectToAction(acion, controller), and so on.
example
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View();
}
public ActionResult Redirect()
{
return this.RedirectToAction("Index");
}
}
EDIT
If your action needs to collect tons of data to pass to the view, you could redirect very early, by detecting the condition of redirection, and loading all the data inside the other action, based on simple route data such as database IDs, or simple strigs or numbers.
== OR ==
You can render javascript code to change the URL in the client side, when the page loads: Modify the URL without reloading the page
This works only in very recent browsers (current date nov/2013).

MVC C# - Simplest Possible Implementation

My first try of MVC. Am trying to implement a simple example. Inspiration from here. Have I got this pattern (yet!)?
View: "Hey, controller, the user just told me he wants the first person"
Controller: "Hmm, having checked his credentials, he is allowed to do that... Hey, model, I want you to get me the first person"
Model: "First person... got it. Back to you, Controller."
Controller: "Here, I'll collect the new set of data. Back to you, view."
View: "Cool, I'll show the first person to the user now."
View:
namespace WinFormMVC
{
public partial class Form1 : Form
{
controller cont = new controller();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = cont.checkPermissionsAndGetFirstPerson();
}
}
}
Controller:
public class controller
{
public string checkPermissionsAndGetFirstPerson()
{
string returnValue = "";
if (checkPermissions())
{
model m = new model();
returnValue = m.getFirstPerson();
}
return returnValue;
}
public bool checkPermissions()
{
return true;
}
}
Model:
public class model
{
public string getFirstPerson()
{
return "Bill Smith";
}
}
Hmm... I am not sure if I'd call this MVC... As with ASP.NET WebForm, this form is more like an MVP pattern.
As per my understanding, in MVC, controller is the one responsible for managing all resources and flow of the code. In your example, you basically creating a Windows Form first (the view) and then attach a controller to it which is more of a MVP sort of things.
In a classical MVC pattern, the Model, once instantiated, will be linked to the View and when the model changes, the view will get notified (possibly through Observer / PubSub pattern).
Button click, etc. from the View will be routed to the controller which will coordinate those sort of stuffs.
see: this.
I would describe MVC more like this:
Request (MVC url routing, some event passed from previous UI etc)
Controller - check credentials, get data, return Model
Model - represents the data passed back from the Controller
View - render the Model returned by the Controller. Depending on the Model may display UI to initialise new Controller actions. May also pass Model back to next Controller action.
I think it can be a little confused because in many Model implementations (such as Linq) they provide data definition and access, but it's still the Controller that knows where to start (even if it's the Model that knows how to save its own changes).
So, your code should be something like:
//Controller:
public class PersonController
{
public PersonAction Detail(int personId)
{
Person returnValue;
//get person from DB and populate returnValue
return new PersonAction( returnValue );
}
}
//Model:
public class Person
{
public string FirstName {get; set;}
public string LastName {get; set;}
}
//View:
public partial class PersonDetailView : MVCForm<Person>
{
public Form1( Person model ):base(model) {
textBox1.Text = model.FirstName + " " + model.LastName;
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = model.FirstName + " " + model.LastName;
}
}
What this example is missing is the framework that makes this all possible - there are two significant parts to that:
Something that takes/parses parameters and based on that calls a controller's action method. For instance in Asp.net MVC this is the routing handlers - the call above would be the request url: ~/Person/Detail/personId
Something that takes the result from the action (PersonAction in the example above) and finds the correct view to display. In this example it would open a PersonDetailView form and pass the Person model to it.
There are lots of example frameworks for an MVC implementation for WinForms - one of them may be a good starting point.
To adopt the MVC pattern you want to implement the following:
The view hooks up to the Model and listens for changes.
The controller hooks up to the view and handles specific events i.e. button presses etc
The model processes requests made by the controller and notifies the view.
I agree with Jimmy you would want to integrate something like the Observer pattern to this type of system so its possible for the Model to inform the View when it changes so the View can then update itself accordingly.
The difference with MVP is it introduces a Presenter class which monitors the Model on behalf of the View, in other words the View doesn't know about the Model, it only knows about its Presenter. The Presenter responds to changes in the Model and updates the View accordingly.
I think there are a few corrections to be made to your narrative. Strinctly speaking the view does not contact the controller, the user contacts the controller directly. In a web app it looks like this.
User: Hey web app, can I have the resource at /people/1
Routing engine: That means you person controller. get the first user.
User controller: Model, I need you to get me user record for the authenticated user, and the person record for the first person.
User Controller: Right. I know the authenticated user is an admin, and person one does exist. So return the Admin view for person to the user.
Rendering engine: Build up the html from the view (template) and person object (data)
This is difficult to do in webforms. I guess the best way is to have a page for each controller, and have that page dynamiclly choose and display a user control. One for each view. It is important in MVC that the view is dumb. All requests are handled directly by controllers, which then select which view to use.
Your checkPermissionsAndGetFirstPerson method is probably doing too much. Authorization and fetching data should probably be separate operations.
Also, if your Form1 class is your view, it probably shouldn't be constructing the controller. That seems backwards.
Most information you'll find on MVC in .NET will be for ASP.NET MVC web applications. You might want to check out the WinFormsMVC project on CodePlex to see how someone else has tackled this problem.
http://winformsmvc.codeplex.com/
Here's another WinForms MVC implementation on CodePlex. Looks like it's got a bit more documentation.
http://koosserymvcwin.codeplex.com/
You might find this tutorial very helpful: http://nerddinnerbook.s3.amazonaws.com/Intro.htm. Written by Scott Guthrie, it explains the MVC workflow very well. Part 4 should have the basics you're looking for.

Categories

Resources