Sitecore ASP.NET - manage aliases per domain - sitecore

I have site running Sitecore 6.3. This site include some subsites (for example www.a.com & www.b.com). I want to ask: is it possible to create separate aliases for this sites (e.g. www.a.com/alias & www.b.com/alias should redirect to different pages). Now if create an alias for site www.a.com it will be also in www.b.com. Any ideas how to manage this?
Thnx.

This is possible. I have already made a Sitecore support ticket for this. I have also worked this out and for me their solution worked fine. (haven't implemented it on the live website yet, because we had no agreement on the costs yet). This is some sample code you might want to look at:
class MultiSiteAliasResolver : AliasResolver
{
public new void Process(HttpRequestArgs args)
{
Assert.ArgumentNotNull(args, "args");
if (!Settings.AliasesActive)
{
Tracer.Warning("Aliases are not active.");
}
else
{
Sitecore.Data.Database database = Sitecore.Context.Database;
if (database == null)
{
Tracer.Warning("There is no context database in AliasResover.");
}
Item aliasItem = getAliasItem(args);
if (aliasItem != null)
{
LinkField linkField = aliasItem.Fields["Linked item"];
if (linkField != null)
{
Item AliasLinkedTo = Sitecore.Context.Database.GetItem(linkField.TargetID);
if (AliasLinkedTo != null)
{
Sitecore.Context.Item = AliasLinkedTo;
}
}
else
{
base.Process(args);
}
}
}
}
/// <summary>
/// Gets the alias item.
/// </summary>
/// <param name="args">The args.</param>
/// <returns></returns>
private Item getAliasItem(HttpRequestArgs args)
{
string websitePath = Sitecore.Context.Site.RootPath.ToLower();
if (args.LocalPath.Length > 1)
{
Item aliasItem = Sitecore.Context.Database.GetItem(websitePath + "/settings/aliassen/" + args.LocalPath);
if (aliasItem != null)
{
return aliasItem;
}
}
return null;
}
}
This class could be inserted in the web.config in place of the AliasResolver. For example:
<processor type="CommandTemplates.Classes.MultiSiteAliasResolver, CommandTemplates" />
I hope this will work for you, good luck!
update: In my example I have a folder under each website node "/settings/aliassen/", that's the location I want the users to set alliases. By the way, also notice that when you change the AliasResolver like this the window that the standard Sitecore Alias button triggers won't have the needed functionality anymore. I haven't had any time to dins a way to make that work, however you could always explain the content managers how to work with your new solution.

Related

Sitecore 8 search against index for pages giving a specific tag

I'm working on upgrading from 8.1 to 8.2 update 3. I understand that the search/indexing was changed and some code is obsolete or no longer works.
Unfortunately in one of our class projects there were some methods our sitecore partners had built for us that are no longer working due to obsolete code and now I need help updating that code. I've been able to narrow it down to just 2 files, with some simple code.
Here is the first set of code:
public partial class TagResults
{
/// <summary>
/// Searches against the Lucene index for pages given a specific tag
/// </summary>
/// <returns></returns>
public List<BasePage> GetPagesForTag(string Tag, int page, int pageSize, out int totalCount)
{
var tags = new List<BasePage>();
Index searchIndex = SearchManager.GetIndex(Constants.LuceneIndexes.Tags);
using (IndexSearchContext context = searchIndex.CreateSearchContext())
{
//The wildcard search allows us to pull back all items with the given tag
var query = new WildcardQuery(new Term(Constants.LuceneFields.Tags, Tag));
SearchHits hits = context.Search(query);
totalCount = hits.Length;
//Go through the results
SearchResultCollection results = hits.FetchResults(page * pageSize, pageSize);
foreach (SearchResult result in results)
{
var searchItem = result.GetObject<Item>();
Item currentDbItem = ItemUtility.GetItem(searchItem.ID);
//Store the item if it exists and is a descendant of the news listing
if (currentDbItem != null)
{
tags.Add(new BasePage(currentDbItem));
}
}
}
return tags.ToList();
}
public static bool IsItemCastable(Item sitecoreItem)
{
return sitecoreItem != null && !string.IsNullOrEmpty(sitecoreItem[FieldIds.IsTagResultsComponent]);
}
}
I think I have some of this changed correctly:
ISearchIndex searchIndex = ContentSearchManager.GetIndex(Constants.LuceneIndexes.tags);
using (IProviderSearchContext context = searchIndex.CreateSearchContent())
But then I get stuck on
SearchHits hits = context.Search(query);
totalCount = hits.Length;
//Go through the results
SearchResultCollection results = hits.FetchResults(page * pageSize, pageSize);
foreach (SearchResult result in results)
Now I'm asking a lot but I am learning. If someone could help me correct this, I would be really appreciative. I've been doing a lot of searching to try to figure out how to correct this but I feel like I'm missing something and I just need some help.
Thank you in advance.

Sitecore workflow approval state query

I have created workflow in my sitecore project and on final state ( Approval ) I just want auto publish to a particular database.
So where should I do the changes to point to database.
Thanks
In order to perform automatic publishing, your final state should contain a workflow action, that does the job for you. You may take a look on Sample Workflow (that comes by default with Sitecore) - Approved state. It contains child item Auto Publish, that has two fields.
Type string:
Sitecore.Workflows.Simple.PublishAction, Sitecore.Kernel
sets the class that in fact does publishing. You may inherit from that class and implement your own behavior, supply extra parameters etc. I would advise you to take dotPeek or Reflector and look-up this class implementation so that you may adjust your own code.
Parameters:
deep=0
..stands for publishing child items recursively.
Update: Lets take a look on decompiled class from Sample Workflow Auto Publish action:
public class PublishAction
{
public void Process(WorkflowPipelineArgs args)
{
Item dataItem = args.DataItem;
Item innerItem = args.ProcessorItem.InnerItem;
Database[] targets = this.GetTargets(dataItem);
PublishManager.PublishItem(dataItem, targets, new Language[1]
{
dataItem.Language
}, (this.GetDeep(innerItem) ? 1 : 0) != 0, 0 != 0);
}
private bool GetDeep(Item actionItem)
{
return actionItem["deep"] == "1" || WebUtil.ParseUrlParameters(actionItem["parameters"])["deep"] == "1";
}
private Database[] GetTargets(Item item)
{
using (new SecurityDisabler())
{
Item obj = item.Database.Items["/sitecore/system/publishing targets"];
if (obj != null)
{
ArrayList arrayList = new ArrayList();
foreach (BaseItem baseItem in obj.Children)
{
string name = baseItem["Target database"];
if (name.Length > 0)
{
Database database = Factory.GetDatabase(name, false);
if (database != null)
arrayList.Add((object)database);
else
Log.Warn("Unknown database in PublishAction: " + name, (object)this);
}
}
return arrayList.ToArray(typeof(Database)) as Database[];
}
}
return new Database[0];
}
}
GetTargets() method from above default example does publishing to all targets that are specified under /sitecore/system/publishing targets path. As I mentioned above, you may create your own class with your own implementation and reference that from workflow action definition item.
You can look into Sample workflow's Auto publish action. But in general you can create a Workflow Action with type: Sitecore.Workflows.Simple.PublishAction, Sitecore.Kernel and set parameters as deep=1&related=1&targets=somedb,web&alllanguages=1

Custom Data Source on Rendering Items

I'm having a Sitecore 8 MVC solution, and I have to extend the behavior of Data Source. It's pretty similar to what other people have done with queryable datasources before (such as http://www.cognifide.com/blogs/sitecore/reduce-multisite-chaos-with-sitecore-queries/ etc), but I've hooked into the <mvc.getXmlBasedLayoutDefinition> pipeline instead. It works fine and my custom data sources are resolved as they are entered in the layouts field on an item or on standard values.
But, when the custom data source is specified as a default data source on a rendering item, things becomes a bit trickier. I could solve it through the same pipeline, but that solution didn't look very nice. It means I'd have to load each rendering that hasn't a data source specified in the layout, and do the processing and resolve it from there. There must be a more natural way of doing this.
Does anyone know where to put such implementation logic for the default data source? (The <resolveRenderingDatasource> pipeline looked promising, but didn't execute in this scenario)
From what I understand, you may want to extend XmlBasedRenderingParser class. Here are the steps that should do the trick:
Create a new file App_Config\include\Sitecore.Mvc.Custom.config:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<initialize>
<processor
patch:after="processor[#type='Sitecore.Mvc.Pipelines.Loader.InitializeRoutes, Sitecore.Mvc']"
type="My.Assembly.Namespace.RegisterCustomXmlBasedRenderingParser, My.Assembly"/>
</initialize>
</pipelines>
</sitecore>
</configuration>
Create CustomXmlBasedRenderingParser class:
using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Mvc.Extensions;
using Sitecore.Mvc.Presentation;
namespace My.Assembly.Namespace
{
public class CustomXmlBasedRenderingParser : XmlBasedRenderingParser
{
protected override void AddRenderingItemProperties(Rendering rendering)
{
RenderingItem renderingItem = rendering.RenderingItem;
if (renderingItem != null && !rendering.DataSource.ContainsText())
{
rendering.DataSource = ResolveRenderingItemDataSource(renderingItem);
}
base.AddRenderingItemProperties(rendering);
}
private static string ResolveRenderingItemDataSource(RenderingItem renderingItem)
{
string dataSource = string.Empty;
if (renderingItem.DataSource != null && renderingItem.DataSource.StartsWith("query:"))
{
string query = renderingItem.DataSource.Substring("query:".Length);
Item contextItem = Context.Item;
Item queryItem = contextItem.Axes.SelectSingleItem(query);
if (queryItem != null)
{
dataSource = queryItem.Paths.FullPath;
}
}
return dataSource;
}
}
}
Create RegisterCustomXmlBasedRenderingParser class:
using Sitecore.Mvc.Configuration;
using Sitecore.Mvc.Presentation;
using Sitecore.Pipelines;
namespace My.Assembly.Namespace
{
public class RegisterCustomXmlBasedRenderingParser
{
public virtual void Process(PipelineArgs args)
{
MvcSettings.RegisterObject<XmlBasedRenderingParser>(() => new CustomXmlBasedRenderingParser());
}
}
}
What is more, if you want your code to be executed for DataSource defined on both Rendering and Presentation Details, you should be able to use the code below:
using System.Xml.Linq;
using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Mvc.Presentation;
namespace My.Assembly.Namespace
{
public class CustomXmlBasedRenderingParser : XmlBasedRenderingParser
{
public override Rendering Parse(XElement node, bool parseChildNodes)
{
Rendering rendering = base.Parse(node, parseChildNodes);
ResolveRenderingItemDataSource(rendering);
return rendering;
}
private static void ResolveRenderingItemDataSource(Rendering rendering)
{
if (rendering.DataSource != null && rendering.DataSource.StartsWith("query:"))
{
string query = rendering.DataSource.Substring("query:".Length);
Item contextItem = Context.Item;
Item queryItem = contextItem.Axes.SelectSingleItem(query);
if (queryItem != null)
{
rendering.DataSource = queryItem.Paths.FullPath;
}
}
}
}
}
Please remember that this code is not tested properly and may not work out of the box in your environment. Anyway I hope it will give you at least a good indication where to start.

Scopes not created from a template cannot have FilterParameters Error

I am trying to build on the "WebSharingAppDemo-SqlProviderEndToEnd" msdn sample application to build out a custom MSF implementation. As part of that I added parameterized filters to the provisioning. I have been referencing http://jtabadero.wordpress.com/2010/09/02/sync-framework-provisioning/ for some idea of how to do this. Now that I have that in place, when I re-initialize the "peer1" database and try to provision it initially I now get an error:
Scopes not created from a template cannot have FilterParameters.
Parameter '#my_param_name' was found on Table '[my_table_name]'.
Please ensure that no FilterParameters are being defined on a scope
that is not created from a template.
The only guess I have as to what a "template" is, is the provisioning templates that the Sync Toolkit's tools can work with, but I don't think that applies in the scenario I'm working with.
I have been unable to find anything that would indicate what I should do to fix this. So how can I get past this error but still provision my database with parameterized filters?
The below code is what I'm using to build the filtering into the provisioning (SqlSyncScopeProvisioning) object.
private void AddFiltersToProvisioning(IEnumerable<TableInfo> tables)
{
IEnumerable<FilterColumn> filters = this.GetFilterColumnInfo();
foreach (TableInfo tblInfo in tables)
{
this.AddFiltersForTable(tblInfo, filters);
}
}
private void AddFiltersForTable(TableInfo tblInfo, IEnumerable<FilterColumn> filters)
{
IEnumerable<FilterColumn> tblFilters;
tblFilters = filters.Where(x => x.FilterLevelID == tblInfo.FilterLevelID);
if (tblFilters != null && tblFilters.Count() > 0)
{
var tblDef = this.GetTableColumns(tblInfo.TableName);
StringBuilder filterClause = new StringBuilder();
foreach (FilterColumn column in tblFilters)
{
this.AddColumnFilter(tblDef, column.ColumnName, filterClause);
}
this.Provisioning.Tables[tblInfo.TableName].FilterClause = filterClause.ToString();
}
}
private void AddColumnFilter(IEnumerable<TableColumnInfo> tblDef, string columnName, StringBuilder filterClause)
{
TableColumnInfo columnInfo;
columnInfo = tblDef.FirstOrDefault(x => x.ColumnName.Equals(columnName, StringComparison.CurrentCultureIgnoreCase));
if (columnInfo != null)
{
this.FlagColumnForFiltering(columnInfo.TableName, columnInfo.ColumnName);
this.BuildFilterClause(filterClause, columnInfo.ColumnName);
this.AddParamter(columnInfo);
}
}
private void FlagColumnForFiltering(string tableName, string columnName)
{
this.Provisioning.Tables[tableName].AddFilterColumn(columnName);
}
private void BuildFilterClause(StringBuilder filterClause, string columnName)
{
if (filterClause.Length > 0)
{
filterClause.Append(" AND ");
}
filterClause.AppendFormat("[base].[{0}] = #{0}", columnName);
}
private void AddParamter(TableColumnInfo columnInfo)
{
SqlParameter parameter = new SqlParameter("#" + columnInfo.ColumnName, columnInfo.GetSqlDataType());
if (columnInfo.DataTypeLength > 0)
{
parameter.Size = columnInfo.DataTypeLength;
}
this.Provisioning.Tables[columnInfo.TableName].FilterParameters.Add(parameter);
}
i guess the error is self-explanatory.
the FilterParameters can only be set if the scope inherits from a filter template. you cannot set the FilterParameters for a normal scope, only FilterClause.
Using parameter-based filters is a two step process: Defining the filter/scope template and creating a scope based on a template.
I suggest you re-read the blog entry again and jump to the section Parameter-based Filters.

Retrieve List Items from a different Site Collection in SharePoint 2010

I am having issues with retrieving list items from a different site collection. I don't have issues when trying to recieve list items from within my current site collection. For example, http://myintranet.com/Departments/IT works. But http://myintranet.com/sites/Departments/IT returns an error.
if (!String.IsNullOrEmpty(SiteName) && !String.IsNullOrEmpty(SPContext.Current.Web.Url))
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite intranetSite = new SPSite(SPContext.Current.Web.Url))
{
using (SPWeb currentWeb = intranetSite.AllWebs["/sites/projects/Physics"])
{
SPList postList = currentWeb.Lists.TryGetList("Issues");
if (postList != null)
{
IssueList.DataSource = postList.Items.GetDataTable();
IssueList.DataBind();
}
}
}
});
}
I haven't used any different code to what I normally do when trying to recieve list items. The only difference is that this time I getting list items from another site collection.
Thanks for any help!
The problem is intranetSite.AllWebs. This will only get SPWeb objects under your current site collection.
You cannot infer another site collection directly from one site collection.
Even though /sites/projects LOOKS like chid site collection from /, it;s not. /sites is just a managed path. / and /sites/projects are at the same level of the site collection hierarchy.
What you need to do is to this:
if (!String.IsNullOrEmpty(SiteName) && !String.IsNullOrEmpty(SPContext.Current.Web.Url))
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPWeb currentWeb = new SPSite("http://server/sites/projects/Physics").OpenWeb())
{
SPList postList = currentWeb.Lists.TryGetList("Issues");
if (postList != null)
{
IssueList.DataSource = postList.Items.GetDataTable();
IssueList.DataBind();
}
}
});
}