another technical blog...technically

Wednesday, July 29, 2015

Strategy: catalog connection with managed metadata multivalue field

Everybody knows about SharePoint catalog connection... maybe

What if you have a pre-existing catalog connection and your customer asks you to switch from a single value field (generally ItemCategory) to a multivalue field?

In a ideal world you should quote this and say "don't do it, don't even think about it"

In a business world you'll say "Yes, why not?".
I tried to convert the single value field in a multivalue field... trust me... don't try this if you don't like strange side effects.

AS IS
This is the typical product catalog configuration:
  • A product catalog site which is used as backend website
  • Contents are crawled by search service application
  • Public sites connect to indexed catalog


Solution
To understand next steps, mind every link under categories navigation term is allowed.
Let's assume you have a term set like that
  • Category 1
    • Subcategory 11
    • Subcategory 12
  • Category 2 
    • Subcategory 21
The catalog connection automatically creates these category friendly urls:

http://site/category1
http://site/category1/subcategory11
http://site/category1/subcategory11
http://site/category2
http://site/category2/subcategory21

So let's assume i have a product named Test, which is tagged on ItemCategory with term "Subcategory 11", i'll go to URL http://site/category1/subcategory11/test .

But what if i tell you that links like these below will not repond with a 404?
http://site/category1/test
http://site/category1/subcategory12/test
http://site/category2/test
http://site/category2/subcategory21/test

This behaviour will be extremely useful for us.

Editing product catalog
Because you don't want to destroy catalog connection, you just have to add a TaxonomyFieldTypeMulti field to the product catalog item content type
1
2
3
4
5
6
7
8
9
10
11
12
<field displayname="MultivalueItemCategory" enforceuniquevalues="FALSE" group="Custom" id="{E7548D45-7EBF-4510-94E4-079ACFFD7BF6}" mult="TRUE" name="MultivalueItemCategory" required="FALSE" showfield="Term1033" sourceid="{d5f28009-1f31-45bf-8b91-5aef7dd33f07}" staticname="MultivalueItemCategory" type="TaxonomyFieldTypeMulti">
  <customization>
    <arrayofproperty>
   <property>
     <name>TextField</name>
     <value instance:type="types:string" xmlns:instance="http://www.w3.org/2001/XMLSchema-instance" xmlns:types="http://www.w3.org/2001/XMLSchema">{024FECDC-E8A7-4DAC-BEB1-E9C373708BE5}</value>
   </property>
    </arrayofproperty>
  </customization>
</field>
<field displayname="MultivalueItemCategory_0" group="Custom" hidden="TRUE" id="{024FECDC-E8A7-4DAC-BEB1-E9C373708BE5}" name="MultivalueItemCategoryTaxHTField0" required="FALSE" showinviewforms="FALSE" sourceid="{d5f28009-1f31-45bf-8b91-5aef7dd33f07}" staticname="MultivalueItemCategoryTaxHTField0" type="Note">
</field>
Link this new field to the term set you use to tag catalog items.
After that, you can create a event receiver in order to write the first  value entered in MultivalueItemCategory field in ItemCategory field (or the field you use for the catalog connection).
Create Content Search Web Part replacements
This is the most annoying part, we have to create a Web Part that we will use in category pages.
This web part does essentially three things:
  1. Recover the current navigation term
  2. Make a query searching che term related to the navigation term, in the MultivalueItemCategory we defined above
  3. Substitute Path values (catalog item friendly url) in order to make links relative to the current navigation term
  4. Show results
The core methods are
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
protected void Page_Load(object sender, EventArgs e)
{
 try
 {
  if (SPContext.Current.FormContext.FormMode == SPControlMode.Display)
  {
   TaxonomySession taxonomySession = new TaxonomySession(SPContext.Current.Site);
   Term term = null;
 
   SPSecurity.RunWithElevatedPrivileges(() =>
   {
    using (SPSite elevatedSite = new SPSite(SPContext.Current.Site.ID))
    {
     TaxonomySession elevatedTaxonomySession = new TaxonomySession(elevatedSite);
     term = TaxonomyNavigationContext.Current.NavigationTerm.GetTaxonomyTerm(elevatedTaxonomySession);
    }
   });
 
   CatalogConnectionManager catalogConnectionManager = new CatalogConnectionManager(SPContext.Current.Site);
   List<catalogconnectionsettings> catalogConnectionSettings = catalogConnectionManager.ConnectedPublishingCatalogs;
   this.catalogConnectionSettings = catalogConnectionSettings[0];
 
   this.RenderGeneric(term);
  }
 }
 catch (Exception ex)
 {
  // Do something
 }
}
 
 
private void RenderGeneric(Term term)
{
 try
 {
  ...
 
  this.productsTable = this.GetProducts_Generic(term, SPContext.Current.Site, null);
 
  ...
 }
 catch (Exception ex)
 {
  // Do something
 }
}
 
