Mar 27, 2009

Nullable and ?? Operator

After reading the article, The C# ?? null coalescing operator (and using it with LINQ), I did a quick test like the following code. It seems the compiler does different thing for Nullabe type, and other reference type with ?? operator. In fact, ?? should not be called operator, it is shortcut for compiler instruction. It will be more effective to use "t1.GetValueOfDefault()" than "t1 ?? 0" . But latter seems more language built-in feature than API.

int? t1 = null;
int t2 = t1 ?? 0;
int t3 = (t1.HasValue ? t1.GetValueOrDefault() : 0);
int t4 = t1.GetValueOrDefault();

DateTime? d1 = null;
DateTime d2 = d1.GetValueOrDefault();


string s = null;
string s2 = s ?? "fred";

//reflector translate to the following
    int? t1 = null;
    int? d3 = t1;
    int t2 = d3.HasValue ? d3.GetValueOrDefault() : 0;
    int t3 = t1.HasValue ? t1.GetValueOrDefault() : 0;
    int t4 = t1.GetValueOrDefault();
    DateTime d2 = null.GetValueOrDefault();
    string s = null;
    string s2 = s ?? "fred";


Mar 26, 2009

Generic method

The following code shows some example of generic method

//the T can be inferred from the type of input parameter
public static T DoByInferType<t>(T input)
{
    return default(T);
}

//the Toutput cannot be inferred by the input parameter
public static Toutput DoByExplicitType<Tinput, Toutput>(Tinput input)
{
    return default(Toutput);
}

int result = Utililty.DoByInferType(1);
//or (the <int> is optional)
//int result = Utililty.DoByInferType<int>(1);

//<string, int> has be explicit
int result2 = Utililty.DoByExplicitType<string, int>("1");

List<string> l = new List<string>();

Converter<string, int> converterUsingDelegate = delegate(string theString)
{
    return int.Parse(theString);
};

//public List<toutput> ConvertAll<toutput>(Converter<T, TOutput> converter);
//the TOutput can be inferred from the input paramether
List<int> intList1 = l.ConvertAll(converterUsingDelegate);

Mar 18, 2009

Using user style sheet to modify the style of a web site

I tried to modify the style by using user style sheet. But some of style just could not take effect. I seemingly forget the basic rule of css cascade. The cascade works in the following order of importance:

  1. User styles flagged as !important
  2. Author styles flagged as !important
  3. Author styles
  4. User styles
  5. Styles applied by the browser/user agent

Mar 16, 2009

Function.createDelegate

