schuirink.net
main destinations: home | the web & the world | out of here
Google

news headlines

News headlines collected from 498 newsfeeds.

weblogs.asp.net non-ms bloggers

url: http://weblogs.asp.net

Developing custom field type for SharePoint 2010


The ECM features of SharePoint 2010 are excellent. The best thing is the extendibility of the platform using SharePoint designer and Visual Studio. By default SharePoint includes field types such as Single line text, multi-line text etc. The following is the snapshot of the fields available in SharePoint 2010

clip_image001

The out of the box field controls are useful for most situations, but still you may need additional field types when building business applications. Fortunately you can build custom field controls using Visual Studio 2010 and deploy to SharePoint. Custom field control can provide a unique editing and display experience. Custom field controls can be used to include custom client-side validation and a unique editing experience.

In this article I am going to demonstrate how you can build custom field control for SharePoint 2010. For the purpose of this article, I am going to build a custom field control that inherits the single line of text. When displaying the control, it will show the entered text in

tags. Also the field will convert the text to upper case while displaying. The custom field will throw error if it contains more than 10 characters. The examples looks simple, my intention is to show you how easily you can build custom controls. In real time you can add your business logic to build your own field controls.

Open Visual Studio, from the file menu select new project. In the new project dialog, select empty SharePoint project as the template. I have named the project as ?MyCustomFieldProject?

clip_image003

In the SharePoint customization wizard, make sure you select ?deploy as farm solution?. Also you can enter the local site URL where you can deploy the custom field.

clip_image004

Click the Finish button. Visual Studio will create an empty project. In Visual Studio solution explorer, the project looks as follows.

clip_image005

Now you need to add a class to the solution that represents the custom field. Now right click the project and select Add -> Class

clip_image007

I have named the class as ?MyHeaderField?

clip_image009

The class just created have the following code.

clip_image010

Now you need to set the class as public. You need to include the using statement to include Microsoft.SharePoint to get access to the Sharepoint built in types. As I mentioned initially MyHeaderField needs to inherit the SharePoint Text field which is ?SPFieldText?. Now you need to override the 2 default construtors. After making the mentioned changes, the code file looks as follows.

clip_image012

Now I am going to override 2 methods as follows.

  • GetValidatedString ? This will be used to validate the data before saving to database.
  • GetFieldValueAsHtml ? this is how the value will be displayed in the page.

The implementation of the methods are as follows.

clip_image013

Each field type you define should have a corresponding entry in the form of XML file in the XML folder under 14\Template folder. The XML file will have the following naming convention

  • It should start with fldtypes_
  • After _ you can define the field name. It is a good practice to specify the class name as the field name, though it is not a must
  • In the XML file, you need to define the fields such as TypeName, parent type name, type display name, corresponding class and assembly.

Now in the Visual Studio project, you need to add a XML file and while deploying it should be deployed to the folder 14\Template\XML. To do this, you can add a mapped folder to your project. Right click the project in solution explorer, select Add -> SharePoint mapped folder

clip_image015

In the Add mapped folder dialog, expand Template and select XML

clip_image016

Now you can see the XML folder under your project. Any files created here will be deployed to the 14\Template\XML folder in the SharePoint farm where the solution is deployed. Now you need to add the XML file for your field.

Right click the project, select Add -> New Item. Now in the template selection, select Data as the category and then select XML as the file type. I have named fldtypes_MyHeaderField.xml

clip_image018

I have updated the content of the XML file as follows. Be noted that $SharePoint.Project.AssemblyFullName$ will be replaced automatically by the correct assembly name wile deploying. All the other fields are self-explanatory.

clip_image020

Now we are done with all the requirements. From the solution explorer, right click the project and click deploy.

clip_image021

Once deployed, you can add new columns to SharePoint lists and libraries with the type ?MyHeaderField?. Add the new column to SharePoint types will show the new type you added.

clip_image022

I have added a new column named ?MyHeader? to my publishing page content type. Now when I try to add text to the column, it will validate it. See a simple validation

clip_image023

SharePoint 2010 is extensible as you can build and deploy custom fields that address your custom business requirements.



Changing a Control?s Output Dynamically


