вторник, 17 ноября 2009 г.
понедельник, 16 ноября 2009 г.
Spirals
In COM times IDispatch and IExpando interfaces were used to enable COM components written in strongly typed languages to enter the world of VisualBasic and JScript.
Now DynamicObject and ExpandoObject let C# not only to interoperate with dynamic languages but to be dynamic itself.
среда, 11 ноября 2009 г.
Combining ASP.NET AJAX component descriptors
If you have worked with ASP.NET AJAX you know that every instance of ScripCompomentDescriptor created on server side generates startup javascript code at the end of the page. Something like this:
Sys.Application.add_init(function() {
$create(AjaxControlToolkit.DynamicPopulateBehavior, {"PopulateTriggerID":"ctl00_SampleContent_Label1","ServiceMethod":"GetHtml","ServicePath":"/AJAX/AjaxControlToolkit/Samples/DynamicPopulate/DynamicPopulate.aspx","UpdatingCssClass":"dynamicPopulate_Updating","id":"dp1"}, null, null, $get("ctl00_SampleContent_Panel1"));
});
And the more instances you create the bigger your page size. You should not bother if there are only a few components on your page or when you turn on compression for dynamic content. But if dynamic compression is not an option declaration of dozens of ajax script controls or behaviours can easily twice the page size. ASP.NET AJAX doesn’t have a built-in way of combining multiple ajax component declarations so I had to resort to our old friend Reflection.
All combining logic I’ve put into the class derived from System.Web.UI.ScriptManager. Classes ScriptControlBase and ExtenderControlBase intercept script descriptors registration and register their in our special ScriptManager. The ScriptManager at last possible point, before ASP.NET renders registered startup scripts, combines registered script descriptors, generates necessary javascript code and registers it as startup script. That’s it.
Combined script controls (or behaviours) creation looks like this:
Sys.Application.add_init(function()
{
$createMultiple(TestWeb.UserCard,['ctl03_item','ctl04_item','ctl05_item','ctl06_item','ctl07_item','ctl08_item','ctl09_item','ctl10_item'],
{serviceMethod:["GetUserInfo"],servicePath:["/CombinedDescriptorsExample/Services/Users/GetUserInfo.svc"],userId:[123,0,1,[1,6],2,[2,7],3,3,4,4,0,5]},
null,
null);
});
$createMultiple is a function similar to $create, but it creates.. multiple components of a script control/behaviour type.
It takes 5 arguments: name of a script control type to create, array of html elements’ ids, object describing properties setters, events setter and component references setters. Each setter has the name of property (event, component ref) and the value which is always an array. If all script control instances have the same value for the property then the value-array will have only one element, otherwise it is an array where each odd elements is a value and it’s next element is an index (or array of indexes) in html elements array.
Combining is controlled by ScriptManager’s property CombineScriptDescriptors.
A few steps and you can use it with AjaxControlToolkit:
- Add reference to CombinedDescriptors.dll (or whatever dll you’ve put the classes in) to AjaxControlToolkit project
- Derive ExtenderControlBase class (AjaxControlToolkit\ExtenderBase\ExtenderControlBase.cs) from my ExtenderControlBase class
- Derive ScriptControlBase class (AjaxControlToolkit\ExtenderBase\ScriptControlBase .cs) from my ScriptControlBase class
- Derive ToolkitScriptManager class (AjaxControlToolkit\ToolkitScriptManager\ToolkitScriptManager.cs) from my ToolkitScriptManager class
If you want to test it with AjaxControlToolkit SampleWebSite , change the web site’s trust level to Full (<system.web><trust level="Full"/>), add CombineScriptDescriptors=”true” to the declaration of the ajaxToolkit:ToolkitScriptManager in \App_Themes\SampleSiteTheme\ToolkitScriptManager.skinfile and add the code for $createMultiple function to Common.js in AjaxControlToolkit project.
As Reflection to private types and members is used it may not work in next versions of ASP.NET.
Now it works in .NET 3.5 and .NET 4 Beta 2.
четверг, 8 октября 2009 г.
HttpApplication.Init method
HttpApplication class has a method Init. It is virtual and called by ASP.NET runtime when initializing of a HttpApplication is almost finished i.e. all modules have been initialized and all event handlers in the Global.asax have been registered. It is also lat time when you can attach handlers to the HttpApplication events. The method is quite handy if you want to place your custom HttpApplication in a separate class library project.
I’ve used it to see which modules are registered for an application and subscribed for the application events, and how much time each stage of the request processing takes. The output looks like the following.
See attached file
Modules | HttpApplication event handlers | Timing | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
OutputCache Session WindowsAuthentication FormsAuthentication PassportAuthentication RoleManager UrlAuthorization FileAuthorization AnonymousIdentification Profile ErrorHandlerModule ServiceModel DefaultAuthentication | BeginRequest ASP.global_asax.Application_BeginRequest AuthenticateRequest System.Web.Security.WindowsAuthenticationModule.OnEnter System.Web.Security.PassportAuthenticationModule.OnEnter DefaultAuthentication System.Web.Security.DefaultAuthenticationModule.OnEnter PostAuthenticateRequest System.ServiceModel.Activation.HttpModule.ProcessRequest AuthorizeRequest System.Web.Security.UrlAuthorizationModule.OnEnter System.Web.Security.FileAuthorizationModule.OnEnter ResolveRequestCache System.Web.Caching.OutputCacheModule.OnEnter AcquireRequestState System.Web.Profile.ProfileModule.OnEnter AcquireRequestStateAsync System.Web.SessionState.SessionStateModule.BeginAcquireState System.Web.SessionState.SessionStateModule.EndAcquireState ReleaseRequestState System.Web.SessionState.SessionStateModule.OnReleaseState UpdateRequestCache System.Web.Caching.OutputCacheModule.OnLeave EndRequest System.Web.SessionState.SessionStateModule.OnEndRequest System.Web.Security.PassportAuthenticationModule.OnLeave System.Web.Profile.ProfileModule.OnLeave |
|
вторник, 29 сентября 2009 г.
Perfomant Eval
Add the following code to your base page and base user control.
protected TItem Eval<TItem>()
{
return (TItem)GetDataItem();
}
ASP.NET white space cleaning with no runtime cost
I think many asp.net developer looking at the markup generated by a ASP.NET pages wanted to get rid of those white space without necessity of changing nice indents of their pages and user controls.
Existing solutions of the problem based on one of the two methods: implementing a cleaning HtmlTextWriter and returning an instance of it in Page.CreateHtmlTextWriter override, or implementing a cleaning Stream and setting the HttpResponse.Filter property to an instance of the Stream.
But both methods incur runtime performance costs (I am going to show in a next post why that happens).
In my solution white space in generated markup removed at pages’ compile time, so that at runtime it looks as if white space was removed manually by the developers.
One would say that it is not actually a solution because it relies on Reflection and depends on implementation details of the particular version of ASP.NET. I would answer – Thanks God that I haven’t had to resort to the help of unsafe code and pointer arithmetic :)
Let’s start with the beginning. When ASP.NET generates C#/VB code for an ASP.NET page it uses ControlBuilders representing almost every entity (except text) in the page tree. Besides holding information about the part of the page it represents, they let controls creators change different aspects of generated code (in .NET 3.5 SP1 including ability to change generated CodeDom). For regular pages control builders exist at compile time only, but in “no compile” pages they actually create at runtime the parts they are responsible for.
As a page at runtime time is a tree of controls, server side code and text , the page at compile time is a tree of control builders. Each builder holds a collection of subbuilders in an ArrayList. Untyped collection is used because literal strings are placed in subbuilders collection not being wrapped in control builders.
Knowing all that we can traverse control builder tree from the root, iterate over the each builder’s subbuilders collection, find instances of strings and replace them with cleaned versions.
Getting access to the root control builder at right time was not easy. I tried different ways but all had shortcomings or inconveniences. But then examining .NET sources by Reflector I found the perfect way - PageParserFilter. PageParserFilter “provides an abstract base class for a page parser filter that is used by the ASP.NET parser to determine whether an item is allowed in the page at parse time”. This ability (among other useful things) was added to ASP.NET 2.0 as a result of cooperation between ASP.NET team and SharePoint team poring their product to ASP.NET. The only method of interest now is PageParserFilter.ParseComplete(ControlBuilder rootBuilder) and it is the right place and time for accessing the root builder. The remaining part is easy. See the attached web site project. Compile the classes in a dll, drop it in Bin folder, small change to web.config and voilà– ASP.NET white space cleaning with no runtime cost!
BTW the code has been working for a few projects in the wild with no problems.
UPDATE (17 Aug 2010): I’ve updated the sample to work with MVC 2 and MVC 3 Preview 1 (including support of Razor view engine).
UPDATE (9 Oct 2010): Now it works with MVC 3 Beta.
UPDATE (4 May 2011): Finally with MVC 3 RTW
суббота, 19 сентября 2009 г.
Tuple as value type
There is new type in .NET BCL - Tuple. What is it is explained in the article CLR Inside Out: Building Tuple. The BCL team has decided it to be a reference type. The reason is well motivated but I think there are cases when having a tuple as a valuetype is beneficial. One of the such case is when you use a tuple as a key in a dictionary. Creating an object in the heap just to get a value from the dictionary or to find out whether it exists would be.. at least not proper use of GC. Especialy when you do it in a tight loop.
Honestly, using keys in dictionaries were the only reason I have used tuples before. Now not to interfere with with Tuple from BCL and to conform to it I have renamed my value type Tuple to TupleValue, properties Value1, Value to Item1, Item2, factory method New to Create.
Implementation is trivial. The only important detail is IEquatable<T>. A value type not implementing this interface is boxed when used as a key in a dictionary.
using System;
using System.Collections.Generic;
namespace Omari
{
public static class TupleValue
{
public static TupleValue<TItem1, TItem2> Create<TItem1, TItem2>(TItem1 item1, TItem2 item2)
{
return new TupleValue<TItem1, TItem2>(item1, item2);
}
public static TupleValue<TItem1, TItem2, TItem3> Create<TItem1, TItem2, TItem3>(TItem1 item1, TItem2 item2, TItem3 item3)
{
return new TupleValue<TItem1, TItem2, TItem3>(item1, item2, item3);
}
}
public struct TupleValue<TItem1, TItem2> : IEquatable<TupleValue<TItem1, TItem2>>
{
TItem1 _item1;
TItem2 _item2;
public TItem1 Item1 { get { return _item1; } }
public TItem2 Item2 { get { return _item2; } }
public TupleValue(TItem1 item1, TItem2 item2)
{
_item1 = item1;
_item2 = item2;
}
public bool Equals(TupleValue<TItem1, TItem2> other)
{
return EqualityComparer<TItem1>.Default.Equals(_item1, other.Item1) &&
EqualityComparer<TItem2>.Default.Equals(_item2, other.Item2);
}
public override bool Equals(object obj)
{
if (obj.GetType() != typeof(TupleValue<TItem1, TItem2>))
return false;
return Equals((TupleValue<TItem1, TItem2>)obj);
}
public override int GetHashCode()
{
return EqualityComparer<TItem1>.Default.GetHashCode(_item1) ^
EqualityComparer<TItem2>.Default.GetHashCode(_item2);
}
}
public struct TupleValue<TItem1, TItem2, TItem3> : IEquatable<TupleValue<TItem1, TItem2, TItem3>>
{
TItem1 _item1;
TItem2 _item2;
TItem3 _item3;
public TItem1 Item1 { get { return _item1; } }
public TItem2 Item2 { get { return _item2; } }
public TItem3 Item3 { get { return _item3; } }
public TupleValue(TItem1 item1, TItem2 item2, TItem3 item3)
{
_item1 = item1;
_item2 = item2;
_item3 = item3;
}
public bool Equals(TupleValue<TItem1, TItem2, TItem3> other)
{
return EqualityComparer<TItem1>.Default.Equals(_item1, other.Item1) &&
EqualityComparer<TItem2>.Default.Equals(_item2, other.Item2) &&
EqualityComparer<TItem3>.Default.Equals(_item3, other.Item3);
}
public override bool Equals(object obj)
{
if (obj.GetType() != typeof(TupleValue<TItem1, TItem2, TItem3>))
return false;
return Equals((TupleValue<TItem1, TItem2, TItem3>)obj);
}
public override int GetHashCode()
{
return EqualityComparer<TItem1>.Default.GetHashCode(_item1) ^
EqualityComparer<TItem2>.Default.GetHashCode(_item2) ^
EqualityComparer<TItem3>.Default.GetHashCode(_item3);
}
}
}
понедельник, 27 июля 2009 г.
overVARing
var commandLine = SomeClass.SomeProperty;
var splitCommandLine = SomeClass.SomeMethod();
It tells nothing about the types of the variables.
Using var keyword is tolerable when you explicitly pronounce the type of the expression on the right side of the assignment or when the contract (your expectations) of the variable is important, but not its exact type.
var logger = new FastLogger();
var amout = Convert.ToInt32(input);
var logger = (ILogger)state; //or as ILogger
var query = from person in db.Persons where person.Age > 65 select person;
воскресенье, 14 июня 2009 г.
C# 4.0 lock statement implementation
We all know what C# lock statement turns into.
Giving
static void Main(string[] args)
{
lock (s_lock)
{
}
}
We get
private static void Main(string[] args)
{
object CS$2$0000;
Monitor.Enter(CS$2$0000 = s_lock);
try
{
}
finally
{
Monitor.Exit(CS$2$0000);
}
}
But in C# 4 lock statement uses new overload of Monitor.Enter and enters guarded region inside try block.
private static void Main(string[] args)
{
object CS$2$0000;
bool <>s__LockTaken0 = false;
try
{
Monitor.Enter(CS$2$0000 = s_lock, ref <>s__LockTaken0);
}
finally
{
if (<>s__LockTaken0)
{
Monitor.Exit(CS$2$0000);
}
}
}
If you want to know what it was made for read this exhaustive Joe Duffy’s explanation.
If you have thought that the window between Monitor.Enter and try block is too short to be considered read this case.
пятница, 5 июня 2009 г.
New SOS commands in CLR 4.0 Beta1
I seems that SOS will have several new commands in CLR 4.0.
How did I find that out? I just retrieved SOS help file (it’s just a binary resource in SOS.dll) from .NET 2.0 SOS and .NET 4.0 SOS and fed the files to WinDiff. And that is what we have.
New commands:
Examining code and stacks
ThreadState
Diagnostic Utilities
VerifyObj
FindRoots
HeapStat
GCWhere
ListNearObj
FinalizeQueue
AnalyzeOOM
Examining the GC history
HistInit
HistStats
HistRoot
HistObj
HistObjFind
HistClear
New arguments for two commands:
!ObjSize [<Object address>] | [-aggregate] [-stat]
!FinalizeQueue [-detail] | [-allReady] [-short]
Supporting DML:
>> Does SOS support DML?
Yes. SOS respects the .prefer_dml option in the debugger. If this setting is
turned on, then SOS will output DML by default. Alternatively, you may leave
it off and add /D to the beginning of a command to get DML based output for it.
Not all SOS commands support DML output.
четверг, 4 июня 2009 г.
Introduction
Hi everybody. I created this blog to share my .NET findings and thoughts. It is also a way to learn English, so if you find my English really weird remember what the blog's name is stand for :)