1

我目前正在开发一个 Umbraco MVC 4 项目版本 6.0.5。该项目目前使用 Vega.USiteBuilder 在后台基于具有映射属性的强类型类构建适当的文档类型。因此,我所有的剃须刀文件都继承自 UmbracoTemplatePageBase

我遇到了一个路障,试图从剃刀文件中调用 HTTP GET。例如,具有多个字段的搜索表单要提交给控制器操作方法,使用 SurfaceController 使用 Html.BeginUmbracoForm。

我的 Html.BeginUmbracoForm 看起来像这样

@using (Html.BeginUmbracoForm("FindTyres", "TyreSearch"))
{
 // Couple of filter fields
}

我基本上有一个场景,我想从 Umbraco 外部的外部数据库(Umbraco 数据库外部)检索一些记录,并将自定义视图模型中的结果返回到我的 Umbraco 前端视图。一旦我的控制器和操作方法设置为从 SurfaceController 继承,然后编译它并提交搜索,我会在请求的 url 指定的位置找到 404 资源:/umbraco.RenderMVC。

这是我的代码片段:

public ActionResult FindTyres(string maker, string years, string models, string vehicles)
        {
            var tyreBdl = new Wheels.BDL.TyreBDL();
            List<Tyre> tyres = tyreBdl.GetAllTyres();

            tyres = tyres.Where(t => string.Equals(t.Maker, maker, StringComparison.OrdinalIgnoreCase)
                                     && string.Equals(t.Year, years, StringComparison.OrdinalIgnoreCase)
                                     && string.Equals(t.Model, models, StringComparison.OrdinalIgnoreCase)
                                     && string.Equals(t.Version, vehicles, StringComparison.OrdinalIgnoreCase)).ToList();

            var tyreSearchViewModel = new TyreSearchViewModel
            {
                Tyres = tyres
            };

            ViewBag.TyreSearchViewModel = tyreSearchViewModel;

            return CurrentUmbracoPage();
        }

然后我求助于使用标准 MVC,Html.BeginForm(唯一的区别)。重复上述步骤并提交搜索,我收到以下 YSOD 错误。

使用 SurfaceController 表单时,只能在 Http POST 的上下文中使用 UmbracoPageResult

下面是 HTML BeginForm 的片段

@using (Html.BeginForm("FindTyres", "TyreSearch"))
{
 // Couple of filter fields
}

我觉得我正在与 Umbraco 路线作斗争,以使我的控制器将自定义模型返回到剃刀文件。我用谷歌搜索了很多,试图弄清楚如何进行基本搜索以将自定义模型返回到我的 Umbraco 前端视图,直到我尝试创建自定义路线但这对我也不起作用。

我的控制器是否需要从特殊的 umbraco 控制器类继承才能返回自定义模型?我基本上喜欢调用 HTTP GET 请求(这是必须的),以便我的条件搜索字段正确反映在 url 的查询字符串中。例如,在点击搜索按钮时,我必须在地址浏览器栏中看到示例 url

http://[域名]/selecttyres.aspx/TyresSearch/FindTyresMake=ASIA&Years=1994&Models=ROCSTA&Vehicles=261

因此,我不能使用 Surface Controller,因为它将在 HTTP Post 的上下文中运行。

有没有我可以阅读更多关于 umbraco 控制器、路由和管道的好的资源材料。

我希望这个场景对你有意义。如果您有任何问题,请告诉我。我需要理解这个概念才能从这里继续我的项目,而且我确实有一个截止日期。

4

2 回答 2

1

关于这个有很多问题,寻找权威方法的最佳位置是Umbraco MVC 文档

但是,是的,您会发现,如果使用,Html.BeginUmbracoForm(...)您将被迫HttpPost采取行动。使用这种功能(搜索表单),我通常使用 GET 方法手动构建表单,并让它向特定节点 URL 提交查询字符​​串。

<form action="@Model.Content.Url"> ... </form>

在该页面上,我包含一个@Html.Action("SearchResults", "TyresSearch")其本身具有映射到查询字符串中的键的模型:

[ChildAction]
public ActionResult(TyreSearchModel model){

    // Find results
    TyreSearchResultModel results = new Wheels.BDL.TyreBDL().GetAllTyres();

    // Filter results based on submitted model
    ...

    // Return results
    return results;
}

结果视图只需要有一个模型TyreSearchResultModel(或任何您选择的模型)。

这种方法绕过了对 Umbraco 控制器实施的需求,并且非常简单。

于 2013-07-11T10:56:09.837 回答
1