A question that pops up occasionally in ASP.NET forums or sites like Stack Overflow is how to change a control?s output dynamically. Well, since the CSS Friendly Control Adapters came out, I knew how to do it statically, through static registration on a .browser file (it can also be done dynamically, for all controls of a certain type, by adding a fully qualified type name to HttpContext.Current.Request.Browsers.Adapters collection), but I decided to go and try to do it dynamically, without registration. More specifically, I wanted to achieve two things:

  • Apply a XSL transformation to the generated output, provided it is XML-compliant;
  • Change the output through code in an event handler-like fashion.

So, here?s what I came up with:

   1: <%@ Register Assembly="WebApplication1" Namespace="WebApplication1" TagPrefix="web" %>
   2: ...
   3: <web:OutputAdapterControl runat="server" TargetControlID="table" OnOutput="OnOutput" XslPath="~/table.xsl" />
   4:  
   5: <asp:Table runat="server" ID="table"/>

I have two control declarations, one is for a well known asp:Table, and the other is for my OutputAdapterControl. On its declaration, I have a property that references the asp:Table through its id, one property for an external XSL transformation file and the final one for registering an event handler.

The code for the OutputAdapterControl is:

   1: namespace WebApplication1
   2: {
   3:     [NonVisualControl]
   4:     public class OutputAdapterControl : Control
   5:     {
   6:         private static readonly FieldInfo occasionalFieldsField = typeof(Control).GetField("_occasionalFields", BindingFlags.NonPublic | BindingFlags.Instance);
   7:         private static readonly FieldInfo flagsField = typeof(Control).GetField("flags", BindingFlags.NonPublic | BindingFlags.Instance);
   8:  
   9:         public OutputAdapterControl()
  10:         {
  11:             this.Enabled = true;
  12:         }
  13:  
  14:         public String XslPath
  15:         {
  16:             get;
  17:             set;
  18:         }
  19:  
  20:         public String TargetControlID
  21:         {
  22:             get;
  23:             set;
  24:         }
  25:  
  26:         public Boolean Enabled
  27:         {
  28:             get;
  29:             set;
  30:         }
  31:  
  32:         public event EventHandler Output;
  33:  
  34:         private ControlAdapter getControlAdapter(Control control)
  35:         {
  36:             Object flags = flagsField.GetValue(control);
  37:             MethodInfo setMethod = flags.GetType().GetMethod("Set", BindingFlags.NonPublic | BindingFlags.Instance);
  38:             setMethod.Invoke(flags, new Object[] { 0x8000 });
  39:  
  40:             Object occasionalFields = occasionalFieldsField.GetValue(control);
  41:             FieldInfo rareFieldsField = occasionalFields.GetType().GetField("RareFields");
  42:             Object rareFields = rareFieldsField.GetValue(occasionalFields);
  43:  
  44:             if (rareFields == null)
  45:             {
  46:                 rareFields = FormatterServices.GetUninitializedObject(rareFieldsField.FieldType);
  47:                 rareFieldsField.SetValue(occasionalFields, rareFields);
  48:             }
  49:  
  50:             FieldInfo adapterField = rareFields.GetType().GetField("Adapter");
  51:             ControlAdapter adapter = adapterField.GetValue(rareFields) as ControlAdapter;
  52:  
  53:             return (adapter);
  54:         }
  55:  
  56:         private void setControlAdapter(Control control, ControlAdapter controlAdapter)
  57:         {
  58:             Object occasionalFields = occasionalFieldsField.GetValue(control);
  59:             FieldInfo rareFieldsField = occasionalFields.GetType().GetField("RareFields");
  60:             Object rareFields = rareFieldsField.GetValue(occasionalFields);
  61:             FieldInfo adapterField = rareFields.GetType().GetField("Adapter");
  62:             adapterField.SetValue(rareFields, controlAdapter);
  63:         }
  64:  
  65:         internal void RaiseOutputEvent(OutputEventArgs e)
  66:         {
  67:             if (this.Output != null)
  68:             {
  69:                 this.Output(this, e);
  70:             }
  71:         }
  72:  
  73:         protected override void OnPreRender(EventArgs e)
  74:         {
  75:             if ((this.Enabled == true) && (String.IsNullOrWhiteSpace(this.TargetControlID) == false))
  76:             {
  77:                 Control control = this.FindControl(this.TargetControlID);
  78:                 ControlAdapter controlAdapter = this.getControlAdapter(control);
  79:                 OutputAdapterControlAdapter newAdapter = new OutputAdapterControlAdapter(this, controlAdapter, control, this.XslPath);
  80:  
  81:                 this.setControlAdapter(control, newAdapter);
  82:             }
  83:  
  84:             base.OnPreRender(e);
  85:         }
  86:     }
  87: }

