Archives

Archives / 2009 / March
  • Changing Thread-Safety Dynamically

    Sometimes there may be a need to decide dynamically (through code in your program) whether a class is thread-safe or not. This is the technique I use:

    public class SomeClass

    {

        private Boolean threadSafe = false;

        private readonly Object syncRoot = new Object();

        //gets or sets whether this object is thread-safe or not

        //in this case we are locking directly on the syncRoot field

        public Boolean ThreadSafe

        {

            get { lock(this.syncRoot) { return(this.threadSafe); } }

            set { lock(this.syncRoot) { this.threadSafe = value; } }

        }

        //Property used for thread synchronization

        public Object SyncRoot

        {

            get

            {

                return(this.ThreadSafe == true ? this.syncRoot : new Object());

            }

        }

        public void SomeMethod()

        {

            //always lock on the SyncRoot property, not the syncRoot field

            lock (this.SyncRoot)

            {

                //do something

            }

        }

    }

    Read more...

  • Interface Inheritance

    I am normally against having an interface inherit from another one, but there's a situation where I am in favor of it: web service interfaces!

    The reason is that we can write code like this:

    using (ChannelFactory<IMyService> factory = new ChannelFactory<IMyService>())

    {

        using (IMyService svc = factory.CreateChannel())

        {

        }

    }

    instead of:

    using (ChannelFactory<IMyService> factory = new ChannelFactory<IMyService>())

    {

        IMyService svc = factory.CreateChannel();

        using (svc as IDisposable)

        {

            //the generated proxy does implement IDisposable!

        }

    }

    I think this leads to more elegant code. I know there's a problem with using a ChannelFactory like this, and I will come back to it in a future post! :-)

    Read more...

  • Enterprise Library 5 Wish List

    Updated! 

    The guys from the Enterprise Library development team are taking feature suggestions for the upcoming Enterprise Library 5.

    I have suggested the following:

    • A configuration editor for Unity, like ther is for all the other application blocks
    • A LINQ provider block
    • Inclusion of XSD schema files for all application blocks, so that we can have intellisense on Visual Studio
    • ADDED: Externalization of the code generation module, like LinFu (I had forgot this one)

    You can submit your own here: http://blogs.msdn.com/agile/archive/2009/01/26/enterprise-library-5-what-s-on-your-wish-list.aspx.

    Read more...

  • Setting Custom Identity in WCF

    WCF was designed to be fully extensible, at all levels. If I want to pass a custom identity (an application-defined username and role and the desired culture) to a WCF web service (not using ASP.NET compatibility mode), this is what I do:

    1. I defined a custom AuthenticateAttribute attribute, which implements IContractBehavior, IClientMessageInspector and IDispatchMessageInspector (a message inspector for both the client and server ends)
    2. I add this attribute to the service interface, at the interface level, next to [ServiceContract]
    3. On the Web.config file, I add a line <serviceAuthorization principalPermissionMode="None" /> to the behavior definition

    Please note that on my sample class, I am not currently sending the actual username, role and culture, but it is very easy to do, perhaps through message header properties.

    When the web service receives the request, before it is actually forwarded to the apropriate method, it sets the Thread.CurrentPrincipal, Thread.CurrentCulture and Thread.CurrentUICulture properties.

    Read more...

  • Catch All Exceptions

    As you may know, an exception is always thrown in the context of a running thread; what happens if there is no try...catch block protecting that thread? The exception is propagated to the application domain level, where, eventually, it will cause your application to crash.

    Since you cannot be sure that all threads are running (and you may not want to do so, anyway) inside a try...catch block, there are two things you can do to, 1) at least, be notified when an exception occurs and 2) decide what to do when that happens. In a Windows Forms application, the System.Windows.Forms.Application class is where this is done.

    The argument to Application.SetUnhandledExceptionMode can be one of:

    • UnhandledExceptionMode.Automatic: exception is caught in the Application.ThreadException handler, if there is no entry in the App.config or Web.config that disables it
      UnhandledExceptionMode.CatchException: exception is caught in the ThreadException handler
      UnhandledExceptionMode.ThrowException: exception is thrown, the ThreadException handler is ignored

    See this example: 

    Application.SetUnhandledExceptionMode(UnhandledExceptionMode.Automatic);

    Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);

    void Application_ThreadException(Object sender, ThreadExceptionEventArgs e)

    {

        //do something with e.Exception

    }

    If you don't have a Windows Forms application, but instead a console application or a Windows Service, you can still catch all exceptions at the application domain level:

    AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

    void CurrentDomain_UnhandledException(Object sender, UnhandledExceptionEventArgs e)
    {

        //Object exception = e.ExceptionObject;
        //Boolean terminating = e.IsTerminating;
    }

    Finally, if you have an ASP.NET application, you add an event handler to the HttpApplication.Error event. This can be done in several ways:

    1) Add an event handler to the Error event from anywhere (a page, a control, a module, etc): 

    HttpContext.Current.ApplicationInstance.Error += new EventHandler(ApplicationInstance_Error);

    void ApplicationInstance_Error(object sender, EventArgs e)
    {

        //Exception ex = HttpContext.Current.Server.GetLastError();
        //HttpContext.Current.Server.ClearError();

    }
    2) Implement the Application_Error method on Global.asax.cs:

    protected void Application_Error(Object sender, EventArgs args)

    {

        //Exception ex = HttpContext.Current.Server.GetLastError();
        //HttpContext.Current.Server.ClearError();

    }

    3) Implement a custom IHttpModule and hook to the Error event (my favorite):

    public class ErrorModule: IHttpModule

    {

        public void Init(HttpApplication app)

        {

            app.Error += Application_Error;

        }

        void app_Error(object sender, EventArgs e)
        {
            //Exception ex = HttpContext.Current.Server.GetLastError();
            //HttpContext.Current.Server.ClearError();

        }

    }

     

    Read more...

  • ASP.NET Validation with the Enterprise Library Validation Block

    The Enterprise Library comes with a custom ASP.NET validator, that gets validation from the metadata defined in your classes. If you have seen my previous post, you know how to add validation metadata to a POCO, usually a data transfer object. Basically, you either 1) add attributes to public properties and fields or 2) configure XML files. I'll stick to the first approach. What I'll show you next is how to do validation on web forms based on the validation metadata from a class. First, add a reference to the Microsoft.Practices.EnterpriseLibrary.Validation.Integration.AspNet assembly, and enter the following markup on you ASPX page:

    <asp:TextBox runat="server" ID="text" />

    <entlib:PropertyProxyValidator runat="server" ControlToValidate="text" SourceTypeName="SomeRequest, SomeAssembly" PropertyName="Text" />

    <asp:Button runat="server" ID="button" CausesValidation="true" Text="Click Me" />

    And that's it! The PropertyProxyValidator, in this case, will check the NotNullValidatorAttribute, StringLengthValidatorAttribute and ContainsCharactersValidatorAttribute that are applied to the Name property of the SomeRequest class.

    The available validator attributes on assembly Microsoft.Practices.EnterpriseLibrary.Validation are:

    - ContainsCharactersAttribute: Performs validation on strings by verifying if it contains a character set using the ContainsCharacters mode.

    - DateTimeRangeValidatorAttribute: Performs validation on DateTime instances by comparing them to the specified boundaries.

    - DomainValidatorAttribute: Validates an object by checking if it belongs to a set.

    - EnumConversionValidatorAttribute: Validates a string by checking it represents a value for a given enum type.

    - HasSelfValidationAttribute: Indicates the target type defines self validation methods.  

    - IgnoreNullsAttribute: Indicates that a null value is to be allowed by the validator represented by the validation attributes for the language element this attribute is bound.

    - NotNullValidatorAttribute: Logs a failure when validating a null reference.

    - ObjectCollectionValidatorAttribute: Performs validation on collection objects by applying the validation rules specified for a supplied type to its members.

    - ObjectValidatorAttribute: Performs validation on objects by applying the validation rules specified for a supplied type.

    - PropertyComparisonValidatorAttribute: Performs validation by comparing the a value with the value of a property on the target object by using a specified comparison operation.

    - RangeValidatorAttribute: Performs validation on instances by comparing them to the specified boundaries.

    - RegexValidatorAttribute: Performs validation on strings by matching them to a Regex.

    - RelativeDateTimeValidatorAttribute: Validates a DateTime value by checking it belongs to a range relative to the current date.

    - SelfValidationAttribute: Marks a method as implementing self validation logic. Used in conjunction with HasSelfValidationAttribute.

    - StringLengthValidatorAttribute: Performs validation on strings by comparing their lengths to the specified boundaries.

    - TypeConversionValidatorAttribute: Validates a string by checking it represents a value for a given type.

    - ValidatorCompositeAttribute: Indicates that the kind of composition to use when multiple ValidatorAttribute instances are bound to a language element.

    It is very easy to define your own validators: just inherit from BaseValidationAttribute and implement your own validation logic.

    The only drawback is that the page is always posted, that is, there is no JavaScript client validation, but you can place this inside an UpdatePanel, and it works just fine.

    Read more...

  • Validation of WCF Requests with the Enterprise Library Validation Block

    In order to enable validation of the properties of a request message, you only need to add a [ValidationBehavior] attribute to your service interface, just next (or before) the [ServiceContract], and a [FaultContract(typeof(ValidationFault))] on the method declaration. The ValidationBehaviorAttribute and ValidationFault classes are defined in the Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF assembly and are part of the Validation Application Block of the Enterprise Library 4.1, more specifically, of the WCF integration module.

    Here is an example:

    [ServiceContract("http://someuri")]
    
    [ValidationBehavior] 
    
    public interface IRequest
    
    {
    
        [OperationContract]
    
        [FaultContract(typeof(ValidationFault))]
    
        SomeResponse DoSomething(SomeRequest req);
    
    } 
    
    

     In your request class (data transfer objects), you must then add validation attributes for each of the properties that you want to validate. For example:

    [DataContract] 
    
    public class SomeRequest
    
    {
    
        [NotNullValidator(MessageTemplate = "{1} is null")]  //the property cannot be null
    
        [StringLengthValidator(4, 40, MessageTemplate = "The {1} must have between 4 and 40 characters")]  //must have between 4 and 40 characters
    
        [ContainsCharactersValidator("_/\\.;,:\'\"", ContainsCharacters = Any, Negated = true,  MessageTemplate = "The {1} contains invalid characters")]  //may not contain '_', '/', '\', '.', ';', ':', '\'' or "\"' characters
    
        public String Name
    
        {
            get; set;
        }   
    }
    
    

    Notice the {1} placeholder on the MessageTemplate property value: it is replaced by the current validating member name, in this case, the Name property. Valid placeholders depend on the actual validator used, but there are some common ones, which are:

    • {0}: The current value of the field or property
    • {1}: The name of the field or property
    • {2}: The tag name

    Also, you can have resource values instead of hardcoded strings; instead of the MessageTemplate, add MessageTemplateResourceName and MessageTemplateResourceType, and the error string will be obtained from the resource named MessageTemplateResourceName from the assembly that contains the MessageTemplateResourceType type.

    Your requests will then be automatically validated before they are transmitted, and, in the case of a validation exception, you will receive a FaultException<ValidationFault>, from which you will be able to extract validation errors, through the Details list property.

    In the next post, I will explain how you can add validation to ASP.NET forms from the same metadata that is defined on the data transfer object class.

    Bookmark and Share

    Read more...

  • New Cumulative Update for SharePoint Released

    A new cumulative update for SharePoint (actually one for WSS and another one for MOSS) has been released.

    Request the WSS one (http://support.microsoft.com/kb/961755) from http://support.microsoft.com/hotfix/KBHotfix.aspx?kbnum=961755&kbln=en-us and the MOSS one (no details page yet) from http://support.microsoft.com/hotfix/KBHotfix.aspx?kbnum=961756&kbln=en-us. A link will be sent to the e-mail address you indicate.

    Requirements are just WSS SP1 and MOSS SP1. These updates include all other updates released since SP1.

    You should install first the WSS update and then the MOSS one. Afterwards, run

    psconfig -cmd upgrade -inplace b2b –force

    Read more...

  • ASP.NET Page Events Lifecycle

    When using  master pages, the normal page event lifecycle is a little different. Here is the actual order:

    1. Page.OnPreInit
    2. MasterPageControl.OnInit (for each control on the master page)
    3. Control.OnInit (for each contol on the page)
    4. MasterPage.OnInit
    5. Page.OnInit
    6. Page.OnInitComplete
    7. Page.LoadPageStateFromPersistenceMedium
    8. Page.LoadViewState
    9. MasterPage.LoadViewState
    10. Page.OnPreLoad
    11. Page.OnLoad
    12. MasterPage.OnLoad
    13. MasterPageControl.OnLoad (for each control on the master page)
    14. Control.OnLoad (for each control on the page)
    15. OnXXX (control event)
    16. MasterPage.OnBubbleEvent
    17. Page.OnBubbleEvent
    18. Page.OnLoadComplete
    19. Page.OnPreRender
    20. MasterPage.OnPreRender
    21. MasterPageControl.OnPreRender (for each control on the master page)
    22. Control.OnPreRender (for each control on the page)
    23. Page.OnPreRenderComplete
    24. MasterPageControl.SaveControlState (for each control on the master page)
    25. Control.SaveControlState (for each control on the page)
    26. Page.SaveViewState
    27. MasterPage.SaveViewState 
    28. Page.SavePageStateToPersistenceMedium
    29. Page.OnSaveStateComplete
    30. MasterPageControl.OnUnload (for each control on the master page)
    31. Control.OnUnload (for each control on the page)
    32. MasterPage.OnUnload
    33. Page.OnUnload

    Read more...

  • Enterprise Library Lifetime Managers

    Update: fixed a bug in the attached code.

    Enterprise Library comes with several lifetime manager, which you can use to control how your objects are stored and retrieved. The available lifetime managers are:

    • ExternallyControlledLifetimeManager: stores a weak reference to objects which are created elsewhere
    • PerThreadLifetimeManager: stores objects in a thread static dictionary)
    • ContainerControlledLifetimeManager (the default): stores objects in the Unity container
    • TransientLifetimeManager: does not store objects, create a new one every time it is requested

    In web applications, we may need additional options, for example:

    • Store objects in the current session
    • Store objects in the current request
    • Store objects in the current application

    So, I wrote three new lifetime managers, for each of these requirements: WebSessionLifetimeManager, WebRequestLifetimeManager and WebApplicationLifetimeManager. Another possibility would be a pooled lifetime manager, which will be the subject for a future post.

    Read more...

  • Dependency Injection on an ASP.NET Page

    In order to have dependency injection on your ASP.NET pages, the best way to go is through a customized page handler factory. A page handler factory is a class directly or indirectly derived from PageHandlerFactory who has the responsibility to create a new instance of a Page. What we do is, we call the base class implementation of GetHandler method and then we call IUnityContainer's BuildUp method. Of course, we must also

    1. have previously initialized the Unity container, possibly on Application_Start method of Global.asax.cs
    2. configure interceptors for the types you want in Web.config. In this example, since I am registering an interface, I will be using InterfaceInterceptor, but you can also use VirtualMethodInterceptor or TransparentProxyInterceptor. I will talk about these in a future post.
    3. replace the existing page handler factory with our onw in Web.config

    See the attached code, and replace ISomething for your own interface and ConcreteSomething, in Web.config, for the actual implementation of this interface.

    Read more...

  • Enterprise Library Call Handlers

    Call Handlers are Enterprise Library's extension mechanism. They allow code to be injected before or after a method is called. Enterprise Library, as of version 4.1, comes with the following call handlers and associated handler attributes, in assembly Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers:

    • AuthorizationCallHandler / AuthorizationCallHandlerAttribute
    • CachingCallHandler / CachingCallHandlerAttribute
    • ExceptionCallHandler / ExceptionCallHandlerAttribute
    • LogCallHandler / LogCallHandlerAttribute
    • PerformanceCounterCallHandler / PerformanceCounterCallHandlerAttribute
    • ValidationCallHandler / ValidationCallHandlerAttribute

    If you know the Enterprise Library, you can easily guess their meaning from their names.

    I have written two additional call handlers:

    • TransactionCallHandlerAttribute (implements ICallHandler): wraps the target method in a transaction scope
    • TriesCallHandlerAttribute (implements ICallHandler): tries to invoke the target method a number of times, while an exception is thrown

    For simplicity's sake, I have implemented ICallHandler in the attribute class, so the ICallHandler.CreateHandler method only returns this.

    Usage is like this:

    [TransactionCallHandler(TransactionScopeOption.Required)]

    void SomeMethod();

    and

    [TriesCallHandler(3, Delay = 500)]

    void SomeOtherMethod();

    Enjoy!

    Read more...

  • Calling Web Service Methods Synchronously in ASP.NET AJAX

    Update: I had forgot to send the code for the synchronous executor. Here it is, as an attachment. 

    AJAX, standing for Asynchronous JavaScript and XML, is, well, asynchronous by default. Usually, that is exactly what we want, but there may be times when we want to execute some operation synchronously.

    The ASP.NET AJAX (previously known as ASP.NET AJAX Extensions) allows us out of the box to call web service methods asynchronously. See this example:

    ... 

    <script type="text/javascript">

    function onAddSuccess(result, context, functionName)

    {

        window.alert('Result: ' + result);

    }

    function onAddFailure(error, context, functionName)

    {

        window.alert('Error: ' + error);

    }

     </script>

    ... 

    <asp:ScriptManager ID="ScriptManager" runat="server">

    <Services>

    <asp:ServiceReference Path="~/CalculatorService.asmx" />

    </Services>

    </asp:ScriptManager>

    <asp:Button runat="server" ID="Button1" OnClientClick="CalculatorService.Add(1, 1, onAddSuccess, onAddFailure, null)" Text="Add 1 + 1" />

    ...

    [ScriptService]

    [WebService(Namespace = "http://tempuri.org/")]

    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

    public class CalculatorService : WebService

    {

    [
    ScriptMethod]

    [WebMethod]

    public Int32 Add(Int32 a, Int32 b)

    {

    return (a + b);

    }

    }

    If all goes well, you would get the string "Result: 2" coming from the onAddSuccess callback function.

    But in some cases, for example, an ASP.NET Custom Validator, you must get an answer immediately. Have a look at the following code:

    function ExecuteSynchronously(url, method, args)

    {

    var executor = new Sys.Net.XMLHttpSyncExecutor();

    // Instantiate a WebRequest.

    var request = new Sys.Net.WebRequest();

    // Set the request URL.

    request.set_url(url + '/' + method);

    // Set the request verb.

    request.set_httpVerb('POST');

    // Set request header.

    request.get_headers()['Content-Type'] = 'application/json; charset=utf-8';

    // Set the executor.

    request.set_executor(executor);

    // Serialize argumente into a JSON string.

    request.set_body(Sys.Serialization.JavaScriptSerializer.serialize(args));

    // Execute the request.

    request.invoke();

    if (executor.get_responseAvailable())

    {

    return (executor.get_object());

    }

    return (false);

    }

    function add()

    {

    var result = ExecuteSynchronously('CalculatorService.asmx', 'Add', { a: 1, b: 2 });window.alert('Result: ' + result);

    }

    <asp:Button runat="server" ID="Button1" OnClientClick="add()" Text="Add 1 + 1" />

    You get the result immediately in the add method.

    Bookmark and Share

    Read more...

  • No-Compile Web User Controls

     When using no-compile web user controls (where the CompilationMode directive is set to Never), you cannot just add them to your web page declaratively.

    There are two ways to do it:

    • Programmatically, by calling Page.LoadControl, casting the returned value to the appropriate class (UserControl-derived or PartialCachingControl, if the web user control has the OutputCache directive) and set its properties manually
    • Use the aspnet_compiler tool to build your site beforehand (another project), add a reference to this project and then register your web user control as a regular server control, with the Assembly and Namespace properties instead of Src

    I built a simple control that allows us to declare a no-compile web user control. It allows us to declare its attributes in the markup (through the implementation of the IAttributeAccessor interface), but we also have to specify the location of its .ascx file. I believe this is much better to have a declarative approach, whenever possible, to a programmatic one.

    This is how it should be used:

    <someprefix:DynamicUserControl runat="server" VirtualPath="~/SomeWebUserControl.ascx SomeProperty="1" SomeOtherProperty="false"/> 

    Here is the code:

    using System;

    using System.Data;

    using System.Configuration;

    using System.Web;

    using System.Web.Security;

    using System.Web.UI;

    using System.Web.UI.WebControls;

    using System.Web.UI.WebControls.WebParts;

    using System.Web.UI.HtmlControls;

    using System.ComponentModel;

    namespace Controls

    {

    [
    Themeable(false)]

    public class DynamicUserControl: Control, IAttributeAccessor

    {

    #region Private fields private System.Web.UI.AttributeCollection attributes = null;

    private String virtualPath = String.Empty;

    #endregion

    #region
    Public constructorpublic DynamicUserControl()

    {

    this.attributes = new System.Web.UI.AttributeCollection(this.ViewState);

    }

    #endregion

    #region
    Public properties

    [Browsable(true)]

    [Localizable(false)]

    [Description("")]

    [DefaultValue("")]

    [UrlProperty("*.ascx")]

    public String VirtualPath

    {

    get

    {

    return (this.virtualPath);

    }

     

    set

    {

    this.virtualPath = value ?? String.Empty;

    }

    }

    [
    Browsable(false)]public System.Web.UI.AttributeCollection Attributes

    {

    get

    {

    return (this.attributes);

    }

    }

    #endregion

    #region
    Protected override methodsprotected override void OnLoad(EventArgs e)

    {

    Control ctrl = this.Page.LoadControl(this.VirtualPath);

    Control innerCtrl = null;if (ctrl is PartialCachingControl)

    {

    innerCtrl = (ctrl
    as PartialCachingControl).CachedControl;

    }

    else if (ctrl is UserControl)

    {

    innerCtrl = ctrl;

    }

    if (innerCtrl != null)

    {

    foreach (String key in this.Attributes.Keys)

    {

    PropertyDescriptor prop = TypeDescriptor.GetProperties(innerCtrl)[key];if (prop != null)

    {

    TypeConverter converter = prop.Converter;

    if (converter != null)

    {

    prop.SetValue(innerCtrl, converter.ConvertFrom(
    this.attributes[key]));

    }

    else

    {

    converter =
    TypeDescriptor.GetConverter(prop.PropertyType);if (converter != null)

    {

    prop.SetValue(innerCtrl, converter.ConvertFrom(
    this.attributes[key]));

    }

    else

    {

    prop.SetValue(innerCtrl,
    Convert.ChangeType(this.attributes[key], prop.PropertyType));

    }

    }

    }

    }

    this.Controls.Add(innerCtrl);

    }

    base.OnLoad(e);

    }

    #endregion

    #region
    IAttributeAccessor Memberspublic String GetAttribute(String key)

    {

    return (this.Attributes[key]);

    }

    public void SetAttribute(String key, String value)

    {

    this.attributes[key] = value;

    }

    #endregion

    }

    }

    Read more...

  • Useful Expression Builders

    Expression builders are a cool subject... they work with no-compile pages and provide a lot of declarative power!

    How many times have you had the need to display values that are mostly equal, but slightly different than resources included in you .resx file?

    For example, supose you have resource entry with key "User" which maps to value "User", and you also want to be able to display "Users". Normally, you would have to add another entry to the .resx file for the "Users" value. Enter the ConcatExpressionBuilder! See this example:

    <%$ Concat:SomeGlobalResourceFile.ResourceKey,'SomeText',SomeOtherGlobalResourceFile.SomeOtherKey,'SomeOtherText',SomeLocalResourceKey %>

    As you can guess, it mimics the behavior of the String.Concat method, but it can accept both literal strings (included in '') as well as global and local resource keys.

    But what if you wanted to format a long value from a resource key? Enter the FormatExpressionBuilder:

    <%$ Format:'Number is {0:2}',SomeGlobalResourceFile.LongResourceKey %>

    The first argument before the first ',' is the format expression, and the others are arguments to it. The format expression can also come from a resource key:

    <%$ Format:SomeLocalResourceKey,SomeGlobalResourceFile.SomeResourceKey,'SomeText' %>

    Basically, it implements the String.Format method.

    What about execute some code without code regions? Here is the CodeExpressionBuilder:

    <%$ Code:DateTime.Now.Date %>

    Here is my full list of general-purpose expression builders:

    ApplicationExpressionBuilder Returns a value stored in the application
    CodeExpressionBuilder Executes code
    ConcatExpressionBuilder Concatenates a number of expressions, which may come from resource files
    CookieExpressionBuilder Returns a value stored in a cookie
    FormatExpressionBuilder Formats an expression with any number of arguments, which may come from resource files
    InRoleExpressionBuilder Checks if the current user belongs to a role
    ProfileExpressionBuilder Returns a profile value
    QueryStringExpressionBuilder Returns a value from the query string
    RequestExpressionBuilder Returns a value from the request
    SessionExpressionBuilder Returns a value stored in the session

    In the attached file, you can see all of these expression builders, together with their editors. Enjoy, and let me know if you like them or if you find any problems!

    Read more...