Tuesday, December 23, 2008

XSLT note - xsl:output method

There are 3 method option in xsl:output element, xml, html, text. only xml option will output xml declaration. only text will disables output escaping. In your style sheet, you want to export < , text will output "<", but xml and html will output <

Monday, December 22, 2008

XSLT note 6 - fast search node

We can make search much faster if we generate index. We generate index by using xsl:key.

<?xml version='1.0'?> <?xml-stylesheet type="text/xsl" href="key_sample.xsl" ?> <titles> <book title="XML Today" author="David Perry"/> <book title="XML and Microsoft" author="David Perry"/> <book title="XML Productivity" author="Jim Kim"/> </titles> <?xml version='1.0'?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > <!-- create index for book based on @author --> <xsl:key name="title-search" match="book" use="@author"/> <xsl:template match="/"> <HTML> <BODY> <!-- use index title-search to search book where index value = 'David Perry' --> <xsl:for-each select="key('title-search', 'David Perry')"> <div> <xsl:value-of select="@title"/> </div> </xsl:for-each> </BODY> </HTML> </xsl:template> </xsl:stylesheet>

XSLT note 5 - Cross tab transformation

<!-- input file --> <?xml version="1.0" encoding="utf-8" ?> <?xml-stylesheet type="text/xsl" href="crosstab.xslt" version="1.0"?> <ActivityList> <Item> <Day>1</Day> <Type>Meal</Type> <Name>Breakfast</Name> <Note></Note> </Item> <Item> <Day>1</Day> <Type>Meal</Type> <Name>Dinner</Name> <Note>lots of stuff</Note> </Item> <Item> <Day>1</Day> <Type>Tour</Type> <Name>Great wall</Name> <Note></Note> </Item> <Item> <Day>2</Day> <Type>Meal</Type> <Name>Breakfast</Name> <Note></Note> </Item> <Item> <Day>2</Day> <Type>Airport</Type> <Name>Transfer to hotel</Name> <Note></Note> </Item> <Item> <Day>3</Day> <Type>Airport</Type> <Name>Transfer to airport</Name> <Note></Note> </Item> <Item> <Day>3</Day> <Type>Meeting</Type> <Name>Face to face meeting</Name> <Note></Note> </Item> </ActivityList> <!-- xslt --> <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" > <xsl:output method="html" indent="yes"/> <xsl:template match="/"> <xsl:variable name="distinctDayList" select="/ActivityList/Item[not(Day=preceding-sibling::Item/Day)]/Day"></xsl:variable> <xsl:variable name ="distinctTypeList" select="/ActivityList/Item[not(Type=preceding-sibling::Item/Type)]/Type"></xsl:variable> <html> <header> <style type="text/css"> table, td, th { border:solid 1px black } table { border-collapse:collapse; } </style> </header> <body> <h1>Cross tab demo</h1> <table> <tr> <!--build day row--> <th>Type</th> <xsl:for-each select="$distinctDayList"> <xsl:sort select="Day"/> <th> <xsl:value-of select="."/> </th> </xsl:for-each> </tr> <xsl:for-each select="$distinctTypeList"> <xsl:sort select="Type" data-type="text"/> <tr> <td> <xsl:value-of select="."/> </td> <xsl:variable name="currentType" select="."></xsl:variable> <xsl:for-each select="$distinctDayList" > <td> <xsl:for-each select="/ActivityList/Item[Day=current() and Type=$currentType]"> <xsl:value-of select="Name"/> <xsl:if test="position()!=last()"> , </xsl:if> </xsl:for-each> </td> </xsl:for-each> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet> <!-- output file --> <html><header><style type="text/css"> table, td, th { border:solid 1px black } table { border-collapse:collapse; } </style></header><body> <h1>Cross tab demo</h1> <table> <tr> <th>Type</th> <th>1</th> <th>2</th> <th>3</th> </tr> <tr> <td>Meal</td> <td>Breakfast , Dinner</td> <td>Breakfast</td> <td></td> </tr> <tr> <td>Tour</td> <td>Great wall</td> <td></td> <td></td> </tr> <tr> <td>Airport</td> <td></td> <td>Transfer to hotel</td> <td>Transfer to airport</td> </tr> <tr> <td>Meeting</td> <td></td> <td></td> <td>Face to face meeting</td> </tr> </table> </body> </html>

XSLT note 3 - attribute tricks

When you want to output the value of node to destination, you can use <xsl:value-of select="xpath" />. This works only when the destination is not in side of an attribute. If the output is in side of an attribute, you need to use {}. For example.

<xsl:output method="html"/> <xsl:variable name="sortorder">ascending</xsl:variable> <xsl:template match="employees"> <xsl:apply-templates select="employee"> <xsl:sort select="." data-type="text" order="{$sortorder}"/> </xsl:apply-templates> </xsl:template> <xsl:template match="employee"> <a href="{.}"><xsl:value-of select="."/></a> </xsl:template>

If you want to output a attribute of source element, you need to use @attributeName, or attribute::attributeName.

To add an attribute to an output node, you can also use xsl:attribute, like the following.

<xsl:template match="/"> <a> <xsl:attribute name="href">http://google.com</xsl:attribute> <xsl:text>Google</xsl:text> </a> </xsl:template>

Some time we want to convert element to attribute. For example, we want to convert

<Employee> <Name>Fred</Name> <Age>18</Age> </Employee> <Employee Name="Fred" Age="18" />

We can use this template

<xsl:template match="Employee"> <xsl:element name="{name(.)}"> <xsl:for-each select="*"> <xsl:attribute name="{name(.)}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:for-each> </xsl:element> </xsl:template> or <xsl:template match="Employee"> <xsl:copy> <xsl:for-each select="*"> <xsl:attribute name="{name(.)}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:for-each> </xsl:copy> </xsl:template>

Friday, December 19, 2008

XSLT note 3 - variable

You can basically build a variable just as building any output. The simple way is

<xsl:variable name="v" select="xpath-expression" />

But you don't have to use select. Yiou can construct your variable in the constructor. Following is some sample

<xsl:variable name="Subtotals"> <!-- consturctor: can be any markup --> <xsl:for-each select="Row"> <number> <xsl:value-of select="Quantity * Price"/> </number> </xsl:for-each> </xsl:variable> <xsl:variable name="header"> <h1 style="color:red;">This is demo</h1> </xsl:variable> <xsl:variable name="tmpResult"> <xsl:apply-templates select="$orderRow" /> </xsl:variable>

How to use variable

If a variable contains a set of nodes. you can use the variable in other XPath expressions without any limitations. For example,

<xsl:variable name="books" select="//book"/> <xsl:for-each select="$books/author"> </xsl:for-each> <!-- same as <xsl:for-each select="//book/author"> </xsl:for-each> -->

If you are using constructor to build a constructor, the variable can hold any arbitrary content, this content is called result tree fragment. You can imagine a result tree fragment (RTF) as a fragment or a chunk of XML code. You can assign a result tree fragment to a variable directly, or result tree fragment can arise from applying templates or other XSLT instructions. The following code assigns a simple fragment of XML to the variable $author.

<xsl:variable name="author"> <firstname>Jirka</firstname> <surname>Kosek</surname> <email>jirka@kosek.cz</email> </xsl:variable>

Now let's say we want to extract the e-mail address from the $author variable. The most obvious way is to use an expression such as $author/email. But this will fail, as you can't apply XPath navigation to a variable of the type "result tree fragment."

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" extension-element-prefixes="exsl" version="1.0"> ... <!-- Now we can convert result tree fragment back to node-set --> <xsl:value-of select="msxsl:node-set($author)/email"/> ... </xsl:stylesheet>

If you don't reuse the content of result tree, you can put copy-of statement to where you want your output to be.

<xsl:copy-of select="$header"/>

variable has a scope, like the following example shows, the $castList is referenced outside of the definition scope, so it is illegal.

<xsl:template match="Program" mode="Details"> <p> <xsl:variable name="castList" select="CastList" /> <xsl:apply-templates select="$castList" mode="DisplayToggle" /> </p> <xsl:apply-templates select="$castList" /> </xsl:template>

XSLT note 2 - copy template

Here is a template that copy original xml file.

<xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template>

XSLT note 1 - built-in template

A simple xslt is a empty xslt.

<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> <xsl:output method="xml" indent="yes"/> </xsl:stylesheet>

But it does something, it actually is equivalent to the following style sheet. Those template are built-in and can not be removed.

<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> <xsl:output method="xml" indent="yes"/> <xsl:template match="* | /"> <xsl:apply-templates /> </xsl:template> <xsl:template match="text() | @*"> <xsl:value-of select="." /> </xsl:template> <xsl:template match="processing-instruction() | comment()" /> </xsl:stylesheet>

