Show partial view based on parameter - asp.net-mvc

In the process of updating a C# MVC 2.0 application!
I have a view “Signup” and another view “ForgotPassword”.
Each view have a with a submit button.
Each form is submitted to the same Controller but to two different ActionResult:
[HttpPost]
public ActionResult Signup(SignupModel signupModel)
{…}
[HttpPost]
public ActionResult ForgotPwd(ForgotPasswordModel forgotPasswordModel)
{…}
Upon completion my goal is to redirect the user to a “thankyou” page but based on where the user is coming from (either Signup or ForgotPassword) I wish to display a particular message (or a different UI).
Inside the same Controller, I created a “Thankyou” ActionResult:
public ViewResult Thankyou()
{
return View();
}
I was thinking of adding a parameter to my Thankyou() method which would allow me to know where the user is coming from (Signup or ForgotPwd). From there, make the “thankyou” page display the appropriate UI/message.
I’m looking for a clean and simple solution.
Should I create two View User Controls and show the appropriate one based on the parameter being passed?
In addition, instead of having an “ActionResult” for my Thankyou() method couldn’t I use a “PartialViewResult” ?
EDIT:
I was actually considering something along those lines…
Where ThankyouType is an Enum.
[HttpPost]
public ActionResult Signup(SignupModel signupModel)
{
//Validation code...
return View("Thankyou", ThankyouType.SignupDone);
}
[HttpPost]
public ActionResult ForgotPassword(ForgotPasswordModel forgotPasswordModel)
{
//Validation code...
return View("Thankyou", ThankyouType.ForgotPasswordDone);
}
And then have my “Thankyou” ViewResult like this:
public ViewResult Thankyou(ThankyouType type)
{
return View(type);
}
Doesn’t seem like I can create a strongly typed view based on Enum (unless I’m wrong).
Perhaps I’ll read more on PartialViewResults and/or find examples…but then again, I could be completely wrong.

I would personally give the ThankYou view a model that has the message you want to display, and have your two controller actions render the ThankYou view directly on success rather than calling a ThankYou action.
However, if you're sure you want a redirect, you may consider using the TempData collection to store a message or a key of some kind. The ThankYou controller can then retrieve this value and pass it to the View. This situation is what TempData was made for.
Edit
There's no reason you shouldn't be able to use an enum value as your model type, but if that gives you trouble you should at least be able to create a model type that has an enum property on it.
The strategy of sending the ThankYouType as part of the redirect request would work just fine, if that's what you prefer. The only potential downside is that it would look like this in the URL:
http://domain.com/controller/ThankYou?type=ForgotPasswordDone
I have no real arguments against it. There are lots of options. Use the one that feels best to you.

Related

Working with tempdata in mvc

As I have read that once you set a tempdata, it will last till next request and if you need to use it more then we need to use keep. But in this situation there is somewhere my tempdata is being lost.
The scenario is below:
I have a view and corresponding to that I have a action method in my controller and here I just set a tempdata as below:
Controller class:
public actionresult myview()
{
tempdata["Empid"]= sourceid;
}
The view consists of several renderAction as below and all these actionmethods in controller return some partialviews
#html.renderAction("details","mycontroller")
#html.renderAction("details","mycontroller")
#html.renderAction("details","mycontroller")
#html.renderAction("details","mycontroller")
Now in partialviews, I have several ajaxified calls suppose in one of the partialview , I have a post method using ajax like below:
$.post("action", "controller",{}});
Please ignore syntactical mistakes as I only have problem in understating the logic of tempdata.
So, coming to above, now the post methods have actionmethods that uses the tempdata that i have set when my view page loads i.e tempdata["Empid"] because this tempdata is needed to get details of employee.
So, it gets the data, reurn json formatted data and I show it in view perfectly.
Uptill here everything is fine. Now, I have one of the partialviews that uses the ajax post to hit controller which is not the same controller but a different cs file. Here this tempdata goes off.
Why is it happening so..
TempData is designed for a short life by default. So the data you set to TempDataDictionary object persists only from one request to the next request. After that it is not going to be available.
You can use the TempDataDictionary.Keep() method to persist the value for the next request again.
public ActionResult Index()
{
TempData["Message"]="Hello";
return View();
}
public ActionResult GetCustomer()
{
var msg = TempData["Message"] as string;
TempData.Keep("Message");
return View();
}

Asp.NET MVC View with different objects

If i have a controller action "Create" that returns a view with the following as the Model type:
public class PaymentModel
{
public Model.SummaryInformation SummaryInformation;
public Model.CardDetail CardDetail;
}
If there is a button on this view that POST's to an action "New" and I want that action to recieve a different object e.g.
public class PaymentNewModel
{
public Model.CardDetail CardDetail;
}
Is this possible? I do not want to use the same Model when the view is rendered to the Model that is POSTed
I'm not aware of anything that would prevent this. The action binder doesn't really care, as long as it can figure it out.
I assume the SummaryInformation object is only used for presentation? (it does not affect the input form?) In that case, you could pass it via ViewData and just bind the view directly against the CardDetail. This is closer to the MVC philosophy, but probably not a huge deal one way or the other.

ASP.NET MVC - Go to a different view without changing URL

