
SharePoint (49)
Workaround for javascript Cross Domain calls through AirWatch Browser in SharePoint
Written by Luca CostanteIn the last period, This email address is being protected from spambots. You need JavaScript enabled to view it. and I are working hard with AirWarch environment (in special case AirWatch Browser) and our applications based on SharePoint 2013.
One of the most important (and dangerous) issue is related to the javascript Cross Domain (if you don't know what it's, I''m suggesting you to read this article).
We had a lot of applications that get data, manipulate it and forwarded to other applications from other applications. Unfortunately, all of these applications has their own URLs and a lot of them are in different domains.
We started to analyze the issue finding a workaround that is not impacting our infrastructure too much. Following, the description of the workaround:
- we created new URLs for the applications in cross domain area in order to have URLs in the form of subdomain. This is an example
- imagine to have 2 applications: A with URL http://tetris.contoso.com and application B with http://pacman.contoso.com. If from application A you try to call a WebService or another service via ajax (javascript), AirWach Browser will block it to avoid the issue of cross domain (for security reason)
- our idea (and the solution is):
- create for application B an additional URL like http://pacman.tetris.contoso.com.
- On IIS we added to the bindings of the web application the new URL
- checked if the application is adding to the response the header "Access-Control-Allow-Origin". We did not have it, so to have it, we created the Global.asax object and into the Global.asax.cs class we added the following code
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin" , "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
Magically, everything started to work fine. With this approach, we are now able to allow applications to communicate each other.
Anonymous: how to configure it and what you need to check if it stops to working
Written by Luca CostanteWorking with anonymous zone in SharePoint is every time very hard to work.
First of all you need to:
- enable it into the web application with a specific zone
- Navigate to SharePoint 2010 Central Administration -> Application management -> Manage web applications.
- Choose the web application you would like to configure and click on Authentication Providers
- Click on the zone that you would configure
- On the Edit Authentication screen choose the Enable anonymous access option and click on save.
- use the URL of the configured zone to enable the anonymous
- Our next step is to open your SharePoint site -> Site Actions -> Site Permissions
- Specify which parts of your web site you would like to enable anonymous access for and click on OK (Entire web site is suggested)
- Navigate to Galleries -> Master Pages and page layouts
- Click on the library tab
- Click on Library Permissions
- Click on Anonymous Access
- Specify the permission level of anonymous users. In our case we would like anonymous users to be able to view items.
- Navigate to Site Actions –> View All Site Content
- Click on Style Library and repeat the actions in steps 4 – 8.
- Now is the time to test. Close the browser and re-open it (is suggested to use a Chrome of Firefox browser for these test to not allow Internet Explorer to send automatically the credentials if configured). If we see the ” Sign In” button on the top of the screen that means our configuration is correct and we can access the site anonymously.
It worked for us for a long time but a particular day, it stopped to work. The users started to receive 401 error (access denied).
We started the analysis and we:
- checked the configuration in another web application and it worked
- checked the file web.config and it was correctly filled
- parsed GBs and GBs of logs to find out the issue
After long days we found out the issue: the reason was a user policy which denied access on the web application for one user account on all zones. After removing this policy from the zone providing the anonymous access eveything is working as expected.
I hope that this solution can help someone else :)
Hi,
if you're trying to remove a ContentDataBase following these steps
- Remove the ContentDataBase from the Central Administration
- Inside SQL, the DB is not removed. If you try to delete it (right click on the DB name and click on delete button) yuo will receive a SQL error (615 in my case)
and not works, try to execute the following SQL Commands, it works for me
Good morning,
I would describe a strange situation (never appeared before).
I was in a situation where in my web applications there was a series of wrong actions with backup of the ContentDB and site collection. The idea is to clean the situation making a Backup-SPSite of the site colleciton that I need, remove all site collection not used or that are wrong, create a new one and restore the backup.
All seems to proceed correctly until i should execute Restore-SPSite command. I press enter and:
"Restore-SPSite : No content databases are available for this operation but the site collection is scheduled for deletion in at least one content database. Either wait for the deletion operation to complete or create a content database, and then try the operation again. To create a content database, click "Content databases" on the Application Management page, select the Web application to use, and then click "Add a content database"."
After some searches, I found the solution:
- Get-SPDeletedSite (to view the list of the sitecollections that were not removed correctly)
- Remove-SPDeletedSite -Identity <GUID> (to remove the site collection listed with the previous command
- Get-SPDeletedSite (to check that everything is clean)
- Run Gradual Site Deletion Timer Job (waiting the ending)
- FINALLY: Restore with PS!
Remove duplicated results from Content Search Web Part
Written by Luca CostanteRecently, I faced a really thorny issue regarding the search engine of SharePoint 2013 . After moving some pages from into a folder, I've created a Content Search Web Part (CSWP) to display that pages. I don't know why but some search results are displayed as duplicate values.
An option to resolve the issue is to use the Search Results Web Part that is able to give matching results because the query builder gives a Remove Duplicates option in the Settings tab. Unfortunately, the CSWP does not give this option on its Settings tab. Moreover, the default settings for the CSWP is to trim the duplicated values. The setting is, however, actually available in the web part definition and to be sure of its configuration I've:
- exported the web parts
- found the string "TrimDuplicates". If the value is "true" it means that the CSWP should remove the duplicates, if "false" not (it’s the equivalent of the Remove Duplicates option in the Search Results web part)
So why are we still getting duplicates? Probably there is a bug on the CSWP. To understand better the problem, I found this blog where it is described the current scenario and there are more details.
At the end, to fix this issue through a workaround (worked for me), I've followed these steps:
- In the CSWP query builder, go to the Refiners tab
- Click the little “Show more” link at the bottom
- In the “Group By” dropdown, select “—Show all properties—“ and then select DocumentSignature
- Click on the "OK" button a save the page
You should now see the correct number of results with the CSWP.
SharePoint 2013 : Realize a multiple selection on File Types Refinement Panel
Written by Luca CostanteIn these days, me and This email address is being protected from spambots. You need JavaScript enabled to view it. had working on an easy requirement but that to realized it, we we thought too much.
What we need to realize it is a simple Item type refinement panel that works with a multiple selection, easy.
A first idea was to change the settings on the refinement from single selection to multiple selection. But it not produced what we expected:
- The label was changed from Type to extentions. Example: from Web Pages to html, etc.
- some items that were found they not had the respective item in the refinement panel and some associations were wrong: example the videos are grouped with the html filter, etc.
After some analysis phases, we were able to make these assumptions:
- a lot of items were crawled with the dispform.aspx, so they were grouped as html. They had another Managed Property (MP) "SecondaryFileExtention" that contained the correct file extention of the item
- Some items, for example the video, are managed from SharePoint with a particular Content Type (ContentTypeId=). These items appears in the search both FileType MP and SecondaryFileExtention MP empty
- to complete the work, the File Type filter need to group on:
- for some items on the FileType MP
- for some items on the SecondaryFileExtention MP
- for some items on the ContentType MP
- The logic of the refinement panel is not able to apply OR rules (written by himself by the respective refinement panel display template) on different Managed Properties.
At the end of a long week of tests, we had the solution:
- We created a new Managed Property with the name LC.ResultType that contains the follow crawled properties (all of the single MP)
- ows_ContentTypeId
- ows_FileType
- ows_File_x0020_Type
- After a full crawl to allow the Managed Property to be filled, we modified the OOB Multi Selection Display Template to point to our Custom Managed Property in each occurrences
- We creted the follow mapping of the item types, save and publish the new Display Template
Custom Multi selection Display Template example that use the custom Managed Property LC..ResultType:
<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:A29FA29F-C1488-11d1-1010-C2F400AA002">
<head>
<title>Multi-value</title>
<!--[if gte mso 9]><xml>
<mso:CustomDocumentProperties>
<mso:CompatibleManagedProperties msdt:dt="string"></mso:CompatibleManagedProperties>
<mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden>
<mso:CompatibleSearchDataTypes msdt:dt="string"></mso:CompatibleSearchDataTypes>
<mso:MasterPageDescription msdt:dt="string"></mso:MasterPageDescription>
<mso:ContentTypeId msdt:dt="string">0x0101002039C03B61C64EC4A04F5361F385106604</mso:ContentTypeId>
<mso:TargetControlType msdt:dt="string">;#Refinement;#</mso:TargetControlType>
<mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
<mso:CrawlerXSLFile msdt:dt="string"></mso:CrawlerXSLFile>
<mso:HtmlDesignPreviewUrl msdt:dt="string"></mso:HtmlDesignPreviewUrl>
<mso:HtmlDesignConversionSucceeded msdt:dt="string">True</mso:HtmlDesignConversionSucceeded>
<mso:HtmlDesignStatusAndPreview msdt:dt="string">http://SEARCH.lucacostante.com/_catalogs/masterpage/Display Templates/Filters/MultiValue_ResultType.html, Conversion successful.</mso:HtmlDesignStatusAndPreview>
</mso:CustomDocumentProperties></xml><![endif]-->
</head>
<body>
<div id="Filter_MultiValue">
<!--#_
var Options = {
ShowCounts: TRUE
};
var listData = ctx.ListData;
var hasControl = !$isNull(ctx.RefinementControl) && !$isNull(ctx.ClientControl);
IF(hasControl) {
var hasNoListData = ($isEmptyArray(listData));
var propertyName = ctx.RefinementControl.propertyName;
var displayTitle = Srch.Refinement.getRefinementTitle(ctx.RefinementControl);
var isExpanded = Srch.Refinement.getExpanded(ctx.RefinementControl.propertyName);
var useContains = FALSE;
var useKQL = FALSE;
var refiners = [];
var refinersAll = [];
IF (hasNoListData) {
listData = [];
}
// TODO: unify same FileType
listData = mapResultType(listData);
IF (ctx.RefinementControl.csr_filters) {
FOR(var t = 0; t < ctx.RefinementControl.csr_filters.LENGTH; t++) {
refinersAll.push({
PropertyName: ctx.RefinementControl.csr_filters[t].PropertyName,
RefinementName: ctx.RefinementControl.csr_filters[t].RefinementName,
RefinementTokens: ctx.RefinementControl.csr_filters[t].RefinementTokens,
RefinementTokensMap: ctx.RefinementControl.csr_filters[t].RefinementTokensMap,
RefinementCount: ctx.RefinementControl.csr_filters[t].RefinementCount,
IsSelected: FALSE
});
}
}
var currentRefinementCategory = ctx.ClientControl.getCurrentRefinementCategory(ctx.RefinementControl.propertyName);
var hasAnyFilterTokens = (!$isNull(currentRefinementCategory) && currentRefinementCategory.get_tokenCount() > 0);
var renderEmptyContainer = hasControl && (hasNoListData && !hasAnyFilterTokens);
IF(!renderEmptyContainer) {
var listDataTokenToDisplayMap = {};
var listDataTokenToCountMap = {};
IF(!hasNoListData) {
FOR (var i = 0; i < listData.LENGTH; i++) {
var FILTER = listData[i];
IF(!$isNull(FILTER)) {
FOR (var j = 0; j < FILTER.RefinementTokens.LENGTH; j++) {
listDataTokenToDisplayMap[FILTER.RefinementTokens[j]] = FILTER.RefinementName;
listDataTokenToCountMap[FILTER.RefinementTokens[j]] = FILTER.RefinementCount;
}
IF(!hasAnyFilterTokens && !$isEmptyString(FILTER.RefinementName) && !$isEmptyString(FILTER.RefinementTokens)) {
refiners.push(
{
PropertyName: FILTER.RefinerName,
RefinementName: FILTER.RefinementName,
RefinementTokens: FILTER.RefinementTokens,
RefinementTokensMap: FILTER.RefinementTokensMap,
RefinementCount: FILTER.RefinementCount,
IsSelected: FALSE
});
}
}
}
}
IF(hasAnyFilterTokens) {
FOR(var j = 0; j < currentRefinementCategory.get_tokenCount(); j++) {
var token = currentRefinementCategory.t[j];
var displayValue = listDataTokenToDisplayMap[token];
IF($isEmptyString(displayValue) && !$isNull(currentRefinementCategory.m)) {
displayValue = currentRefinementCategory.m[token];
}
IF(!$isEmptyString(displayValue) && !$isEmptyString(token)) {
IF (refinersAll.LENGTH > 0) {
FOR (var k = 0; k < refinersAll.LENGTH; k++) {
FOR (var t = 0; t < refinersAll[k].RefinementTokens.LENGTH; t++) {
IF (refinersAll[k].RefinementTokens[t] == token) {
refinersAll[k].IsSelected = TRUE;
break;
}
}
}
}
ELSE {
refiners.push(
{
PropertyName: FILTER.RefinerName,
RefinementName: displayValue,
RefinementTokens: token,
RefinementCount: !$isNull(listDataTokenToCountMap[token]) ? listDataTokenToCountMap[token] : 0,
IsSelected: TRUE
});
}
}
}
}
}
ctx.RefinementControl["csr_propertyName"] = propertyName;
ctx.RefinementControl["csr_displayTitle"] = displayTitle;
//ctx.RefinementControl["csr_filters"] = refiners;
ctx.RefinementControl["csr_filters"] = hasAnyFilterTokens && refinersAll.LENGTH > 0 ? refinersAll : refiners;
ctx.RefinementControl["csr_isExpanded"] = isExpanded;
ctx.RefinementControl["csr_renderEmptyContainer"] = renderEmptyContainer;
ctx.RefinementControl["csr_useContains"] = useContains;
ctx.RefinementControl["csr_useKQL"] = useKQL;
ctx.RefinementControl["csr_showCounts"] = Options.ShowCounts;
// SHOW Item
renderRefinerItems(ctx);
}
_#-->
<!--#_
FUNCTION mapResultType(listData) {
var map = { };
// Standard ResultType...
map[Srch.U.loadResource("rf_ResultTypeRefinerValue_MSPowerPoint")] = {
"RefinerName": "LC.ResultType",
"RefinementValues": ["ppt", "pptx", "pps", "ppsx", "odp", "pptm", "potm", "potx", "ppam", "ppsm"]
};
map[Srch.U.loadResource("rf_ResultTypeRefinerValue_MSWord")] = {
"RefinerName": "LC.ResultType",
"RefinementValues": ["docx", "doc", "dot", "rtf", "txt", "docm", "nws", "dotx"]
};
map[Srch.U.loadResource("rf_ResultTypeRefinerValue_MSExcel")] = {
"RefinerName": "LC.ResultType",
"RefinementValues": ["xls", "xlsx", "csv", "odc", "ods", "xlsb", "xlsm", "xltm", "xltx", "xlam"]
};
map[Srch.U.loadResource("rf_ResultTypeRefinerValue_AdobePDF")] = {
"RefinerName": "LC.ResultType",
"RefinementValues": ["pdf"]
};
map[Srch.U.loadResource("rf_ResultTypeRefinerValue_Video")] = {
"RefinerName": "LC.ResultType",
"RefinementValues": ["0x0120D520A8*", "wmv", "avi", "flv", "mov", "mpeg"]
};
map["Audio File"] = {
"RefinerName": "LC.ResultType",
"RefinementValues": ["mp4", "mp3", "wma", "ra", "Podcast"]
};
map[Srch.U.loadResource("rf_ResultTypeRefinerValue_Archive")] = {
"RefinerName": "LC.ResultType",
"RefinementValues": ["zip", "rar"]
};
map[Srch.U.loadResource("rf_ResultTypeRefinerValue_Webpage")] = {
"RefinerName": "LC.ResultType",
"RefinementValues": ["HTML", "xml", "MHTML"]
};
// Specific ResultType
map["News"] = {
"RefinerName": "LC.ResultType",
"RefinementValues": ["0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF390039E7E22DFD724B12B47BFBC3F5AA086D000580873f397b481ab8c1115a1cfc37a8*", "0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF390039E7E22DFD724B12B47BFBC3F5AA086D000580873F397B481AB8C1115A1CFC37A800a3b3a6c651184e438510779fe223a2a6*"]
};
map["Tool"] ={
"RefinerName": "LC.ResultType",
"RefinementValues": ["0x01000268E795EAEA4ABB8E5C2E8D0AB2485C*"]
};
map["PhotoGallery"] = {
"RefinerName": "LC.ResultType",
"RefinementValues": ["0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF390039e7e22dfd724b12b47bfbc3f5aa086d00b1d929c83a1a4f37ae818af558a4898200116ce8a6eddf43c9af19c678407d4166*"]
};
var retListData = NEW Array();
var assocListData = NEW Array();
FOR (var i = 0; i < listData.LENGTH; i++) {
var FILTER = listData[i];
var mappedRefinementName = NULL;
FOR(var KEY IN map) {
IF (map[KEY].RefinerName == FILTER.RefinerName) {
FOR (var j = 0; j < map[KEY].RefinementValues.LENGTH; j++) {
var actualValue = FILTER.RefinementValue.toLowerCase();
var candidateValue = map[KEY].RefinementValues[j].toLowerCase();
IF (actualValue == candidateValue ||
(actualValue.startsWith("0x") && actualValue.startsWith(candidateValue.SUBSTRING(0, candidateValue.LENGTH - 1))))
{
mappedRefinementName = KEY;
break;
}
}
IF (!$isNull(mappedRefinementName)) {
break;
}
}
}
var mappedFilter = NEW Object();
IF (!$isNull(mappedRefinementName)) {
mappedFilter.RefinerName = map[mappedRefinementName].RefinerName;
mappedFilter.RefinementCount = FILTER.RefinementCount;
mappedFilter.RefinementName = mappedRefinementName;
mappedFilter.RefinementTokens = [];
//var resultTypeTokenWrapper = (mappedFilter.RefinerName.toLowerCase() == "contenttypeid") ? FUNCTION (x) {RETURN x;} :
// Srch.RefinementUtil.stringValueToEqualsToken;
var resultTypeTokenWrapper = FUNCTION(token) {
IF (token.startsWith("0x")) {
RETURN token;
}
RETURN Srch.RefinementUtil.stringValueToEqualsToken(token);
};
FOR (var j IN map[mappedRefinementName].RefinementValues) {
mappedFilter.RefinementTokens.push(resultTypeTokenWrapper(map[mappedRefinementName].RefinementValues[j]));
}
IF ($isNull(assocListData[mappedFilter.RefinementName])) {
assocListData[mappedFilter.RefinementName] = mappedFilter;
}
ELSE {
assocListData[mappedFilter.RefinementName].RefinementCount += mappedFilter.RefinementCount;
}
}
}
FOR (var KEY IN assocListData) {
retListData[retListData.LENGTH] = assocListData[KEY];
}
RETURN retListData;
}
_#-->
<!--#_
AddPostRenderCallback(ctx, FUNCTION() {
$('#Container input[type=checkbox]').ON('click', FUNCTION() {
IF ($(this).IS(':checked')) {
$(this).parent().find('label').css("font-weight", "bold").css("color", "#2D2D2D");
} ELSE {
$(this).parent().find('label').css("font-weight", "").css("color", "");
}
});
});
_#-->
<!--#_
FUNCTION renderRefinerItems(ctx) {
var propertyName = ctx.RefinementControl["csr_propertyName"];
var displayTitle = ctx.RefinementControl["csr_displayTitle"];
var filters = ctx.RefinementControl["csr_filters"];
var isExpanded = BOOLEAN(ctx.RefinementControl["csr_isExpanded"]);
var renderEmptyContainer = BOOLEAN(ctx.RefinementControl["csr_renderEmptyContainer"]);
var useContains = BOOLEAN(ctx.RefinementControl["csr_useContains"]);
var useKQL = BOOLEAN(ctx.RefinementControl["csr_useKQL"]);
var showCounts = BOOLEAN(ctx.RefinementControl["csr_showCounts"]);
IF($isEmptyString(propertyName) || (!$isNull(renderEmptyContainer) && renderEmptyContainer)) {
_#-->
<div id="EmptyContainer"></div>
<!--#_
}
ELSE IF(!$isNull(filters) && Srch.U.isArray(filters) && !$isEmptyArray(filters)) {
var expandedStatus = !$isNull(isExpanded) ? isExpanded : TRUE;
var iconClass = "ms-core-listMenu-item ";
iconClass += expandedStatus ? " ms-ref-uparrow " : " ms-ref-downarrow ";
_#-->
<div id="_#= propertyName =#_-MultiRefiner">
<div id="Container">
_#= Srch.U.collapsibleRefinerTitle(propertyName, ctx.ClientControl.get_id(), displayTitle, iconClass) =#_
<div class="ms-ref-unselSec" id="UnselectedSection">
<div id="unselShortList" class="ms-ref-unsel-shortList">
<!--#_
FOR (var i = 0; i < filters.LENGTH; i++) {
var FILTER = filters[i];
IF(!$isNull(FILTER)) {
var inputValues = "";
var isSelected = BOOLEAN(FILTER.IsSelected);
var inputName = propertyName + '_ChkGroup';
var inputId = inputName + "_" + FILTER.RefinementName;
var nameClass = "ms-ref-name " + (showCounts ? "ms-displayInline" : "ms-displayInlineBlock ms-ref-ellipsis");
var selectClass = " custom-ref-fullwidth " + ((i == (filters.LENGTH - 1)) ? "" : " bordered-bottom ") + (isSelected ? " bold-text " : "");
IF (FILTER.RefinementTokensMap) {
// multi typed refinement CASE
FOR(var KEY IN FILTER.RefinementTokensMap) {
inputValues += KEY + ":" + FILTER.RefinementTokensMap[KEY] + "|";
}
}
ELSE {
inputValues = FILTER.RefinementTokens;
}
_#-->
<div id="Value" class="_#= selectClass =#_">
<!--#_
IF(isSelected) {
_#-->
<div class="cust-filter-ck">
<INPUT TYPE="checkbox" class="ms-padding0 ms-margin0 ms-verticalAlignMiddle" id="_#= $htmlEncode(inputId) =#_" name="_#= $htmlEncode(inputName) =#_" data-displayValue="_#= $htmlEncode(filter.RefinementName) =#_" VALUE="_#= $htmlEncode(inputValues) =#_" checked="" onclick="MultiRefinement.SubmitRefinement('_#= $scriptEncode(filter.PropertyName) =#_', $getClientControl(this), '_#= $scriptEncode(inputId) =#_', _#= isSelected =#_);" />
</div>
<!--#_
} ELSE {
_#-->
<div class="cust-filter-ck">
<INPUT TYPE="checkbox" class="ms-padding0 ms-margin0 ms-verticalAlignMiddle" id="_#= $htmlEncode(inputId) =#_" name="_#= $htmlEncode(inputName) =#_" data-displayValue="_#= $htmlEncode(filter.RefinementName) =#_" VALUE="_#= $htmlEncode(inputValues) =#_" onclick="MultiRefinement.SubmitRefinement('_#= $scriptEncode(filter.PropertyName) =#_', $getClientControl(this), '_#= $scriptEncode(inputId) =#_', _#= isSelected =#_);" />
</div>
<!--#_
}
_#-->
<label FOR="_#= $htmlEncode(inputId) =#_" class='_#= nameClass =#_'>
_#= $htmlEncode(FILTER.RefinementName) =#_
</label>
<!--#_
IF (showCounts) {
_#-->
<label FOR="_#= $htmlEncode(inputId) =#_" class='_#= nameClass =#_ cust-ref-count'>
<span id='RefinementCount' class='ms-ref-count ms-textSmall'> (_#= $htmlEncode(Srch.U.toFormattedNumber(FILTER.RefinementCount)) =#_) </span>
</label>
<!--#_
}
_#-->
</div>
<!--#_
}
}
_#-->
</div>
</div>
<!--#_
}
_#-->
</div>
</div>
<!--#_
}
_#-->
</div>
</body>
</html>
Results:
How expected, now we have a custom refiner that is able to filter on two property (in this case, but you can also add more property): the extention and the content type.
Display a custom Managed Property inside the Item_CommonItem_Body.html Display Template
Written by Luca CostanteHi everybody,
today I'm encourring in a strange problem: I need to display a value of a custom Managed Property inside the "Item_CommonItem_Body.html" Display Template, near the date visualization.
Here a little image regarding the result that I need (inside the red box there is the value of my custom Managed Property).
To add this value, you need to manipulate the "Item_CommonItem_Body.html" Display Template. How we know, to view the custom managed property, we need to declare it on top of the page and after we need to update the respective result type. So I go inside the result type page and I'm not able to see a result type that follow the "Item_CommonItem_Body.html" Display Template.
I've created a new result type that link to the Common Item Body, but when I reload the page, all items displayed are corrupted, the html il broken. Infact, all items had the id with undefined value and all not works fine.
At that time, the question was: how I can use it?
The solution is: you need to add the custom Managed Metadata definition inside the "Item_WebPage.html" Display template. After that, when you return inside the result type page, you need to copy the current one that contains the "Item_WebPage.html" display template. The system propones to update it.
Now the system is able to manage that values. So, now you can add the code to display the value inside the "Item_CommonItem_Body.html" Display template.
At the end of the history, to manage a custom Managed property inside the "Item_CommonItem_Body.html" display template, you need:
- Define the Managed Metadata property inside the "Item_WebPage.html" display template
- Create and update a result type based on "Item_WebPage.html"
- Use you custom managed metadata property inside the "Item_CommonItem_Body.html"
Note: if you don't want problems with a wrong displaying of the results, you mustn't never create a result type that use the "Item_CommonItem_Body.html".
Enable Scheduling settings via Client SharePoint Object Model
Written by Luca CostanteI would to share with the network the snippet code to enable the Scheduling settings via Client SharePoint Object Model APIs.
This first block provide to enable the Scheduling on all pages list of the site collection
public void EnablePagesSchedulingOnAllSiteCollection(CustomWebApplication wa)
{
try
{
foreach (CustomSiteCollection sc in wa.SiteCollections)
{
using (ClientContext context = new ClientContext(wa.Url + sc.Url))
{
context.Credentials = new NetworkCredential(wa.UserName, wa.UserPassword, wa.UserDomain);
context.Load(context.Site.RootWeb, w => w.Webs, w => w.ServerRelativeUrl);
context.ExecuteQuery();
PageHelper.EnableScheduling(context, context.Site.RootWeb, true,sc.LanguageShortCode,logFilePath);
}
}
}
catch (Exception ex)
{
string message = string.Format("------------- Exception EnablePagesSchedulingOnAllSiteCollection: {0}", ex.Message);
Logger.WriteLog(message, logFilePath);
}
}
The second block provide to enable the settings on the list page recursively
using Microsoft.SharePoint;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Publishing;
using Microsoft.SharePoint.Publishing.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Client.Common.Helpers
{
public class PageHelper
{
public static Guid StartDateGUID
{
get
{
return new Guid("51d39414-03dc-4bd0-b777-d3e20cb350f7");
}
}
public static Guid EndDateGUID
{
get
{
return new Guid("a990e64f-faa3-49c1-aafa-885fda79de62");
}
}
internal static string GetPageListName(string language)
{
string pagesListName = string.Empty;
switch (language)
{
case "it": pagesListName = "Pagine"; break;
default: pagesListName = "Pages"; break;
}
return pagesListName;
}
internal static void EnableScheduling(ClientContext context, Web currWeb, bool recursive, string language, string logFilePath)
{
try
{
List pages = ListHelper.GetList(context, currWeb, GetPageListName(language), logFilePath);
EventReceiverDefinitionCollection eventReceivers = pages.EventReceivers;
pages.EnableModeration = true;
pages.EnableMinorVersions = true;
pages.Update();
//To enable Scheduling in the list
string assembly = "Microsoft.SharePoint.Publishing, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c";
string fullName = "Microsoft.SharePoint.Publishing.Internal.ScheduledItemEventReceiver";
EventReceiverType typeItemUpdating = EventReceiverType.ItemUpdating;
EventReceiverType typeItemAdded = EventReceiverType.ItemAdded;
string itemUpdatingERName = "Item Updating Event Handler For Scheduling";
string itemAddedERName = "Item Added Event Handler For Scheduling";
bool foundUpdating = false;
bool foundAddedd = false;
foreach (EventReceiverDefinition e in eventReceivers)
{
if (string.Compare(e.ReceiverName, itemUpdatingERName, true) == 0)
foundUpdating = true;
if (string.Compare(e.ReceiverName, itemAddedERName, true) == 0)
foundAddedd = true;
}
if (!foundUpdating)
{
EventReceiverDefinitionCreationInformation erItemUpdating = new EventReceiverDefinitionCreationInformation();
erItemUpdating.ReceiverName = itemUpdatingERName;
erItemUpdating.EventType = typeItemUpdating;
erItemUpdating.ReceiverAssembly = assembly;
erItemUpdating.ReceiverClass = fullName;
eventReceivers.Add(erItemUpdating);
}
if (!foundAddedd)
{
EventReceiverDefinitionCreationInformation erItemAdded = new EventReceiverDefinitionCreationInformation();
erItemAdded.ReceiverName = itemAddedERName;
erItemAdded.EventType = typeItemAdded;
erItemAdded.ReceiverAssembly = assembly;
erItemAdded.ReceiverClass = fullName;
eventReceivers.Add(erItemAdded);
}
List<FieldLinkCreationInformation> fieldsToAdd = new List<FieldLinkCreationInformation>();
fieldsToAdd.Add(new FieldLinkCreationInformation() { Field = context.Site.RootWeb.Fields.GetById(StartDateGUID) });
fieldsToAdd.Add(new FieldLinkCreationInformation() { Field = context.Site.RootWeb.Fields.GetById(EndDateGUID) });
context.Load(fieldsToAdd[0].Field, f => f.Id);
context.Load(fieldsToAdd[1].Field, f => f.Id);
context.ExecuteQuery();
foreach (FieldLinkCreationInformation f in fieldsToAdd)
{
if (pages.Fields.Where(c => c.Id == f.Field.Id).Count() == 0)
pages.Fields.Add(f.Field);
else
{
pages.Fields.Where(c => c.Id == f.Field.Id).FirstOrDefault().Hidden = false;
pages.Fields.Where(c => c.Id == f.Field.Id).FirstOrDefault().Update();
}
}
context.ExecuteQuery();
foreach (ContentType ct in pages.ContentTypes)
{
try
{
context.Load(ct, c => c.FieldLinks, c => c.Fields, c => c.Name);
context.ExecuteQuery();
foreach (FieldLinkCreationInformation f in fieldsToAdd)
{
if (ct.FieldLinks.Where(c => c.Id == f.Field.Id).Count() == 0)
ct.FieldLinks.Add(f);
else
ct.FieldLinks.Where(c => c.Id == f.Field.Id).FirstOrDefault().Hidden = false;
if (ct.Fields.Where(c => c.Id == f.Field.Id).Count() == 0)
ct.Fields.Add(f.Field);
else
ct.Fields.Where(c => c.Id == f.Field.Id).FirstOrDefault().Hidden = false;
}
ct.Update(true);
}
catch (Exception ex)
{
Logger.WriteLog(string.Format("Error on CT {0}: {1} ", ct.Name, ex.Message), logFilePath);
}
}
if (!pages.DefaultView.ViewFields.Contains("Scheduling Start Date"))
{
pages.DefaultView.ViewFields.Add("Scheduling Start Date");
}
if (!pages.DefaultView.ViewFields.Contains("Scheduling End Date"))
{
pages.DefaultView.ViewFields.Add("Scheduling End Date");
}
pages.DefaultView.Update();
pages.Update();
context.ExecuteQuery();
Logger.WriteLog(string.Format("Publishing enabled on list Pages of site {0}.", currWeb.ServerRelativeUrl), logFilePath);
if (recursive)
{
context.Load(currWeb, w => w.Webs);
context.ExecuteQuery();
foreach (Web subWeb in currWeb.Webs)
{
EnableScheduling(context, subWeb, recursive, language, logFilePath);
}
}
}
catch (Exception ex)
{
Logger.WriteLog(string.Format("Error during EnableScheduling on web {0}: {1}", currWeb.ServerRelativeUrl, ex), logFilePath);
}
}
}
}
Bad request (400 error) when you use REST API to search items and the querytext contains the single quote character
Written by Luca CostanteToday I'm working with a particular error: when I search items that contains the single quote character through the REST API, I receive a bad request error (400 error).
The first steps is to analyze the response from the server:
- Request: GET http://test.lucacostante.com/_api/search/query?querytext='path:http://test.lucacostante.com/Lists/Banners/Forms/AllItems.aspx OR path:http://test.lucacostante.com/Pages/L'universo.aspx'&rowlimit=5&selectproperties='Title,Path'
- Response: Error 400: {"error":{"code":"-1, Microsoft.SharePoint.Client.InvalidClientQueryException","message":{"lang":"en-US","value":"The expression \"'path:http://test.lucacostante.com/Lists/Banners/Forms/AllItems.aspx OR path:http://test.lucacostante.com/Pages/L'universo.aspx'\" is not valid."}}}
The problem is the single quote ' character into the query that provide to create a wrong query.
I've tried to encode the URL but this not resolve my problem. The solution is simpler: I need only to add another single quote to resolve my problem ('').
- Request: GET http://test.lucacostante.com/_api/search/query?querytext='path:http://test.lucacostante.com/Lists/Banners/Forms/AllItems.aspx OR path:http://test.lucacostante.com/Pages/L''universo.aspx'&rowlimit=5&selectproperties='Title,Path'
- Response: HTTP/1.1 200 OK
Copy page function not copy the WebPart (Resolved)
Written by Luca CostanteToday I've resolved a strange problem: when an user tries to copy a page from a folder to another one into the Pages library, the system provides to copy the page but if it contains some webparts, they will not be copied.
These are some assumptions:
- if you have a web site based on Publishing site template, the copy page feature works fine
- if you have only the major version versioning system on the Pages library the copy page feature doesn't work
The solution is that the copy page needs that on the Pages Library is enabled the versioning system with minor and major versioning. This allow also the copy of the webpart during the copy phase.
More...
Custom Claims Provider - Results not showing in People Picker
Written by Luca CostanteIn these days I'm working on a Custom Claim Provider that assign claims reading data from the User Profiles, SharePoint Groups, Custom DataBases, LDAP, etc.
Today I've a strange problem: when I use the People Picker, the system found the item (into the DB) ma not shows it (see the image below).
The problem is on a miss-match from the URL schema specified into the method FillClaimTypes (that is called when you enable the Farm feature that turn on your Custom Claim Provider and sets the allowed URLs) and the URL schema assigned to your claim.
I've resolved assigning the same schema URL and now all works fine.
Error Creating Web Application in SharePoint 2013 (timeout error)
Written by Luca CostanteIf you have a slowly (virtual) machine, you can ran into an issue when creating a new SharePoint 2013 web application.
Everything appeared to be going correctly until the dialog box displayed "Internet Explorer cannot display the webpage".
If you make some check, you can observe that:
- in IIS the Application Pool and Site were both created as well
- some virtual directorys are empty
- the content database is not created
The problem is a time out in IIS.
You need to increase the time on IIS in order to give to SharePoint the time to create all components. To do that, you need to
- Open IIS Manager and select the SharePoint Central Administration Application Pool (many thanks This email address is being protected from spambots. You need JavaScript enabled to view it.for the tests)
- On the right hand side of the window click Select Application Pool Defaults
- Change the following 3 Process Model time settings from 90 to 400
- Ping Maximum Response Time
- Shutdown Time Limit
- Startup Time Limit
Now, you are able to create correctly the web applications.
SharePoint 2013 Error – “We’re having a problem opening this location in File Explorer, Add this web site to your Trusted sites list and try again”
Written by Luca CostanteIntroduction
File Explorer SharePoint features is a very useful function that enables users to open a document library as if it is a normal folder (network folder).
This would give the user access to normal file operations such as edit, copy, move etc.
Issue
If you click on the button into the ribbon the following error message "We’re having a problem opening this location in File Explorer. Add this web site to your Trusted Sites list and try again." appears and the library does not open in File Explorer:
Solution
After searching a bit in the Internet, I found that I have to start the WebClient service.
The first thing you need to do is to ensure that you have already installed the Desktop Experience feature in your Windows Server. If it’s your case, you can follow the steps below to do it:
- Go to Run, type Server Manager and press Enter
- Select Features and then select Add Features
- Expand "User Interface And Infrastracture"
- Select Desktop Experience and select Add Required Features on the popup screen
- Click Next then click Install
- Restart your computer
- Go to Windows services and Start (with authomatic settings) WebClient service.
Windows Azure is the Cloud platform of Microsoft.
I've a virtual machine with windows server 2012 R2 and SharePoint 2013 and I use it to prepare demos, to share environment with my team, make tests, etc. Very often I need to navigate my test environment with a public url and I use the Fully Qualified Domain Name of the machine.
The problem generally is to have on the same URL more sites that need to be available. The solution is to use:
- alternate access mapping (AAM) on SharePoint with a particula port (>1024)
- Add the binding for the site on IIS with the same port specified on the AAM
- allow that port on the Windows Firewall.
At this point, the last action to is to go on the azure web platform, select the virtual machine and you need to add an endpoint where you are mapping a public port (that will be used through the internet) with the port specified in IIS and on the AAM.
Et voila, now you can navigate the site via internet by a specific port.
For each site that you need to navigate by internet, you need to make the previous steps with a different port.
Note: if you have "Timeout error" when you surf the site via Internet, you need to check that on the Windows Server Firewall is added the exception for the port that the site is using.