3

I have two partial views “MyPopular” and “MyBlogs”. And there are two controllers – “ArticleController.cs” and “ThePopularController.cs”. Both these partialviews contains buttons.

Initially it renders both partial views inside the index view.

On post action handler for blog’s click, it is asked to redirect to “BlogHome“ action where it will return a simple string “Blog Home” (instead of a view). On post action handler for popular’s click, it is asked to redirect to “PopularHome“ action where it will return a simple string “Popular Home”. But currently, when I click on any of the button, it renders localhost:1988/Article index; without partial content.

Note: The result is same even when I used ContentResult and ActionResult. Note: Please highlight if I am going through the wrong way for achieving such a simple task.

How do we correct it to do the proper redirecting?

//ArticleController

public class ArticleController : Controller
{

    public ActionResult Index()
    {
        //Index returns no model
        return View();
    }

    public string BlogHome()
    {
        return "Blog Home";
    }


    //ChildActionOnly attribute indicates that this action should not be callable directly via the URL. 
    [ChildActionOnly]
    public ActionResult MyBlogs()
    {
        Thread.Sleep(500);
        return PartialView(GetAllBlogEntries());
    }

    [ChildActionOnly]
    [HttpPost]
    public void MyBlogs(string blogclick)
    {
        RedirectToAction("BlogHome");
    }


    private IEnumerable<Blog> GetAllBlogEntries()
    {
        return new[]
                    {
                        new Blog { ID = 1, Head = "Introduction to MVC", PostBy = "Lijo", Content = "This is a ..." },
                        new Blog { ID = 2, Head = "jQuery Hidden Gems", PostBy = "Lijo", Content = "This is a ..." },
                        new Blog { ID = 3, Head = "Webforms Intenals", PostBy = "Lijo", Content = "This is a ..." }
                    };
    }



}

// ThePopularController

public class ThePopularController : Controller
{

    public string PoularHome()
    {
        return "Poular Home";
    }


    //ChildActionOnly attribute indicates that this action should not be callable directly via the URL. 
    [ChildActionOnly]
    public ActionResult MyPopular()
    {
        Thread.Sleep(500);
        return PartialView(GetPopularBlogs());
    }


    [ChildActionOnly]
    [HttpPost]
    public void MyPopular(string popularpress)
    {
        RedirectToAction("PoularHome");
    }


    private IEnumerable<PopularTutorial> GetPopularBlogs()
    {
        return new[]
                    {
                        new PopularTutorial { ID = 17, Title = "Test1", NumberOfReads = 1050 },
                        new PopularTutorial { ID = 18, Title = "Test2", NumberOfReads = 5550 },
                        new PopularTutorial { ID = 19, Title = "Test3", NumberOfReads = 3338 },
                        new PopularTutorial { ID = 20, Title = "Test4", NumberOfReads = 3338 },
                        new PopularTutorial { ID = 21, Title = "Test5", NumberOfReads = 3338 },
                        new PopularTutorial { ID = 22, Title = "Test6", NumberOfReads = 3338 },
                        new PopularTutorial { ID = 23, Title = "Test7", NumberOfReads = 3338 },
                    };
    }
}

//Index.cshtml

All Blogs List
@Html.Action("myblogs")

<br />
<br />

Popular Tutorial
@Html.Action("mypopular","thepopular")

//MyPopular.cshtml

@model IEnumerable<MyArticleSummaryTEST.PopularTutorial>

@{
var grid = new WebGrid(Model, canPage: true, canSort: false, rowsPerPage: 3);
}

@grid.GetHtml(
            columns: grid.Columns(grid.Column("", format: @<text>@item.Title</text>))
        )


@using (Html.BeginForm())
{
<div>
    <input type="submit" name ="popularpress" id="2"/>  
</div>
}

//MyBlogs.cshtml

@model IEnumerable<MyArticleSummaryTEST.Blog>

<section>
<ul>
    @Html.DisplayForModel()
</ul>
</section>

@using (Html.BeginForm())
{
<div>
<input type="submit" name ="blogclick" id="1"/>  
</div>
}

//Blog Display Template

@model MyArticleSummaryTEST.Blog

<li>
<h3>@Html.DisplayFor(x => x.Head)</h3>
@Html.DisplayFor(x => x.Content)
</li>

READING:

  1. asp.net MVC partial view controller action

  2. Using Html.BeginForm to post to the current controller

  3. Loading a partial view in jquery.dialog

  4. How can i generate html in action from partial view?

  5. Returning Redirect or PartialView from the same Action

  6. Redirect to Refer on Partial View Form Post using ASP.NET MVC

  7. Why are Redirect Results not allowed in Child Actions in Asp.net MVC 2

  8. ValidationSummary not appearing with Partial Views

  9. Redirecting from a Partial View the "Right" Way in ASP.Net MVC 2 http://geekswithblogs.net/DougLampe/archive/2011/08/05/redirecting-from-a-partial-view-the-right-way-in-asp.net.aspx

  10. Partial Requests in ASP.NET MVC http://blog.stevensanderson.com/2008/10/14/partial-requests-in-aspnet-mvc/

  11. Progressive enhancement tutorial with asp.net mvc 3 and jquery http://www.matthidinger.com/archive/2011/02/22/Progressive-enhancement-tutorial-with-ASP-NET-MVC-3-and-jQuery.aspx