And the code for the control adapter is:

   1: namespace WebApplication1
   2: {
   3:     public class OutputAdapterControlAdapter : ControlAdapter
   4:     {
   5:         private static readonly FieldInfo controlField = typeof(ControlAdapter).GetField("_control", BindingFlags.NonPublic | BindingFlags.Instance);
   6:         private static readonly MethodInfo controlRenderMethod = typeof(Control).GetMethod("Render", BindingFlags.NonPublic | BindingFlags.Instance);
   7:         private static readonly MethodInfo controlAdapterRenderMethod = typeof(ControlAdapter).GetMethod("Render", BindingFlags.NonPublic | BindingFlags.Instance);
   8:  
   9:         public OutputAdapterControlAdapter(OutputAdapterControl outputControl, ControlAdapter original, Control control, String xslPath)
  10:         {
  11:             this.OutputControl = outputControl;
  12:             this.Original = original;
  13:             this.XslPath = xslPath;
  14:             controlField.SetValue(this, control);
  15:         }
  16:  
  17:         protected OutputAdapterControl OutputControl
  18:         {
  19:             get;
  20:             private set;
  21:         }
  22:  
  23:         protected String XslPath
  24:         {
  25:             get;
  26:             private set;
  27:         }
  28:  
  29:         protected ControlAdapter Original
  30:         {
  31:             get;
  32:             private set;
  33:         }
  34:  
  35:         protected override void Render(HtmlTextWriter writer)
  36:         {
  37:             StringBuilder builder = new StringBuilder();
  38:             HtmlTextWriter tempWriter = new HtmlTextWriter(new StringWriter(builder));
  39:  
  40:             if (this.Original != null)
  41:             {
  42:                 controlAdapterRenderMethod.Invoke(this.Original, new Object[] { tempWriter });
  43:             }
  44:             else
  45:             {
  46:                 controlRenderMethod.Invoke(this.Control, new Object[] { tempWriter });
  47:             }
  48:  
  49:             if (String.IsNullOrWhiteSpace(this.XslPath) == false)
  50:             {
  51:                 String path = HttpContext.Current.Server.MapPath(this.XslPath);
  52:  
  53:                 XmlDocument xml = new XmlDocument();
  54:                 xml.LoadXml(builder.ToString());
  55:  
  56:                 builder.Clear();
  57:  
  58:                 XslCompiledTransform xsl = new XslCompiledTransform();
  59:                 xsl.Load(path);
  60:                 xsl.Transform(xml, null, tempWriter);
  61:             }
  62:  
  63:             OutputEventArgs e = new OutputEventArgs() { Html = builder.ToString() };
  64:  
  65:             this.OutputControl.RaiseOutputEvent(e);
  66:  
  67:             if (e.Html != builder.ToString())
  68:             {
  69:                 builder.Clear();
  70:                 builder.Append(e.Html);
  71:             }
  72:  
  73:             writer.Write(builder.ToString());
  74:         }
  75:     }
  76: }

Finally there?s the event argument:

   1: namespace WebApplication1
   2: {
   3:     [Serializable]
   4:     public class OutputEventArgs : EventArgs
   5:     {
   6:         public String Html
   7:         {
   8:             get;
   9:             set;
  10:         }
  11:     }
  12: }

And a sample event handler:

   1: protected void OnOutput(object sender, OutputEventArgs e)
   2: {
   3:     e.Html = e.Html.ToUpper();
   4: }

Please note that this relies heavily on reflection, and, for that matter, will only work with ASP.NET 4.0. It can be made to work with ASP.NET 2/3.5, but you will have to change the code to get to the stored control adapter in the Control class. Thanks to João Angelo for reminding me of that!

