I have created a form that I would like to make into a 2 step form. I have followed this tutorial: https://umbraco.com/blog/creating-multi-step-forms-using-a-surfacecontroller/ and Have the form showing, and the data driven drop-downs are working. When I click next I get an error. I should note, before I started making the form 2 steps the form is working and posting data without issue.
It just seems like is ignoring the action to add to the step index. I should also note a am new to MVC.
the error is:
Resource Cannot be Found .... Requested URL /umbraco/RenderMvc
Here is the Model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Lurie.Models
{
public class Spec2Model
{
public Spec2Model()
{
StepIndex = 0;
ProductInfoStep = new ProductInfoStep();
RequestInfoStep = new RequestInfoStep();
}
public bool Previous { get; set; }
public bool Next { get; set; }
public int StepIndex { get; set; }
public ProductInfoStep ProductInfoStep { get; set; }
public RequestInfoStep RequestInfoStep { get; set; }
}
public class ProductInfoStep
{
public int Id { get; set; }
public int Product { get; set; }//Creates Dropdown
public IEnumerable<SelectListItem> ListOfProducts { get; set; } // Creates options in Dropdown... see Surface Controller
[Required]
[Display(Name = "Thickness")]
public string Thickness { get; set; }
[Required]
[Display(Name = "Exterior Finish")]
public int ExteriorFinish { get; set; }//Creates Dropdown
public IEnumerable<SelectListItem> ListOfExteriorFinishes { get; set; } // Creates options in Dropdown... see Surface Controller
[Required]
[Display(Name = "Exterior Substrate")]
public int ExteriorSubstrate { get; set; }//Creates Dropdown
public IEnumerable<SelectListItem> ListOfExteriorSubstrates { get; set; }
[Required]
public int Core { get; set; }//Creates Dropdown
public IEnumerable<SelectListItem> ListOfCores { get; set; }
[Required]
[Display(Name = "Interior Substrate")]
public int InteriorSubstrate { get; set; }//Creates Dropdown
public IEnumerable<SelectListItem> ListOfInteriorSubstrates { get; set; }
[Required]
[Display(Name = "Interior Finish")]
public int InteriorFinish { get; set; }//Creates Dropdown
public IEnumerable<SelectListItem> ListOfInteriorFinishes { get; set; }
}
public class RequestInfoStep
{
///Quote Portion
public bool RequestSample { get; set; }
public bool RequestQuote { get; set; }
[Required]
[Display(Name = "Name")]
public string Name { get; set; }
[Required]
[Display(Name = "Address")]
public string Address { get; set; }
[Required]
[Display(Name = "City")]
public string City { get; set; }
[Required]
[Display(Name = "State")]
public string State { get; set; }
[Required]
[Display(Name = "Zip Code")]
[MaxLength(5, ErrorMessage = "Zip code can not exceed 5 Characters")]
[MinLength(5, ErrorMessage = "Zip code must be 5 Characters")]
public string Zip { get; set; }
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[Display(Name = "Phone")]
[RegularExpression("^[0-9]*$", ErrorMessage = "Must be numeric")]
[MaxLength(10, ErrorMessage = "Must Not Exceed 10 Char")]
[MinLength(9, ErrorMessage = "Must Not at least 9 Char")]
[DisplayFormat(DataFormatString = "{0:###-###-####}")]
public string Phone { get; set; }
[Required]
[Display(Name = "Project Name")]
public string ProjectName { get; set; }
[Required]
[Display(Name = "Project Description")]
public string ProjectDescription { get; set; }
[Required]
[Display(Name = "Quantity")]
public string Qty1 { get; set; }
[Required]
[Display(Name = "Size")]
public string Size1 { get; set; }
[Required]
[Display(Name = "Quantity")]
public string Qty2 { get; set; }
[Required]
[Display(Name = "Size")]
public string Size2 { get; set; }
[Required]
[Display(Name = "Quantity")]
public string Qty3 { get; set; }
[Required]
[Display(Name = "Size")]
public string Size3 { get; set; }
[Display(Name = "Additional Sizes")]
public string AdditionalSizes { get; set; }
}
}
The Controller:
using Lurie.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Umbraco.Web.Mvc;
using Umbraco.Web;
using System.Text;
using System.Net.Mail;
using umbraco.NodeFactory;
namespace Lurie.Controllers
{
public class Spec2SurfaceController : SurfaceController
{
[ChildActionOnly]
public ActionResult ShowForm()// links controller to template/macro
{
Spec2Model myModel = new Spec2Model();
// This will generate dropdown values
var AllComponents = umbraco.uQuery.GetNodeByUrl("/panels/products/panel-components");
var Components = AllComponents.ChildrenAsList.Where(n => n.NodeTypeAlias == "panelComponent");
var AllProducts = umbraco.uQuery.GetNodeByUrl("/panels/products");
var Products = AllProducts.ChildrenAsList.Where(n => n.NodeTypeAlias == "panelProduct");
// Product Dropdown
List<SelectListItem> ListOfProducts = new List<SelectListItem>();
foreach (var node in Products)
{
ListOfProducts.Add(new SelectListItem
{
Text = node.Name,
Value = node.Id.ToString() // This allows us to lookup a node for further content creation
});
}
myModel.ProductInfoStep.ListOfProducts = ListOfProducts;
// EX Finish Dropdown
List<SelectListItem> ListOfExteriorFinishes = new List<SelectListItem>();
foreach (var node in Components)
{
if (node.GetProperty("componentType").Value.Contains("Exterior Finish")) {
ListOfExteriorFinishes.Add(new SelectListItem
{
Text = node.Name,
Value = node.Id.ToString() // This allows us to lookup a node for further content creation
});
}
}
myModel.ProductInfoStep.ListOfExteriorFinishes = ListOfExteriorFinishes;
// EX Finish Substrate
List<SelectListItem> ListOfExteriorSubstrates = new List<SelectListItem>();
foreach (var node in Components)
{
if (node.GetProperty("componentType").Value.Contains("Exterior Substrate"))
{
ListOfExteriorSubstrates.Add(new SelectListItem
{
Text = node.Name,
Value = node.Id.ToString() // This allows us to lookup a node for further content creation
});
}
}
myModel.ProductInfoStep.ListOfExteriorSubstrates = ListOfExteriorSubstrates;
// Core Dropdown
List<SelectListItem> ListOfCores = new List<SelectListItem>();
foreach (var node in Components)
{
if (node.GetProperty("componentType").Value.Contains("Core"))
{
ListOfCores.Add(new SelectListItem
{
Text = node.Name,
Value = node.Id.ToString() // This allows us to lookup a node for further content creation
});
}
}
myModel.ProductInfoStep.ListOfCores = ListOfCores;
// Internal Substrate Dropdown
List<SelectListItem> ListOfInteriorSubstrates = new List<SelectListItem>();
foreach (var node in Components)
{
if (node.GetProperty("componentType").Value.Contains("Interior Substrate"))
{
ListOfInteriorSubstrates.Add(new SelectListItem
{
Text = node.Name,
Value = node.Id.ToString() // This allows us to lookup a node for further content creation
});
}
}
myModel.ProductInfoStep.ListOfInteriorSubstrates = ListOfInteriorSubstrates;
// Internal Finish Dropdown
List<SelectListItem> ListOfInteriorFinishes = new List<SelectListItem>();
foreach (var node in Components)
{
if (node.GetProperty("componentType").Value.Contains("Interior Finish"))
{
ListOfInteriorFinishes.Add(new SelectListItem
{
Text = node.Name,
Value = node.Id.ToString() // This allows us to lookup a node for further content creation
});
}
}
myModel.ProductInfoStep.ListOfInteriorFinishes = ListOfInteriorFinishes;
// End Dropdown Values
myModel = myModel ?? new Spec2Model();
if (myModel.Previous)
myModel.StepIndex--;
if (myModel.Next)
myModel.StepIndex++;
return PartialView("Spec2Form", myModel); // Links to Partial View
}
[HttpPost]
public ActionResult HandelFormPost(Spec2Model myModel) //Links functions to the form in the partial view...BeginUmbracoForm
{
//ignore validation or saving data when going backwards
if (myModel.Previous)
return CurrentUmbracoPage();
var validationStep = string.Empty;
switch (myModel.StepIndex)
{
case 0:
validationStep = "ProductInfoStep";
break;
case 1:
validationStep = "RequestInfoStep";
break;
}
//remove all errors except for the current step
foreach (var key in ModelState.Keys.Where(k => k.StartsWith(string.Format("{0}.", validationStep)) == false))
{
ModelState[key].Errors.Clear();
}
if (!ModelState.IsValid)
{
return RedirectToCurrentUmbracoPage();
}
if (myModel.StepIndex == 1) // If on final step save data
{
// This will post submittion to Umbraco Database
ProductInfoStep Product = new ProductInfoStep();
RequestInfoStep Request = new RequestInfoStep();
var newRequest = Services.ContentService.CreateContent(Request.Name + "-" + DateTime.Now, CurrentPage.Id, "specBuildFormula");
var myService = ApplicationContext.Services.DataTypeService;
int ProductValue = Product.Product;
var ProductNode = new Node(ProductValue);
int ExteriorFinishValue = Product.ExteriorFinish;
var ExteriorFinishNode = new Node(ExteriorFinishValue);
int ExteriorSubstrateValue = Product.ExteriorSubstrate;
var ExteriorSubstrateNode = new Node(ExteriorSubstrateValue);
int CoreValue = Product.Core;
var CoreNode = new Node(CoreValue);
int InteriorFinishValue = Product.InteriorFinish;
var InteriorFinishNode = new Node(InteriorFinishValue);
int InteriorSubstrateValue = Product.InteriorSubstrate;
var InteriorSubstrateNode = new Node(InteriorSubstrateValue);
newRequest.SetValue("product", ProductNode.Name);
newRequest.SetValue("thickness", Product.Thickness);
newRequest.SetValue("exteriorFinish", ExteriorFinishNode.Name);
newRequest.SetValue("exteriorSubstrate", ExteriorSubstrateNode.Name);
newRequest.SetValue("core", CoreNode.Name);
newRequest.SetValue("interiorSubstrate", InteriorSubstrateNode.Name);
newRequest.SetValue("interiorFinish", InteriorFinishNode.Name);
newRequest.SetValue("requestingSample", Request.RequestSample);
newRequest.SetValue("requestingQuote", Request.RequestQuote);
newRequest.SetValue("QName", Request.Name);
newRequest.SetValue("QEmail", Request.Email);
newRequest.SetValue("QPhone", Request.Phone);
newRequest.SetValue("Qaddress", Request.Address);
newRequest.SetValue("QCity", Request.City);
newRequest.SetValue("QState", Request.State);
newRequest.SetValue("QZip", Request.Zip);
newRequest.SetValue("QProjectName", Request.ProjectName);
newRequest.SetValue("QProjectDescription", Request.ProjectDescription);
newRequest.SetValue("Qty1", Request.Qty1);
newRequest.SetValue("Size1", Request.Size1);
newRequest.SetValue("Qty2", Request.Qty2);
newRequest.SetValue("Size2", Request.Size2);
newRequest.SetValue("Qty3", Request.Qty3);
newRequest.SetValue("Size3", Request.Size3);
newRequest.SetValue("QAdditionalSizes", Request.AdditionalSizes);
newRequest.SetValue("umbracoNaviHide", true);
Services.ContentService.SaveAndPublishWithStatus(newRequest);
//This will compose and send email
var sb = new StringBuilder();
sb.AppendFormat("<div style='width:100%;height:100%;padding-top:40px;padding-bottom:40px;margin:0px;background-color:#555;color:#222;font-family:Arial,sans-serif'>");
sb.AppendFormat("<div style='max-width:650px;padding:30px;margin:auto;background-color:#fff'><table style='width:100%;'><tr><td>");
sb.AppendFormat("<img src='home.UrlAbsolute/assets/LurieGlass_Dark.png' styles='width:100%'/>");
if (Request.RequestSample == true & Request.RequestQuote == false)
{
sb.AppendFormat("<h1> Sample Request From Website </h1>");
}
if (Request.RequestQuote == true & Request.RequestSample == false)
{
sb.AppendFormat("<h1> Quote Request From Website </h1>");
}
if (Request.RequestQuote == true & Request.RequestSample == true)
{
sb.AppendFormat("<h1> Sample & Quote Request From Website </h1>");
}
sb.AppendFormat("<hr style='Margin-top:30px;Margin-bottom:30px;'>");
sb.AppendFormat("<p><b>Name:</b> {0}</p>", Request.Name);
sb.AppendFormat("<p><b>Email:</b> {0}</p>", Request.Email);
sb.AppendFormat("<p><b>Phone:</b> {0}</p>", Request.Phone);
sb.AppendFormat("<p><b>Address</b><br>{0}<br>{1}, {2} {3}</p>", Request.Address, Request.City, Request.State, Request.Zip);
sb.AppendFormat("<hr style='Margin-top:30px;Margin-bottom:30px;'>");
sb.AppendFormat("<p><b>Product Selection:</b> {0}</p>", ProductNode.Name);
sb.AppendFormat("<table width='400px' border='1' style='border-collapse:collapse;border-color:#999;text-align:center;'><tr><th>Component</th><th>Selection</th></tr>");
sb.AppendFormat("<tr><td><b>Exterior Finish</b></td><td>{0}</td></tr>", ExteriorFinishNode.Name);
sb.AppendFormat("<tr><td><b>Exterior Subtrate</td><td>{0}</td></tr>", ExteriorSubstrateNode.Name);
sb.AppendFormat("<tr><td><b>Core</td><td>{0}</td></tr>", CoreNode.Name);
sb.AppendFormat("<tr><td><b>Interior Substrate</td><td>{0}</td></tr>", InteriorSubstrateNode.Name);
sb.AppendFormat("<tr><td><b>Interior Finish</td><td>{0}</td></tr>", InteriorFinishNode.Name);
sb.AppendFormat("</table>");
sb.AppendFormat("<hr style='Margin-top:30px;Margin-bottom:30px;'>");
sb.AppendFormat("<p><b>Project Name:</b> {0}</p>", Request.ProjectName);
sb.AppendFormat("<p><b>Project Description:</b><br> {0}</p>", Request.ProjectDescription);
sb.AppendFormat("<P><b>Quantities and Sizes</b></P><table width='400px' border='1' style='border-collapse:collapse; border-color: #999;text-align: center;'><tr><th>QTY</th><th>SIZE</th></tr>");
sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Request.Qty1, Request.Size1);
sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Request.Qty2, Request.Size2);
sb.AppendFormat("<tr><td>{0}</td><td>{1}</td></tr>", Request.Qty3, Request.Size3);
sb.AppendFormat("</table>");
sb.AppendFormat("<p><b>Additional Sizes and quantities:</b><br> {0}</p>", Request.AdditionalSizes);
sb.AppendFormat("</td></tr></table></div>");
sb.AppendFormat("</div>");
SmtpClient smtp = new SmtpClient("xxx.xxx.com", 587);
smtp.Credentials = new System.Net.NetworkCredential("[email protected]", "xxxxx");
smtp.EnableSsl = true;
MailMessage message = new MailMessage();
message.To.Add(new MailAddress("[email protected]"));
if (Request.RequestSample == true & Request.RequestQuote == false)
{
message.Subject = "Sample Request From Website";
}
else if (Request.RequestQuote == true & Request.RequestSample == false)
{
message.Subject = "Quote Request From Website";
}
else if (Request.RequestQuote == true & Request.RequestSample == true)
{
message.Subject = "Sample & Quote Request From Website";
}
else{
message.Subject = "Sample/Quote Request from Website";
}
message.From = new MailAddress(Request.Email);
message.Body = sb.ToString();
message.IsBodyHtml = true;
try
{
smtp.Send(message);
}
catch (SmtpException)
{
TempData["Failed"] = true;
return CurrentUmbracoPage();
}
TempData["Success"] = true;
return RedirectToCurrentUmbracoPage();
}
return RedirectToCurrentUmbracoPage();
}
}
}
Without going too much into your code, the first thing that stands out at me is that your SurfaceController's first action is decorated with [ChildActionOnly], which will make it a private call to MVC. Try remove that and see if that works?
If you look at the source for the rendered form, and specifically, the attributes for the form tag, what is the url of the action attribute?
Also, when I develop surfacecontrollers, I usually use something like PostMan to see if the surface controller itself is working. Since you are using this in the context of another page, it might be worth trying to eliminate the 'host' page from the equation.
Calling your surface controller directly in PostMan with all the form field values as parameters, can isolate the problem better.
The url of the action attribute is the url of the form's page. The Demo I followed, has the form stepping through a switch instead of actually moving to a new page. So the fact the the url is the same as the page that we are starting on seems correct.
I will have to look into Postman. Thanks for your help.
the error is: Resource Cannot be Found .... Requested URL
/umbraco/RenderMv
This tells me that the url cannot be matched for your POST action, which means the url is incorrect, or the paramters can't be bound matching what that controller action is expecting (so MVC cannot find a suitable route).
Usually, umbraco surface controller urls are in the format:
/umbraco/surface/{controller}/{action}
Need help stepping multi-step form
Hello All,
I have created a form that I would like to make into a 2 step form. I have followed this tutorial: https://umbraco.com/blog/creating-multi-step-forms-using-a-surfacecontroller/ and Have the form showing, and the data driven drop-downs are working. When I click next I get an error. I should note, before I started making the form 2 steps the form is working and posting data without issue.
It just seems like is ignoring the action to add to the step index. I should also note a am new to MVC.
the error is: Resource Cannot be Found .... Requested URL /umbraco/RenderMvc
Here is the Model:
The Controller:
And The Partial View
And here is the code to bring it into the template
Hi Sam,
Without going too much into your code, the first thing that stands out at me is that your SurfaceController's first action is decorated with [ChildActionOnly], which will make it a private call to MVC. Try remove that and see if that works?
Louis
Thanks for the reply Louis. I removed the [ChildActionOnly], but it had no affect. I still get the same error.
Sam,
If you look at the source for the rendered form, and specifically, the attributes for the form tag, what is the url of the action attribute?
Also, when I develop surfacecontrollers, I usually use something like PostMan to see if the surface controller itself is working. Since you are using this in the context of another page, it might be worth trying to eliminate the 'host' page from the equation.
Calling your surface controller directly in PostMan with all the form field values as parameters, can isolate the problem better.
Louis
The url of the action attribute is the url of the form's page. The Demo I followed, has the form stepping through a switch instead of actually moving to a new page. So the fact the the url is the same as the page that we are starting on seems correct.
I will have to look into Postman. Thanks for your help.
Sam,
This tells me that the url cannot be matched for your POST action, which means the url is incorrect, or the paramters can't be bound matching what that controller action is expecting (so MVC cannot find a suitable route).
Usually, umbraco surface controller urls are in the format: /umbraco/surface/{controller}/{action}
Is this error a 404 status code?
Louis
is working on a reply...