is it possible to go to a different View without changing the URL? For example in my Index View, I have a link to go the the Details View but I would like to keep the URL the same.
Thank you very much,
Kenny.
As already mentioned, you could make the Details link an Ajax.ActionLink and use this to change the content of a div.
Failing that, the only other way I can think of doing it is by making your details link a button and POST to your index action. You could apply CSS to the button to make it appear more like a normal html link.
public class HomeController : Controller {
public ActionResult Index() {
return View("Index");
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(int hiddenInputFieldId) {
return View("Details");
}
}
EDIT:
Based on JonoW's comment, you'll have to pass in a 'fake' param with your post, this is not really a problem though, you can just use a hidden input field for it.
You can return the same view from multiple controller actions, but each controller action requires a unique URL:
public class HomeController : Controller {
public ActionResult Index() {
return View("home");
}
public ActionResult About() {
return View("home");
}
}
If you want a link to load up content from a different page without changing the URL, you'll have to use some Ajax to call the server for the content and update the parts of the page you need to change with the new content.
I don't know why you would like to do that, but you could have an Ajax.Actionlink which renders the Details View..
There is almost no reason to hide an URL, not sure what you would like to to.. maybe you explain further that someone can give a better approach.
You can use a good old Server.Transfer for this. However, I'd suggest doing it like has been detailed in this SO post. This gives you an easy way to return an ActionMethod from your current action without peppering your code with Server.Transfer() everywhere.
You can do this by rendering partials- I do this to load different search screens. Sample code is as follows (this is slightly different to my actual code, but you'll get the idea):
<% Html.RenderPartial(Model.NameOfPartialViewHere, Model.SomeVM); %>
Personally though, I don't see why you don't just change the URL?

Controller equivalent of HttpContext.Current in ASP.NET MVC

I'd like to get access to the current executing Controller so I can offload the return of the appropriate ActionResult onto a helper method. To this end, I'm looking for the equivalent of what I would have thought would be ControllerContext.Current but isn't. Thanks!
Edit for clarification: I've got a generic form control which is JavaScript-based but I'd like to add an option so that it works with noscript. At the moment my Controller sets the ViewData.Model to a JSON-ified Models.FormResponse<T>.
This FormReponse is set up with the status of the post and any error messages that were generated, so I'd like a GetActionResult() method which does the script/noscript check (a hidden form input) and either:
Sets the Model to the JSONed FormResponse and returns a View(), or
Serializes the FormResponse to the Session and returns a Redirect().
As this obviously changes the return value and I don't want to do the check myself every time, I need to call View or Redirect from the FormResponse's GetActionResult method in order to call this as:
return formResponse.GetActionResult();
I know with a more astronautical design this could be made even more robust but as the noscript option is not a major feature at the moment, I just need to get a quick solution working that doesn't break other things.
Update #2
The following, implemented in an ActionResult class, does the job for me. Thanks CVertex!
public override void ExecuteResult(ControllerContext context)
{
if (CMSEnvironment.NoScript)
{
Oracle.Response.Redirect(Oracle.Request.UrlReferrer.ToString(), true);
}
context.Controller.ViewData.Model = _model.ToJSON();
new ViewResult()
{
ViewName = Areas.Site.Helpers.SharedView.Service,
ViewData = context.Controller.ViewData
}.ExecuteResult(context);
}
Statics are bad for testability, and very much discouraged in MVC.
Why do you want to access the current controller and action method?
The best way to do this is to implement your own ActionFilter.
This gives you a means of intercepting requests before or after actions methods execute.
EDIT:
By intercepting the result inside OnActionExecuted of a filter, you can do your noscript/script checks and modify your ViewData accordingly for consumption by the View.
Inside OnActionExecuted, you can also do the noscript check and have complete control over the final ActionResult or the ViewData, as you please.
Or, you can write your own ActionResult that makes all these decisions.
So, your controller action ultimately does
return new MyActionResult(format_and_view_agnostic_model_object);
There doesn't appear to be a way to navigate to the current Controller from a thread. That is you could get the ControllerBuilder and you can get the MvcHttpHandler but neither then lets you access the controller instance that the handler is using.

Asp.net mvc: Posting Back from the View

Is it considered better practice to post back to the same controller that did the rendering and redirecting from original controller if necessary? Or is it just the same if one jumps to different controllers from the view?
I create two overloaded actions in the controller, one to render the input form using an HTTP GET and the other to process the form post using an HTTP POST. Something like this:
public ViewResult Foo()
{
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ViewResult Foo( FormCollection form )
{
// process input
if (inputOK)
return RedirectToAction("Index");
return View();
}
The benefit of doing it this way is that if there's an error, the view gets re-rendered with any error and validation messages. If it's successful, there's a redirect to another action, which avoids the duplicate posting warning on browsers if a user refreshes the page - see Post/Redirect/Get on Wikipedia and this blog entry by Stephen Walther.
There are alternatives to taking a FormCollection, e.g. a list of simple parameters or binding to an object. See this article by ScottGu.
I think that the action that is being called should be contained within a relevant controller for that action. If the view needs to call the action it should call it from the relevant controller, not necessarily the controller that it was spawned from.
If you have an inventory controller you don't want to define actions that relate to administration even if an inventory screen might have an administration action on it, as an example.

Resources