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.