Let's take a look what is the function of the template. The first template <xsl:template match="* | /"> apply all the nodes match "* | /" with this template. * is any node, "/" is root node. The <xsl:apply-templates> element first selects a set of nodes using the expression specified in the select attribute. If this attribute is left unspecified, which here is this case, all children of the current node are selected. For each of the selected nodes, <xsl:apply-templates> directs the XSLT processor to find an appropriate <xsl:template> to apply. Templates are tested for applicability by comparing the node to the XPath expression specified in the template's match attribute. If more than one template satisfies the match pattern, the one appearing with the highest priority is chosen. If several templates have the same priority, the last in the style sheet is chosen.

It seems that <xsl:apply-templates /> is same as <xsl:apply-templates select="*" />, but it is not. It is same as <xsl:apply-templates select="* | text() | processing-instruction() | comment() "/>. If we want attribute is included we should use <xsl:apply-templates select="* | @* | text() | processing-instruction() | comment() "/>. This template basically output all the value of element nodes.

Thursday, December 18, 2008

TraceSource

In my post How to control whether to output Trace, I discussed how to output behavior of Trace object. We can control destination with the system.diagnostics.trace section, and control the when to output Trace by using listener's filter or using switch.

But .net offer a better object to replace Trace object, that is TraceSource. It explicitly explicitly works with listener and switch to give user a better control. Here is an article on this issue. Below is some demo code. For new application, we should only use TraceSource object instead of Trace. Please note that now you can use both Listner filter and switch to control whether to output. The reason to use TraceSource over Trace is that TraceSource is instance object, Trace is a static object. You may use different TraceSource to trace different component. This is especially useful to third party component so that their trace may be independent of user's trace. Here is another artical Extending System.Diagnostics