If you look at it carefully, you will see that, if an XSL transformation file is specified, the control adapter will use it to transform the output of the target control. Either way, if an event handler is registered, it will raise the event, passing in the event argument the HTML generated by the target control, possibly modified by the XSL transformation. In the event handler, all you have to do is change the Html property of the event argument.

Let me know if this helps in some way, and have fun!



Scaling ASP.NET websites from thousands to millions?LIDNUG


Here?s the recent presentation made on LIDNUG on scaling ASP.NET websites from thousands to millions of users.

Scaling ASP.NET websites from thousands to millions of users by Omar AL Zabir

Here?re the slides.



Agility in SharePoint: Writing Functional Requirements


SharePoint brings more power than ever to the end user.  As usual, this is a double-edged sword.  Its utility as a development platform is unmatched, but since many of the development tools are accessible from the browser UI, the dividing lines can get blurred.

Requirements-gathering (and subsequent documentation) can be tricky, and it's easy for us technical types to get confused about functional versus technical.  Business users do not care about technical requirements and they should not have the opportunity to dictate them.  If you have to explain a term (for example, "list" or "metadata column") to an end user, then most likely it does not belong under the heading of "functional requirements".

Functional requirements are about what the end user needs to accomplish.  An excellent guide for this is the concept of the User Story, as employed in Agile project management (we're kind of big on that here at Improving).  The basic format is as follows:

As a _______ (what type of user),

I want _________

so that I can ___________

This kind of requirement requires (heh) that you also define acceptance criteria, by which you can determine that the requirement has been fulfilled. The end result is that nobody can claim confusion about what you're trying to do, since the team has already agreed on the definition of "done".



NHibernate Metadata


I know that O/RMs like NHibernate are supposed to shield us from the gory database internals such as tables, views, columns and such; however, at times, I do have the need to know how my domain model translates to the database. NHibernate, of course, provides us with the information we need, but it isn?t always easy to find, so I wrote my own extension methods for ISessionFactory that allow me to get the metadata I need in an easy way:

   1: public static IEnumerable GetComponents(this ISessionFactory sessionFactory, Type entityType)
   2: {
   3:     String entityName = (sessionFactory as ISessionFactoryImplementor).TryGetGuessEntityName(entityType);
   4:     IClassMetadata metadata = sessionFactory.GetClassMetadata(entityName);
   5:  
   6:     for (Int32 i = 0; i < metadata.PropertyTypes.Length; ++i)
   7:     {
   8:         IType property = metadata.PropertyTypes[i];
   9:  
  10:         if (property is ComponentType)
  11:         {
  12:             String propertyName = metadata.PropertyNames[i];
  13:             yield return (entityType.GetProperty(propertyName));
  14:         }
  15:     }
  16: }
  17:  
  18: public static IEnumerable GetUserTypes(this ISessionFactory sessionFactory, Type entityType)
  19: {
  20:     String entityName = (sessionFactory as ISessionFactoryImplementor).TryGetGuessEntityName(entityType);
  21:     IClassMetadata metadata = sessionFactory.GetClassMetadata(entityName);
  22:  
  23:     for (Int32 i = 0; i < metadata.PropertyTypes.Length; ++i)
  24:     {
  25:         IType property = metadata.PropertyTypes[i];
  26:  
  27:         if (property is CustomType)
  28:         {
  29:             String propertyName = metadata.PropertyNames[i];
  30:             yield return (entityType.GetProperty(propertyName));
  31:         }
  32:     }
  33: }
  34:  
  35: public static IEnumerable GetProperties(this ISessionFactory sessionFactory, Type entityType)
  36: {
  37:     String entityName = (sessionFactory as ISessionFactoryImplementor).TryGetGuessEntityName(entityType);
  38:     IClassMetadata metadata = sessionFactory.GetClassMetadata(entityName);
  39:     
  40:     for (Int32 i = 0; i < metadata.PropertyTypes.Length; ++i)
  41:     {
  42:         IType property = metadata.PropertyTypes[i];
  43:  
  44:         if (!(property is OneToOneType) && !(property is ManyToOneType) && !(property is ComponentType))
  45:         {
  46:             String propertyName = metadata.PropertyNames[i];
  47:             yield return (entityType.GetProperty(propertyName));                    
  48:         }
  49:     }
  50: }
  51:  
  52: public static IEnumerable GetAssociations(this ISessionFactory sessionFactory, Type entityType)
  53: {
  54:     String entityName = (sessionFactory as ISessionFactoryImplementor).TryGetGuessEntityName(entityType);
  55:     IClassMetadata metadata = sessionFactory.GetClassMetadata(entityName);
  56:  
  57:     for (Int32 i = 0; i < metadata.PropertyTypes.Length; ++i)
  58:     {
  59:         IType property = metadata.PropertyTypes[i];
  60:  
  61:         if (property is OneToOneType)
  62:         {
  63:             String propertyName = metadata.PropertyNames[i];
  64:             yield return (entityType.GetProperty(propertyName));
  65:         }
  66:         else if (property is ManyToOneType)
  67:         {
  68:             String propertyName = metadata.PropertyNames[i];
  69:             yield return (entityType.GetProperty(propertyName));
  70:         }
  71:     }
  72: }
  73:  
  74: public static PropertyInfo GetIdentifier(this ISessionFactory sessionFactory, Type entityType)
  75: {
  76:     String entityName = (sessionFactory as ISessionFactoryImplementor).TryGetGuessEntityName(entityType);
  77:     AbstractEntityPersister persister = (sessionFactory as ISessionFactoryImplementor).TryGetEntityPersister(entityName) as AbstractEntityPersister;
  78:  
  79:     if (persister != null)
  80:     {
  81:         return (entityType.GetProperty(persister.IdentifierPropertyName));
  82:     }
  83:     else
  84:     {
  85:         return (null);
  86:     }
  87: }
  88:  
  89: public static IEnumerable GetIdentifierColumnNames(this ISessionFactory sessionFactory, Type entityType)
  90: {
  91:     String entityName = (sessionFactory as ISessionFactoryImplementor).TryGetGuessEntityName(entityType);
  92:     AbstractEntityPersister persister = (sessionFactory as ISessionFactoryImplementor).TryGetEntityPersister(entityName) as AbstractEntityPersister;
  93:  
  94:     if (persister != null)
  95:     {
  96:         return (persister.IdentifierColumnNames);
  97:     }
  98:     else
  99:     {
 100:         return (null);
 101:     }
 102: }
 103:  
 104: public static String GetColumnName(this ISessionFactory sessionFactory, Type entityType, String propertyName)
 105: {
 106:     String entityName = (sessionFactory as ISessionFactoryImplementor).TryGetGuessEntityName(entityType);
 107:     AbstractEntityPersister persister = (sessionFactory as ISessionFactoryImplementor).TryGetEntityPersister(entityName) as AbstractEntityPersister;
 108:  
 109:     if (persister != null)
 110:     {
 111:         return (persister.GetPropertyColumnNames(propertyName).SingleOrDefault());
 112:     }
 113:     else
 114:     {
 115:         return (null);
 116:     }
 117: }
 118:  
 119: public static String GetTableName(this ISessionFactory sessionFactory, Type entityType)
 120: {
 121:     String entityName = (sessionFactory as ISessionFactoryImplementor).TryGetGuessEntityName(entityType);
 122:     AbstractEntityPersister persister = (sessionFactory as ISessionFactoryImplementor).TryGetEntityPersister(entityName) as AbstractEntityPersister;
 123:  
 124:     if (persister != null)
 125:     {
 126:         return (persister.TableName);
 127:     }
 128:     else
 129:     {
 130:         return (null);
 131:     }
 132: }
 133:  
 134: public static IEnumerable GetCollections(this ISessionFactory sessionFactory, Type entityType)
 135: {
 136:     String entityName = (sessionFactory as ISessionFactoryImplementor).TryGetGuessEntityName(entityType);
 137:     IClassMetadata metadata = sessionFactory.GetClassMetadata(entityName);
 138:     String prefix = String.Concat(entityName, ".");
 139:     IDictionary collectionMetadata = sessionFactory.GetAllCollectionMetadata().Where(x => x.Key.StartsWith(prefix)).ToDictionary(x => x.Key, x => x.Value);
 140:  
 141:     foreach (String key in collectionMetadata.Keys)
 142:     {
 143:         String propertyName = key.Replace(prefix, String.Empty);
 144:         yield return(entityType.GetProperty(propertyName));
 145:     }
 146: }

A brief explanation:

  • GetProperties: all the mapped properties for a given entity;
  • GetComponents: given an entity type, returns all the properties that are mapped as components;
  • GetUserTypes: all the properties that are mapped as custom user types;
  • GetIdentifier: the property that is mapped as the identifier;
  • GetAssociations: properties mapped as one to one or many to one, that is, that point to another entity;
  • GetCollections: properties mapped as one to many, that is, collections, of any type;
  • GetTableName: the table or view name where the entity is stored;
  • GetIdentifierColumnNames: the names of the column(s) that compose the primary key for the table;
  • GetColumnName: the table or view column that store a given property.


Writing ASP.NET MVC bootstrapper with AutoBox


This will post will show how you can use AutoBox to easily write a bootstrapper for ASP.NET MVC. I have used the latest version of AutoBox (available from nuget, this version also includes Castle.Windsor internally for managing dependencies rather using its own resolver and does not require interface to type naming convention [IAccountRepository ?> AccountRepository]) . To understand what is AutoBox , how you can use it for caching using memcached and let it automatically handle dependencies for controllers and repositories, i would recommend to take a look at this post:

http://weblogs.asp.net/mehfuzh/archive/2011/11/06/introducing-autobox-on-the-fly-dependency-injection-and-caching-container.aspx

Moving forward , let?s consider a simple bootstrapper interface:

  1. public interface IBootStrapperTask
  2. {
  3.     void Execute();
  4. }

The Execute()  method will be invoked during initialization for registering routes, controllers, mappings (AutoMapper), etc. We will have one static factory (Ex. BootStrapper)  that will initiate it through CommonServiceLocator.

  1. public static class BootStrapper
  2. {
  3.     ///
  4.     /// Executes registered tasks.
  5.     ///
  6.     public static void Execute()
  7.     {
  8.         ServiceLocator.Current.GetAllInstances<IBootStrapperTask>().ToList().ForEach(task =>task.Execute());
  9.     }
  10. }

A typical example of a bootstrapping task could be RegisterRoutes:

  1. public class RegisterRoutes : IBootStrapperTask
  2. {
  3.     private readonly RouteCollection routes;
  4.  
  5.     ///
  6.     /// Initializes the new instance of class.
  7.     ///
  8.     public RegisterRoutes()
  9.         : this(RouteTable.Routes)
  10.     {
  11.         // intentionally left blank.
  12.     }
  13.  
  14.     ///
  15.     /// Initializes the new instance of class.
  16.     ///
  17.     internal RegisterRoutes(RouteCollection routes)
  18.     {
  19.         this.routes = routes;
  20.     }
  21.  
  22.     public void Execute()
  23.     {
  24.         routes.Clear();
  25.  
  26.         routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
  27.         routes.IgnoreRoute("{*favicon}", new {favicon = @"(.*/)?favicon.ico(/.*)?"});
  28.  
  29.         Routes.Register(routes);
  30.     }

Here on line 29, i have added Routes.Register which is similar to the BootStrapper.Execute() that further narrows down to specific routing classes. For example. AccountRoutes.

  1. public static void Register(RouteCollection routes)
  2. {
  3.     ServiceLocator.Current.GetAllInstances<IRoutesRegistration>().ToList()
  4.        .ForEach(task => task.Register(routes));
  5. }

The code inside Routes class again pretty straight forward and exactly identical to BootStrapper except the IRoutesRegistration interface. We can also have RegisterControllers but since the dependencies are automatically wired by AutoBox, we only need to specify (if required) what repository methods to be data cached and for what duration.

  1. public class RegisterControllers : IBootStrapperTask
  2. {
  3.     void IBootStrapperTask.Execute()
  4.     {
  5.         Container.Setup<ProductRepository>(x => x.GetProductDetails(0)).Caches(TimeSpan.FromMinutes(1)).VaryByArgs();
  6.         ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
  7.     }
  8. }

More on caching and how MyControllerFactory should look like; please check my previous post as well as the product documentation. Finally, it?s about gluing the whole thing together and we just need to have these lines in global.asax.cs

  1. protected void Application_Start()
  2. {
  3.     // Initializes autobox self.
  4.     Container.Init();
  5.     BootStrapper.Execute();
  6. }

When you will run the project; if you followed the flow then it should work as you have expected it. The project page for AutoBox can be reached here: http://mehfuzh.github.com/AutoBox/ .

 

Hope that helps



Tips and Important Steps for Migrating Apps to Windows Azure


 The following are the few important steps and tips for migrating ASP.NET apps to Windows Azure.

  1. Convert the ASP.NET application into a Web Role project.
  2. Verify that the application is running correctly in the development environment.
  3. Make sure that your application is 64-bit compatible since Window azure is a 64-bit environment.
  4. Since Window Azure Web Roles runs on IIS7 Integrated mode, make sure that your web application does not have any issues with running on IIS 7 Integrated mode.
  5. If your web app is using Session, Membership, Roles and Profile data, you have to find a way to make the state information is working with Windows Azure environment. You can use ASP.NET Universal Providers for handling Session, Membership, Roles and Profile which will be working with Sql Azure. The Windows Azure Caching Service is also providing a provider for ASP.NET Session state which will be faster than working with Sql Azure, but will be bit expensive than using Sql Azure.
  6. If you are using ASP.NET caching, it would be recommended to use The Windows Azure Caching Service. The Windows Azure Caching Service is the better way to use Caching in Windows Azure.
  7. Upload and save files to BLOB storage, if your web application is dealing with documents, media files, etc.
  8. If your application is using any Windows services or using any background processing, migrate these services to Worker Roles.
  9. Put messages to Windows Azure storage Queue or Service Bus Queue if you want to communicate between Web Role and Worker Role.
  10. If you want to make federated claims-based authentication and single sign-on, you can use Windows Azure Access Control Service (ACS) that enables federated authentication. It will work with external identity providers such as Windows Live, Google, Facebook, and Open ID and you can also able to define service identities in ACS that lets you to authenticate without using an external identity provider.
  11. Use startup tasks if you want to perform operations and install components before your Azure Role starts on Virtual Server. You can add startup tasks by editing the ServiceDefinition.csdef file.
  12. Consider moving out some configuration settings in web.config files to ServiceConfiguration.cscfg so that you do not require redeployment after every change in configuration. Data in the ServiceConfiguration.cscfg file can be edited at runtime.
  13. The Windows Azure environment does not provide a SMTP relay or mail relay service. So if your application is using e-mail services, it would be recommended to use a third party service (like SendGrid or AuthSMTP) to send email from inside Windows Azure.
  14. If you are using Sql Azure, use a SQL Server 2008 R2 client so that you can easily migrate database schema and data into Sql Azure. And you can connect the Sql Azure from the SQL Server 2008 R2 client.


 




Email-New Html5 input element


In most of the websites we have contact forms and other forms where we have some standard inputs like Phone,Email and Website URL and those are widely used in any site and has specific features. Email is one of the most standard used input elements which are used in our forms. Till HTML 4.1 we have standard input type text and that?s for we were doing input validation with java script and other technologies. While we all know HTML5 is there and it?s contains lots of goodies, One of them is email input types.

Email input type comes with HTML5 as standard input type. It has all validation by default which are required for email input like we must have @ and . while we entered email input type.

Let?s check email input type in details. Let?s create a ASP.NET MVC3 project with HTML5 Markup like following. To do that I have created a new Project called via File->New Project-> ASP.NET MVC 3 web application like following.

HTML5, Email,Input Element

Once you click ok following dialog box will come. Where you can select HTML5 markup as default.

HTML5Markup

Here I have selected HTML ?Use hTML5 semantic markup?. So It will create a new project with HTML5 semantic markup. Now our Basic ASP.NET MVC application is ready so let?s write some code to check how Email input works. So I have written following code to check how its works in Index view of ASP.NET MVC application.

Following is a code for that.

@{
   ViewBag.Title = "Home Page";
}

@ViewBag.Message

To learn more about ASP.NET MVC visit http://asp.net/mvc.

Now let?s run that in browser. It will look like following.

Email, Input Type, Validation,HTML5

Now I am trying to input wrong email address and when I press submit button. It will show validation like following.

Email Input Type

So it?s showing validation that please input valid email address. Here I have not written any code for validation. So It?s a by default browser functionality. For the browsers which don?t understand email input type it will work as same old input type. That?s it. It's very easy and with the help of HTML5 we can do lots of other stuff. I am going to explain them in future posts. Hope you like it. Stay tuned for more..Happy programming.

Shout it


My first video for code refactoring in visual studio 2010


I have been planning this since long but now Its happened. I have created a video for visual studio 2010 code refactoring features. I have made this video public. Following is a link for that.

http://www.youtube.com/watch?v=HvC63rE7tB4&feature=share

Here is the video..

Please see the video and let me know your feedback. I am not a trained professional in this but I have tried to create it. Hope fully I will master this technique in some time. Stay tuned for more. Till then Happy programming.

Shout it


CodedUI: Close Dialogs and Windows


UI automation could be a very very complex procedure. Several things could change between different executions, controls could be moved or renamed, etc.

Some simple things such as closing a dialog popup/window could be challenging..

Let?s try to recreate the problem. File/New Project in Visual Studio 2010, then select Windows Forms.

Add a button with the following handler on the click event:

MessageBox
private void button1_Click(object sender, EventArgs e)
{
    MessageBox.Show("Try closing me..", "Try closing me..", MessageBoxButtons.OKCancel);
}

Record a CodedUI test that opens our super simple WinForm App, click Button1 and then close the message box. Finally, add one last step to record that closes the Main Window.

Now run the previous CodeUI test and check how the test reports a successful execution. Note that your Message Box is still opened and your application is still waiting for input.

* I imagine that it should be a better way of working around this effect than the following. If you figure it out let me know :).

Let?s create a UIMapExtensions class (containing extensions methods of course)

UIMapExtensions
public static class UIMapExtensions
{
    public delegate void CloseTestControlCallback();

    public static bool CloseWindow(this UITestControl testControl, CloseTestControlCallback closeCallback)
    {
        var closeSuccess =
            testControl.WaitForControlCondition(
                tc =>
                {
                    closeCallback();
                    return !tc.Exists;
                }, 3000);
        return closeSuccess;
    }

    public static bool CancelDialog(this UITestControl testControl)
    {
        var closeSuccess =
            testControl.WaitForControlCondition(
                tc =>
                {
                    Keyboard.SendKeys("{ESC}");
                    return !tc.Exists;
                }, 3000);
        return closeSuccess;
    }

    public static bool AcceptDialog(this UITestControl testControl)
    {
        var closeSuccess =
            testControl.WaitForControlCondition(
                tc =>
                {
                    Keyboard.SendKeys("{ENTER}");
                    return !tc.Exists;
                }, 3000);
        return closeSuccess;
    }

    public static bool CloseWindow(this UITestControl testControl)
    {
        var closeSuccess =
            testControl.WaitForControlCondition(
                tc =>
                {
                    WinApi.PostMessage(tc.WindowHandle, WinApi.WM_CLOSE, 0, 0);
                    return !tc.Exists;
                }, 3000);
        return closeSuccess;
    }
}

I am using 3 techniques in the previous code fragment. In each one of them, we wait for the control to respond to the close action (for 3000 ms).

  1. CloseWindow that receives a delegate to the close action. You can pass in the original Close method generated by the UIMap as you will see in the Test Method code below.
  2. CloseWindow with no arguments using PostMessage Win API and P/Invoke (this is some how brute force :)).
  3. AcceptDialog and CancelDialog: assuming it is a message box with Ok/Cancel buttons and that the window is in the foreground.

Now you can just replace some of generated test code in the Test Class (not in the UIMap):

Test Method
[TestMethod]
public void CodedUITestMethod1()
{
    this.UIMap.OpenApplication();
    this.UIMap.OpenPopup();
    //this.UIMap.ClosePopup();

    // try one of the following..
    var closeSuccess = this.UIMap.UItryclosingmeWindow.CloseWindow(this.UIMap.ClosePopup);
    //var closeSuccess = this.UIMap.UItryclosingmeWindow.AcceptDialog();
    //var closeSuccess = this.UIMap.UItryclosingmeWindow.CancelDialog();
    //var closeSuccess = this.UIMap.UItryclosingmeWindow.CloseWindow();
    if (!closeSuccess)
        Assert.Fail("Popup not closed!");

    this.UIMap.CloseApplication();
}

My two cents..