如何在Umbraco 7.5.8中将自定义模型发布到控制器?

时间:2017-01-28 18:51:24

标签: asp.net-mvc forms post model umbraco

我在CMS内容树中有一个文档类型,模板和一个页面,用于联系页面。文档类型没有CMS数据属性,因为它不需要任何属性。我将Models Builder用于其他页面没有问题,但是对于这个页面,我在我的MVC项目中创建了自己的自定义模型。

我已经阅读了我能找到的每个教程,并查看了每个论坛帖子并在Umbraco论坛和Stackoverflow上发布,对于我的生活,我无法弄清楚我做错了什么。模型名称和命名空间与自动生成的模型构建器1不冲突。

我的理解是发布表单,SurfaceController是要走的路 - RenderController更适合呈现内容。所以我的控制器扩展了SurfaceController。使用Umbraco.BeginUmbracoForm(等)

我已经尝试了SurfaceController和RenderController的每个组合与UmbracoTemplatePage,UmbracoViewPage以及改变我的模型的每种方式,以扩展RenderModel和IPublishedContent来测试每个。在尝试使用RenderController时,我已使用RenderModel参数覆盖默认的Index方法,以使用renderModel参数创建模型的实例。

通常我得到的错误是“无法将源类型Umbraco.Web.Models.RenderModel绑定到模型类型xxx”。有时我尝试过的组合允许Get成功,然后在Post上给出这个错误。

我甚至尝试从CMS中删除页面并使用标准的MVC控制器和路由 - 这允许我显示页面,甚至在我的视图上使用标准的Html.BeginForm,我在尝试时出错发布表单(尽管控制器中的代码中有一个断点),它也声明它“无法将源类型Umbraco.Web.Models.RenderModel绑定到模型类型xxx”

这不是那么困难。我准备在这个阶段将笔记本电脑扔出窗外。

我做错了什么????或者至少没有看到我的代码,任何人都可以告诉我这是假设的要做什么?如何将自定义模型表单发布到Umbraco 7.5控制器,而不需要CMS发布的内容属性?

目前,我的视图看起来像这样:

@inherits UmbracoViewPage<Models.Contact>
... 
using (Html.BeginUmbracoForm<ContactController>("Contact", FormMethod.Post

我的控制器看起来像这样:

public class ContactController : SurfaceController
{
    public ActionResult Contact()
    {
        return View("~/Views/Contact.cshtml");
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Contact(Contact contactForm)
    {
        ...
    }

我的模型看起来像这样:

public class Contact : RenderModel
{
    public Contact() : base(UmbracoContext.Current.PublishedContentRequest.PublishedContent, UmbracoContext.Current.PublishedContentRequest.Culture)
    {

    }

    public Contact(IPublishedContent content) : base(content, CultureInfo.CurrentUICulture) 
    {

    }

    [Display(Name = "First Name", Prompt = "First Name")]
    public string FirstName { get; set; }

...

更新:如果我将模型用于模型构建器自动创建的CMS页面,则Get和Post工作正常。但是,当我自定义模型时(即我在〜/ App_Data / Models中放置了同名的部分类并在Developer选项卡上重新生成模型),我发布的模型中的自定义属性始终为null。

我可以从请求表单变量中手动填充这些变量,但这似乎是错误和混乱的。这是怎么回事?

public class ContactPageController : SurfaceController
{
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Contact(ContactPage contactForm)
    {
        try
        {
            contactForm.FirstName = Request.Form["FirstName"];
            contactForm.LastName = Request.Form["LastName"];
            contactForm.EmailAddress = Request.Form["EmailAddress"];
            contactForm.Telephone = Request.Form["Telephone"];
            contactForm.Message = Request.Form["Message"];

            var captchaIsValid = ReCaptcha.Validate(ConfigurationManager.AppSettings["ReCaptcha:SecretKey"]);

            if (ModelState.IsValid && captchaIsValid)
            {
                // Do what you need
                TempData["EmailSent"] = true;

                return RedirectToCurrentUmbracoPage();
            }

            if (!captchaIsValid)
            {
                ModelState.AddModelError("ReCaptchaError", "Captcha validation failed - Please try again.");
            }

            return RedirectToCurrentUmbracoPage();
        }
        catch (Exception ex)
        {
            LogHelper.Error(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType, null, ex);
            return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
        }
    }

更多信息:罗伯特第一次接近,谢谢你。我尝试过使用PartialViews和ChildActions的一种方法,但显然我没有正确地做到这一点。我是否正确地说这个方法需要的原因(即为什么你不能将自定义属性添加到主视图所绑定的模型中)是因为我使用的是模型生成器?

因此,我收到的奇怪错误之一是两个想要代表联系页面的类,另一个关于它期望字典中的一种类型(ContactPage)但接收另一个(联系人) - 即使我已经做了在视图或控制器中没有引用ContactPage。这对我来说,ModelsBuilder在幕后的app启动时为模型添加了文档类型的映射?这也许是为什么你最好采用这种方法让ModelsBuilder做它的事情,并以这种方式用局部视图构建你自己的模型?

我发现这个主题的文档质量确实很差。不确定好的东西是否闭门造车,即需要付费的Umbraco会员资格?对于一个所谓的开源系统,对我来说感觉有点阴暗。

当你知道怎么做时很容易!!

1 个答案:

答案 0 :(得分:4)

根据您的情况,SurfaceController是您猜测的最有可能的候选人,但请将该控制器中的操作视为应用于部分视图,而不是页面使用的完整视图。

不要尝试使用ModelsBuilder ContactPage模型,而是创建自己的模型(原始的Contact模型) - 将其视为数据传输对象,如果你这样做的话需要以任何理由将任何属性应用回ContactPage模型。

我发现SurfaceController在以下条件下获得了最大的成功:

  1. 页面模板不会从用于表单的模型继承;它直接从标准的Umbraco PublishedContentModel或ModelsBuilder生成的模型继承。
  2. 为SurfaceController中定义的操作实现部分视图 - 此视图继承自示例中的Umbraco.Web.Mvc.UmbracoViewPage<Contact>
  3. 部分视图使用BeginUmbracoForm<ContactController>,将POST操作指定为其中一个参数(取决于您使用的是哪个签名)
  4. 您不需要使用Request.Form这样填充任何模型属性。

    例如,我的一个项目中的代码如下所示:

    SurfaceController

    public class FormsController : SurfaceController
    {
        [ChildActionOnly]
        public ActionResult ContactUs()
        {
            return PartialView(new ContactForm ());
        }
    
        [HttpPost]
        public async Task<ActionResult> HandleContactUs(ContactForm model)
        {
            if (ModelState.IsValid)
            {
                if (!await model.SendMail(Umbraco)) // Do something with the model.
                {
    
                }
            }
    
            return RedirectToCurrentUmbracoPage(); // Send us back to the page our partial view is on
        }
    
    }
    

    部分视图:

    @inherits Umbraco.Web.Mvc.UmbracoViewPage<ContactForm>
    @using Digitalsmith.ReCaptcha
    @using (Html.BeginUmbracoForm<FormsController>("HandleContactUs"))
    {
        ...
    }
    

    联系页面模板:

    @inherits Umbraco.Web.Mvc.UmbracoTemplatePage<ContactPage>
    @{
        Layout = "_Layout.cshtml";
    }
    @Html.Action("ContactUs", "Forms")