class Program { public static TraceSource MasterTraceSource = new TraceSource("TraceSourceApp"); static void Main(string[] args) { Trace.WriteLine("program started..."); Trace.Assert(1 != 1, "something wrong"); // MasterTraceSource.TraceInformation("Trace information"); MasterTraceSource.TraceEvent(TraceEventType.Error, 1, "Error message."); MasterTraceSource.TraceEvent(TraceEventType.Verbose, 2, "Warning message."); MasterTraceSource.Close(); return; } } <sources> <source name="TraceSourceApp" switchName="sourceSwitch" switchType="System.Diagnostics.SourceSwitch"> <listeners> <add name="consoleListner" type="System.Diagnostics.ConsoleTraceListener"> <filter type="System.Diagnostics.EventTypeFilter" initializeData="Error"/> </add> <remove name="Default"/> </listeners> </source> </sources> <switches> <add name="sourceSwitch" value="Verbose"/> </switches>

How Trace works with Listner

Listner control destination the output of Trace. Here is how.

<trace autoflush="true" indentsize="4"> <listeners> <remove name="Default" /> <add type="System.Diagnostics.ConsoleTraceListener" name="Console" /> </listeners> </trace>

We can also use share sharedListeners, like below.

<trace autoflush="true" indentsize="4"> <listeners> <remove name="Default" /> <add name="Console" /> </listeners> </trace> <sharedListeners> <add type="System.Diagnostics.ConsoleTraceListener" name="Console" /> </sharedListeners>

How to contro whether output Trace

We already know Listner affect Trace object's output destination. But that is only an aspect of behavior, another aspect is whether the message should be output. The control this we can test a configurable switch's value to determine whether we should output the message. But we need to manually Test the the switch, or we need to write a helper class to wrap the test code. Here is the code.

class Program { static TraceSwitch switch1 = new TraceSwitch("global", "global switch"); static void Main(string[] args) { Trace.WriteLine(switch1.Level); Trace.Assert(2 == 1, "error message is here, because assert fail(condition is false)"); if (switch1.TraceError) { Trace.TraceError("An error happend"); } if (switch1.TraceInfo) { Trace.TraceInformation("just for your information"); } if (switch1.TraceWarning) { Trace.TraceWarning("just a warning"); } } }

We can also use another filter feature of Listener, without using switch1.

<sharedListeners> <add type="System.Diagnostics.ConsoleTraceListener" name="Console"> <filter type="System.Diagnostics.EventTypeFilter" initializeData="Error"/> </add> </sharedListeners>

Trace.Assert

In nunit or other test framework, we have Assert object to test whether result is as expected. If assert is false, then en exception is through. Trace.Assert is provide similar function, but for different purpose. It is for diagnostic. When assert is false, it output the error message to a listener. There is default listener in .net, which is DefaultTraceListener An instance of this class is automatically added to the Debug..::.Listeners and Trace..::.Listeners collections. Explicitly adding a second DefaultTraceListener causes duplicate messages in the debugger output window and duplicate message boxes for asserts. The DefaultTraceListner looks like throwing an exception, but it is not actually an exception, it is the output behavior. If you remove the DefaultTraceListner, you will not see this output.

Forms - Based Authentication

While it is possible to change a newly created SharePoint site collection to use FBA instead of Windows authentication, it is usually a better idea to extend a new Web application from an existing one and configure the new Web application for FBA, leaving the original one set to Windows authentication. There are numerous reasons for this, one being that SharePoint ’ s search uses NTLM (Windows authentication) to authenticate and crawl the site when indexing the content. In the following example, this is the model that is used.

The authentication provider model contains three different providers: membership, role, and profile . The membership provider is the one responsible for the users, including authentication. The role provider is used to determine which users are in which groups. Finally, the profile provider facilitates creating profiles for each user defined in the authentication store. These profiles can contain custom - defined properties along with the standard first and last name, among other properties.

At a minimum, a membership and role provider must be defined. The profile provider is not required, but be aware that omitting it can have adverse effects. For example, a common misperception is that FBA breaks SharePoint ’ s My Site capability. This is not true. My Sites require a profile for the user in order to tie the My Site to the user. If no profile provider is defined, SharePoint cannot create a My Site for that user, which is why many people get the impression that FBA breaks My Sites.

Please ensure the user database for form authentication is accessible.

SharePoint Group

SharePoint allows permission levels to be applied to site users as well as security groups, such as Active Directory groups, that have been added to the site. However, this is not the recommended approach. Rather, Microsoft recommends that site owners and administrators assign permission levels to SharePoint groups and then add site users and security groups to the SharePoint groups.

Friday, December 12, 2008

xxx Approval and Approval Status in list

After a list is enabled "Content Approval", the list has approval status field shows up in the default view. This is system field just like modified, modified by. It has nothing to do with workflow.

The xxx approval field is for workflow xxx. xxx is the workflow name. Even a user approve the workflow in the workflow form, the item's approval status is not necessary synchronized depending your workflow's behavior. To really approve the the item you have to use drop down menu of item, select "approved/reject".

WCF transport-level session

All bindings support configuring the contract on the endpoint with SessionMode.Allowed. The SessionMode property does not refer to the instancing mode, but rather to the presence of a transport-level session (or its emulation in the case of the WS bindings). As its name implies, when the SessionMode property is configured with SessionMode.Allowed, it merely allows transport sessions, but does not enforce it. The exact resulting behavior is a product of the service configuration and the binding used. If the service is configured for per-call, it still behaves as per-call service. When the service is configured for a per-session service, it will behave as a per-session service only if the binding used maintains a transport-level session. For example, the BasicHttpBinding can never have a transport-level session due to the connectionless nature of the HTTP protocol. The WSHttpBinding without security and without reliable messaging will also not maintain a transport-level session. In both of these cases, even though the service is configured with InstanceContextMode.PerSession and the contract with SessionMode.Allowed, the service will behave as a per-call service, and the calls to Dispose() are asynchronous; that is, the client is not blocked after the call while WCF disposes of the instance.

Tuesday, December 9, 2008

WF Dependency Property snippet is just three letters!

WF Dependency Property snippet is just three letters!

ManualWorkflowSchedulerService

By default, workflow runtime use DefaultWorkflowSchedulerService as scheduler, what this means is that the workflow instance run in a separate thread. So if you want to wait for the workflow to finished, you need AutoResetEvent object to synchronize the thread. But in asp.net you make want to use a single thread. Here is an article Using Workflows with ASP.NET.

//you need to add this to to runtime initialization ManualWorkflowSchedulerService manualService = new ManualWorkflowSchedulerService(); _workflowRuntime.AddService(manualService); //you need to perform additional steps //to run the workflow. WorkflowInstance instance = _workflowRuntime.CreateWorkflow( typeof(SimpleCalculatorWorkflow.Workflow1), wfArguments); instance.Start(); ManualWorkflowSchedulerService manualScheduler = _workflowRuntime.GetService(typeof(ManualWorkflowSchedulerService)) as ManualWorkflowSchedulerService; manualScheduler.RunWorkflow(instance.InstanceId);

WF runtime engine

The workflow runtime is just a class, you create a instance of the class in your application, make it a static or global, so the instance live through all the live of your application, in this case, your application is hosting the workflow runtime. In fact your application can create more than one runtime. However, you typically won't need to do that. A single instance of the workflow runtime is capable of managing the execution of multiple workflow instances. One possible reason to create multiple runtime instances in a single appDomain would be if each instance required a different set of conflicting runtime services or configuration settings. You can also extend the WorkflowRuntme class to initialize the runtime engine.

Beginning with .NET 3.5, Microsoft has added the ability to expose workflow instances as WCF services. To implement this, they developed a hybrid workflow runtime class named WorkflowServiceHost (found in the System.ServiceModel namespace and packaged in the System. WorkflowServices assembly). This class combines the basic capabilities of WorkflowRuntime (it hosts workflow instances) with ServiceHost (a WCF class that exposes services to clients). Use WorkflowServiceHost when you implement your own service host application instead of using Internet Information Services (IIS) or Windows Activation Services (WAS).

The runtime engine provides an execution environment for your workflows. You don’t directly execute workflows within your application. Instead, you ask the runtime engine to create an instance of a workflow, which you then instruct to start.

By default, workflows execute asynchronously in a thread that is managed by the runtime engine. This allows you to start multiple workflows from your host application at the same time, with all of them under the control of the runtime engine.

Each workflow can go through multiple execution states throughout its lifetime. For example, all workflows start in the created state and then move into the running state when execution begins. The workflow can also pass into states such as suspended, terminated, or completed. Other events associated with a workflow such as idled, persisted, loaded, or unloaded are possible. It is the runtime engine that manages the life and death of each workflow as it passes through these states.

The runtime engine is also responsible for scheduling and managing execution threads, workflow persistence, workflow transactions (committing of batched work), and workflow tracking. However, while the responsibility for these tasks rests with the runtime engine, it doesn’t actually handle these duties by itself. Each of these tasks has been implemented as a runtime service that you create and register with the runtime engine during application startup. This modular design permits you to swap out a default implementation in favor of one that you’ve developed.

Included in the runtime engine is a flexible rules evaluation engine. This engine is able to evaluate simple rule conditions such as those that you add to an IfElseActivity or WhileActivity. Or it can handle a complex set of rules (called a RuleSet) that you specify within a PolicyActivity. A RuleSet defines multiple rules that are evaluated in sequence and automatically reevaluated based on the actions of rules later in the set.

The workflow runtime engine also exposes several public events that can be handled by the host application. These events allow you to directly monitor the status of each workflow as it passes between execution states. Each event carries with it an instance of the WorkflowInstance class. This class acts as a proxy to the real workflow instance that is managed by the runtime engine.

Get the output from a workflow

The output of the workflow instance is can be obtained by the OutputParameters like the following.

_workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) { _result = (Double)e.OutputParameters["Result"]; _waitHandle.Set(); };

Debugger WF

To debug a workflow, you need to set the workflow's host project to be the startup project. If this project is class library project, you need to set the default start action, so that the start action trigger a process.

Workflow are different

Workflows represent a different programming model. It’s a model that promotes a clear separation between what to do and when to do it. This separation allows you to change the when without affecting the what. Workflows generally use a declarative programming model rather than a procedural one. With this model, business logic can be encapsulated in discrete components. But the rules that govern the flow of control between components are declarative.

Sunday, December 7, 2008

Site column and field type

They are different concept. Site column is higher level concept, and field type are lower level. Site column reference field type. Site column examples are City, Company, FirstName. It can be reused when create new content type and list. Field type examples are Text, Choice, Notes. But WSS3 allow user to create a customized field types. The motivation for doing this is to gain a greater level of control over initialization, rendering, and data validation that goes on behind a column.

A example of site column is as follow.

<Field ID="{0C5BDEB7-0E0E-4c38-A2E5-F39941E61CE9}" SourceID="http://schemas.microsoft.com/sharepoint/v3" Name="Industry" StaticName="Industry" DisplayName="Industry" Type="Choice" Format="RadioButtons" Group="Litware Columns"> <CHOICES> <CHOICE>High Tech</CHOICE> <CHOICE>Legal</CHOICE> <CHOICE>Medical</CHOICE> </CHOICES> <Default>High Tech</Default> </Field>

A custom field type represents a new data type for columns. A custom field type is wrttern in managed code and compiled into .net assembly that must be installed in GAC. A custom field has two responsibility the business logic, and render UI. So here the UI can be separated into another class, BaseFieldControl.

// example of creating a custom field type public class CompanySizeField : SPFieldText { public CompanySizeField(SPFieldCollection fields, string fieldName) : base(fields, fieldName) { } public CompanySizeField(SPFieldCollection fields, string typeName, string displayName) : base(fields, typeName, displayName) { } public override Microsoft.SharePoint.WebControls.BaseFieldControl FieldRenderingControl { get { BaseFieldControl control = new CompanySizeFieldControl(); control.FieldName = this.InternalName; return control; } } // Validate the string. If not valid, throw an SPFieldValidationException public override string GetValidatedString(object value) { if (this.Required || value.ToString().Equals(string.Empty)) { throw new SPFieldValidationException("Company size not assigned"); } return base.GetValidatedString(value); } } // custom field type uses helper class to initialize and render control //this FieldControl use a user control to to render //the TemplateContainer public class CompanySizeFieldControl : BaseFieldControl { protected DropDownList CompanySizeSelector; protected override string DefaultTemplateName { get { return @"CompanySizeFieldControl"; } } public override object Value { get { this.EnsureChildControls(); return this.CompanySizeSelector.SelectedValue; } set { EnsureChildControls(); this.CompanySizeSelector.SelectedValue = (string)this.ItemFieldValue; } } protected override void CreateChildControls() { if (this.Field == null || this.ControlMode == SPControlMode.Display) return; base.CreateChildControls(); this.CompanySizeSelector = (DropDownList)TemplateContainer.FindControl("CompanySizeSelector"); if (this.CompanySizeSelector == null) throw new ConfigurationErrorsException("Corrupted CompanySizeFieldControl.ascx file."); if (!this.Page.IsPostBack) { this.CompanySizeSelector.Items.AddRange(new ListItem[]{ new ListItem(string.Empty, null), new ListItem("Mom and Pop Shop (1-20)", "1-20"), new ListItem("Small Business (21-100)", "21-100"), new ListItem("Medium-sized Business (101-1000)", "101-1000"), new ListItem("Big Business (1001-20,000)", "1001-20000"), new ListItem("Enterprise Business (over 20,000)", "20000+") }); } } }

The field control use a user control as template, so the user control name must be named after the value of DefaultTemplateName property, in this case the name is "ComapanySizeFieldControl" , it should be copied to controltemplates folder.

<SharePoint:RenderingTemplate ID="CompanySizeFieldControl" runat="server"> <Template> <asp:DropDownList ID="CompanySizeSelector" runat="server" /> </Template> </SharePoint:RenderingTemplate>

A backup issue linked with site definition

In WSS, every site is provisioned from a specific site definition. This is true for all top-level sites as well as child sites nested within a site collection. Once a site is provisioned from a particular site defintion, it picks up a dependency on that site definition that remains in effect for the lifetime of the site. A site's dependency on its underlying site defintion can never be removed or changed, and the site definition must be installed and remain functional in the farm for the site to continue working properly.

Consider a scenario in which you create a custom site definition and deploy it within a particular WSS farm. Now imagine that you use this site definition to provision the top-level site within a new site collection. What would happen if you attempted to back up the site collection along with its top-level site by using the STSADM.EXE command-line utility and then restore it in another WSS farm? This would not work properly unless your custom site definition is installed in both farms.

Friday, December 5, 2008

Page Layout

Master pages enable developers and designers to define the overall look and feel of the Publishing site with just a single file, along with some additional branding files such as CSS or images. Just as in ASP.NET 2.0 sites, SharePoint sites also leverage content pages that fill in the content placeholders defined within a master page. Publishing sites take this a bit further by introducing a type of content page called a page layou. Page layouts, when combined with the master page, define the rendering and layout of a page. When the page layout is requested, SharePoint fetches the master page referenced within the SPWeb.CustomMasterUrl property and merges the two together. Developers and designers use page layouts to host editable regions of a page, implemented with Web Parts and field controls.

Page layouts have a special relationship with content types within a Publishing site. Each page layout must be associated with exactly one content type. This content type must inherit from the

Page content type

found in the Publishing Content Types group. Content types are used in a Publishing site to define the schema and rules for a particular type of content. For example, a Press Release content type may have fields for the title and byline, the date of the release, the press release body, optionally some reference links, as well as references with short bios for other companies mentioned in the press release. In addition, it may also have a special workflow associated with it defining a special approval process for the press release.

Keep in mind that the content type only defines the schema and rules for the type of content; it does not address the presentation in any way. This is where page layouts come into play. Page layouts, when combined with a master page, define the rendering/look and feel of a requested page. In addition, developers can associate multiple page layouts with a single content type to give content owners the utmost control in selecting different rendering options for a particular page type. When a content owner initiates the process of creating a new page within a ublishing site, the first thing he or she has to do is select a content type/page layout combination.

Moreover, content owners are not restricted to the page layout that is selected at the time of page creation. At any point in the future, even after the page has been published, a content owner can edit the page and change the selected page layout. The only limitation is that the only page layouts available are those associated with the content type selected when the page was created. This is because a page’s content type cannot be switched from one content type to another after it has been created. In addition, page layouts can only be associated with exactly one content type; no page layout can be associated with more than one content type.

Page layout is the layout of the associated page, which is created using a content type. A Page layout is like a xslt to transform a xml(instance) of a content type(xsd). When I want to edit an instance, this instance is always instance of the associated content type(xsd), not instance of xslt. When create page layout in sharepoint designer, the first step is to select a content type(xsd). And give it a name and title. The page layout will be saved in master page gallary. So the page layout is a file. In class library, page layout inherit from PublishingLayoutPage, which inherit from WebPartPage. In sharepoint, Page Layout is a content type, it inherit from system page layout, which inherit from Page. You can add web part, field control, the field defined in the associated content type(xsd), also available. Below is example of page layout

<%@ Page language="C#" Inherits="Microsoft.SharePoint.Publishing.PublishingLayoutPage,Microsoft.SharePoint.Publishing, Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" meta:progid="SharePoint.WebPartPage.Document" %> <%@ Register Tagprefix="SharePointWebControls" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="PublishingNavigation" Namespace="Microsoft.SharePoint.Publishing.Navigation" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <asp:Content ContentPlaceholderID="PlaceHolderPageTitle" runat="server"> <SharePointWebControls:FieldValue id="PageTitle" FieldName="Title" runat="server"/> </asp:Content> <asp:Content ContentPlaceholderID="PlaceHolderMain" runat="server"> <h1>Advance Recruit!</h1> <SharePointWebControls:TextField FieldName="JobTitle" runat="server" id="TextField1"> </SharePointWebControls:TextField> </asp:Content>

The question is master page come into play, when edit page layout in sharepoint , it is render in a master page.

To create instance of associated content type, first you need to enable a content type to a document library. Then select new "the associated content type", you then need to page layout. The page layout can be changed later.

There are two way to edit a page. one is view the page, and then select "Edit Page" in the site action.

Another way is to go the document library of the page, and use the ECB menu. To edit the content of the instance, we can do this in the IE, select the ECB menu, select edit properties. To change the page layout(xslt), we can select ECB menu, select edit in sharepoint designer, sharepoint designer will prompt you, that "The page cannot be edited in sharepoint designer, you can the content in the browser, or edit the corresponding page layout in the sharepoint designer. " , then select edit in browser, then select page menu, select "Page setting and schedule", then change the page layout selection. Below is sample of instance of content type

<%@ Page Inherits="Microsoft.SharePoint.Publishing.TemplateRedirectionPage, Microsoft.SharePoint.Publishing,Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" %> <%@ Reference VirtualPath="~TemplatePageUrl" %> <%@ Reference VirtualPath="~masterurl/custom.master" %> <html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"> <head> <!--[if gte mso 9]><xml> <mso:CustomDocumentProperties> <mso:PublishingContact msdt:dt="string">1073741823</mso:PublishingContact> <mso:display_urn_x003a_schemas-microsoft-com_x003a_office_x003a_office_x0023_PublishingContact msdt:dt="string"> System Account</mso:display_urn_x003a_schemas-microsoft-com_x003a_office_x003a_office_x0023_PublishingContact> <mso:PublishingContactPicture msdt:dt="string"></mso:PublishingContactPicture> <mso:PublishingContactName msdt:dt="string"></mso:PublishingContactName> <mso:ContentTypeId msdt:dt="string"> 0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007948130EC3DB064584E219954237AF390074DECF7CA992D04DABE3BF7005B8DB9C0002B1A009B64D6C40A65B11619F9CAE59</mso:ContentTypeId> <mso:Comments msdt:dt="string"></mso:Comments> <mso:PublishingContactEmail msdt:dt="string"></mso:PublishingContactEmail> <mso:PublishingPageLayout msdt:dt="string">http://mismitdfyang/_catalogs/masterpage/AdvancedRecruitLayout.aspx, Advance Recruit</mso:PublishingPageLayout> <mso:JobTitle msdt:dt="string">Senior SharePoint Developer</mso:JobTitle> <mso:ScheduleEndNotificationIntervalUnit msdt:dt="string">0</mso:ScheduleEndNotificationIntervalUnit> <mso:Audience msdt:dt="string"></mso:Audience> <mso:ScheduleEndNotificationInterval msdt:dt="string">0</mso:ScheduleEndNotificationInterval> <mso:ReviewRequestInterval msdt:dt="string">0</mso:ReviewRequestInterval> <mso:ReviewRequestIntervalUnit msdt:dt="string">0</mso:ReviewRequestIntervalUnit> </mso:CustomDocumentProperties> </xml><![endif]--> <title>Want ta sharepoint developer</title></head>

It seems to me that page layout is like nested master page. It merge with master page, however, you can add web part, and user contents, and of course most importantly, the field controls generated by associated content type(xsd)

A safe master page

The master page use contentplaceholder as reserve space for the client to fill in it with customized content. If you develop a master page with a placeholder, it is optional for the content page to fill in the placeholder. If the client fill in a placeholder, which is not defined in master page, this will throw an exception. So to be safe, the master page, should have all the placeholder that all client pages use. MSDN has an article about How to create a minimal master page. But is is not necessary, if you develop a master page which will never be applied to the content page out of the box, and it is only used by your customized content page. In this case , you have full control of what place holder be put in the master page.

But you can control the whether the client page's content is visible or not in the master page. There is the trick.

<asp:panel visible=”false” runat=”server”> <asp:ContentPlaceHolder ID=”PlaceHolderPageImage” runat=”server” /> <asp:ContentPlaceHolder ID=”PlaceHolderBodyLeftBorder” runat=”server” /> </asp:panel>

synchronize master page for application page and site page

The master page of application page is under "_layouts" folder, an example is like MasterPageFile="~/_layouts/application.master". Here is trick to demo how to switch it to the site's master page.

public class SuperBrandingModule : IHttpModule { public void Init(HttpApplication context) { context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute); } void context_PreRequestHandlerExecute(object sender, EventArgs e) { Page page = HttpContext.Current.CurrentHandler as Page; if (page != null) { page.PreInit += new EventHandler(page_PreInit); } } void page_PreInit(object sender, EventArgs e) { Page page = sender as Page; if (page != null) { // Is there a master page defined? if (page.MasterPageFile != null) { // only change the application.master files as those are the offenders if (page.MasterPageFile.Contains("application.master")) { SPWeb site = SPContext.Current.Site.RootWeb; if (site.Properties["CurrentMasterPage"] != null) { string CurrentMasterPage = site.Properties["CurrentMasterPage"]; if (!CurrentMasterPage.Equals(string.Empty)) { page.MasterPageFile = CurrentMasterPage; } } } } } } public void Dispose() { } }

SharePoint RPC - URL protocal

You can use URL Protocol in combination with Collaborative Application Markup Language (CAML) and Windows SharePoint Services Remote Procedure Call Protocol (RPC) to post requests to a front-end Web server running Windows SharePoint Services. Use the CAML Method element to post a single request, or a Batch element containing multiple Method elements to post multiple requests, through the post body of a form in an .aspx page. The following programming task shows how to create a form for posting requests. Go to sharpe

http://moss1:9001/sites/team/_vti_bin/owssvr.dll?Cmd=Display&List={86E88F11-F330-4F3D-A475-30056687E39B}&XMLDATA=TRUE

More can be found here

ASP.NET expression builder

Here is an article about asp.net expression

Thursday, December 4, 2008

Site definition

A site definition itself does not represent a creatable site template. Instead, a site definition contains one or more configurations, and these configurations are what appear to users as creatable site templates. Therefore, the STS site definition contains three different configurations: Team Site, Blank Site, and Document Workspace.

Similar to a WSS feature, a site definition is defined with a set of Collaborative Application Markup Language (CAML)-based files that are deployed within a named directory on the file system of each front-end Web server in the farm. Site definitions are deployed within the 12\TEMPLATE\SiteTemplates directory. The core file of the site template is 12\TEMPLATE\SiteTemplates\{sitetemplate_name}\xml\onent.xml. It is referenced in the 12\TEMPLATE\{culture}\XML directory in WEBTEMP.XML files, where the folder is the locale identifier (12\TEMPLATE\1033\XML for US English).

Here is sample of the onet file, it define every thing about the site

A xml file in the 12\TEMPLATE\{culture}\XML folder can contains the configuration of more than one site templates.Here is an exmaple

When creating a new site by using the STSADM.EXE command-line utility or through custom code, you are often required to reference a site definition and one of its configurations by name. This is done by specifying the name of the site definition followed by the pound sign and the integer identifier of the configuration. For example, you can use STS#0 to reference the site template titled Team Site and STS#1 to reference the site template titled Blank Site. The following example uses one of these site template references when creating a new top-level site by using the STS command-line utility.

STSADM.EXE -o createsite -url http://Domain.com
                         -ownerlogin Domain\Administrator
                         -owneremail administrator@Domain.com
                         -sitetemplate STS#1

Wednesday, December 3, 2008

WebPart can be only edit if it is hosted in WebPart Zone

We can add web part into a content page in sharepoint directly, but they can not be customized in share browser, it be customized in sharepoint designer. If you want user to customize it in browser, you have put in web part zone.

Tuesday, December 2, 2008

Web folder in IE7

IE6 support opening a url as web folder, but this function is gone in ie7. But web folder function is still accessible in windows explorer. select the address bar , select web folders, select menu file -> new web folder, enter url. Then click the web folder it should be ok.

Content type

Content types are a powerful new enhancement introduced in WSS 3.0. The central idea is that a content type defines the underlying schema for either an item in a list or a document in a document library. However, it’s important to understand that content types are defined independently outside the scope of any list or document library. After you have created a content type, you can use it across several different lists or several different document libraries.

Unlike a list, it is not possible to create a column in a content type directly based on an underlying field type. Columns within a content type must be defined in terms of existing site columns.

How to create site column

Site column is a reusable elements to build a content type or define a list. For example, if you have lots of lists which is using zip code, instead of redefining the zip code in all the lists, you can create a zip code site column so that you can use it across all the lists. Here site column and field type means the same thing, it is like int or string in .net. But it also can have some logic or UI associate with it.There are three ways to build a site column or field types.

First you can use IE to do that manually. Secondly, you can use feature to deploy a field definition authorized with CAML, after activate to a site, the site can pick up the site column. Thirdly, you can build a custom field type.

fields definition authorized with CAML

<Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Field ID="{0C5BDEB7-0E0E-4c38-A2E5-F39941E61CE9}" SourceID="http://schemas.microsoft.com/sharepoint/v3" Name="Industry" StaticName="Industry" DisplayName="Industry" Type="Choice" Format="RadioButtons" Group="Litware Columns"> <CHOICES> <CHOICE>High Tech</CHOICE> <CHOICE>Legal</CHOICE> <CHOICE>Medical</CHOICE> </CHOICES> <Default>High Tech</Default> </Field> <Field ID="{BED99611-EDE0-41cb-8C05-0FBD96A15D0F}" Type="Note" RichText="TRUE" AppendOnly="TRUE" Name="ActivityNotes" DisplayName="Activity Notes" Sortable="FALSE" SourceID="http://schemas.microsoft.com/sharepoint/v3" Group="Litware Columns"> </Field> </Elements>

A custom field type represents a new data type for columns. Custom field types are appealing to .NET developers because they are written in managed code and compiled into .NET assembly DLLs that must be installed in the Global Assembly Cache (GAC). Along with managed code to perform initialization and validation, a custom field type is also defined in terms of one or more ASP.NET server-side controls that give you extra control over rendering and enable you to leverage techniques that are popular in standard ASP.NET development.

CAML Debugging Through Diagnostic Logging

CAML content definitions have no debugging support through Visual Studio. This can make it frustrating to develop custom content types, lists, and other provisioning components. You can, however, enable verbose logging through SharePoint Central Administration. From the Operations tab, under Logging and Reporting, select Diagnostic Logging. You can then set Event Throttling to report on all categories, to report on events of information criticality and above, and to report verbosely. For a personal development server, you can use just one log file for a period of ten minutes. The default path for the logs is C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\LOGS. You may want to import the log into Microsoft Office Excel 2007 or just use Visual Studio or Notepad to read the file.

Monday, December 1, 2008

SPGridView

SharePoint has some very useful controls defined in the Microsoft.SharePoint.WebControls namespace that extend common ASP.NET controls with the SharePoint functionality and look and feel. Perhaps the most useful Web control is SPGridView. The SPGridView control extends the ASP.NET GridView class with SharePoint’s style declarations and has additional support for WSS data sources such as Lists and Cross-Site Queries using the SPDataSource class.

Dynamic Master Page , Application Page's Master Page

In sharepoint, the content page can use a master page like below.

<%@ Page language="C#" MasterPageFile="~masterurl/default.master" Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage,Microsoft.SharePoint,Version=12.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" meta:webpartpageexpansion="full" meta:progid="SharePoint.WebPartPage.Document" %>

When MasterPageFile attribut is either "~masterurl/default.master" or "~masterurl/custom.master", the master page is dynamic master page, in this case you don't need to modify the content page to change its master page, master page is dynamically determined by two site property, "MasterUrl" or CustomMasterUrl. If you specify other values, then master page is bound.

