Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

umbraco mvc surface controller, can't return view from HttpPost Action

Overview of the problem:

I've created a Surface controller with an action that is called using @Html.Action(...).

The @Html.Action call is done within a Macro partial view and the macro is included within the content of a page using the rich text editor.

(I'm new to this so if i'm going about things the wrong way then please let me know.)

The Surface controller has a GET and a POST action but it's the get action called within the macro partial.

Get action renders fine, entering no data into the form will invalidate the model state (which is what i'm currently testing).

submitting the form (with no entered data) means i can step into my POST action, ModelState.IsValid is set to false and CurrentUmbracoPage() is returned.

All fine... No Exceptions encountered when debugging...

It's at this point that the error text "Error loading Partial View script" appears on the page.

All I'm trying to do is return the same page with the validation messages showing.

Details:

Umbraco v6.0.5

The Controller I'm currently working on is used to reset a user's password. I also have a login conroller that is getting around this issue by using RedirectToCurrentUmbracoPage().

to access the page that contains the macro i use the address http://{testhost}/Reset-Password the error text returned reads: Error loading Partial View script (file: ~/Views/MacroPartials/ResetPassword.cshtml)

code is within a seperate solution and views and bin directories are copied accross. nuget package UmbracoCMS.Scaffolding is used.

Controller code:

public class ResetPasswordSurfaceController : SurfaceController {        
        [ChildActionOnly]
        [HttpGet]
        public ActionResult Reset(string token, string email) {
             // Validation Code Omited             
             var user = Membership.GetUser(username);
             return PartialView("Reset", new ResetPasswordSurfaceModel { UserID =     user.ProviderUserKey.AsInt() });
        }

        [HttpPost]
        public ActionResult PostReset(ResetPasswordSurfaceModel model) {
            if (ModelState.IsValid) { 
                 //Password reset code omited                 
                  return RedirectToCurrentUmbracoPage();
             }
            //works but only partial view content is rendered
            // return PartialView("Reset",model);         
            return CurrentUmbracoPage();
        }
    }

View - ~\Views\ResetPasswordSurface\Reset.cshtml:

@model UmbracoExt.Models.ResetPasswordSurfaceModel
@using (Html.BeginUmbracoForm("PostReset", "ResetPasswordSurface")) {
      @Html.EditorForModel() 
    <input type="submit" value="Submit" />
}

Macro Partial View - ~\Views\MacroPartials\ResetPassword.cshtml:

@inherits Umbraco.Web.Macros.PartialViewMacroPage       
@Html.Action("Reset", "ResetPasswordSurface")

Any help is appreciated.

Edit:

Removing the [HttpGet] attribute from the Reset Action has revealed that after the PostReset action is called the Reset action is also called.

Renaming PostReset to Reset and re-adding the httpget attribute to the original Reset Action results in the post action being called twice. the second time it is called causes the exception: Can only use UmbracoPageResult in the context of an Http POST when using a SurfaceController form

I have reverted the changes so i'm back at Reset ([HttpGet]) being called after the PostReset action.

So the problem still stands. How can i get around this issue? I need to return the result from the PostReset Action.

like image 289
X-Dev Avatar asked May 30 '13 03:05

X-Dev


2 Answers

This is how I solved this problem:

  1. I created extension method for model:

    public static class ExtensionMethods
    {
       public static void MapModel<T>(this WebViewPage<T> page) where T : class
       {
          var models = page.ViewContext.TempData.Where(item => item.Value is T);
    
          if (models.Any())
          {
             page.ViewData.Model = (T)models.First().Value;
             page.ViewContext.TempData.Remove(models.First().Key);
          }
       }
    }
    
  2. Controller code:

    [HttpPost]
    public ActionResult Index(MyModel model)
    {
        TempData.Add("MyModel", model);
        return RedirectToCurrentUmbracoPage();
    } 
    
  3. Partial view code:

     @using UmbracoTest.Extension
     @using UmbracoTest.Models
     @model MyModel
     @{
         this.MapModel<MyModel>();
      } 
    
     @using (Html.BeginUmbracoForm("Index", "Home", FormMethod.Post))
     { 
          <div>
            @Html.TextBox("Text", Model.Text )
          </div>
    
         <input type="submit" name="submit" value="Submit" />
     }
    
like image 88
milos Avatar answered Nov 15 '22 20:11

milos


The Answers were given to me here

All credit goes to Shannon Deminick

The post action does not return anything for the response (that bit was new to me). After the post when the Reset action is run the second time, since the modelstate is maintained, by passing a newly instantiated model, this model will inherit the model state of the model processed in the POST action (PostReset).

During the second time the Reset action was called, the validation logic meant it never gets to the point where it returns the partial view.

i temporarily bypassed the validation logic and sure enough the model validation messages were displayed.

like image 40
X-Dev Avatar answered Nov 15 '22 20:11

X-Dev