如何在 Umbraco 中创建虚拟节点
How to create a virtual node in Umbraco
情况
我在 Umbraco 7.3 中创建了一个新部分,我可以在其中管理目录(创建、编辑和删除产品)。当我创建一个产品时,我将其所有信息存储在 Umbraco 数据库的 table 中。请注意,我没有在树中创建节点,我只是直接使用数据库。
问题
例如,当我在该目录中创建 "Product A" 时,我会自动生成自定义 URL “/products/product-A” 并存储在数据库中的 table 中.但是,URL 不存在,因为我没有物理节点:
Page not found
No umbraco document matches the url '/products/product-A'.
由于我没有物理节点,我如何才能 "create" 一个 虚拟 节点并为该 URL 分配一个模板?
听起来您不需要 Umbraco 处理您的产品 URL。
您需要将自定义路由添加到您的 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
根据您的 Gist,您需要创建 VirtualProductNode 吗?您可以 return Umbraco 页面 (nodeReference) 然后使用该页面 (template/controller) 处理产品数据吗?
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 文档,然后必须进入内容部分,创建一个页面并再次 select pdf - 不必要的额外工作)
有一个页面定义了该部分,其模板将根据 url 显示正确的 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;
}
}
我最后能弄明白。谢谢您的回答!
1。为我们的虚拟页面创建一个class
首先是创建一个 class,即继承自 PublishedContentWrapped
的 ProductVirtualPage
。最后一个 class 为 IPubslihedContent
实现提供了一个抽象基础 class 来包装和扩展另一个 IPublishedContent
。我们将使用 属性 Product 从 Razor 视图中获取 Product
并进行渲染。
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;
}
}
}
2。基于 UmbracoVirtualNodeRouteHandler
创建我们的处理程序
在树中我们需要创建一个引用节点,在我的例子中它的 ID 为 3286。我们将在调用 FindContent()
方法时将其传递给 ProductVirtualPage(nodeReference, product)
方法。
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);
}
}
3。注册我们的自定义路线
我们需要使用 MapUmbracoRoute
添加自定义路由并将其绑定到提供 ApplicationEventHandler
.
的 ApplicationStarted
方法
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());
}
}
4。创建控制器
控制器只会 return 视图,传递我们的 RenderModel model
。
public class ProductController : RenderMvcController
{
public ActionResult GetProduct(RenderModel model, int id)
{
return View("Product", model);
}
}
5。景色
@{
Layout = "~/Views/Shared/_MasterLayout.cshtml";
var productModel = Model.Content.Product;
var product = productModel as Product;
}
<pre>
Product Info
---------------
Id: @product.Id
Name: @product.Name
</pre>
情况
我在 Umbraco 7.3 中创建了一个新部分,我可以在其中管理目录(创建、编辑和删除产品)。当我创建一个产品时,我将其所有信息存储在 Umbraco 数据库的 table 中。请注意,我没有在树中创建节点,我只是直接使用数据库。
问题
例如,当我在该目录中创建 "Product A" 时,我会自动生成自定义 URL “/products/product-A” 并存储在数据库中的 table 中.但是,URL 不存在,因为我没有物理节点:
Page not found
No umbraco document matches the url '/products/product-A'.
由于我没有物理节点,我如何才能 "create" 一个 虚拟 节点并为该 URL 分配一个模板?
听起来您不需要 Umbraco 处理您的产品 URL。
您需要将自定义路由添加到您的 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
根据您的 Gist,您需要创建 VirtualProductNode 吗?您可以 return Umbraco 页面 (nodeReference) 然后使用该页面 (template/controller) 处理产品数据吗?
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 文档,然后必须进入内容部分,创建一个页面并再次 select pdf - 不必要的额外工作)
有一个页面定义了该部分,其模板将根据 url 显示正确的 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;
}
}
我最后能弄明白。谢谢您的回答!
1。为我们的虚拟页面创建一个class
首先是创建一个 class,即继承自 PublishedContentWrapped
的 ProductVirtualPage
。最后一个 class 为 IPubslihedContent
实现提供了一个抽象基础 class 来包装和扩展另一个 IPublishedContent
。我们将使用 属性 Product 从 Razor 视图中获取 Product
并进行渲染。
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;
}
}
}
2。基于 UmbracoVirtualNodeRouteHandler
创建我们的处理程序
在树中我们需要创建一个引用节点,在我的例子中它的 ID 为 3286。我们将在调用 FindContent()
方法时将其传递给 ProductVirtualPage(nodeReference, product)
方法。
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);
}
}
3。注册我们的自定义路线
我们需要使用 MapUmbracoRoute
添加自定义路由并将其绑定到提供 ApplicationEventHandler
.
ApplicationStarted
方法
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());
}
}
4。创建控制器
控制器只会 return 视图,传递我们的 RenderModel model
。
public class ProductController : RenderMvcController
{
public ActionResult GetProduct(RenderModel model, int id)
{
return View("Product", model);
}
}
5。景色
@{
Layout = "~/Views/Shared/_MasterLayout.cshtml";
var productModel = Model.Content.Product;
var product = productModel as Product;
}
<pre>
Product Info
---------------
Id: @product.Id
Name: @product.Name
</pre>