The “Exec” task needs a command to execute.
I have lost one hour trying to figure out what is the source of the message: "The "Exec" task needs a command to execute." (Visual Studio 2005)
It occurred that when modifying the post-build action I have left one empty line... Removing it solved the problem...
Microsoft Search Server Express 2008 – two issues
Recently we have started using Miscrosoft Search Server Express 2008 (MOSS) as a search engine for some of EPiServer based projects (replacing default EPiServer search engine). But the context of usage is not that important now.
To be clear - I think MOSS is a very nice product that is great for medium projects. But we encountered two issues with it - one already solved and one still not fixed.
Starting with solved one
It occurred that MOSS by default is not crawling pdf files. I'm not sure why - because pdf files are one of the most popular ones... I found solution to that on Nicholas's blog - Microsoft Search Server PDF iFilter Installation
You can read about details on his blog. Just to highlgiht those are steps to add pdf crawling to MOSS:
- you will need to install Acrobat Reader on the same machine where MOSS is installed
- modify some register keys
- add pdf extension to the list of files extensions to be crawled
That was quite easy
Update: Some times there might be still the problem with PDF crawling. It might be an issue with wrong CLSID of Adobe IFilter. Here can be found a solution to that: http://blogs.msdn.com/ifilter/archive/2007/03/29/indexing-pdf-documents-with-adobe-reader-v-8-and-moss-2007.aspx
Second issue is still waiting for solving.
What is the problem? Results sorting, not by rank but by chosen managed properties.
We are using QueryEx. According to MSDN it is possible to change default sorting of results returned by search server. You can see that the QueryPacket has element:
It should be possible to send QueryPacket with SortByProperties element set to something like this:
1 2 3 4 | <SortByProperties> <SortProperty name="Page" direction="ascending" order="1"></SortProperty> <SortProperty name="Heading" direction="ascending" order="2"></SortProperty> </SortByProperties> |
where both Path and Heading are managed properties that are available in results.
Unfortunately, there is no change in results sorting - they are still sorted by rank. We have even tried to add names of the properties in lowercase - as someone suggested in comments.
I'm still looking for a solution to the second problem - so, if you have any suggestion please, do not hesitate to let me know
LinkItemCollection property in EPiServer
I was really happy reading on EPiServer Labs blog post by Ted Nyberg that in EPiServer CMS 5 R2 there is a new property type introduced - LinkItemCollection. You can read more on Ted's blog - but in short, it is a native property that does what old good Multi-page property has done so far (and some others implementation of multi link property).
I was using multi-page property in many projects and still I will be using it on all EPiServer 4.6x projects, but for sure, in all new CMS 5 I will go with LinkItemCollection. Especially that what I have just checked it is "smarter" then Multi-page property. "Smarter" because it knows what links it stores - and for example, while moving document (or deleting) that is referred by LinkItemCollection now we will get a warning. This was not possible with Multi-page property.
Still there are some areas where probably I will stick to Multi-page property. It is great base for creating new specialized properties for different purposes. We have created few new properties for which Multi-page property source code was a base like for example property called multi-image list - which allows for adding images with caption, alt text, link URL and so on. I'm not sure for now if it is possible with the new property - if not multi-page property isn't dead for us (at least for the time being
)
How to make a page type a ‘leaf’
In one of my projects I had to create page type that was supposed to be a 'leaf' in page tree structure (for this page type no children should be possible to create). First thought was to go to admin mode, to configuration of page types and turn off all page types on "Available page types". I was very surprised that it can't be done. Even if one chooses no page types to be available and save configuration it does not work (when one will open this tab again - all page types will be chosen).
After short investigation I have found post on EPiServer forum. Greger Olofsson describes there some possibilities how this can be achieved. I have tried two of them:
- create a dummy page type and choose it not to be available in edit mode and then select it as only one available for our 'leaf' page type,
- subscribe to the CreatingPage event and check what page type name (or id) is used and abort the creation of the new page
Both of them works but have some drawbacks. When selecting dummy page for our 'leaf' page type in edit mode, after clicking 'Create New' link (from context menu or toolbar) we get this page:

It may be confusing for editors because it gives no information why there is no new page page type to choose.
Subscribing to CreatingPage event is not better. I did it with this code (in Global.asax.cs):
protected void Application_Start(Object sender, EventArgs e)
{
EPiServer.DataFactory.Instance.CreatingPage = new EPiServer.PageEventHandler(OnCreatingPage);
}
private string[] GetLeafPageTypes()
{
string leafPageTypesConfigurationValue = System.Web.Configuration.WebConfigurationManager.AppSettings["leafPageTypes"];
string delimStr = ",";
char[] delimiter = delimStr.ToCharArray();
return leafPageTypesConfigurationValue.Split(delimiter);
}
protected void OnCreatingPage(object sender, PageEventArgs e)
{
PageData parentPage = EPiServer.DataFactory.Instance.GetPage(e.Page.ParentLink);
foreach (string leafPageType in GetLeafPageTypes())
{
if (parentPage.PageTypeName.ToLower() == leafPageType.ToLower().Trim())
{
e.CancelAction = true;
e.CancelReason = "Page type is lea";
return;
}
}
}
Few words of explanation. I decided to keep configuration which page type is a leaf in web.config which looks like this:
<appSettings> <add key="leafPageTypes" value="[Public] Start page,[Public] Search page" /> </appSettings>;
It does work and does not allow new page to be created. It does show my warning to the editor ("Page type is a leaf"). But it is done after choosing page type of new page and after pressing Save button (so also after editor has filled in all properties values and after seeing informations which properties are mandatory to fill).
Then for some time I tried to modify context menu (the one that is showing on right mouse button) but I realized that I will also have to modify toolbar (where new page button is present also). And then I decided to do it in NewPage.aspx file located in edit folder. I know that this shouldn't be done mostly because it will be lost (it can be lost to be more specific) during upgrades. But my change is very simply and very easy to add after possible upgrade. What I did? I have added to this page similar code as I tested on CreatingPage event. I have added to markup file those lines:
<%@ Import namespace="EPiServer"%>
<%@ Import namespace="EPiServer.Core" %>
<script runat="server">
private string[] GetLeafPageTypes()
{
string leafPageTypesConfigurationValue = System.Web.Configuration.WebConfigurationManager.AppSettings["leafPageTypes"];
string delimStr = ",";
char[] delimiter = delimStr.ToCharArray();
return leafPageTypesConfigurationValue.Split(delimiter);
}
protected override void OnLoad(System.EventArgs e)
{
foreach( string leafPageType in GetLeafPageTypes() )
{
if (CurrentPage.PageTypeName.ToLower() == leafPageType.ToLower().Trim())
{
ErrorMessage.Text = "Page type is leaf. Cannot have children";
PageTypeList.Visible = false;
Cancel.Visible = false;
}
}
base.OnLoad(e);
}
</script>
and Label control to display my message:
<asp:Label ID="ErrorMessage" runat="server" ForeColor="red" ></asp:Label>
I'm still using appSettings key to keep configuration which page type are a 'leaf' ones. Now when editor wants to create new page under 'leaf' page type page after clicking "Create New" link he/she sees that information:
So as you can see I achieved two things:
- it is possible to define page type (or page types) as a 'leaf' by editing one key in web.config
- it is easy to make page type a 'leaf' just for some time without changing it's configuration (available page types)
- editor now can see information why he/she can't create new page with chosen parent.
I suppose that there are different way to do something similar. If you know them - please let me know
Get posted data (XFormData) from XForm
Recently we have had to get posted data from xform from code. To do it we developed this method:
/// <summary>/// Retives posted data for xform defined for CurrentPage.
///</summary>
/// <param name="pageReference">PageReference of page for each posted data of xform should be returned</param>
/// <param name="xFormPropertyName">Property name of CurrenPage page type. Property has to be of type XForms</param>
/// <param name="xFormFolderPath">XFormFolder path where xForm is saved.</param>
/// <returns>Returns list of XFormData objects - each XFormData object contains data posted with xform</returns>
private IList<XFormData> GetXFormData(PageReference pageReference, string xFormPropertyName, string xFormFolderPath)
{
if (pageReference == null || pageReference == PageReference.EmptyReference)
return null;
PageData pageData = GetPage(pageReference);
PropertyData xFormProperty = pageData.Property[xFormPropertyName];
if (xFormProperty == null || xFormProperty.Value == null)
return null;
if (!(xFormProperty is PropertyXForm))
return null;
IList<XForm> xFormFolder;
if( xFormFolderPath != String.Empty )
xFormFolder = XFormFolder.GetForms(xFormFolderPath);
else
xFormFolder = XFormFolder.GetForms();
foreach (XForm xform in xFormFolder)
{
Guid formGuid = new Guid(CurrentPage[xFormPropertyName].ToString());
if (formGuid.CompareTo((Guid)xform.Id) == 0)
{
return xform.GetPostedData(CurrentPage.PageLink.ID, DateTime.Now.AddDays(-7), DateTime.Now);
}
}
return null;
}
It gets as parameters PageReference of page for which posted data should be returned, property name of property that contains XForm and folder name where xform is stored (if any). As output from method we get list of XFormData objects where each item contains data posted with xform.
It works in EPiServer CMS 5 where some changes in XForm handling has been introduced (strong typing).
Here is post on forum where is shown how to do it in EPiServer 4.6x.
WebResource.axd problem in EPiServer CMS 5
With our first EPiServer CMS 5 based solution we had strange problem related with WebResource.axd. We were getting the exception:
The WebResource.axd handler must be registered in the configuration to process this request
After searching for this exception in Google I have found a post about this on Fredrik Haglund's blog. We have had applied his patch and it seems to solve the problem (at least until it will be solved by EPiServer or whoever responsible for that).
Anyway I thought that we did something special in that one project and that this problem is that project specific only. Unfortunately it occurred that the exception is thrown from time to time in all our EPiServer CMS 5 projects. The worst thing is that we are not able to reproduce error or identify what makes this error more probable to occur. It is thrown from time to time without any clear reason.
For now we have started to adding patch to all ours CMS 5 projects. But this is something that has to be solved somehow. We are monitoring EPiServer's forum and waiting for this problem to be solved. When you will read comments to the Fredrik's post you can see that they are working on that - and I will keep my finger crossed for them to fix it
UPDATE:
Today I have found this post. It seems that the reason of error has been found and that there is a workaround.
Do security updates! (and remember to include that in the requirements of the server specification)
In one of the projects I was technical architect in we were struggling with strange error. When accessing main URL of the application we were getting NullReferenceException. But when accessing same site with language code at the end of URL everything was ok. What was the problem? Lack of SP1 for .Net Framework 2.0 installed.
There is also second lesson. Be very detail when crating specifications. When we were delivering server specification we told the Administrator that we will need .Net Framework 2.0. We forgot to mention that all security updates has to be installed on the server.
Here is the link to the problem and it's solution description.
Do I like to work with EPiServer CMS 5?
After working with EPiServer CMS 5 in two projects I already have some thoughts about it. In those two projects I was involved both as developer and technical architect so I have split my comments into two parts.
As developer:
It took some time to get used to:
- read-only PageData object instances (you can ready about it here)
- new VPP
- new way of managing datafactory - it takes some time to get used to write EPiServer.DataFactory.Instance instead EPiServer.Global.EPDataFactory
Of course there are few nice new things like for example new filter: FilterForVisitor
As technical architect:
I really like:
- improved performance (nice test here)
- new way of defining site configuration in web.config
- installing new modules with EPiServer Manager
- new handling of custom property types
- permanent links - this one is really cool
and I had some problems with:
- searching on developer forums for information if different behavior is due to changes introduced in CMS 5 or bug (after some time I have found link to issue tracker with list of the bugs)
- searching for examples how some things should be done in CMS 5 - for example how to get path to page folder (found on developers forum, not on EPiServer Knowledge Center)
In general we had problems with:
- still too few information in SDK
- poor intellisense in VS - no description of methods, properties...
- no episerver enterprise section - very useful (and often used in 4.6x) but not present in CMS 5
- quite a lot of bugs, for example:
- FriendlyURL caching - fixed in SP1
- simple address and external link
To summarize - I really liked working with new EPiServer and kind of hoping that in my next project we will be using CMS 5. Of course there are still things to improve - can't wait to see how CMS 5 will be developing.
GetPage for visitor?
I started working with EPiServer CMS 5 four months ago and I really like it. It's performance (good analyze of it you can find here) is much better then EPiServer 4.6x and there are few breaking changes that makes developers work easier. One of them is new filter: FilterForVisitor (described at the end of article at episerver.com ). It takes as an argument PageDataCollection and filter out pages that visitor has no right to see:
PageReference listingContainer = CurrentPage["RssSource"] as PageReference; PageDataCollection children = GetChildren(listingContainer); FilterForVisitor.Filter(children);
Cool but... it works only with PageDataCollections. It would be great if there was method that takes as an argument PageData object (or in ideal world PageReference) and checks if visitor can see it. Now if I want to check it I have to do something like this:
PageReference pageRef = new PageReference(someId);
PageData tmpPage = EPiServer.DataFactory.Instance.GetPage(pageRef, AccessLevel.NoAccess);
if( tmpPage.QueryDistinctAccess( AccessLevel.Read ) )
return tmpPage;
else
return null;
Why GetPage with argument AccessLevel.Read - could not return null if visitor has no right to see it? Yes - I know that it will throw exception but making flow of application with catch block isn't that nice.
Does anyone know better way of doing check if visitor can access page?