private DataTable GetProducts_Generic(Term term, SPSite currentSite)
{
 DataTable dt = null;
 string queryText = string.Empty;
 
 try
 {
  if (term != null)
  {
   queryText = string.Format(@"owstaxIdMultivalueItemCategory:""GPP|#{1}""", term.Id);
 
   List<string> selectManagedProperties = new List<string>() { ... };
   List<string> ascendingManagedProperties = new List<string>() { ... };
 
   if (!string.IsNullOrEmpty(queryText))
   {
    // Get product data table (in this case i use my library)
    dt = SearchQueryHelper.GetSearchQueryData(currentSite, queryText, selectManagedProperties, null, this.catalogConnectionSettings.ResultSourceId, false, ascendingManagedProperties, null, null);
   }
  }
 
  List<string> sourceUrls = this.GetUrls2SubstituteSource(TaxonomyNavigationContext.Current.NavigationTerm);
  string destUrl = this.GetUrl2SubstituteDestination(TaxonomyNavigationContext.Current.NavigationTerm);
  dt = this.RewritePaths(dt, sourceUrls, destUrl);
 }
 catch (Exception ex)
 {
  // Do something
 }
 
 return dt;
}
 
private DataTable RewritePaths(DataTable dataTable, List<string> sourceUrls, string destUrl)
{
 try
 {
  string path = string.Empty;
 
  foreach (DataRow dr in dataTable.Rows)
  {
   path = dr["Path"].ToString();
 
   Uri uri = new Uri(path);
   string friendlyUrl = uri.Segments[uri.Segments.Length - 1];
   string baseUrl = uri.OriginalString.Replace(uri.LocalPath, string.Empty);
   string rewrittenUrl = string.Format("{0}/{1}/{2}", baseUrl, destUrl, friendlyUrl);
 
   dr["Path"] = rewrittenUrl;
  }
 }
 catch (Exception ex)
 {
  // Do something
 }
 
 return dataTable;
}
 
private List<string> GetUrls2SubstituteSource(NavigationTerm navigationTerm)
{
 List<string> urls = new List<string>();
 
 try
 {
  List<navigationterm> navigationTerms = TaxonomyHelper.GetPinnedTerms(navigationTerm.TermSet);
 
  foreach (NavigationTerm nv in navigationTerms)
  {
   string relativeUrl = TaxonomyHelper.GetRelativeUrl(nv);
   urls.Add(relativeUrl);
  }
 }
 catch (Exception ex)
 {
  // Do something
 }
 
 return urls;
}
 
private string GetUrl2SubstituteDestination(NavigationTerm navigationTerm)
{
 string url = string.Empty;
 
 try
 {
  url = TaxonomyNavigationContext.Current.NavigationTerm.FriendlyUrlSegment.DefaultValue;
 }
 catch (Exception ex)
 {
  // Do something
 }
  
 return url;
}
About the single product page you can create a web part or a page layout, which has to contain methods similar to the previous web part.
This web part, must get the product using the navigation term and the friendly url segment and show the result.

Editing publishing site 
In pages document library, you have to create a category page (which contains the category CSWP replacement), and a product page (which contains the product CSWP replacement) and then edit target page settings for terms like this


And that's all folks.

written in: Milano, Italia

Related Posts:

0 commenti:

Post a Comment

Because of a lot of SPAM about courses, I need to moderate all comments here.
I ensure you that I will answer whenever possible (if you are not a spammer).

Me, myself and I

My Photo
I'm just another IT guy sharing his knowledge with all of you out there.
Wanna know more?