Stumped on MVC XForm

Vote:
 

I have added propertyfor(x=>x.pageform) and the form displays as expected.  the issue i a running into is the current submission of the form.  the following is the error i am recieving.

Exception details:
InvalidOperationException: The RouteData must contain an item named 'action' with a non-empty string value.
Stack trace:

[InvalidOperationException: The RouteData must contain an item named 'action' with a non-empty string value.]
   at System.Web.Routing.RouteData.GetRequiredString(String valueName)
   at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1a.b__17()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1a.<>c__DisplayClass1c.b__19()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1a.<>c__DisplayClass1c.b__19()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1a.<>c__DisplayClass1c.b__19()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1a.<>c__DisplayClass1c.b__19()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult)
   at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
   at EPiServer.Web.Mvc.XForms.XFormActionBaseResult.InvokeAction(Controller controller, String actionName)
   at EPiServer.Web.Mvc.XForms.XFormFailedActionResult.ExecuteResult(ControllerContext context)
   at EPiServer.Web.Mvc.ActionControllerBase.HandleUnknownAction(String actionName)
   at System.Web.Mvc.Controller.<>c__DisplayClass1d.b__18(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass4.b__3(IAsyncResult ar)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
   at System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass4.b__3(IAsyncResult ar)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
   at System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult)
   at System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult)
   at System.Web.Mvc.MvcHandler.<>c__DisplayClass8.b__3(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass4.b__3(IAsyncResult ar)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
   at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
   at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

The RouteData must contain an item named 'action' with a non-empty string value

   What am i misssing.  Thanks in advance Ladies and Gents

#64533
Dec 28, 2012 15:23
Vote:
 

Just peeked a little in one of our EPiServer 7 MVC projects, and as far as I can see we have a couple of extra methods in our controller:

IContentRepository _dataFactory;

private readonly XFormPageUnknownActionHandler _xformHandler;

public ArticlePageController(IContentRepository dataFactory, XFormPageUnknownActionHandler xformHandler)
{
    _dataFactory = dataFactory;
    _xformHandler = xformHandler;
}

[AcceptVerbs(HttpVerbs.Post)]
public virtual ActionResult Success(ArticlePage currentPage, XFormPostedData xFormPostedData)
{
    return View("Index", new ArticlePageViewModel().InjectFrom(currentPage));
}

[AcceptVerbs(HttpVerbs.Post)]
public virtual ActionResult Failed(ArticlePage currentPage, XFormPostedData xFormPostedData)
{
    return View("Index", new ArticlePageViewModel().InjectFrom(currentPage));
}

        [AcceptVerbs(HttpVerbs.Post)]
        public virtual ActionResult DoSubmit(XFormPostedData xFormpostedData)
        {
            return _xformHandler.HandleAction(this);
        }

Not sure what the currentPage parameter is doing there though.. My guess is the method you're missing is the DoSubmit controller method. The InjectFrom is just some automapping stuff.

Hope this helps

Frederik

#64543
Dec 30, 2012 13:45
Vote:
 

Hey Fredrik,  I have added the two actions, but on my form submission, or propertyfor, are you passing any parameters into the helper,

@html.PropertyFor(x=>x.PageForm, new{xxxxx=xxxx} .  I am still getting the same result when trying to submit.  I am new to how xforms are now handled in episerver mvc.  Where do i map the propertyfor xform to use DoSubmit for my action result etc.  I am a bit unclear on this.  Thanks Fredrik.

#64545
Dec 30, 2012 20:35
Vote:
 

Hi Joshua

See if this helps:

@using EPiServer.XForms.Util
@model EPiServer.XForms.XForm

<section id="form">
    @Html.ValidationSummary()
    @Html.DisplayForModel(new { XFormParameters = new XFormParameters() { SuccessAction = "Success", FailedAction = "Failed" } })
</section>

Frederik   

#64546
Dec 30, 2012 21:29
Vote:
 

That did it.  thanks for you time and help on this Frederik.  Its much appreciated.

#64550
Dec 30, 2012 23:52
Vote:
 

Hi, how do I do the same for an XForm inside a block?

I have tried c/p Success, Failed and DoSubmit methods to my BlockController, however when I submit data, I get this page (404):

http://localhost:12347/XFormBlock/XFormPost?XFormId=9ac95421-bc25-41a5-b19c-3c6c79f04ad9&postAction=XFormPost&failedAction=Failed&successAction=Success

 

#65005
Jan 17, 2013 12:22
Vote:
 

@Marija

It is only possible to post to an instance of a page. If you look into the decompiled code for XForms, you'll see that it requires an instance of the current page at some point.

That does not mean it's not possible, you just need to post to the current page controller instead of the XFormBlock controller.

#65041
Jan 18, 2013 9:11
Vote:
 

Hi, thank you for your answer. I have realized that in the meantime.

However, when I put the code for Success, Failed and DoSubmit in, let's say EventPageController and just leave the View as Fredrik pointed out, my URL looks like this (and gives 404):

http://localhost:12347/XFormBlock/DoSubmit?XFormId=9ac95421-bc25-41a5-b19c-3c6c79f04ad9&postAction=DoSubmit&failedAction=Failed&successAction=Success

So, I suppose I should specify the controller on the view:

@Html.ValidationSummary()
@Html.DisplayForModel(new { XFormParameters = new XFormParameters() { SuccessAction = "Success", FailedAction = "Failed", PostAction = "DoSubmit", PostController = "EventPageController"} })

This gives me another 404:

http://localhost:12347/EventPageController/DoSubmit?XFormId=9ac95421-bc25-41a5-b19c-3c6c79f04ad9&postAction=DoSubmit&postController=EventPageController&failedAction=Failed&successAction=Success

What is supposed to be specified in PostController or maybe I am doing it completely wrong?

Thank you!

 

#65043
Jan 18, 2013 9:50
Vote:
 

Heres what I have in my controller (a base controller inherited by all page controllers):

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult XFormPost(XFormPostedData xFormpostedData)
{
	var formData = new XFormPageHelper().GetXFormData(thisxFormpostedData);

var
 result = XFormActionHelper.DoAction(formDataxFormpostedDatatrue); return this.RedirectToAction("Index"); }
#65051
Edited, Jan 18, 2013 11:35
Vote:
 

Hi, still no luck :(

When you Ctrl+Click on "Index"  take you? This is red (not existing) for me.

Is this how your BaseController looks like?

public class BaseController<T> : PageController<T> where T : PageData
    {
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult XFormPost(XFormPostedData xFormPostedData)
        {
            var formData = new XFormPageHelper().GetXFormData(this, xFormPostedData);

            var result = XFormActionHelper.DoAction(formData, xFormPostedData, true);

            return this.RedirectToAction("Index");
        }
    }   
#65062
Jan 18, 2013 14:10
Vote:
 

Does anyone have some insight on this?

I have moved with my other tasks, I still don't know how to deal with having XForm on a block working.

#65283
Jan 24, 2013 15:01
Vote:
 

Sorry for replying so late.

I've just written a blog post explaining how I did it for our project, please take a look if you're still looking for a solution.

http://www.eyecatch.no/blog/2013/01/using-xforms-and-mvc-in-an-episerver-7-block/

#65359
Edited, Jan 28, 2013 10:51
Vote:
 

Thx a lot!

#65369
Jan 28, 2013 11:07
Vote:
 

Nice article Azzlack!

#65376
Jan 28, 2013 14:06
Vote:
 

Hey... yeah, good article, however, has anyone worked out how to turn on the validation?

The HtmlHelper doesn't generate any validation, its also not checked on the server side and input items marked as must contain a value are posted without any errors.

Spent ages crawling through the SDK, any ideas?

#65580
Feb 01, 2013 15:38
Vote:
 

When you put a break point in Failed, does it hit it?


It should be that just returning a view model from Failed, displays the validation errors.

#65581
Feb 01, 2013 15:53
Vote:
 

I've tried that yes...  Both Success and Fail.  It still just runs Index.  I've double checked the parameters, they are all fine.  Its strange as the Css values you set for input fields also don't get rendered to the screen.

I've been looking through the SDK and tried loads of different methods to at least try and retrieve the Validation that was set for the fields, but can't find anything....   Oh well, i'll keep looking

#65582
Feb 01, 2013 16:05
Vote:
 

Yes, this has happened to me while trying out the code. If you are using an XForm on page (not on a block), I can send you my whole code to try it out. Let me know if you need it.

#65591
Feb 01, 2013 16:14
Vote:
 

That would be great if you could.....  it is on a Block, however, if it gets Validation working properly i'll definitely take a look and then see if I can work out where its going wrong....

Thanks!

#65593
Feb 01, 2013 16:22
Vote:
 

Controller:

public class TextPageController : MogulBaseController<TextPage>
    {
        private readonly XFormPageUnknownActionHandler _xformHandler;

        public TextPageController(XFormPageUnknownActionHandler xformHandler)
        {
            _xformHandler = xformHandler;
        }

        public ActionResult Index(TextPage currentPage)
        {
            var viewModel = new TextPageViewModel();
            Mapper.Map(currentPage, viewModel);

            return View(viewModel);
        }
        
        [AcceptVerbs(HttpVerbs.Post)]
        public virtual ActionResult Success(TextPage currentPage, XFormPostedData xFormPostedData)
        {
            var viewModel = new TextPageViewModel();
            Mapper.Map(currentPage, viewModel);

            viewModel.ShowThankYouView = true;
            viewModel.ThankYouForSubmittingFormText = LocalizationService.Current.GetString("/xform/thankyoutext");

            return View("Index", viewModel);
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public virtual ActionResult Failed(TextPage currentPage, XFormPostedData xFormPostedData)
        {
            var viewModel = new TextPageViewModel();
            Mapper.Map(currentPage, viewModel);

            viewModel.ShowThankYouView = false;

            return View("Index", viewModel);
        }

        /// <summary>
        /// Handles the XForm postback
        /// </summary>
        /// <param name="xFormpostedData">The posted xform data.</param>
        /// <returns>The current view.</returns>
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult XFormPost(XFormPostedData xFormpostedData)
        {
            return _xformHandler.HandleAction(this);
        }
    }

View:

@using EPiServer.Web.Mvc.Html
@using EPiServer.XForms.Util
@model Cornerstone.Web.Views.TextPage.TextPageViewModel

...
            @if (@Model.ShowThankYouView)
            {
                @Model.ThankYouForSubmittingFormText
            }
            else
            {
                @Html.ValidationSummary()
                @Html.PropertyFor(m => m.Form, new { XFormParameters = new XFormParameters() { SuccessAction = "Success", FailedAction = "Failed", PostAction = "XFormPost" } })
            }
...

View model has a property public XForm Form { get; set; }, and page type has:

        [Display(
            GroupName = SystemTabNames.Content,
            Order = 400
        )]
        public virtual XForm Form { get; set; }

   Please not that I do NOT have any code in the MogulBaseController. I didn't copy what Azzlack posted earlier 

Hope this helps!

  

#65596
Feb 01, 2013 16:28
Vote:
 

Thanks for that... i'll have a look and let you know how i can get on!

#65604
Feb 01, 2013 17:21
Vote:
 

I've come up with a solution that supports XForms in block types with the validation still fully working...

http://blog.nansen.com/2013/03/creating-xform-block-in-episerver-7-mvc.html

#66592
Edited, Mar 05, 2013 22:16
Vote:
 

Did anyone get Xform working in blocks with validation. I have followed instructions at Azzlack's blog but still no validation.

#78968
Dec 05, 2013 17:02
Vote:
 
#78974
Dec 05, 2013 20:18
Vote:
 

@Sayeed What exactly is not working? We are using the same code with success here.

#78994
Dec 06, 2013 9:44
Vote:
 

Here's my code:

Form Block View

@using EPiServer.XForms.Util
@using EPiServer.Web.Mvc.Html
@using EPiServer.Templates.Logicalis.Models.Blocks
@model XFormViewModel

<div class="section section--panel section--secondary event--form">
    <h2 @Html.EditAttributes(m => m.Title)>@Model.Title</h2>
    @Html.ValidationSummary()
    
    @using (Html.BeginXForm(Model.Form, new { action = Model.ActionUrl, @class = "form xform" }))
    {
        @Html.PropertyFor(x => x.Form)    
    }    
</div>

Form Block View Model

using EPiServer.XForms;

public class XFormViewModel
{
    public string Title { get; set; }
    public XForm Form { get; set; }
    public string ActionUrl { get; set; }
}

Form Block

[ContentType(GroupName = Global.GroupNames.Specialized, 
	GUID = "FA326346-4D4C-4E82-AFE8-C36279006179", 
	DisplayName = "Form Block", 
	Description = "Form Block")]
public class FormBlock : SiteBlockData
{
    [Display(GroupName = SystemTabNames.Content, Order = 1, Name = "Title")]
    [CultureSpecific]
    public virtual string Title { get; set; }

    [Display(GroupName = SystemTabNames.Content, Order = 2, Name = "The Form", Description = "Select a Form")]
    [CultureSpecific]
    public virtual XForm Form { get; set; }
}

Default Controller which inherits from BaseController class. The Default COntroller handles requests for pages that don't have their own controller.

public class DefaultPageController : PageControllerBase<SitePageData>
{
    public ViewResult Index(SitePageData currentPage)
    {
        if (currentPage == null)
        {
            currentPage = PageContext.Page as SitePageData;
        }

        var model = CreateModel(currentPage);
        return this.View(string.Format("~/Views/{0}/Index.cshtml", currentPage.GetOriginalType().Name), model);
    }

    private static IPageViewModel<SitePageData> CreateModel(SitePageData page)
    {
        var type = typeof(PageViewModel<>).MakeGenericType(page.GetOriginalType());
        return Activator.CreateInstance(type, page) as IPageViewModel<SitePageData>;
    }
}

Base controller is exactaly the same as in your post.

The problem I am having is that I am not getting validation messages on form postbacks in blocks. Forms on pages work fine.

#79007
Dec 06, 2013 10:25
Vote:
 

Ok. I got it partially working. I have removed the code from the Base Controller to the DefaultController. It now works for all pages that are using the DefaultController. However, for pages that use their own controller e.g. NewsController, it still doesn't work. I am getting this error:

Server Error in '/' Application.

The RouteData must contain an item named 'action' with a non-empty string value.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.InvalidOperationException: The RouteData must contain an item named 'action' with a non-empty string value.

Source Error: 

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace: 


[InvalidOperationException: The RouteData must contain an item named 'action' with a non-empty string value.]
   System.Web.Routing.RouteData.GetRequiredString(String valueName) +232
   System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) +91
   System.Web.Mvc.<>c__DisplayClass1a.<InvokeActionResultWithFilters>b__17() +33
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +613
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +613
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +613
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +613
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +613
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +263
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +676
   System.Web.Mvc.<>c__DisplayClass1a.<InvokeActionResultWithFilters>b__17() +33
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +613
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +613
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +613
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +613
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +613
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +263
   System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__22(IAsyncResult asyncResult) +240
   System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__18(IAsyncResult asyncResult) +28
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +15
   System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +63
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +15
   System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__3(IAsyncResult asyncResult) +42
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +15
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +1799
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +3300
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +1536

    

#79010
Dec 06, 2013 11:42
This thread is locked and should be used for reference only. Please use the Episerver CMS 7 and earlier versions forum to open new discussions.