我设法通过路由劫持找到了我的解决方案,这使我能够将自定义视图模型返回到我的视图并使用 HTTP GET。它对我来说效果很好。

Digby,您的解决方案看起来很合理,但我没有尝试过。如果我的页面上确实有一个小部件,我肯定会尝试使用您的方法。

这是详细信息。我基本上通过创建从 RenderMvcController 派生的控制器来覆盖 Umbraco 默认 MVC 路由。简而言之,您通过实现从 RenderMvcController 派生的控制器并在给定文档类型名称后重命名控制器名称来实现路由劫持。推荐阅读 Umbraco 参考资料 ( http://our.umbraco.org/documentation/Reference/Mvc/custom-controllers ) 这也是一篇很棒的文章 ( http://www.ben-morris.com/using -umbraco-6-to-create-an-asp-net-mvc-4-web-application )

这是我的代码片段:

 public class ProductTyreSelectorController : Umbraco.Web.Mvc.RenderMvcController
    {
        public override ActionResult Index(RenderModel model)
        {
            var productTyreSelectorViewModel = new ProductTyreSelectorViewModel(model);

            var maker = Request.QueryString["Make"];
            var years = Request.QueryString["Years"];
            var models = Request.QueryString["Models"];
            var autoIdStr = Request.QueryString["Vehicles"];

            var width = Request.QueryString["Widths"];
            var aspectRatio = Request.QueryString["AspectRatio"];
            var rims = Request.QueryString["Rims"];

            var tyrePlusBdl = new TPWheelBDL.TyrePlusBDL();              
            List<Tyre> tyres = tyrePlusBdl.GetAllTyres();

            if (Request.QueryString.Count == 0)
            {
                return CurrentTemplate(productTyreSelectorViewModel);
            }

            if (!string.IsNullOrEmpty(maker) && !string.IsNullOrEmpty(years) && !string.IsNullOrEmpty(models) &&
                !string.IsNullOrEmpty(autoIdStr))
            {
                int autoId;
                int.TryParse(autoIdStr, out autoId);

                tyres = tyres.Where(t => string.Equals(t.Maker, maker, StringComparison.OrdinalIgnoreCase) &&
                                         string.Equals(t.Year, years, StringComparison.OrdinalIgnoreCase) &&
                                         string.Equals(t.Model, models, StringComparison.OrdinalIgnoreCase) &&
                                         t.AutoID == autoId)
                             .ToList();

                productTyreSelectorViewModel.Tyres = tyres;
            } 
            else if (!string.IsNullOrEmpty(width) && !string.IsNullOrEmpty(aspectRatio) && !string.IsNullOrEmpty(rims))
            {
                tyres = tyres.Where(t => string.Equals(t.Aspect, aspectRatio, StringComparison.OrdinalIgnoreCase) &&
                                         string.Equals(t.Rim, rims, StringComparison.OrdinalIgnoreCase)).ToList();

                productTyreSelectorViewModel.Tyres = tyres;
            }




            var template = ControllerContext.RouteData.Values["action"].ToString();

            //return an empty content result if the template doesn't physically 
            //exist on the file system
            if (!EnsurePhsyicalViewExists(template))
            {
                return Content("Could not find physical view template.");
            }

            return CurrentTemplate(productTyreSelectorViewModel);
        }
    }

请注意,我的 ProductTyreSelectorViewModel 必须从 RenderModel 继承才能正常工作,并且我的文档类型称为 ProductTyreSelector。这样,当我的模型与操作结果 CurrentTemplate 一起返回时,页面的 Umbraco 上下文将被保留,并且我的页面再次被适当地呈现。这样,我所有的查询字符串都将显示我想要的所有搜索/过滤字段。

这是我的 ProductTyreSelectorViewModel 类的片段:

 public class ProductTyreSelectorViewModel : RenderModel
    {
        public ProductTyreSelectorViewModel(RenderModel model)
            : base(model.Content, model.CurrentCulture)
        {
            Tyres = new List<Tyre>();
        }

        public ProductTyreSelectorViewModel(IPublishedContent content, CultureInfo culture)
            : base(content, culture)
        {
        }

        public ProductTyreSelectorViewModel(IPublishedContent content)
            : base(content)
        {
        }

        public IList<Tyre> Tyres { get; set; }
    }

这种方法可能适用于给定页面上的一到两个 HTTP GET 表单。如果一个页面中有多个表单,那么一个好的解决方案可能是使用 ChildAction 方法。我会进一步试验的东西。

希望这可以帮助!

于 2013-07-14T23:36:55.813 回答