Community
  • 1
  • 1
LCJ
  • 22,196
  • 67
  • 260
  • 418
  • 1
    You have some fundamental misunderstandings. In your index.cshtml, you want to be using ActionLink, not Action. Action will attempt to execute the action, in this case an HTTP redirect which is not appropriate, rather than provide a link you can click on. I'm sure that it's a link that you want. Given that there's no need for the ChildActionOnly -- it will prevent what you want -- or the POST actions, since it will be a GET request. I may be wrong on what you're trying to achieve, but I think you've made it more complicated than it needs to be. – tvanfosson Feb 24 '12 at 14:13

4 Answers4

4

There are number of errors in you code:

  1. When calling child action MyBlogs from parent action Index, having @using (Html.BeginForm()) in the MyBlogs view, generates the form that posts to Index action, not the MyBlogs one. Same story for Populars. So, no suprise that every submit re-renders Index action contents - that is action requested by your form. Try using overload of Html.BeginForm that accepts route parameters.
  2. [ChildActionOnly] means that action is not accessible by outside world, be request HttpGet, Post, by url or any other means. It can be used only with Html.Action helper. So, when you correct the 1st error, you won't be still able to post on that action. You should remove ChildActionOnly attribute if that action should handle post requests.
  3. If it's the real code you posted, it does not (and should not) redirect. You should correct method signature and add missing return statement

This code

[HttpPost]
public void MyBlogs(string blogclick)
{
    RedirectToAction("BlogHome");
}

Should be

[HttpPost]
public ActionResult MyBlogs(string blogclick)
{
    return RedirectToAction("BlogHome");
}

This should work

archil
  • 39,013
  • 7
  • 65
  • 82
  • Thanks. I corrected the above mentiioed three items. Now, I am getting "Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'". This error is happening in the Index.cshtml after coming back from the controller. The change I made is like Html.BeginForm("Index","Article") in MyBlogs.cshtml and MyPopular.cshtml. How do we make it working? – LCJ Feb 23 '12 at 15:38
  • @Lijo what do inner exceptions say? – archil Feb 23 '12 at 16:13
  • Inner Exception says, "Child actions are not allowed to perform redirect actions."}. But I have removed all the words "child" from the code that I written. Still it complains about child action. How do we correct it? – LCJ Feb 24 '12 at 05:22
  • if you Post to Index action, when rendering partial view with @Html.Action, HttpPost MyBlogs will be chosen, not HttpGet one. HttpPost MyBlogs performs redirection, so you get an error – archil Feb 24 '12 at 06:34
3

The problem lies with @using (Html.BeginForm()).

When we do not specify any action and controller name in BeginForm, It will post Data to the Url of the page. (In this scenario Article/Index ).

You can specify the Action and Controller to post the data,

Like, in MyBlogs.cshtml

@using(Html.BeginForm("MyBlogs","Article")){
...}

in MyPopular.cshtml

@using(Html.BeginForm("MyPopular","ThePopular")){
...}
Manas
  • 2,534
  • 20
  • 21
  • I am getting the following error page when clicked on the button. How do we correct it? "An error occurred during the compilation of a resource required to service this request. The type or namespace name 'ArticleSummary' does not exist in the namespace 'MyArticleSummaryTEST' (are you missing an assembly reference?)" "public class _Page_Views_ThePopular_PoularHome_cshtml : System.Web.Mvc.WebViewPage { " – LCJ Feb 24 '12 at 05:27
  • Just Verify if ArticleSummary class belongs to MyArticleSummaryTEST name space.... – Manas Feb 24 '12 at 06:37
1

well, not sure if it's the full story or not, but you have:

public string PoularHome()
{
    return "Poular Home";
}

which is merely a method. you then issue (from your MyPopular method):

RedirectToAction("PoularHome");

As PoularHome() isn't returning a type of ActionResult (or derivation), then the pipeline is going to ignore this 'request'. You need to seriously look at returning the appropriate type. Try refactoring your method (action) as such and see if it helps:

public ContentResult PoularHome()
{
    return Content("Poular Home");
}

no guarantees - just a 30K feet observation.

jim tollan
  • 22,305
  • 4
  • 49
  • 63
  • Didn't work when I used ContentResult or even ActionResult (and returned a View() objetc). My simple question is - how do we usually redirect to other views from partial views? – LCJ Feb 23 '12 at 13:54
0

By your code it looks like you are redirecting to an action that isn't in the current controller. If the action isn't in the current controller you need to use the overload that specifies both the controller and the action. Otherwise it will just drop into the default route and send you to index.

Also you need to Return a RedirectToAction. This is still a type of ActionResult that must be returned.

swannee
  • 3,346
  • 2
  • 24
  • 40