如何在Umbraco中创建虚拟节点

时间:2016-02-26 08:49:40

标签: umbraco umbraco7

场合

我在Umbraco 7.3中创建了一个新部分,我可以在其中管理目录(创建,编辑和删除产品)。当我创建产品时,我将其所有信息存储在Umbraco数据库的表中。请注意我不在树中创建节点,我只是直接使用数据库。

问题

例如,当我创建"产品A"在该目录中,我自动生成并存储自定义URL" / products / product-A"在数据库中的表中。但是,该URL不存在,因为我没有物理节点:

  

找不到网页

     

没有umbraco文档与网址' / products / product-A'匹配。

由于我没有物理节点,我怎样才能创建" 虚拟节点并为该URL分配模板?

3 个答案:

答案 0 :(得分:12)

我最终可以解决这个问题。谢谢你的回答!

1。为我们的虚拟页面创建一个类

首先要创建一个继承自ProductVirtualPage的{​​{1}}类。最后一个类为PublishedContentWrapped实现提供了一个抽象基类,它包装和扩展了另一个IPubslihedContent。我们将使用属性 Product 从Razor视图中获取IPublishedContent并进行渲染。

Product

2。根据{{​​1}}

创建我们的处理程序

在树中我们需要创建一个引用节点,在我的例子中它具有id 3286.当调用public class ProductVirtualPage : PublishedContentWrapped { private readonly Product _product; public ProductVirtualPage(IPublishedContent content, Product product ) : base(content) { if (product.Name == null) throw new ArgumentNullException("productName"); _product = product; } public Product Product { get { return _product; } } } 方法时,我们将它传递给UmbracoVirtualNodeRouteHandler方法。

ProductVirtualPage(nodeReference, product)

3。注册我们的自定义路线

我们需要使用FindContent()添加自定义路由,并将其绑定到提供public class ProductVirtualNodeRouteHandler : UmbracoVirtualNodeRouteHandler { private ProductService _productService; protected override IPublishedContent FindContent(RequestContext requestContext, UmbracoContext umbracoContext) { // Get the real Umbraco IPublishedContent instance as a reference point var nodeReference = new UmbracoHelper(umbracoContext).TypedContent(3286); //Get the product Id from the URL (http://example.com/Products/product/57) var productId = umbracoContext.HttpContext.Request.Url.Segments[3]; // Create an instance for the ProductService _productService = new ProductService(new ProductRepository(), new SiteRepository()); // Get the product from the database var product = _productService.GetById(Convert.ToInt32(productId)); // Get the virtual product return new ProductVirtualPage(nodeReference, product); } } 的{​​{1}}方法。

MapUmbracoRoute

4。创建控制器

控制器只返回视图,通过我们的ApplicationStarted

ApplicationEventHandler

5。视图

public class ContentServiceEventsController : ApplicationEventHandler
{

    protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication,
        ApplicationContext applicationContext)
    {
        // Add a route for the Products
        RouteTable.Routes.MapUmbracoRoute(
            "ProductPage",
            "Products/Product/{id}/",
            new
            {
                controller = "Product",
                action = "GetProduct"
            },
            new ProductVirtualNodeRouteHandler());
    }
}

答案 1 :(得分:2)

听起来你不需要你的产品网址由Umbraco处理。

您需要在RouteConfig.cs文件中添加自定义路由,例如

routes.MapRoute(
  name: "Products",
  url: "Products/{id}",
  defaults: new { controller = "Products", action = "Product", id = UrlParameter.Optional }
);

然后创建一个ProductsController

public class ProductsController : Controller
{
    public ActionResult Product(int id)
    {
        // Retrieve product from database
        // Return view
    }

如果您需要访问UmbracoContext,这里有一个很好的例子: http://shazwazza.com/post/Custom-MVC-routing-in-Umbraco

答案 2 :(得分:0)

从你的Gist,你需要创建VirtualProductNode吗?你能否返回Umbraco页面(nodeReference),然后使用该页面(模板/控制器)来处理产品数据?

protected override IPublishedContent FindContent(RequestContext requestContext, UmbracoContext umbracoContext)
{
    // Get the real Umbraco IPublishedContent instance as a reference point
    var nodeReference = new UmbracoHelper(umbracoContext).TypedContent(3286);  

     contentRequest.PublishedContent = nodeReference;

     return contentRequest.PublishedContent != null;
}

我们执行类似于存储在“媒体”部分中的pdf文档的列表页面。 pdf文档组织在映射到虚拟URL结构的文件夹中。 “内容”部分没有页面。

(我们不希望编辑上传所有pdf文档,然后必须进入内容部分,创建页面并再次选择pdf - 不必要的额外工作)

有一个页面定义了该部分,其模板将根据网址显示正确的pdf。模板使用url在“媒体”部分中找到相应的文件夹,并列出pdf文件。

public class ProductsContentFinder : IContentFinder
{
    public bool TryFindContent(PublishedContentRequest contentRequest)
    {
        if (contentRequest != null)
        {
            // url: /store/products/product-name
            var path = contentRequest.Uri.GetAbsolutePathDecoded();
            var parts = path.Split(new[] { '/' }, System.StringSplitOptions.RemoveEmptyEntries);
            if (parts.Length > 1)
            {
                var level1 = string.Concat('/', string.Join("/", parts.Take(2)), '/');
                var node = contentRequest.RoutingContext.UmbracoContext.ContentCache.GetByRoute(level1);
                 //find product page
                 var products = node.AncestorOrSelf("Products");

                 if (products != null)
                 {
                     contentRequest.PublishedContent = products;
                 }
             }
         }

         return contentRequest.PublishedContent != null;
     }
 }