Obtain View name in Controller, ASP.NET MVC - asp.net-mvc

I am using asp.net mvc. I have 4 pages that show list of events(different type of events) and "Details" link on each page leads to "EventDescription.aspx" View.
The "EventDescription.aspx" has a link called "Back to Events" which has to take the user to the appropriate page.
Eg: if the "Details" request came from page1 the "Back to Events" link needs to point to page1.aspx. Same for page2.aspx,page3.aspx,page4.aspx.
My plan is to capture the view name (page1.aspx) in controller action "EventDescription" and store in ViewData before displaying the "EventDescription.aspx" and user the ViewData value for "Back to Events" link.
How to obtain the name of the View from where the request comes from inside a Action?
Thank in advance.

When you render the page, you also need to render a link that will point to the correct page when Back to Events is clicked. This is best set up in the controller method, where you readily have access to all of the necessary information.
An easy way to do this is to put the return link information in a ViewData variable (untested pseudocode follows). In your controller method:
ViewData["ReturnPath"] = "/Content/Page/1";
And then in your view:
<% =Html.ActionLink("Back To Events", ViewData["ReturnPath"]) %>
or something similar.
Alternatively, you could try something like
ViewContext.RouteData.Values["action"]
...if you don't mind the magic string there. This will give you the calling action.

if you just want to get the Url where you came from you can do this in your Action
ViewData["ReturnPath"] = this.Request.UrlReferrer.AbsolutePath;
This give you the Url of the page where you came from. If your from Page1 then you go to EventDescription. In your EventDescription Action, your ReturnPath ViewData has the Url of Page1. Or Vice Versa.

