There is a whitepaper about new features of ASP.NET 4.5, dozens of blog posts, videos from conferences, some tutorials and MSDN.aspx) topic describing overall changes. But why there are no reports about what types were actually added in .NET 4.5 Beta? Where are lists of “new types added to assembly N” or “types that became public in assembly N”? I understand that these lists are not very interesting and that it is more convenient to read descriptions of the new features. Nobody cares about details until they start working against you. And this is normal, right and ok, but now I have some free time and I want to share info about new types that were added or became public in .NET 4.5 comparing to .NET 4.0.
It is pretty simple to do compiled assemblies diff if you have NDepend or similar tool, but what if you (like me) have no license? I started thinking to enumerate public types via reflection, but soon recalled that .NET 4.5 beta replaces assemblies of .NET 4.0 during installation and Assembly.LoadFrom will not work. To overcome this I decided to parse and compare XML documentation that comes along with all .NET assemblies. Simple as that, every public type is documented and difference between old and new version of documentation will give me at least names of types.
Ok, where to get xml documentation files for .NET 4.0? Binaries with xml docs of .NET 4.0 and 4.5 are located in :\Program Files[(x86)]\Reference Assemblies\Microsoft\Framework.NETFramework.
What I wanted is to get some statistics. There are 969 new public types in .NET 4.5. But it does not mean that those are completely new things, because it is not, it means that out of the box .NET 4.5 Beta has +969 new types comparing to .NET 4.0 and now there are totally 14971 public and documented types in .NET 4.5. Almost 15K only public types - that’s incredibly huge number.
Most of new types are located in System.IdentityModel, System.Web and System.Windows.Controls.Ribbon assemblies. Taking into account that System.IdentityModel is providing authentication and authorization features and System.Windows.Controls.Ribbon is UI library allowing use of Microsoft Ribbon for WPF, we can make a conclusion that vast amount of new changes is connected with web.
But the most interesting thing was to examine minor changes and see that something new and really useful has been added. And I encourage you to look over list of new classes and I bet you will find something interesting.
LINQPad script with which I did the documentation comparison is listed below. Excel report with some diagrams is also available online.
voidMain(){// in case of non 64 bit system change "Program Files (x86)" to "Program Files"stringnet40Dir=@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\";stringnet45Dir=@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\";// 1. Get all types from all xml doc files in both directories that are containing .NET assemblies and group them by assembliesvarnet40Grouped=GetPublicTypesByAssembly(net40Dir);varnet45Grouped=GetPublicTypesByAssembly(net45Dir);// 2. Get list of newly added assembliesvarnewAssemblies=net45Grouped.Where(kvp=>!net40Grouped.ContainsKey(kvp.Key)).ToList();Console.WriteLine("New assemblies in .NET 4.5 Beta: (total count - {0})",newAssemblies.Count);newAssemblies.ForEach(kvp=>Console.WriteLine(kvp.Key));Console.WriteLine();// 3. Get all assemblies that are not present in .NET 4.5 betavarnonExistentAssemblies=net40Grouped.Where(kvp=>!net45Grouped.ContainsKey(kvp.Key)).ToList();Console.WriteLine("Assemblies that are not present in .NET 4.5 Beta folder comparing to .NET 4.0: (total count - {0})",nonExistentAssemblies.Count);nonExistentAssemblies.ForEach(kvp=>Console.WriteLine(kvp.Key));Console.WriteLine();// 4. Get all new types in .NET 4.0 and .NET 4.5 Beta assembliesvarnet40=net40Grouped.SelectMany(kvp=>kvp.Value).ToList();varnet45=net45Grouped.SelectMany(kvp=>kvp.Value).ToList();varnewTypes=net45.Except(net40).ToList();Console.WriteLine("Types count in .NET 4.0:|{0}",net40.Count);Console.WriteLine("Types count in .NET 4.5 Beta:|{0}",net45.Count);Console.WriteLine("New types count in .NET 4.5 Beta comparing to .NET 4.0:|{0}",newTypes.Count);// 5. Get assemblies that are containing new typesvarassembliesWithChanges=net45Grouped.Where(kvp=>newTypes.Any(type=>kvp.Value.ContainsValue(type.Value)));// 6. Remove existent in .NET 4.0 types from assembliesWithChanges to get clear lists of new types grouped by assembliesvarnewTypesGrouped=assembliesWithChanges.ToDictionary(typesGroup=>typesGroup.Key,typesGroup=>typesGroup.Value.Except(net40).Select(kvp=>kvp.Value).ToList());Console.WriteLine("New types by assembly:");foreach(varassemblyWithNewTypesinnewTypesGrouped){Console.WriteLine("{0}|{1}",assemblyWithNewTypes.Key,assemblyWithNewTypes.Value.Count);foreach(vartypeNameinassemblyWithNewTypes.Value){Console.WriteLine(typeName);}Console.WriteLine();}}Dictionary<string,Dictionary<int,string>>GetPublicTypesByAssembly(stringxmlDocsDirectory){string[]xmlDocFiles=Directory.GetFiles(xmlDocsDirectory,"*.xml");varresult=newDictionary<string,Dictionary<int,string>>();foreach(varxmlDocinxmlDocFiles){varroot=XDocument.Load(xmlDoc).Root;if(root==null)continue;varmembers=root.Element("members");if(members==null)continue;vartypesByAssembly=members.Elements("member").Where(e=>e.Attribute("name").Value.StartsWith("T:")).ToDictionary(e=>e.Attribute("name").Value.GetHashCode(),e=>e.Attribute("name").Value.Substring(2)/* T: */);result.Add(Path.GetFileNameWithoutExtension(xmlDoc)+".dll",typesByAssembly);}returnresult;}
And at the end here are links that will help a bit to embrace the changes of .NET 4.5 Beta:
UPDATE: igoogle_themes.zip archive is no longer available through Wayback Machine since it is pointing to mattberseth2.com which is not working. However archive could be found on my SkyDrive.
Today when I had to find a theme for ASP.NET GridView the first resource I found in my memory was Matt Berseth’s blog (Google also found something for me but I’m convinced that “favorites list” in my memory is a much better and reliable source). Matt had great examples of AJAX control extenders and some other things connected with styling of ASP.NET controls on his site. But while domain still belongs to Matt Berseth, the site is currently down and not available.
Browse through over 150 billion web pages archived from 1996 to a few months ago.
In fact it never helped me, but I wanted to get rarely visited pages or downloads of a big size so it is nothing to complain. And at this time I was interested in recovery of popular resource and to my relief the page was crawled 20 times from the 3rd of November, 2007. And sample project download was also available! So it took me something near to 20 minutes to get what I wanted and this is nothing comparing to the efforts needed to create my own CSS for a GridView.
When I had worked on ASP.NET MVC project I really liked how input is validated with Data Annotations attributes. And when I had to return to the Web Forms, and write a simple form with some validation, I was wondering how I lived before with standard validator controls. For me, it was never convenient, when I had to write an enormous amount of server tags just to state that “this is required field which accepts only numbers in specified range…”. Yes, there is nothing terrible in declaration of two or three validation controls instead of one. But, if I had a choice, I would like to write only one validator per field and keep all input validation logic as far as I can from the UI markup. And being a developer the code-only approach is most natural for me.
System.ComponentModel.DataAnnotations namespace was introduced in .NET 3.5, and now its classes are supported by wide range of technologies like WPF, Silverlight, RIA Services, ASP.NET MVC, ASP.NET Dynamic Data but not in Web Forms. I thought that someone had already implemented ready-to-use Validator Control with client-side validation, but after searching the Web and most popular open source hosting services I found nothing. Ok, not nothing, but implementations what I have found lacked client-side validation and had some other issues. So I decided to write my own Data Annotations Validator that will also support client-side validation.
Creating Data Annotations Validator Control
Server-Side
As I wanted to achieve compatibility with existing validation controls (new validator is not a replacement for an old ones, it is just an addition to them), it was decided to inherit from BaseValidator. This class does all necessary initialization on both client- and server-sides and exposes all necessary methods for overriding.
First of all EvaluateIsValid method of BaseValidator should be overridden.
123456789101112131415161718192021
protectedoverrideboolEvaluateIsValid(){objectvalue=GetControlValidationValue(ControlToValidate);foreach(ValidationAttributevalidationAttributeinValidationAttributes){// Here, we will try to convert value to type specified on RangeAttibute.// RangeAttribute.OperandType should be either IConvertible or of built in primitive typesvarrangeAttibute=validationAttributeasRangeAttribute;if(rangeAttibute!=null){value=Convert.ChangeType(value,rangeAttibute.OperandType);}if(validationAttribute.IsValid(value))continue;ErrorMessage=validationAttribute.FormatErrorMessage(DisplayName);returnfalse;}returntrue;}
The only interesting aspect of this method is line 16. I’m using FormatErrorMessage method of ValidationAttribute to use all the goodness like support of resources and proper default error message formatting. So, now there is no need to invent something with error messages.
Next thing to deal with is where to get ValidationAttributes collection. There is System.Web.DynamicData.MetaTable class that could be used to retrieve attributes. It was introduced in the first versions of ASP.NET Dynamic Data and now in 4.0 version of Dynamic Data, MetaTable has a static method CreateTable which accepts Type as input parameter. Why using MetaTable, why not retrieve attributes of Type directly from PropertyInfo for specified property name? Because MetaTable also supports retrieving of custom attributes that are applied to property through MetadataTypeAttribute and merges attributes applied to property both in metadata class and entity class. And again, why inventing something new when everything that is needed is right here?
Now let’s look a bit into the future - if we place ObjectType property into DataAnnotationsValidator, it means that we should specify this property for every validator control on page. This is redundancy and leads to copy-pasting which is not acceptable. Lets step aside and create MetadataSource control that will act like metadata provider for validators on page.
Here I also thought about DisplayAttribute which is used to format default error message. Now how ObjectType of MetadataSouce should be specified? Well, we can do it programmatically on Page_Load or do it.. programmatically with CodeExpressionBuilder to keep all control setup in one place.
This is all what was needed to provide server-side validation.
Client-Side
First of all, lets check what standard validator controls could be replaced with Data Annotations attributes.
Data Annotations Attribute
Standard Validator Control
RequiredAttribute
RequiredFieldValidator
StringLengthAttribute
-
RegularExpressionAttribute
RegularExpressionValidator
-
CompareValidator
RangeAttribute
RangeValidator
I have no ideas how to replace CompareValidator and I don’t think it is so critical and necessary to think on it. Time to look how standard validator controls are working on the client side.
Every validator that works on the client side should override AddAttributesToRender method of BaseValidator class. This method adds some fields to resulting javascript object. For example, RequiredFieldValidator adds evaluationfunction and initialvalue fields.
After examining source code of standard validator controls I found that every control sets evaluationfunction field that states a name for a javascript function that actually performs validation on the client-side. RequiredFieldValidator evaluation function is represented below.
The val parameter is a validator object that was initialized with all the fields that were set in the AddAttributesToRender method. Plain and simple, if you need to supply your validator on client-side with some information override AddAttributesToRender and add what you want. To replace standard validators DataAnnotationsValidator is doing a little trick - it adds all standard evaluationfunction names, error messages and all necessary fields that are used by standard validation functions. Evaluation function of DataAnnotationsValidator:
The only thing that remains is to get list of fields and values that are needed for validation functions. Every Data Annotation validation attribute will have an Adapter class that stores an array of ClientValidationRule classes. ClientValidationRule is just a container for storing javascript object field names and evaluationfunction.
privatestaticreadonlyDictionary<Type,Func<ValidationAttribute,string,ValidationAttributeAdapter>>PredefinedCreators=newDictionary<Type,Func<ValidationAttribute,string,ValidationAttributeAdapter>>{{typeof(RangeAttribute),(attribute,displayName)=>newRangeAttributeAdapter(attributeasRangeAttribute,displayName)},{typeof(RegularExpressionAttribute),(attribute,displayName)=>newRegularExpressionAttributeAdapter(attributeasRegularExpressionAttribute,displayName)},{typeof(RequiredAttribute),(attribute,displayName)=>newRequiredAttributeAdapter(attributeasRequiredAttribute,displayName)},{typeof(StringLengthAttribute),(attribute,displayName)=>newStringLengthAttributeAdapter(attributeasStringLengthAttribute,displayName)}};publicstaticValidationAttributeAdapterCreate(ValidationAttributeattribute,stringdisplayName){Debug.Assert(attribute!=null,"attribute parameter must not be null");Debug.Assert(!string.IsNullOrWhiteSpace(displayName),"displayName parameter must not be null, empty or whitespace string");// Added suport for ValidationAttribute subclassing. See http://davalidation.codeplex.com/workitem/695varbaseType=attribute.GetType();Func<ValidationAttribute,string,ValidationAttributeAdapter>predefinedCreator;do{if(!PredefinedCreators.TryGetValue(baseType,outpredefinedCreator))baseType=baseType.BaseType;}while(predefinedCreator==null&&baseType!=null&&baseType!=typeof(Attribute));returnpredefinedCreator!=null?predefinedCreator(attribute,displayName):newValidationAttributeAdapter(attribute,displayName);}
As I said previously, idea was borrowed directly from ASP.NET MVC, so if you are familiar with its validation mechanisms you don’t need to learn how it works here. Approach here is almost identical to ASP.NET MVC which was described well by Brad Wilson. As in ASP.NET MVC DAValidation.IClientValidatable interface exposes an extension point and we can now create a custom validation attribute, implement IClientValidatable interface, write validation function or mix existing ones and get both server- and client-side validation. There is a great set of validation attributes - Data Annotations Extensions created by Scott Kirkland so it is only client function must be changed in order to use them with DataAnnotationsValidator.
My name is Alexander Manekovskiy. I’m .NET developer currently working in BIT, where my main duties are to develop and maintain couple of .NET based solutions and sometimes represent company on regional IT conferences and meetings. Also I’m working as a trainer at ITStep.
I work primarily on the Microsoft .NET technologies stack and my experience is mainly connected with different intranet web-based applications which were tightly integrated with various 3rd party solutions and products such as Microsoft Office, Adobe InDesign, different Storefronts, CRM systems, etc.
I like trying new things and I’m always open to new interesting ideas and concepts. And in this blog I’m going to write about practices, tools and ideas that in my mind could be useful or just interesting for .NET developer. The second idea of running this blog is to have an online 24/7 memory stick.
I’m always open to cooperation and you can freely contact me by email or skype: