HTTP GET使用Umbraco MVC Surface Controller从外部数据库返回自定义模型

时间:2013-07-10 01:05:53

标签: asp.net-mvc-4 umbraco

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

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

我的Html.BeginUmbracoForm看起来像这样

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

我基本上有一个场景,我想从Umbraco外部的外部数据库(Umbraco数据库外部)中检索一些记录,并将自定义视图模型中的结果返回给我的Umbraco前端视图。一旦我的控制器和操作方法被设置为从SurfaceController继承并随后编译并提交搜索,我得到的404资源无法找到所请求的URL指定的位置:/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错误。

  

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

下面是HTML BeginForm的片段

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

我觉得我正在与Umbraco路线作战,让我的控制器将自定义模型返回到剃刀文件。我用Google搜索了很多,试图找出如何进行基本搜索,将自定义模型返回到我的Umbraco前端视图,直到我尝试创建自定义路线但这对我来说也不起作用。

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

  

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

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

是否有很好的资源材料我可以在umbraco控制器,路径和管道上阅读更多信息。

我希望这种情况对你有意义。如果您有任何疑问,请告诉我。我需要理解这个概念,继续我的项目,我确实有一个截止日期。

2 个答案:

答案 0 :(得分:1)

关于此问题存在很多问题,寻找权威方法的最佳位置是Umbraco MVC documentation

但是,您会发现,如果您使用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控制器实现的需求并且非常简单。

答案 1 :(得分: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-applicatio

以下是我的代码片段:

 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方法。我会进一步尝试的东西。

希望这有帮助!