I suggest you use TempData instead of ViewData. For instance you could have a setting like this.
public ActionResult Details(int id)
{
var event = repository.GetByID(id);
if (event != null)
{
TempData["ReturnPath"] = Request.UrlReferrer.ToString();
return View(event);
}
else { //....... ; }
}
And in your View you could have a regular ActionLink like so
<% =Html.ActionLink("Back To Events", TempData["ReturnPath"]) %>
If you want to be DRY, you could also create an Action method in your controller just to handle the redirects like so.
public ActionResult GoBack()
{
return Redirect(TempData["ReturnPath"]);
}
And in your View a normal ActionLink like so
<% =Html.ActionLink("Back To Events", "GoBack") %>

Put the return path in TempData (not ViewData) and it can pass from the calling page to the Details page. See also http://jonkruger.com/blog/2009/04/06/aspnet-mvc-pass-parameters-when-redirecting-from-one-action-to-another/

Related

#RenderPage - Render a edit page

I want to render a page but that page be a "edit" page. Something like this
#RenderPage("~/Views/Edit/25.cshtml")
But this doesn't work and probably i should pass the parameter "25" as a parameter, but so far without success. In my program I've got two tabs and both call(render) pages throw Ajax (Jqueryui - http://jqueryui.com/tabs/) and i would like to when i click in a tab he call the edit view with a specific id.
It's possible? How i should do that?
To render tabs via ajax in asp.net mvc you can do it this way.
CSHTML:
Create tab control, each anchor in tab header uses different routevalues. Ofcourse you can link them to different actions of controller:
<div id=tabs>
<ul>
<li>#Html.ActionLink("Tab1", "Edit", new { id = 25 })</li>
<li>#Html.ActionLink("Tab2", "Edit", new { id = 26 })</li>
</ul>
</div>
Controller, note that you are returning a partial view here which gets rendered into the tabcontrol:
public ActionResult Edit(int id)
{
// You probably want to load the Model from the db with id param. I just write a message
ViewBag.Message = id;
return PartialView("Edit");
}
My partialview Edit.cshtml:
<span>Edit me #ViewBag.Message</span>
Javascript, just create your tab control normally:
$("#tabs").tabs();
Generally if you want to render some partial view with parameters I'd personally go for
#Html.Action("Edit", "Controller", new {id=25})
If you want some actions to be performed on click for the specific tab then i would suggest you should go with Ajax.
Have a look to jQuery.Ajax.
Or else you want it a pure http web request, then you can have certain query string to be passed on the same page when user clicks on the tab and load the content accordingly by identified the passed value.

Make ActionLink to specific user

How do I make the links on the site lead to the current user's page(s)? I dont want them to get lists of every user but only themselves. I'm thinking something like this for my menu links:
#Html.ActionLink("My Details", "Details", "Customers", Membership.GetUser().ProviderUserKey)
I think it's better if you send user to "My Details" page without any parameter or route values.
The page is going to show current users data. So why to pass it like this?
Just Redirect user to "My Detail" page, and after that, when user is in that page, you can get current user using: HttpContext.CurrentUser.
Don't put user data in route values. Instead you can get it in that page's controller and pass it to the page.
If you want the "Links" to display to show when the page is viewed by an authenticated user, create a ChildAction that returns the data you want like:
[Authorize]
[ChildActionOnly]
public ActionResult UserLinks() {
var items = someRepository.GetLinks(User.Identity.Name);
return PartialView(items,"SomePartialView");
}
Then, use the RenderAction in the view like so:
#{ Html.RenderAction("UserLinks");}
Secondly, I agree with the comment by "Afshin Gh". Rather than passing data in your "ActionLink(s)", you could code it in your Controller to filter the data as required - like I'm showing in the "UserLinks" method above. This way, someone can't just manipulate the Url to display data for another customer.

ASP.NET MVC: Returning a view with querystring intact

I'm creating a messaging web app in ASP.NET and are having some problems when displaying an error message to the user if they go to send a message and there is something wrong.
A user can look through profiles of people and then click, 'send a message'. The following action is called (url is /message/create?to=username) and shows them a page where they can enter their message and send it:
public ActionResult Create(string to)
{
ViewData["recipientUsername"] = to;
return View();
}
On the page that is displayed, the username is entered in to a hidden input field. When the user clicks 'send':
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection, string message)
{
try
{
//do message stuff that errors out
}
catch
{
ModelState.AddModelErrors(message.GetRuleViolations()); //adding errors to modelstate
}
return View();
}
So now the error message is displayed to the user fine, however the url is changed in that it no longer has the querystring (/message/create). Again, this would be fine except that when the user clicks the refresh button, the page errors out as the Create action no longer has the 'to' parameter.
So I'm guessing that I need to maintain my querystring somehow. Is there any way to do this or do I need to use a different method altogether?
I assume you are doing something like...
<% Html.BeginForm("Create", "Controller") { %>
<% } %>
As you are creating the Form's action url through routing, the existing route values will be lost in the process. The easiest way to avoid this is by just using the parameterless version of BeginForm, since you are on the page you are posting to.
<% Html.BeginForm() { %>
<% } %>
This will use the current url, query string and all, as the ACTION of the form. Otherwise, you will need to pass in the route value to in the BeginForm overload.
Recommend you take a look at the PRG pattern which will help with this.
http://devlicio.us/blogs/tim_barcz/archive/2008/08/22/prg-pattern-in-the-asp-net-mvc-framework.aspx

how to call controller from button click without using ajax mvc

I'm new to web programming in general so this is probably a really simple question. I couldn't find anything on the web however.
What I want to do is call my controller with the typed search string and return the results from a database and paginate the results. Right now I am using a function that is called when the button is pressed. The function looks like so:
function SubmitSearch() {
var searchBox = document.getElementById('searchBox');
var searchButton = document.getElementById('SearchButton');
$.post("MyController/MyAction/",
{
searchString: searchBox.value,
page: null
}, function(result) {
$('#searchResults').html(result);
searchButton.value = "Search";
});
}
What happens is my controller is called, and my searchResults div is populated with the results and paginated. The user can click any search result returned to view the details.
The problem is when the user clicks the browsers 'back' button, the page returns to the state before the search was entered, and this is because of the ajax call. What I want to do is, call the controller and have the page load like google would. Instead of using a PartialView, I would use a View (my guess).
How would I call the controller and have the page RELOAD with the results. I must be missing something fundamental because this definitely seems like it should be easy.
If you don't want to use AJAX then you need to place your text field in a form element on your page, something like:
<form action="MyController/MyAction/" method="get">
<input id="SearchBox" name="SearchBox" type="text" />
<button type="submit">Search</button>
</form>
Then in your controller return the view with the list of results.
You probably also want to look into RESTful URLs and the PRG (Post, Redirect, Get) pattern to maintain the integrity of the back button and enable correct bookmarking of pages etc.
I think you might actually be looking for an AJAX History library to help when the Back button is pressed rather than altering your app. Take a look at this blog post.
Aspx:
<% using (Html.BeginForm<MyController>(m => m.MyAction(null)) { %>
<%= Html.TextBox("q"); %>
<% } %>
// Listing
Controller:
public class MyController : Controller
{
public ActionResult MyAction(string q)
{
var repository; // instance of your repository.
if (String.IsNullOrEmpty(q))
{
return View(repository.GetAllBlogs());
}
return View(repository.SearchBlogs(q));
}
}

Render action return View(); form problem

I'm new to MVC, so please bear with me. :-)
I've got a strongly typed "Story" View. This View (story) can have Comments.
I've created two Views (not partials) for my Comments controller "ListStoryComments" and "CreateStoryComment", which do what their names imply. These Views are included in the Story View using RenderAction, e.g.:
<!-- List comments -->
<h2>All Comments</h2>
<% Html.RenderAction("ListStoryComments", "Comments", new { id = Model.Story.Id }); %>
<!-- Create new comment -->
<% Html.RenderAction("CreateStoryComment", "Comments", new { id = Model.Story.Id }); %>
(I pass in the Story id in order to list related comments).
All works as I hoped, except, when I post a new comment using the form, it returns the current (parent) View, but the Comments form field is still showing the last content I typed in and the ListStoryComments View isn’t updated to show the new story.
Basically, the page is being loaded from cache, as if I had pressed the browser’s back button. If I press f5 it will try to repost the form. If I reload the page manually (reenter the URL in the browser's address bar), and then press f5, I will see my new content and the empty form field, which is my desired result.
For completeness, my CreateStoryComment action looks like this:
[HttpPost]
public ActionResult CreateStoryComment([Bind(Exclude = "Id, Timestamp, ByUserId, ForUserId")]Comment commentToCreate)
{
try
{
commentToCreate.ByUserId = userGuid;
commentToCreate.ForUserId = userGuid;
commentToCreate.StoryId = 2; // hard-coded for testing
_repository.CreateComment(commentToCreate);
return View();
}
catch
{
return View();
}
}
The answer is to use return RedirectToAction(). Using this enforces the PRG pattern and achieves my goal.
My earlier comment to my original post did cause an error, that I guess I'm still confused about, but this works:
return RedirectToAction("Details", "Steps", new { id = "2" });
I, and this is a personal opinion, think you've tackled this the wrong way.
Personally I would;
Create a view called ListStories.
Create a partial view that lists the
stories.
Create a partial view to create a
story.
When you want to add a story, simply
show the add story html.
Then when the user presses a button
you do a jQuery postback, add the
new story and return a PartialView
of either the new story or all the
stories.
If you return a partial view of all
stories then replace the bounding
div that contains all the stories
with the new data.
If you return only a single story
then append it to the end of the div
containing the stories.
I know this means a lot of re-work and it sounds complex and like a lot of work but doing it like this means greater flexibility later on because you can re-use the partial views or you can make a change once and all views using that partial view are now updated.
also, using jQuery means that the adding of stories looks seemless w/out any obvious post back which is nice.
Since the problem seems to be caching, you can simply disable/limit caching.
Add the following attribute to your actions:
[OutputCache(Duration = 0, VaryByParam = "none")]
This will tell the browser to cache the page, but for 0 seconds. When the post reloads the page, you should see the desired results.
The answer is to make sure your form action is properly set. If you have used renderaction and not set the form controller and action manually then the action will be the current URL.
Try:
<% using (Html.BeginForm("ActionName", "ControllerName")) {%>
Instead of:
<% using (Html.BeginForm()) {%>

Resources