Development With A Dot

Blog on development in general, and specifically on .NET

Sponsors

News

My Friends

My Links

Permanent Posts

Portuguese Communities

March 2009 - Posts

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

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
Posted: Mar 08 2009, 12:24 PM by Ricardo Peres | with 23 comment(s) |
Filed under: ,
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.

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.

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!

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
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

}

}

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!

More Posts « Previous page