I'm trying to understand what exact method is generating view? As I've understood when we're sending http- request to a server the following subsequent of actions is executed:
Router is creating ControllerContext class instance
Router is creating a corresponding controller class instance
Router is invoking a corresponding controller's action.
After the action method return an instance actResult of ActionResult the actResult.ExecuteResult(ControllerContext context) is invoked.
Question: Is my understanding of the request processing true? And I don't understand what exactly generate a response text? I'm interested in what method generates the response body?
You can find more about this HERE or HERE.
To address your specific question:
The action returns a result. If this result is a view result the appropriate view engine is selected and then this engine will render the view.
Details from my first link:
View Result
The action method receives user input, prepares the appropriate response data, and then executes the result by returning a result
type. The result type can be ViewResult, RedirectToRouteResult,
RedirectResult, ContentResult, JsonResult, FileResult, and
EmptyResult.
View Engine
The first step in the execution of the View Result involves the selection of the appropriate View Engine to render the View Result. It
is handled by IViewEngine interface of the view engine. By default
Asp.Net MVC uses WebForm and Razor view engines. You can also register
your own custom view engine to your Asp.Net MVC application as shown
below:
protected void Application_Start()
{
//Remove All View Engine including Webform and Razor
ViewEngines.Engines.Clear();
//Register Your Custom View Engine
ViewEngines.Engines.Add(new CustomViewEngine());
//Other code is removed for clarity
}
View
Action method may returns a text string,a binary file or a Json formatted data. The most important Action Result is the ViewResult, which renders and returns an HTML page to the browser by using the current view engine.
Related
I'm using ASP.NET MVC in Visual Studio 2015. The app has the following structure:
MyApp
Controllers
Controller1
Actions
Create
Delete
Details
Edit
IndexPartial
Controller2
Actions
Edit
Controller3
Actions
Edit
Views
Controller1
Create
Delete
Details
Edit
IndexPartial
Controller2
Edit
Controller3
Edit
The app displays Controller1/IndexPartial view on the Controller2/Edit view and on Controller3/Edit. This partial view displays rows of data, each with Edit, Details, Delete buttons which take the user to the Controller1 views for those actions.
When the user is done with the Controller1 action, they need to return to Controller2/Edit or Controller3/Edit via the Back to List button or when the Save/Delete buttons are clicked. But how do we determine where the user originated? Did the user come from the Edit of Controller2 or Controller3?
We've thought of using a session variable. Can RouteConfig.cs be used to track the user's path and help determine where s/he should return? How do we do this via routes in MVC?
Thank you for your help.
Update: This is all done via the server; no JavaScript (Angular, etc.).
The routing engine has nothing to do with what you need. You need to track user navigation and a good way to do this is using ActionFilters.
You can create a custom ActionFilter that checks the UrlReferrer on its OnActionExecuted and decides how to redirect the request to the appropriate Controller/Action.
[Example]
ActionFilter
public class RedirectAfterActionFilter : ActionFilterAttribute, IActionFilter
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
// Your decision logic
if (filterContext.HttpContext.Request.UrlReferrer.AbsolutePath == "something usefull")
{
filterContext.Result = new RedirectToRouteResult("Your Route Name", routeValues: null); // redirect to Home
}
base.OnActionExecuted(filterContext);
}
}
ActionFilter usage
[RedirectAfterActionFilter]
public ActionResult DoSomethingAndGetRedirected()
{
// Save, Edit or Whatever
//...
return new EmptyResult(); // no need to return since the user will be redirected by the filter
}
Extra: Read How to redirect from a action filter if you dislike to use Route names to redirect.
There are two aspects to this:
The "Back to List" link
The "Save/Delete" actions
As far as the "Back to List" link, your controller should be giving the view all the information it needs to produce a viable GUI. Pass an identifier (or even the actual return URL) to the view in the ViewBag as a dynamic property and let the view render the link to the destination.
For the "Save/Delete" actions, it depends on how they are implemented.
If it's all JS with http requests then the same concept above applies.
If you are posting back to the server however, the controller will have to do the redirection with something like RedirectToAction().
How about storing the previous location in a ViewBag and then populate your button href with the ViewBag content...
Or
You can use Url Referrer, which fectches the previous url that linked to current page.
Of course the best method will depend on your implementantion, without seeing your code those two are the best option that I can think of.
I am building MVC 4 application.
The authorization and exception handling is done using Filters.
In filter, I can either redirect user to my error page using RedirectToRouteResult
or return view of my error page using ViewResult.
Which variant is better in practice and why?
1.Return View doesn't make a new requests, it just renders the view without changing URLs in the browser's address bar.
2.Return RedirectToAction makes a new requests and URL in the browser's address bar is updated with the generated URL by MVC.
3.Return Redirect also makes a new requests and URL in the browser's address bar is updated, but you have to specify the full URL to redirect
4.Between RedirectToAction and Redirect, best practice is to use RedirectToAction for anything dealing with your application actions/controllers. If you use Redirect and provide the URL, you'll need to modify those URLs manually when you change the route table.
5.RedirectToRoute redirects to a specific route defined in the Route table.
If you want to move on error page with static data with limited messages then use ViewResult else use RedirectToRouteResult in this you can use as you want.
It depends on whether there is any logic in an error action that populates a view model (e.g.setting the http status code) or you only have a static view. Of course you could move this logic to the filter, but this would prevent you from being able to redirect from another action that doesn't use the same filter.
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).
I am testing a push notification on a calendar application. When I create an event on calendar application, my website gets a HttpPost request with a JSON string. I wrote code like this but I couldn't receive the JSON string in my action method.
[HttpPost]
public ActionResult Push(String jsonReq)
{
Console.write(jsonReq);
return View();
}
When I create model in the same structure as JSON, then I can receive the request. it seems to be tightly coupled to JSON structure ? I am using in ASP.Net MVC 4.
[HttpPost]
public ActionResult Push(JSONModel jsonModel)
{
return View();
}
ASP.NET MVC model binding works the following way - it parses the request, tries to find a name-to-name corresponding between its parameters and Action paramaters, and if found instantiates latter. You are not sending parameter with name jsonReq, so you cannot receive something in your action method.
If you really want to work with plan json string without letting ASP.NET MVC parse it for your, you have two options:
Access it via HttpContext.Request inside the action
Write custom model binder that will map the request body to the jsonReq parameter
The request would not have a value named jsonReq so would not know to map the json to that action parameter.
Where as your JSONModel will have property names that match the JSON named values coming into the request thus the object us populated.
I am pretty sure I am doing something wrong here. I have been developing a web app using MVC and Razor and I never thought of using the form element. Now so much has already been done with master pages and sub pages that it means restructuring most of our code in order to use form element and the would result in multiple form elements on a page.
That aside, in Asp.Net if I wanted to access any control in the C# code behind I could just give it an ID="SomeID" and a RUNAT="SERVER". Then in my code behind I could set its value and properties.
When I do this in Razor, I use lines like:
<input id="hiddenPostBack" runat="server" type="hidden" />
Why can't I access this in the controller? I want to detect a postback and set the value to false if it is the first time the page loads, and if not, then set the value to true. Then based on this, I will read it either server side or client side and do something.
My real question is, how do I "do something" both server side and client side given that I don't have a form element. I was under the impression that if I wanted to pass values from client to server and back, the easiest way to do this is with a hidden input. But I am just not getting how to accomplish this with MVC3 and razor.
A move from WebForms to MVC requires a complete sea-change in logic and brain processes. You're no longer interacting with the 'form' both server-side and client-side (and in fact even with WebForms you weren't interacting client-side). You've probably just mixed up a bit of thinking there, in that with WebForms and RUNAT="SERVER" you were merely interacting with the building of the Web page.
MVC is somewhat similar in that you have server-side code in constructing the model (the data you need to build what your user will see), but once you have built the HTML you need to appreciate that the link between the server and the user no longer exists. They have a page of HTML, that's it.
So the HTML you are building is read-only. You pass the model through to the Razor page, which will build HTML appropriate to that model.
If you want to have a hidden element which sets true or false depending on whether this is the first view or not you need a bool in your model, and set it to True in the Action if it's in response to a follow up. This could be done by having different actions depending on whether the request is [HttpGet] or [HttpPost] (if that's appropriate for how you set up your form: a GET request for the first visit and a POST request if submitting a form).
Alternatively the model could be set to True when it's created (which will be the first time you visit the page), but after you check the value as being True or False (since a bool defaults to False when it's instantiated). Then using:
#Html.HiddenFor(x => x.HiddenPostBack)
in your form, which will put a hidden True. When the form is posted back to your server the model will now have that value set to True.
It's hard to give much more advice than that as your question isn't specific as to why you want to do this. It's perhaps vital that you read a good book on moving to MVC from WebForms, such as Steve Sanderson's Pro ASP.NET MVC.
If you are using Razor, you cannot access the field directly, but you can manage its value.
The idea is that the first Microsoft approach drive the developers away from Web Development and make it easy for Desktop programmers (for example) to make web applications.
Meanwhile, the web developers, did not understand this tricky strange way of ASP.NET.
Actually this hidden input is rendered on client-side, and the ASP has no access to it (it never had). However, in time you will see its a piratical way and you may rely on it, when you get use with it. The web development differs from the Desktop or Mobile.
The model is your logical unit, and the hidden field (and the whole view page) is just a representative view of the data. So you can dedicate your work on the application or domain logic and the view simply just serves it to the consumer - which means you need no detailed access and "brainstorming" functionality in the view.
The controller actually does work you need for manage the hidden or general setup. The model serves specific logical unit properties and functionality and the view just renders it to the end user, simply said. Read more about MVC.
Model
public class MyClassModel
{
public int Id { get; set; }
public string Name { get; set; }
public string MyPropertyForHidden { get; set; }
}
This is the controller aciton
public ActionResult MyPageView()
{
MyClassModel model = new MyClassModel(); // Single entity, strongly-typed
// IList model = new List<MyClassModel>(); // or List, strongly-typed
// ViewBag.MyHiddenInputValue = "Something to pass"; // ...or using ViewBag
return View(model);
}
The view is below
//This will make a Model property of the View to be of MyClassModel
#model MyNamespace.Models.MyClassModel // strongly-typed view
// #model IList<MyNamespace.Models.MyClassModel> // list, strongly-typed view
// ... Some Other Code ...
#using(Html.BeginForm()) // Creates <form>
{
// Renders hidden field for your model property (strongly-typed)
// The field rendered to server your model property (Address, Phone, etc.)
Html.HiddenFor(model => Model.MyPropertyForHidden);
// For list you may use foreach on Model
// foreach(var item in Model) or foreach(MyClassModel item in Model)
}
// ... Some Other Code ...
The view with ViewBag:
// ... Some Other Code ...
#using(Html.BeginForm()) // Creates <form>
{
Html.Hidden(
"HiddenName",
ViewBag.MyHiddenInputValue,
new { #class = "hiddencss", maxlength = 255 /*, etc... */ }
);
}
// ... Some Other Code ...
We are using Html Helper to render the Hidden field or we could write it by hand - <input name=".." id=".." value="ViewBag.MyHiddenInputValue"> also.
The ViewBag is some sort of data carrier to the view. It does not restrict you with model - you can place whatever you like.
As you may have already figured, Asp.Net MVC is a different paradigm than Asp.Net (webforms). Accessing form elements between the server and client take a different approach in Asp.Net MVC.
You can google more reading material on this on the web. For now, I would suggest using Ajax to get or post data to the server. You can still employ input type="hidden", but initialize it with a value from the ViewData or for Razor, ViewBag.
For example, your controller may look like this:
public ActionResult Index()
{
ViewBag.MyInitialValue = true;
return View();
}
In your view, you can have an input elemet that is initialized by the value in your ViewBag:
<input type="hidden" name="myHiddenInput" id="myHiddenInput" value="#ViewBag.MyInitialValue" />
Then you can pass data between the client and server via ajax. For example, using jQuery:
$.get('GetMyNewValue?oldValue=' + $('#myHiddenInput').val(), function (e) {
// blah
});
You can alternatively use $.ajax, $.getJSON, $.post depending on your requirement.
First of all ASP.NET MVC does not work the same way WebForms does. You don't have the whole runat="server" thing. MVC does not offer the abstraction layer that WebForms offered. Probabaly you should try to understand what controllers and actions are and then you should look at model binding. Any beginner level tutorial about MVC shows how you can pass data between the client and the server.
You are doing it wrong since you try to map WebForms in the MVC application.
There are no server side controlls in MVC. Only the View and the
Controller on the back-end. You send the data from server to the client by
means of initialization of the View with your model.
This is happening on the HTTP GET request to your resource.
[HttpGet]
public ActionResult Home()
{
var model = new HomeModel { Greeatings = "Hi" };
return View(model);
}
You send data from client to server by means of posting data to
server. To make that happen, you create a form inside your view and
[HttpPost] handler in your controller.
// View
#using (Html.BeginForm()) {
#Html.TextBoxFor(m => m.Name)
#Html.TextBoxFor(m => m.Password)
}
// Controller
[HttpPost]
public ActionResult Home(LoginModel model)
{
// do auth.. and stuff
return Redirect();
}