function greet(message) {
        alert(message + ", " + this.name);
    }

    var instance = { name: "fred" };
    
    //when you create a delegate, "this" in the delegate function body
    //refer to the instance passed in
    var greetSomeone = Function.createDelegate(instance, greet);
    greetSomeone("hello");
    /*
    Function.createDelegate = function Function$createDelegate(instance, method) {
    /// 
    /// 
    /// 
    /// 
    var e = Function._validateParams(arguments, [
        { name: "instance", mayBeNull: true },
        { name: "method", type: Function }
    ]);
    if (e) throw e;
    return function() {
        return method.apply(instance, arguments);
    }
}

Function.createCallback

   var createCallback = function(method, context) {
    return function() {
        //the arguements is passed in when the this callback
        //method is call
        //if there is parameter passed
        //package the parameter with the context
        //into an array, an invoke the callback
        //method with the array
        var l = arguments.length;
        if (l > 0) {
            var args = [];
            for (var i = 0; i < l; i++) {
                args[i] = arguments[i];
            }
            //the last array member is the 
            //the context
            args[l] = context;

            //apply with array argument 
            return method.apply(this, args);
        }

        //if there is no parameters 
        //just invoke the callback method with
        // the context as the only parameter
        return method.call(this, context);
    }
}

function eat(foodName, animalName) {
    alert(animalName + " eat " + foodName);
}

function Animal(name) {
    if (!name) {
        this.name = name;
    }
    else {
        this.name = "animal";
    }

    //eat is the function will be called
    //name is the predetermined pass-in parameter
    //this parameter will be the last parameter in the function
    //the order paraemeter will be passed in when the callback is called
    this.eat = createCallback(eat, name);
}

var a = new Animal("fred");
//"grass" is passed in when callback is called
a.eat("grass");

Mar 10, 2009

Create a SharePoint Solution

SharePoint use solution file to deploy solution. There are some tools to create a solution file automatically, like stsdev. But it still important to understand how the solution deployment works

MakeCab does not care about the how to deploy the solution. The job of Makecab.exe is to package all the source file and a ddf file. Sharepoint solution engine take care about of installation and deployment based on the ddf file and the manifest.xml file

The first job is to create a cab file. To create a cab file, makecab.exe need to use the ddf file. the ddf file tells makecab what files need to be packages and how they are organized in the package(what subfolder to hold a file). Below is an exmaple that are generated by the stsdev utility.

; Generated by STSDEV at 3/11/2009 12:26:53 AM .OPTION EXPLICIT .Set CabinetNameTemplate=FirstFeature.wsp .set DiskDirectoryTemplate=CDROM .Set CompressionType=MSZIP .Set UniqueFiles=off .Set Cabinet=on .Set DiskDirectory1=DeploymentFiles ;*** Solution manifest DeploymentFiles\manifest.xml ;*** Assembly files bin/debug/FirstFeature.dll ;*** add files for FirstFeature feature .Set DestinationDir=FirstFeature RootFiles\TEMPLATE\FEATURES\FirstFeature\elements.xml RootFiles\TEMPLATE\FEATURES\FirstFeature\feature.xml ;*** add files for FirstFeature\css feature .Set DestinationDir=FirstFeature\css RootFiles\TEMPLATE\FEATURES\FirstFeature\css\mystyle.css ;*********************************** ;*** Begin TemplateFiles section *** ;*********************************** .Set DestinationDir=IMAGES\FirstFeature RootFiles\TEMPLATE\IMAGES\FirstFeature\AfricanPith32.gif

Now we have all the files package the wsp file. Solution Deployment is accomplished in two step, installation and deployment. Installation is to add the package to central admin storage. Deployment is to physically deploy the files to a web server and install the feature to the web server. During installation, the engine will check the manifest.xml and feature_name\feature.xml file to check if all the files required are included in the package. If yes, the installation will succeed. If not, the installation will abort. During deployment, the engine will also use the manifest.xml and feature.xml to copy the files to front end server. It is possible that the package has some files that feature required. In that case, those are just ignored, the engine only copy those files that are shown in manifest.xml and feature.xml. To copy files, the engine does not care about the Module nodes in the element manifest files, it cares about in feature.xml, the and in the manifest. If you file that your wsp file has included the content files, but they are not copied to the front end server, you need to make sure they are shown those nodes.

To install a solution, we can use command line.

"C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\bin\stsadm.exe" -o addsolution -filename DeploymentFiles\FirstFeature.wsp "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\bin\stsadm.exe" -o execadmsvcjobs

To deploy a soltuion, we can use command line,

"C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\bin\stsadm.exe" -o deploysolution -name FirstFeature.wsp -immediate -allowgacdeployment "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\bin\stsadm.exe" -o execadmsvcjobs

To undeploy a solution,

"C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\bin\stsadm.exe" -o retractsolution -name FirstFeature.wsp -immediate

To uninstall a solution,

"C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\bin\stsadm.exe" -o deletesolution -name FirstFeature.wsp

To upgrade a solution,

"C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\bin\stsadm.exe" -o upgradesolution -name FirstFeature.wsp -filename DeploymentFiles\FirstFeature.wsp -local -allowgacdeployment

This upgrade only update the configuration database, if the solution has been deployed to front end server, the solution need to be redeployed again to the front end server.

In development, we don't really need to use solution deployment, only need to copy the feature file and other content files to folder 12, and install the feature again.

xcopy /e /y "RootFiles\*" "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12" stsadm.exe -o installfeature {-filename | -name } [-force]

Mar 7, 2009

ContentPlaceHolder trick

  • ContentPlaceHolder in master page is reference in Content control in content page
  • Content control's Id can be empty, but the ContentPlaceHolderID need to be filled. The position of Content control in content page does not matter.
  • In ContentPlaceHolder, you can fill in some default content. But they will be override once content page reference it.
  • If you use nested ContentPlaceHolder and you want to fill the content, its parent ContentPlaceHolder can not be reference, otherwise, the content in nested ContentPlaceHolder will not be used.

Mar 5, 2009

Global Site Definition

The Global site definition is located at the 12\TEMPLATES\GLOBAL path. It contains the standard default.master page template along with instructions to provision an instance of default.master page into the Master Page gallery of every new site. The Global site definition also contains provisioning logic to create the following four site collection–scoped lists in every new top-level site:Web Parts gallery, List Template gallery, Site Template gallery, User Information Profile list

Site Definition vs Site Template

Site definition are deployed within 12\template\sitetemplates directory and are referenced in 12\template\1033\xml\webtemp*.xml files Wss offer site definitions to provide users with createable site templates out of the box. A site definition named sts prvoides familar site templates such as Team Site, Blank site, and document workspace.

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.

Site definition --contains--> configurations <--referenced by webtemp*.xml --> display configuration as creatable site template

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://site.com -ownerlogin xx\xx -owneremail xx@xx.com -sitetemplate STS#1

Changing a built-in site definitions and templates

One of the challenges in WSS 2.0 was adding new functionality to existing site definitions and templates. This was because the official guidance from Microsoft was to never edit an existing site definition or template once sites have been provisioned using it, and that developers should not modify the site definitions provided in the out - of - the - box installations, as future updates (hotfixes and service packs) could overwrite the files. To address this, Microsoft added the capability of Feature stapling.

Feature stapling involves creating a special Feature, known as a stapling Feature, that associates a Feature with an existing site template. Once a Feature has been stapled to a site template, any future sites provisioned using the site template will automatically activate the stapled Feature. This enables developers to customize site templates without actually changing the site template itself; instead they can append functionality without touching the source files that make up the site template.

Stapling is achieved using the < FeatureSiteTemplateAssociation > site element. This element accepts two attributes: Id , the ID of the Feature to be stapled, and TemplateName , the ID of the site template. For example, the following CAML contained in a Feature element manifest file would staple the MyFirstFeature to all future sites provisioned using the Blank Site site template ( STS#1 ), assuming the stapling Feature were activated:

 < ?xml version="1.0” encoding=”utf-8"? > 
  
    
  

Feature used to activate other feature

Sometime you can use a feature simply to activate other features.


    
     
    
 < /Feature > 

When to make a feature hidden

When creating a Feature that contains a Feature receiver performing certain tasks that require special permissions, consider making it a hidden Feature, thereby requiring activation via STSADM.EXE. Why? When a Feature is activated from the browser interface, the code is executed within the context of the configured identity of the application pool hosting the Web application containing the site collection. This identity may not have the necessary permissions, such as writing to the file system. However, when a Feature is activated using STSADM.EXE, the identity of the user performing the command is used, who may have more permissions than the application pool’s identity.

Feature Scope

A Feature's scope enables developers quantify how broad the effects of activating the Feature are. If a Feature is scoped at the site level, then activation affects only the SharePoint site it is activated within. However, if it is scoped at a site collection level, then the activation affects all sites within the site collection. To administrator, the scope affect where the feature can be activated to after the feature is installed. If it is farm feature, it can be activated at http://.../_admin/ManageFarmFeatures.aspx, if it is webApplication feature, it can be activated at http://.../_admin/ManageWebAppFeatures.aspx, if it is sitecollection, it can be activated at http://../sitecollection/_layouts/ManageFeatures.aspx?Scope=Site, if it is site feature, it can be activated at http://../site/_layouts/ManageFeatures.aspx

To a developer, the scope affect the receiver's properties.Feature.Parent. For example, if it s a web feature. You can write code like, SPWeb site = properties.Feature.Parent as SPWeb;

Mar 2, 2009

The order of service call

By default the service call can be called without any pre-defined order. Microsoft provide a proprietary feature to support ordered call. This is only meaningful only when session is supported. IsInitiating and IsTerminating are two properties of OperationContract attribute. By default IsInitiating is true, means it can be called first in a session. IsTerminating is false by default, means the session can call other service after this call.

ServiceContract vs ServiceBehavior

In WCF, ServiceContract attribute affect the behavior of both client and server, while ServiceBehavior only affect the behavior of server. ServiceContract can apply both to interface and class, but ServiceBehavior can only apply to class implementation. ServiceContract affect the wsdl emitted, but ServiceBehavior will not affect wsdl emitted.

public enum SessionMode
{
   Allowed,
   Required,
   NotAllowed
}
[AttributeUsage(AttributeTargets.Interface|AttributeTargets.Class,
                Inherited=false)]
public sealed class ServiceContractAttribute : Attribute
{
   public SessionMode SessionMode
   {get;set;}
   //More members
}

[AttributeUsage(AttributeTargets.Class)]
public sealed class ServiceBehaviorAttribute : Attribute, IServiceBehavior
{

}

// Summary:
//     Specifies the number of service instances available for handling calls that
//     are contained in incoming messages.
public enum InstanceContextMode
{
    // Summary:
    //     A new System.ServiceModel.InstanceContext object is created for each session.
    PerSession = 0,
    //
    // Summary:
    //     A new System.ServiceModel.InstanceContext object is created prior to and
    //     recycled subsequent to each call. If the channel does not create a session
    //     this value behaves as if it were System.ServiceModel.InstanceContextMode.PerCall.
    PerCall = 1,
    //
    // Summary:
    //     Only one System.ServiceModel.InstanceContext object is used for all incoming
    //     calls and is not recycled subsequent to the calls. If a service object does
    //     not exist, one is created.
    Single = 2,
}



InstanceContextMode is a property of ServiceBehavior attribute, it affect server only. Its default value is PerSession.PerSession, but PerCall can get the best scalability, which is generally recommended. But PerSession is not compatible with transport protocol binding like basicHttpBinding. And the implementation requires to follow IDisposable pattern and Session retore pattern to support PerCall behavior.

SessionMode mode is a property of ServiceContract, it affect both the client. It is default value is "Allowed". It tells the client whether it should keep a session with server. When you create proxy at client side, that proxy will create a session in first call. If you create another proxy, that will create a new session. In order to correlate all messages from a particular client to a particular instance, WCF needs to be able to identify the client. One way of doing that is to rely on a transport-level session; that is, a continuous connection at the transport level, such as the one maintained by the TCP and IPC protocols. As a result, when using the NetTcpBinding or the NetNamedPipeBinding, WCF associates that connection with the client. The situation is more complex when it comes to the connectionless nature of the HTTP protocol. Conceptually, each message over HTTP reaches the services on a new connection. Consequently, you cannot maintain a transport-level session over the BasicHttpBinding. The WS binding, on the other hand, is capable of emulating a transport-level session by including a logical session ID in the message headers that uniquely identifies the client. In fact, the WSHttpBinding will emulate a transport session whenever security or reliable messaging is enabled.

When we implement our service, we can use different combination of SessionMode(client), InstanceContextMode(server), and transporation binding. SessionMode and InstanceContextMode has no configuration confict, which means any SessionMode can go with any InstanceContextMode. But there are some design conflict. For example, SessionMode.NotAllowed does not go with InstanceContextMode.PerSession very well. To maintain a instance per session, client should support session as well. If client does not allowed session, every service call is treated as new session. But it will not caused configuration error. To support SessionMode.Required, binding can not be basicHttpBinding. The combination of SessionMode.Required and basicHttpBinding will generate a configuration error. InstanceContextMode.PerSession can works with basicHttpBinding, but every service call will treated as new session.