Customizing Sitefinity SearchResults - displaying Product thumbnails
I found an article in the blogs that allowed customization of the search results to show Product thumbnails:
www.sitefinity.com/.../customizing-sitefinity-searchresults---displaying-product-thumbnails
I have been trying to get this functionality into our search results as it would be very useful, however I seem to have missed something as I receive this error message once the site has been rebuilt and a search submitted:
Exception Details: System.ArgumentException: There is no field with the specified name.
Source Error:
Line 34: var productItem = catalogManager.GetProduct(myitem.GetValue("OriginalContentId"));
Hello,
Could you please try the following sample instead.
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
using
System.Web.UI;
using
System.Web.UI.WebControls;
using
Telerik.Sitefinity.Ecommerce.Catalog.Model;
using
Telerik.Sitefinity.Modules.Ecommerce.Catalog;
using
Telerik.Sitefinity.Services.Search.Data;
using
Telerik.Sitefinity.Utilities.TypeConverters;
namespace
SitefinityWebApp.Custom_Templates
public
partial
class
SearchResultsProducts : System.Web.UI.UserControl
protected
void
Page_Load(
object
sender, EventArgs e)
this
.resultsList.ItemDataBound += ResultsListItemDataBound;
this
.catalogManager = CatalogManager.GetManager();
void
ResultsListItemDataBound(
object
sender, RepeaterItemEventArgs e)
var myitem = e.Item.DataItem
as
IDocument;
if
(myitem !=
null
)
var type = myitem.GetValue(
"ContentType"
);
//You need to check for the type of the item you have gotten in your search results
//we're checking if the item is a Product:
if
(TypeResolutionService.ResolveType(type) ==
typeof
(Product))
var productItem = e.Item.DataItem
as
Product;
//get the control that will display the image
var thumbnailControl = e.Item.FindControl(
"productThumbnail"
)
as
Image;
//set the image URL
thumbnailControl.ImageUrl = productItem.PrimaryImageUrl;
private
CatalogManager catalogManager;
Thanks for your help, I tried your suggestion but received another error:
Server Error in '/' Application.
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[NullReferenceException: Object reference not set to an instance of an object.]
SitefinityWebApp.Custom_Templates.SearchResultsProducts.ResultsListItemDataBound(Object sender, RepeaterItemEventArgs e) in w:\iansystShopping\Templates\Search\SearchResultsProducts.ascx.cs:37
System.Web.UI.WebControls.Repeater.CreateItem(Int32 itemIndex, ListItemType itemType, Boolean dataBind, Object dataItem) +203
System.Web.UI.WebControls.Repeater.CreateControlHierarchy(Boolean useDataSource) +626
System.Web.UI.WebControls.Repeater.OnDataBinding(EventArgs e) +166
System.Web.UI.Control.PreRenderRecursiveInternal() +112
System.Web.UI.Control.PreRenderRecursiveInternal() +221
System.Web.UI.Control.PreRenderRecursiveInternal() +221
System.Web.UI.Control.PreRenderRecursiveInternal() +221
System.Web.UI.Control.PreRenderRecursiveInternal() +221
System.Web.UI.Control.PreRenderRecursiveInternal() +221
System.Web.UI.Control.PreRenderRecursiveInternal() +221
System.Web.UI.Control.PreRenderRecursiveInternal() +221
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +4200
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.272
I'm afraid my knowledge of .NET is very limited, so any help would be gratefully received.
Justin
Hello Justin,
In Sitefinity we use Lucene search indexing engine, for our Search Module. Lucene operates with special document types, that store the basic information necessary for providing the indexing and searching functionality. By default the field name where the original Sitefinity content ID is stored inside each Lucene document varies depending on how the particular module has configured its inbound pipe.
The blog post contained a typo, so I have used the "OriginalContentId" name, whlist the correct field name, according to the unified concept that we have adopted is that all Content types will use the "OriginalItemId" field.
In the current Sitefinity version you're using this is also valid, so using the "OriginalItemId" is the correct approach.
When subscribing to the ResultsListItemDataBound event of your SearchResults widget template you're actually retrieving the Lucene documents that Sitefinity returns. The reason why we're returning this type of documents, and not the actual items is because a search keyword might return instances of several different content types, thus we have come up with a uniform type based on the Lucene document, which carried the necessary information for the search results, namely the title, link, and highlighter results.
The above explains why modifying the search results to display properties of a particular type is not as trivial. However the task is certainly possible. As we've elaborated in the blog post Patrick mentioned in his initial reply, each Lucene document you get on ResultsListItemDataBound will contain the "ContentType" field where you can obtain the correct information what kind of item you're dealing with.
Once you've resolved the type, you can then operate with this type's specific properties, however you first need to get the actual item (remember what you've been working with so far is the Lucene document, not the Sitefinity item). This is done by obtaining the item's ID, which as we've discussed above is stored in the "OriginalContentId" (for Content items) field of the Lucene document.
Once you've retrieved the ID, you can call the resolved type's manager and retrieve the actual item by this ID. Form then on operating with the item is just as with any item of that type - you can get its properties and use them depending on your specific use case scenario.
To summarize the above, the bare minimum you need is:
if
(TypeResolutionService.ResolveType(type) ==
typeof
(Product))
var ID =
new
Guid(myitem.GetValue(
"OriginalItemId"
));
var product = CatalogManager.GetManager().GetProduct(ID);
if
(product !=
null
)
//do something with the product here
Thank you for letting us know of the problems experienced with the sample on the blog post - we have updated the information there to reflect the changes in the product. You can find the updated blog post here.
Regards,
Boyan Barnev
the Telerik team