  1. System Master Page

    Page language="C#" MasterPageFile="~masterurl/default.master"

    Property of "spweb.MasterUrl" is used to represent this token. It is most frequenet used Master page. We use the system master page for all forms and view pages in this site.

  2. Site Master Page

    Page language="C#" MasterPageFile="~masterurl/custom.master"

    Property of "spweb.CustomMasterUrl" is used to represent this token.The site master page will be used by all publishing pages

Although WSS 3.0 sites do not utilize the SPWeb.CustomMasterUrl property, MOSS 2007 publishing sites make heavy use of it. All page layouts are automatically configured to use the master page defined in the SPWeb.CustomMasterUrl property when rendering the site. The master page defined in SPWeb.MasterUrl property is till used for standard SharePoing Pages such as list or form pages.

WSS also supports two static master page tokens that start with either~site or~sitecollection. These static tokens allow you to hardcode a relative path to a master page from the root of either the current site or the current site collection. This allows you to create site page templates that point to a specific custom master page instance without requiring any code to perform redirection. For example, MasterPageFile="~sitecollection/_catalogs/masterpage/fred.master" refer to the root site of site collection's fred.master.

Application Page's Master Page

Application's Page refer to the page reside in the "~/_layouts" folder are served by the files in file systems. It is controlled independently from the content page. Default master page for application page is

MasterPageFile="~/_layouts/application.master"

Reference an dynamic assembly

<%@ Register TagPrefix="msdn" Namespace="MsdnMag" Assembly="__code" %>

Deploy a custom master template

<Module Name="MasterPages" List="116" Url="_catalogs/masterpage"> <File Url="Litware.master" Type="GhostableInLibrary" /> </Module> protected void cmdApplyCustomBrand_Click(object sender, EventArgs e) { SPWeb site = SPContext.Current.Site.RootWeb string MasterUrlPath = site.ServerRelativeUrl; if (!MasterUrlPath.EndsWith(@"/")) MasterUrlPath += @"/"; MasterUrlPath += @"_catalogs/masterpage/Litware.master"; ApplyCustomBrand(MasterUrlPath, site); } protected void ApplyCustomBrand(string MasterUrlPath, SPWeb site) { site.MasterUrl = MasterUrlPath; site.Update(); // use recusion to update all child sites in site collection foreach (SPWeb child in site.Webs) { ApplyCustomBrand(MasterUrlPath, child); } }

However, the ApplyCustomBrand method has also been written to enumerate through all child sites below the top-level site and recursively call itself to update them. This recursion continues to crawl the hierarchy of child sites until the MasterUrl property of every site within the site collection is updated to redirect all site pages so that they link to the instance of litware.master that is provisioned in the Master Page gallery of the top-level site.

Delegation Controls

WSS introduces a powerful new extensibility mechanism known as delegate controls. In some ways, a delegate control is similar to a named placeholder because it defines a region inside a master page that can be substituted with unique content to meet the needs of a particular business solution. Like a placeholder, a delegate control can optionally supply default content that is used until a substitution is performed.

One major difference when compared to placeholders is that the substitution mechanism for replacing the contents of a delegate control is driven through feature activation. Therefore, you can replace what’s defined inside a delegate control in default.master without requiring any changes to default.master or the site pages that link to it. All you need to do is define a Control element within a feature and then activate that feature.

Sunday, November 30, 2008

Instructing a user control is safe

You can instructing a user control that is safe.

<SafeControl Src="~/_controltemplates/*" IncludeSubFolders="True" Safe="True" AllowRemoteDesigner="True" />

Safe Mode Processing

The uncustomized site page is using a file in file system, and they are executed in compiled mode, so the security is more lex. When it is customized the pages is saved in database, and the security is tightened up. These pages are parsed and processed in a special mode known as safe mode, these is to prevent designer inject is untrustable code into the page. For example, the following page can be run correctly before customized by sharepoint designer, but after customization, it can not be run anymore.

<%@ Page Language="C#" MasterPageFile="~masterurl/default.master" meta:progid="SharePoint.WebPartPage.Document" %> <asp:Content ID="main" runat="server" ContentPlaceHolderID="PlaceHolderMain"> <h3>Page 2</h3> <% Response.Write("Hello world from server-side script!"); %> </asp:Content>

In some case, you might want to turn off the protection offered by safe mode, you can do that like the following demo.

<SharePoint> <SafeMode ... > <PageParserPaths> <PageParserPath VirtualPath="/sites/Sales/SitePages/*" IncludeSubFolders="true" CompilationMode="Always" AllowServerSideScript="true" /> </PageParserPaths> </SafeMode> </SharePoint>

Note that a page must be compiled into an assembly DLL to support in-line script, which means that it is not valid to assign a value of Never to the CompilationMode attribute while assigning a value of true to the AllowServerSideScript attribute. Also note that you can assign a value of Auto instead of a value of Always to the CompilationMode attribute. This has the effect of compiling only pages that contain in-line script. When the CompilationMode attribute has a value of Auto, pages without in-line script are still run in no-compile mode.

It is possible to enable in-line script for all site pages within a Web application by configuring the VirtualPath attribute with a value of /* and then setting the CompilationMode attribute to a value of Always or Auto. However, two significant factors should motivate you not to do this.

The first factor is security. By enabling in-line script for all site pages within a Web application, you open the door to attacks on the Web server because any user who has the ability to customize a page can freely write managed code that executes on the Web server.

The second factor pertains to scalability. Earlier in this chapter, I discussed how no-compile pages are more scalable than compiled pages in a large Web application. WSS experiences scaling problems if your Web application attempts to compile and load thousands of assembly DLLs for all of your customized pages. At the very least, you should prefer a CompilationMode setting of Auto instead of Always so that only pages that actually contain script are compiled into assembly DLLs, whereas those pages that do not contain script continue to be parsed and processed in no-compile mode.

Safe mode processing goes a step beyond protecting against in-line script by also considering what controls a user might place on a customized page. For example, imagine a scenario in which a site administrator tries to mount an attack by adding a server-side control to a site page and parameterizing it in a certain way. Safe mode allows the farm administrator to determine which controls can be used in pages that are processed in safe mode.

Customized pages can only contain server-side controls that are explicitly registered as safe controls. Registering a control as a safe control is accomplished by adding a SafeControl entry into the web.config file for the hosting Web application.

<SafeControls> <SafeControl Assembly="Microsoft.SharePoint, …" Namespace="Microsoft.SharePoint.WebControls" TypeName="*" AllowRemoteDesigner="True" /> </SafeControls>

If you want to run server control without the above entry, you need to do the following.

<SharePoint> <SafeMode ... > <PageParserPaths> <PageParserPath VirtualPath="/sites/Sales/*" AllowUnsafeControls="true" /> </PageParserPaths> </SafeMode> </SharePoint>

Note that using this option affects only which server-side controls can be added to a page when customizing a page with a tool, such as the SharePoint Designer. This configuration option does not extend to control instances when users are adding Web Parts to Web Part zones on a page through the browser. Assembly DLLs containing Web Parts must always be explicitly registered by using SafeControl elements for users to be able to place them inside Web Part zones.

Customized Site Page

A customized site page should be compatible with sharepoint designer, like the following.

<%@ Page MasterPageFile="~masterurl/default.master" meta:progid="SharePoint.WebPartPage.Document" %> <asp:Content runat="server" ContentPlaceHolderID="PlaceHolderMain"> <h3>Hello World</h3> A simple page template used to create site pages </asp:Content>

User control in site page

The site Page can be added to the site page in site page in sharepoint directly(not wrapped by web part). You can do these using sharepoint designer.

The control need to put in controltemplates in the template folder. To reference it in site page, use the _controltemplates folder like the following.

<%@ Register TagPrefix="luc" TagName="FileViewer" src="~/_controltemplates/Litware/FileViewer.ascx" %>

Deploying web parts to customized site pages.

There are two ways to deploy web part pages to a site. one is using the elements.xml to define what is inside the web part zone, like the following.

<File Url="WebPartPage.aspx" Name="WebPartPage03.aspx" Type="Ghostable" > <!-- Add a Web Part to left zone --> <AllUsersWebPart WebPartZoneID="Left" WebPartOrder="0"> <![CDATA[ <WebPart xmlns="http://schemas.microsoft.com/WebPart/v2" xmlns:cewp="http://schemas.microsoft.com/WebPart/v2/ContentEditor"> <Assembly>Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly> <TypeName>Microsoft.SharePoint.WebPartPages.ContentEditorWebPart</TypeName> <Title>Yet Another Web Part is Born</Title> <FrameType>TitleBarOnly</FrameType> <cewp:Content> This Web Part was added through declarative logic </cewp:Content> </WebPart> ]]> </AllUsersWebPart> <!-- Add a Web Part to right zone --> <AllUsersWebPart WebPartZoneID="Right" WebPartOrder="0"> <![CDATA[ <WebPart xmlns="http://schemas.microsoft.com/WebPart/v2" xmlns:iwp="http://schemas.microsoft.com/WebPart/v2/Image"> <Assembly>Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly> <TypeName>Microsoft.SharePoint.WebPartPages.ImageWebPart</TypeName> <FrameType>None</FrameType> <Title>Watch My Gears Run</Title> <iwp:ImageLink>/_layouts/images/GEARS_AN.GIF</iwp:ImageLink> </WebPart> ]]> </AllUsersWebPart> </File>

Another way is to adding the web parts using code during the feature activating events, like the following.

SPFile page = site.GetFile("SitePages/WebPartPage02.aspx"); SPLimitedWebPartManager mgr = page.GetLimitedWebPartManager(PersonalizationScope.Shared); // add ContentEditorWebPart to Left Zone ContentEditorWebPart wp1 = new ContentEditorWebPart(); wp1.Title = "My Most Excellent Title"; wp1.ChromeType = PartChromeType.TitleOnly; wp1.AllowClose = false; XmlDocument doc = new XmlDocument(); string ns1 = "http://schemas.microsoft.com/WebPart/v2/ContentEditor"; XmlElement elm = doc.CreateElement("Content", ns1); elm.InnerText = "This Web Part was added through code"; wp1.Content = elm; mgr.AddWebPart(wp1, "Left", 0); // add ImageWebPart Web Part to Right Zone ImageWebPart wp2 = new ImageWebPart(); wp2.ChromeType = PartChromeType.None; wp2.ImageLink = @"/_layouts/images/IPVW.GIF"; mgr.AddWebPart(wp2, "Right", 0);

SharePoint Feature

Feature is mechanism that SharePoint used to deploy customized components. The built in components like document list, team site also deployed using feature. So basically, everything can be deployed as feature, for example list definition, content type, site column, workflow and etc, except a site template. The core of the it are two files feature.xml and elements.xml.

When you deploy features, you put all your files into the a folder, and organize the folder with this structure, CONTROLTEMPLATES, FEATURES\FEATURE_NAMES, IMAGES. The content of the folder will copied to the Template folder(c:\program files\common files\microsoft shared\web server extensions\12\Template).

The elements.xml has lots of element. But one of common use is deploying files by using Module element. You can deploy files like the following.

<Module Path="PageTemplates" Url="SitePages" > <!-- provision standard pages --> <File Url="Page01.aspx" Type="Ghostable" /> <File Url="Page02.aspx" Type="Ghostable" /> <File Url="Page03.aspx" Type="Ghostable" /> <File Url="Page04.aspx" Type="Ghostable" /> <File Url="Page05.aspx" Type="Ghostable" /> <File Url="Page06.aspx" Type="Ghostable" /> <!-- provision Web Part pages --> <File Url="WebPartPage.aspx" Name="WebPartPage01.aspx" Type="Ghostable" /> <File Url="WebPartPage.aspx" Name="WebPartPage02.aspx" Type="Ghostable" /> <!-- provision Web Part page with Web Parts inside --> <File Url="WebPartPage.aspx" Name="WebPartPage03.aspx" Type="Ghostable" > <!-- Add a Web Part to left zone --> <AllUsersWebPart WebPartZoneID="Left" WebPartOrder="0"> <![CDATA[ <WebPart xmlns="http://schemas.microsoft.com/WebPart/v2" xmlns:cewp="http://schemas.microsoft.com/WebPart/v2/ContentEditor"> <Assembly>Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly> <TypeName>Microsoft.SharePoint.WebPartPages.ContentEditorWebPart</TypeName> <Title>Yet Another Web Part is Born</Title> <FrameType>TitleBarOnly</FrameType> <cewp:Content> This Web Part was added through declarative logic </cewp:Content> </WebPart> ]]> </AllUsersWebPart> <!-- Add a Web Part to right zone --> <AllUsersWebPart WebPartZoneID="Right" WebPartOrder="0"> <![CDATA[ <WebPart xmlns="http://schemas.microsoft.com/WebPart/v2" xmlns:iwp="http://schemas.microsoft.com/WebPart/v2/Image"> <Assembly>Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly> <TypeName>Microsoft.SharePoint.WebPartPages.ImageWebPart</TypeName> <FrameType>None</FrameType> <Title>Watch My Gears Run</Title> <iwp:ImageLink>/_layouts/images/GEARS_AN.GIF</iwp:ImageLink> </WebPart> ]]> </AllUsersWebPart> </File> </Module>

Site Page Essential

A page template, such as default.aspx, is compiled into an assembly dynamic-link library (DLL) and loaded into memory just once per Web application. However, this page template and its efficient usage of memory can still be used to serve up pages for thousands of sites. This is an obvious advantage toward scalability.

When a user customizes a site page by using the SharePoint Designer and then saves those changes, a customized version of the page definition is stored in the content database. While this provides flexibility from a customization standpoint, it also can have a negative impact on performance and scalability. When the customized page is requested, its page definition must be retrieved from the Backend database server by the SPVirtualPathProvider component and then fed to the ASP.NET compiler, where it is parsed and loaded into memory. You can imagine that a Web application with thousands of customized pages requires more memory because each customized page definition must be separately parsed and loaded into memory within the application pool that is hosting the current Web application.

You should note that customized pages are not processed by using the standard ASP.NET model in which a page is compiled into an assembly DLL. Instead, customized pages are parsed by the ASP.NET page parser and then processed using the no-compile mode feature that was introduced with ASP.NET 2.0.

As a developer, your initial reaction to this might be to question why customized pages are processed in no-compile mode. Your instincts likely tell you that compiled pages run faster than no-compile pages. However, no-compile pages can be more efficient and more scalable in certain scenarios. This is especially true in a large WSS environment where the number of customized pages can reach into the thousands or tens of thousands

No-compile pages can be loaded into memory and then unloaded in a manner that is not possible for compiled pages because the .NET Framework doesn’t really support the concept of unloading an assembly DLL from memory. The closest equivalent would be to recycle the current Windows process or the current .NET AppDomain. However, this type of recycling involves unloading all assembly DLLs from memory, not just those assembly DLLs that haven’t been used recently. Furthermore, the .NET Framework places an upper limit on the number of assembly DLLs that can be loaded into a .NET AppDomain.

No-compile pages provide higher levels of scalability because they do not require loading new assembly DLLs or managed classes into memory. Instead, the processing of no-compile pages involves loading control trees into memory. WSS can manage the memory usage for the control trees associated with customized pages more efficiently because they are not compiled into assembly DLLs. For example, once WSS has finished processing a customized page, it can unload the page’s control tree to free up memory for other purposes. Furthermore, nocompile pages eliminate the need to go through the compilation process, which actually provides faster response times for pages upon first access.

Add a command to site action dropdown

<CustomAction Id="HelloApplicationPage" GroupId="SiteActions" Location="Microsoft.SharePoint.StandardMenu" Sequence="2000" Title="Hello World Application Page" Description="Getting up and going with inline code"> <UrlAction Url="~site/_layouts/CustomApplicationPages/Hello.aspx"/> </CustomAction>

Below command can be visible only to site admin

<CustomAction Id="CustomApplicationPage3" GroupId="SiteActions" Location="Microsoft.SharePoint.StandardMenu" Sequence="2003" Title="Application Page 3" Description="Admin-only Application page" RequireSiteAdministrator="True" > <UrlAction Url="~site/_layouts/CustomApplicationPages/ApplicationPage3.aspx"/> </CustomAction>

Adding a custom menu item to ECB menu

<CustomAction Id="ApplicationPage4.ECBItemMenu" RegistrationType="List" RegistrationId="101" ImageUrl="/_layouts/images/GORTL.GIF" Location="EditControlBlock" Sequence="105" Title="Application Page 4" > <UrlAction Url="~site/_layouts/CustomApplicationPages/ApplicationPage4.aspx ?ItemId={ItemId}&amp;ListId={ListId}" /> </CustomAction>

Debugging WSS components

Under normal conditions, WSS provides error messages intended for end users in a production environment. This means that WSS doesn’t automatically provide rich diagnostic information or helpful error messages to assist you when you are debugging your code. While you are developing WSS components such as custom application pages, you must modify the web.config file for the current Web application to enable debugging support and error messages that contain stack traces. Here’s a fragment of the web.config file that shows the three important attributes that have been changed from their default values to enable rich

<configuration> <SharePoint> <SafeMode CallStack="true" /> </SharePoint> <system.web> <customErrors mode="Off" /> <compilation debug="true" /> </system.web> </configuration>

While it is essential to modify the web.config file as shown here to enable debugging support, you will also find it occasionally necessary to return the web.config file to its original state. For example, you might create an application page that throws an exception or an event handler that cancels a user’s actions. By returning the web.config file to its original state, you can see how your code will actually behave in a production environment. Therefore, you should become comfortable with the act of changing the web.config file back and forth between debugging mode and standard end user mode.

Thursday, November 27, 2008

Factory vs Constructor

In A better javascript constructor, factory, I said factory is a better way to create object. We have seen jQuery can build a jQuery object using factory. But internally jQuery using constructor/prototype. Let me be clear about what do I mean by factory and constructor in javascript. Both factory and constructor can return build object. Factory has a return statement, but constructor has no return statement. Because of this, factory has be called without and without new, the effects are identical. Constructor has to be call with "new". It would return null reference without "new", and moreover it will run in the context of caller, sometimes the caller is global object. Good factory has no such problem, because it's designer's intention be called this way. But internally jQuery use constructor, see my post. Because constructor has use good feature : prototype. but factory can not. the demo code is as below.

function AnimalConstructor() {}; AnimalConstructor.prototype = { name: "fred" } var an = new AnimalConstructor(); alert(an.name); AnimalConstructor.prototype.age = 18; alert(an.age); //show 18 function AnimalFactory() { return { name: "fred" }; }; var b = AnimalFactory(); alert(b.name); AnimalFactory.prototype.age = 18; alert(b.age); //show undefined

Why, the object created by factory has no secret link to factory's prototype. The object's constructor is not the factory, in our case the object's constructor is [object Object]. So changing factory's prototype has no effect.

In article From closures to prototypes, part 1 and From closures to prototypes, part 2, there is a comparison between closure and prototype. Now it is recommended to implement a framework using constructor, prototype internally, but as facade it is more user friendly using factory, just like jQuery.

jQuery mini

I am fasinated by the jQuery library. I do so much more with so less code. Here I try to mimic jQuery several features: chain operation, extentsion, constructor.

chain operation is pretty easy to mimic. We just need to add "return this;" to the end of a method. Here is my first try

var jQuery = function() { } jQuery.prototype = { version: "1.0", showVersion: function() { alert(this.version); return this; }, work: function() { alert("work"); return this; } } var j = new jQuery(); j.showVersion().work();

Extension is also simple. We just need to decorate its prototype like this

var jQuery = function() { } jQuery.prototype = { version: "1.0", showVersion: function() { alert(this.version); return this; }, work: function() { alert("work"); return this; } } var j = new jQuery(); j.showVersion().work(); jQuery.prototype.sleep = function() { alert("sleep"); return this; } j.sleep();

The constructor is very tricky. First I need to create a jQuery object without "new" keyword. Can we just do this like the following?

var jQuery = function() { return jQuery.prototype; } jQuery.prototype = { version: "1.0", showVersion: function() { alert(this.version); return this; }, work: function() { alert("work"); return this; } } var j = new jQuery(); j.showVersion().work(); //chain works jQuery.prototype.sleep = function() { alert("sleep"); return this; } j.sleep(); //extension works j.version = "2.0"; j.showVersion(); jQuery().showVersion(); //we can create a jQuery object without new, but it show 2.0, it is a singleton.

It works. But seemly, there is a serious bug, that it returns a singleton. So I want to write the following naive code.

var jQuery = function() { return new jQuery.prototype; //jQuery.prototype is not a constructor //return new jQuery.prototype(); //jQuery.prototype is not a constructor }

It says, jQuery.prototype is not a constructor. so we need a constructor function to do the job.

var jQuery = function() { return new jQueryConstructor(); } jQuery.prototype = { version: "1.0", showVersion: function() { alert(this.version); return this; }, work: function() { alert("work"); return this; } } function jQueryConstructor() { }; jQueryConstructor.prototype = jQuery.prototype; //end of library //following is test code. var j = new jQuery(); j.showVersion().work(); //chain works jQuery.prototype.sleep = function() { alert("sleep"); return this; } j.sleep(); //extension works j.version = "2.0"; j.showVersion(); jQuery().showVersion(); //it shows 1.0, it is not a singleton

Now everything works. But there is a potential that user may change the jQuery.prototype accidentally. let's add a reference jQuery.fn = jQuery.prototype, so that user focus on jQuery.fn, and let jQuery.prototype off attention. So I change the code like the following . Please note that the "return new jQueryConstructor()", you must use "new". Without "new", the prototype "jQueryConstructor.prototype = jQuery.fn" has no use. Here is an artical Create Advanced Web Applications With Object-Oriented Techniques more about the "new".

var jQuery = function() { return new jQueryConstructor(); } jQuery.fn = jQuery.prototype = { version: "1.0", showVersion: function() { alert(this.version); return this; }, work: function() { alert("work"); return this; } } function jQueryConstructor() { }; //jQueryConstructor.prototype = jQuery.prototype; jQueryConstructor.prototype = jQuery.fn; var j = new jQuery(); j.showVersion().work(); //chain works jQuery.fn.sleep = function() { alert("sleep"); return this; } j.sleep(); //extension works j.version = "2.0"; j.showVersion(); jQuery().showVersion(); //it shows 1.0, it is not a singleton

Can we make it more simple, yes, let's move the jQueryConstructor into the prototype.

var jQuery = function() { return new jQuery.fn.init(); } jQuery.fn = jQuery.prototype = { init: function() {}, version: "1.0", showVersion: function() { alert(this.version); return this; }, work: function() { alert("work"); return this; } } jQuery.fn.init.prototype = jQuery.fn; var j = new jQuery(); j.showVersion().work(); //chain works jQuery.fn.sleep = function() { alert("sleep"); return this; } j.sleep(); //extension works j.version = "2.0"; j.showVersion(); jQuery().showVersion(); //it shows 1.0, it is not a singleton

Done. I have skeleton of jQuery.

new this

The Animal.init is interesting. "this" refer to Animal function, which can be newed. It shows that function is alsow object, some object can be newed. some can not be newed

function Animal() { }; Animal.prototype = { name: "Animal", sayName: function() { alert(this.name); } } Animal.init = function() { //"this" refer to Animal function, //which can be newed. It shows that function //is alsow object, some object can be newed. some can not be newed return new this; } var an = Animal.init(); an.sayName();

Monday, November 24, 2008

A better javascript constructor, factory

What is wrong with the following code?

function Animal() { this.name = "fred"; this.say = function() { alert("my name is " + this.name); }; } var an = new Animal(); an.say();

What user accidentally, use the it in the following way? The constructor run in the context of global object, or window object. If you design a framework, this is not good thing.

Animal(); say(); //it pollute the global space alert(name); //fred

What if user run the following code.

var an = Animal(); //an is undefined because there is no "new" keyword here an.say();

Following is using factory to do that. It solves the above problem. First, it will not create side effect like pollute the global space, secondly, object can be created with "new" or without.

function Animal() { var r = { name: "fred" } r.say = function() { alert("my name is " + this.name); }; return r; }

I call the function with "return" statement , even the statement "return this", factory. function without return is constructor.

Closure in javascript

I have read a book "Pro JavaScript Techniques", inside it define closure as follow.

Closures are means through which inner functions can refer to the variables present in their outer enclosing function after their parent functions have already terminated.

While it is correct, but if we understand the parent functions as a constructor it is easier. Here is my understanding, closure is feature that we can create a local variable in a constructor, and that variable can be accessed by the created object internally, but it can not be accessed externally. what is unique is that the local variable stay inside a hidden area in the created object. Here is a simple code to demo this.

function Animal(name) { var r = {}; var local_variable = name; r.say = function() { alert(local_variable); } return r; } var a = new Animal("jeff"); a.say(); //alert "fred" alert(a.local_variable); //undefined

If we don't need an object, we just need a function, we can even simplify it like below. In the constructor, name is local variable, the created object is function, this local varible is saved in a hidden area in the function.

function createAlert(name) { return function() { alert(name); } } var say = createAlert("hello"); say();

Closure has another use. Hide the global variable. In the example below, we can have a global variable, it pollutes the environment.

var name = "hello"; function say() { alert(name); } say();

Now we change to use closure like below.

(function() { var name = "hello"; this.say = function() { alert(name) }; } )(); // or (function(name) { this.say = function() { alert(name) }; } )("hello"); say();

At first look, this seems more complicated. we have defined anonymous function, and run the function immediately. This function define a "say" function, and say function reference a local variable. And this variable is not global variable. The benefit of closure is not straight forward here, but it is very important in javascript framework development, because it will cornerstone for encapsulation.

Dyamically adding function to how hierarchy

We can add functionality to whole hierarchy by changing the prototype, for example.

function Animal() { var r = {}; return r; } var a = new Animal(); Object.prototype.greet = function() { alert("hello"); }; a.greet();

In javascript, everything is what?

When I learned c# long ago, I was told everything in .net is object. I used javascript long before I learned c#. But I have never asked myself this question. Now I ask myself this question. I think everything in javascript is object too.

  1. Static object which can not create object
  2. Dynamic object which can create object, its name in javascript is function.

First let's talk about static object, it can be defined like this. and it can have member variable and method.

var o = {}; //or this, they are the same //var o = new Object(); o.greet = function () { alert("hello"); }

Now let's talk about function. I had problem to understand javascript at first, because function is too confusing. Since I came from OO world, I looked at javascript in the eye of OO developer, I tried to map javascript construct into oo construct. In the end, I found that this efford is counter productive, and I decided that javascript function is so unique. We don't have to compare it with c# or java language. But before I have this conclusion, here is my struggle. I think function of javascript can be many thing in traditional OO luanguage. It can be an object, namespace, class, constructor(factory), or function(method). It is such a loose concept.

function as object

Here is as sample an function as object, animal is a function, but it is also an object, you can attache member dyanmically.

var animal = function() { }; animal.name = "fred"; animal.say = function() { alert(this.name); } animal.say();

function as class(constructor)

var Animal = function() { this.name = "fred"; this.greet = function() { alert(this.name); } } var a = new Animal(); a.greet();

function as factory

var Animal = function() { var r = {}; r.name = "fred"; r.greet = function() { alert(this.name); } return r; } var a = Animal(); //no "new" keyword a.greet();

function as function

function greet() { alert("hello"); } greet();

Javascript function is actual very simple, I shouldn't look at it in traditional view. Instead I should focus on its purpose. I think there are two purpose of function.

  1. To create object.

    As demo before, we can use tradition style consturctor, which return nothing. So it has be called using "new". Otherwise bad thing happend, it will be run in the context of global object. Or we can use factory function. It is safe, because it be called with and without "new".

  2. To do other thing.

But our function can have too thing mix purpose together, this is what jQuery does. For example, $("p.neat").addClass("ohmy").show("slow"); Each function does some job, and return an object, for next function call.

Static object and dyanmic object(function), they both have consturctor.

var o = {}; alert(o.constructor); //function Object(){[native code]} var animal = function() { return {} }; alert(animal.constructor); //function Function(){ [native code] } alert(Function.constructor); //function Function(){ [native code] }

But function has prototype, and static object does not have

var o = {}; alert(o.prototype); //undefined var animal = function() { return {} }; alert(animal.prototype); ////[object Object]

Javascript Inheritance

In the world of javascript, everything is object. There is no class. There are two kind of object, one can not create object, let's call it non-constructor object, and one can create object constructor object. Here when I mention constructor, it mean consturctor object. When I mention object, it means all objects including both kinds.

First let's talk about constructor. All object has a constructor, a constructor has a constructor. So can we traverse like this o.constructor.constructor.constructor.... and on and on? Yes, but the final constructor is function Function { [native code] }. Function constructor is itself.

function Dog() { }; var d = new Dog(); alert(d.constructor); //function Dog() {} alert(d.constructor.constructor); //function Function { [native code] }; alert(d.constructor.constructor.constructor); //function Function { [native code] }; alert(d.constructor.constructor.constructor.constructor); //function Function{ [native code] };

Inheritance implementation in javascript is different from "classical" world. Because there is no such thing "class" in javascript. It use prototype to simulate inheritance. We should know this.

  • A constructor has prototype.
  • A non-constructor object has no prototype
  • A prototype is non-constructor object so it has no prototype

The first user defined constructor is the constructor has no parent. Let call it first level constructor. The prototype of first level consturctor is [object Object], which is non-constructor object, but it has contructor which is the first level constructor itself, which means the prototype is of the constructor created by the constructor. So we can say the first level constructor's prototype is created by the constructor.

function Dog() { this.name = "fred"; } var d = new Dog(); alert(Dog.prototype); //[object Object] alert(Dog.prototype.constructor); //function Dog() {}

Now want to simulate the inheritance. So we create second level constructor like this.

function Puppy() { this.age = 18; } Puppy.prototype = new Dog(); // its prototype is a dog alert(Puppy.constructor.prototype); //function (){}, but it is actually a dog var p = new Puppy(); alert(p.name); //it can assess member "name" of it is prototype alert(p.age); var p2 = new Puppy(); p2.name = "jeff"; alert(p2.name); //jeff alert(p.name);

Please note that the object created by the second level constructor can assess the members of of its prototype, which is created by first level constructor. And These members are shared at the beginning, but if it is changed, then a private copy is created at the second level. But the shared copy in the prototype is not changed. In this way, it is memory efficent.

Above we use the pseduoclassical to simulate the inheritance, there is another way to do that, closure. Below is the demo code.

function Dog() { return { name: "fred" } } function Puppy() { var d = Dog(); d.age = 18; return d; } var p = Puppy(); alert(p.name); alert(p.age);

Closue is much clean but it is not easy to understand for new javascript developer particularly those from the classical world. Please note that we don't need to use the "new" keyword to to cal the constructor, but we still can. If use the pesudoclassical way, we need to use new, because the constructor does not return an object explicitly

Sunday, November 23, 2008

CSS specialty

Inline style is 1000.