I've started to write up a few formal blog posts about this, but in the meantime, my session deck is available here:
I've started to write up a few formal blog posts about this, but in the meantime, my session deck is available here:
I've started to write up a few formal blog posts about this, but in the meantime, my session deck is available here:
Andrew Connell has just announced some new tools for SharePoint developers to get their teeth into – these are top tools for people who need to build their own feature files from scratch:
"I finally got sick of writing feature.xml after feature.xml and creating new GUIDs. These repetitive things as well as those that make me take my hands off the keyboard slow me down… and that drives me nuts. Over the last few months I've been polishing and tweaking some stuff I've been working on that I use on a day-to-day basis as a SharePoint developer that speed up my development. Finally, they are at a point where I want to share them for others to benefit from them as I have (and a few folks who've been kind enough to test and provide feedback)."
Full report here: http://andrewconnell.com/blog/archive/2007/08/21/6095.aspx
I've been using this in anger for the last week or so, and I love them…
Andrew Connell has just announced some new tools for SharePoint developers to get their teeth into – these are top tools for people who need to build their own feature files from scratch:
"I finally got sick of writing feature.xml after feature.xml and creating new GUIDs. These repetitive things as well as those that make me take my hands off the keyboard slow me down… and that drives me nuts. Over the last few months I've been polishing and tweaking some stuff I've been working on that I use on a day-to-day basis as a SharePoint developer that speed up my development. Finally, they are at a point where I want to share them for others to benefit from them as I have (and a few folks who've been kind enough to test and provide feedback)."
Full report here: http://andrewconnell.com/blog/archive/2007/08/21/6095.aspx
I've been using this in anger for the last week or so, and I love them…
Answer:
SPControlMode currentControlMode = SPContext.Current.FormContext.FormMode;
SPControlMode can be in one of 4 states:
Very useful if you are having to write code which has to be aware whether or not it is executing in edit mode on a page.
*Two* blogs on the same day. What is the world coming to?
Answer:
SPControlMode currentControlMode = SPContext.Current.FormContext.FormMode;
SPControlMode can be in one of 4 states:
Very useful if you are having to write code which has to be aware whether or not it is executing in edit mode on a page.
*Two* blogs on the same day. What is the world coming to?
Recently I had a requirement to do some cross list queries. The scenario was this:
I had a list at the root of my site collection, and a content type (inheriting from Article Page) which had a lookup field using this list. I had a design requirement to get all the pages in the site collection of that content type, and some render some of the fields (including some of the list fields) to a rollup page..
None of the out of the box controls could do this (specifically, getting values from two lists at the same time)*, so I set about writing my own control.
* Please correct me if I'm wrong…
I started off by iterating through the SPWeb hierarchy, getting all the pages which had the correct content type, generating XML on the fly. I then got the SPListItem which had been specified for that page and added the list values to the XML document, thinking that I could easily use XSLT to render out the results. Walking the tree went something like this:
private void iterateWebs(SPWeb thisWeb)
{
if (PublishingWeb.IsPublishingWeb(thisWeb))
{
PublishingWeb pWeb = PublishingWeb.GetPublishingWeb(thisWeb);
foreach (SPListItem pageItem in pWeb.PagesList.Items)
{
if (pageItem.ContentType = f_MyContentType)
{
addPageToXml(pageItem);
}
}
}
foreach (SPWeb childWeb in thisWeb.Webs)
{
iterateWebs(childWeb);
}
}
This worked perfectly on my dev box, but moving to a location where I had a significant number of webs, I noticed that the time taken to render was becoming slow – in the order of seconds to execute.
So I added some timestamp checks to work out what was taking the time. There were a number of factors, for example, the step to get the Publishing Web was fairly slow, but overall there wasn't one particular operation that took a long time, it was just the culmulative effect of iterating through the object model.
I toyed with the idea of using some sort of caching – this wasn't something that changed frequently. But I didn't really want to get into complexities around refreshing the cache when new pages appeared. That led me to play with the SPSiteDataQuery objects, and get my hands dirty with CAML, and I implemented the same query as follows:
private const string f_ListsPattern = "<Lists ServerTemplate='{0}' Hidden='{1}'/>";
private const string f_WhereQueryPattern = "<{1}><FieldRef Name='{0}' /><Value Type='{3}'>{2}</Value></{1}>";
private const string f_OrderQueryPattern = "<OrderBy><FieldRef Name='{0}' Ascending='False' Nullable='TRUE'/></OrderBy>";
private void buildQuery()
{
SPSiteDataQuery q = new SPSiteDataQuery();
q.Lists = string.Format(f_ListsPattern, "850", "True");
q.Query = string.Format(f_WhereQueryPattern, "ContentType", "Eq", "MyContentType", "Choice");
q.Webs = "<Webs Scope='SiteCollection' />";
q.ViewFields = "<FieldRef Name='Title' /><FieldRef Name='ID' /><FieldRef Name='ContentType' /> [etc - include all the fields required]";
q.RowLimit = 10;
DataTable dt = SPContext.Current.Site.RootWeb.GetSiteData(q);
dt.TableName = "row";
DataSet ds = new DataSet("rows");
ds.Tables.Add(dt);
xDoc.LoadXml(ds.GetXml());
}
This executed in 0.5s the first time it ran after the application had reloaded, and was a very impressive 0.002s after object caching had kicked in.
I suspect that the cause of the difference in execution time is this: each object that is touched in the OM during the for loop results in a (fairly unoptimised) database query. In CAML, though, it is a single, well constructed SQL statement that is generated, and then cached automatically. And that has to be faster any day. If I remember, and have time over the next few days, I'll post some analysis using SQL Profiler to see what is actually happening during these calls.
Recently I had a requirement to do some cross list queries. The scenario was this:
I had a list at the root of my site collection, and a content type (inheriting from Article Page) which had a lookup field using this list. I had a design requirement to get all the pages in the site collection of that content type, and some render some of the fields (including some of the list fields) to a rollup page..
None of the out of the box controls could do this (specifically, getting values from two lists at the same time)*, so I set about writing my own control.
* Please correct me if I'm wrong…
I started off by iterating through the SPWeb hierarchy, getting all the pages which had the correct content type, generating XML on the fly. I then got the SPListItem which had been specified for that page and added the list values to the XML document, thinking that I could easily use XSLT to render out the results. Walking the tree went something like this:
private void iterateWebs(SPWeb thisWeb)
{
if (PublishingWeb.IsPublishingWeb(thisWeb))
{
PublishingWeb pWeb = PublishingWeb.GetPublishingWeb(thisWeb);
foreach (SPListItem pageItem in pWeb.PagesList.Items)
{
if (pageItem.ContentType = f_MyContentType)
{
addPageToXml(pageItem);
}
}
}
foreach (SPWeb childWeb in thisWeb.Webs)
{
iterateWebs(childWeb);
}
}
This worked perfectly on my dev box, but moving to a location where I had a significant number of webs, I noticed that the time taken to render was becoming slow – in the order of seconds to execute.
So I added some timestamp checks to work out what was taking the time. There were a number of factors, for example, the step to get the Publishing Web was fairly slow, but overall there wasn't one particular operation that took a long time, it was just the culmulative effect of iterating through the object model.
I toyed with the idea of using some sort of caching – this wasn't something that changed frequently. But I didn't really want to get into complexities around refreshing the cache when new pages appeared. That led me to play with the SPSiteDataQuery objects, and get my hands dirty with CAML, and I implemented the same query as follows:
private const string f_ListsPattern = "<Lists ServerTemplate='{0}' Hidden='{1}'/>";
private const string f_WhereQueryPattern = "<{1}><FieldRef Name='{0}' /><Value Type='{3}'>{2}</Value></{1}>";
private const string f_OrderQueryPattern = "<OrderBy><FieldRef Name='{0}' Ascending='False' Nullable='TRUE'/></OrderBy>";
private void buildQuery()
{
SPSiteDataQuery q = new SPSiteDataQuery();
q.Lists = string.Format(f_ListsPattern, "850", "True");
q.Query = string.Format(f_WhereQueryPattern, "ContentType", "Eq", "MyContentType", "Choice");
q.Webs = "<Webs Scope='SiteCollection' />";
q.ViewFields = "<FieldRef Name='Title' /><FieldRef Name='ID' /><FieldRef Name='ContentType' /> [etc - include all the fields required]";
q.RowLimit = 10;
DataTable dt = SPContext.Current.Site.RootWeb.GetSiteData(q);
dt.TableName = "row";
DataSet ds = new DataSet("rows");
ds.Tables.Add(dt);
xDoc.LoadXml(ds.GetXml());
}
This executed in 0.5s the first time it ran after the application had reloaded, and was a very impressive 0.002s after object caching had kicked in.
I suspect that the cause of the difference in execution time is this: each object that is touched in the OM during the for loop results in a (fairly unoptimised) database query. In CAML, though, it is a single, well constructed SQL statement that is generated, and then cached automatically. And that has to be faster any day. If I remember, and have time over the next few days, I'll post some analysis using SQL Profiler to see what is actually happening during these calls.