Formsy

by AnthonyDang 2. July 2010 03:19

"Formsy is an XML driven forms engine built with ASP.Net 3.5. Formsy is super easy to use, is completely extensible and generates clean markup for easy styling."

Formsy came about after my experiences with Umbraco Contour. I had to do some crazy code to get Contour to do things it was really not meant for. Getting Contour to regionalize form labels, validation messages, and validation regular expressions was the least crazy thing we needed to do. We made Contour do things that it was never ever meant to do.  

After the Contour experience I realized that I needed some practice with composite controls. So I sat at home and started to make a little forms engine. 

This project encompasses almost everything I have learned about .Net since I started at The Farm in 2007. On this my last day at Farm, I'm pleased to launch and share this open source project of mine to The Farm and to the open source community.

Check it out: http://formsy.codeplex.com

 

 

Tags:
Categories:

Regionalizing validation messages, and regex in Umbraco Contour

by AnthonyDang 26. March 2010 12:23
Umbraco Contour is a great package for ultra fast building of forms. What we used it for was not entirely what it was meant for.
 
We were asked to build a form where labels, validation messages AND the regular expressions to validate phone numbers were all regionalized. Contour uses Umbraco's dictionary to store regionalized labels, so we decided to store our validation messages and regex there. Here is how we did it all...
 
Firstly, we name our field's in the form #Form_FirstName, #Form_LastName etc. In the dictionary, add your languages. Then create items with the same names as the form fields (without the #). This allows Contour to replace your labels. We create two matching items to handle regionalized values for validation messages and regex: #Form_FirstName_vmsg, and #Form_FirstName_regex respectively. 
 
Contour installs RenderForm.ascx under \usercontrols\umbracoContour\ in your project. Noticing this, you can easily change it's CodeBehind property to your own  "RenderForm.ascx.cs" which you inherit from Contour's. Overriding OnPreRender() is where the magic happens. The code is pretty self explanatory. We override OnPreRender(), loop through the fields, use their caption property and a suffix ("_vmsg" or "_regex") to get the values from the dictionary.
 
Here is the code... 
  
 
public class RenderForm : Umbraco.Forms.UI.Usercontrols.RenderForm
{
protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            // get the form fields
            FormStorage fs = new FormStorage();
            var form = fs.GetForm(new Guid(this.FormGuid));
            var fields = form.AllFields;

            foreach (var f in fields)
            {
                // get this field's validator
                var fieldId = f.Id.ToString();
                var vals = Page.Validators
                            .Cast<BaseValidator>()
                            .Where(x => x.ControlToValidate == fieldId).ToList();
                if (vals.Count > 0)
                {
                    foreach (var baseVal in vals)
                    {
  // get the validator type and assign properties
                        BaseValidator val = baseVal as RegularExpressionValidator;
                        if (val != null) // it is RegularExpressionValidator
                        {
                            // get regionalized regular expression
                            string valExpression = GetRegionalizedValidationText(f.Caption, "_regex");
                            ((RegularExpressionValidator)val).ValidationExpression = !string.IsNullOrEmpty(valExpression) ? valExpression : ((RegularExpressionValidator)val).ValidationExpression;
                        }
                        else // either a RequiredFieldValidator or another type which you must handle here!
                        {
                            // cast to another Validator type you are expecting, then set it's properties
                        }
 
   // Get the error message
val = baseVal as BaseValidator;
                        if (val != null)
                        {
                            // get regionalized error message
                            string errorMessage = GetRegionalizedValidationText(f.Caption, "_vmsg"); 
                            val.ErrorMessage = !string.IsNullOrEmpty(errorMessage) ? errorMessage : val.ErrorMessage;
                        } 
                        val.ValidationGroup = form.Name;
                    }
                }
            }          
        } 
 
 
  // Uses's the given string and suffix to get a value from the Umbraco dictionary.
        public string GetRegionalizedValidationText(string key, string type)
        {
            if (key.Contains("#"))
            {
                string itemName = key.Split('#')[1] + type;

                if (umbraco.library.GetDictionaryItem(itemName) != null) // note: item can exist and be ""
                    return umbraco.library.GetDictionaryItem(itemName);
            }
            return ""; // key does not contain #, or not found in dictionary
        } 
 } 
 
Tags:
Categories: .Net | Umbraco

Freeing up space on your server

by AnthonyDang 3. February 2010 06:24

Yesterday we went to install service pack 2 on a Windows  Server 2008 machine. It turns out you need at least 5GB free on C: which we didnt have. After deleting everything we possibly could, including running CCleaner and making the Page File non-existant we were still 400MB off the mark.

 

 Then I noticed a system file c:\hiberfil.sys which was 3GB.

 

Well it turns out that Windows Server 2008 still allocates space for a hibernate file. Who would want to hibernate their Live server?

 

Anyway, this is how to gain an exta 3GB...

 

C:\Users\Administrator>powercfg.exe /hibernate off

 

That's it!

 

 

Tags:
Categories: Hosting

Problem: Inserting custom media types in the WYSIWYG of Umbraco 4.0.2.1 shows blank.gif instead of the correct Url

by AnthonyDang 25. January 2010 15:37
The Scenario
We had a custom media type called Image. We did this to store more information about each image that was uploaded.

The Problem
The CMS user wants to insert the image to the WYSIWYG of one of the content nodes but sees blank.gif inserted into the Url field when they click on the custom media type. This does not occur for standard Umbraco files.

Investigation
I used Charles to see what Umbraco was doing when a user clicks. Umbraco makes a call to ~/umbraco/dialogs/imageViewer.aspx to get the url. Let's take a look at the source code...


protected void Page_Load(object sender, System.EventArgs e) { //Response.Write(umbraco.helper.Request("id")); //Response.End(); // Put user code to initialize the page here if (Request.QueryString["id"] != null) { if (Request.QueryString["id"] != "") { //TODO: fix Nasty FAST'N'CANELINE HACK. .. int MediaId = int.Parse(Request.QueryString["id"]); image.Controls.Clear(); int fileWidth = 0; int fileHeight = 0; string fileName = "/blank.gif"; string altText = ""; try { cms.businesslogic.media.Media m = new cms.businesslogic.media.Media(MediaId); // TODO: Remove "Magic strings" from code. try { fileName = m.getProperty("fileName").Value.ToString(); } catch { try { fileName = m.getProperty("umbracoFile").Value.ToString(); } catch { fileName = m.getProperty("file").Value.ToString(); } } altText = m.Text; try { fileWidth = int.Parse(m.getProperty("umbracoWidth").Value.ToString()); fileHeight = int.Parse(m.getProperty("umbracoHeight").Value.ToString()); } catch { } string fileNameOrg = fileName; string ext = fileNameOrg.Substring(fileNameOrg.LastIndexOf(".")+1, fileNameOrg.Length-fileNameOrg.LastIndexOf(".")-1); string fileNameThumb = GlobalSettings.Path + "/.." + fileNameOrg.Replace("."+ext, "_thumb.jpg"); image.Controls.Add(new LiteralControl("<a href=\"" + GlobalSettings.Path + "/.." + fileNameOrg + "\" title=\"Zoom\"><img src=\"" + fileNameThumb + "\" border=\"0\"/></a>")); } catch { } image.Controls.Add(new LiteralControl("<script>\nparent.updateImageSource('" + GlobalSettings.Path + "/.." + fileName.Replace("'", "\\'") + "','"+altText+"','" + fileWidth.ToString() + "','" + fileHeight.ToString() + "')\n</script>")); } } }


Let's ignore the shamefullness of the code. We've all had our bad moments, and open source projects are bound to have some things like this. Lets comment on what the code does.

Notice this line:
string fileName = "/blank.gif";

Now notice that the bottom catch is empty. This catch is hit whenever a file does not have one of these attibutes:fileName, umbracoFile, file. So filename is never set to anything.

The solution
The last catch needs to get your custom media type. In our case:
Media m = new Media(MediaId);
fileName = m.getProperty("Image").Value.ToString();


That is the fix for Umbraco. So you have a couple options on how to implement it.

1. You can recompile Umbraco's source then redeploy.

2. If you don't want to recompile Umbraco you can can create a new file called ImageViewer.cs that inherits from umbraco.dialogs.imageViewer. Copy and paste the code, do your fix, then modify the ~/umbraco/dialogs/imageViewer.aspx file to inherit from your new file.

I.e. Change the header:
<%@ Page Language="c#" CodeBehind="imageViewer.aspx.cs" AutoEventWireup="True" 
Inherits="umbraco.dialogs.imageViewer" %>


To this:
<%@ Page Language="c#" CodeBehind="MyImageViewer.aspx.cs" AutoEventWireup="True" 
Inherits="My.Project.UmbracoExtensions.MyImageViewer" %>


The downside of both methods is that you will overwrite your changes if you upgrade Umbraco.


The awesome solution
Here is a solution that is awesomely hilarious. Using the already installed Urlrewriting.Net module that comes with Umbraco.

1. Create a new file called ImageViewer.aspx in your project somewhere. Mine was in ~/UmbracoExtensions/

Make the code behind inherit from umbraco.dialogs.imageViewer. Copy and paste the code, do your fix.

2. Open ~/config/UrlRewriting.config and add this entry:

<add name="ImageViewer"
          virtualUrl="~/umbraco/dialogs/imageViewer.aspx(.*)"
          rewriteUrlParameter="IncludeQueryStringForRewrite"
          redirectMode="Permanent"
          destinationUrl="~/UmbracoExtensions/ImageViewer.aspx$1"
          redirect="Application"
          ignoreCase="true" />


This redirects ~/umbraco/dialogs/imageViewer.aspx to your new ~/UmbracoExtensions/ImageViewer.aspx and passes the query string which allows the lookup of the file.

3. Open your ~/web.config and add /UmbracoExtensions/ to your umbracoReservedPaths under appSettings. This allows your newly created file to be redirected to.

That's it!

I find this solution absolutely hilarious! But it means I will not get undone by an upgrade. Hopefully they will eventually fix the imageViewer class to look for other files.

UPDATE
Ok after all that, I found out that you just need to change the alias name in the cmsPropertyType in the database.

First check if your file alias is being used more than once. In our case we had an Image file type, and a field in a document type called Image. So we have to modify the correct one.

Here is how to check your table:
SELECT * FROM [YOUR_DATABASE].[dbo].[cmsPropertyType]
  WHERE Alias LIKE 'Image'


To figure out which was which I did this really lazily. I had a synced db already on dev, so I just changed the alias of one to see if it would change in Umbraco. Note that you must bump the config for the alias to change in Umbraco.

Here is the sql to update your file type alias:
UPDATE [YOUR_DATABASE].[dbo].[cmsPropertyType]
  SET Alias = 'umbracoFile'
  WHERE Alias in ('YOUR_FILE_TYLE_ALIAS') // for multiple file types
  AND id !=  // line is optional



So it turns out there was no coding involved after all. Well at least I learned heaps about how Umbraco was structured :)


Tags:
Categories:

A problem using sIFR for menus that link to databound forms in IE7

by AnthonyDang 6. August 2009 03:39

This is quite possibly the most interesting/annoying/crazy quirk/bug I have ever come across.

Scenario

Your site has a sIFR menu. One of the links goes to a typical databound form (in our case an update user details form).

Problem

The user modifies a field and submits. The database table shows the change. However, when you navigate back to the form using your sIFR menu link, you notice the old value(s) in the fields. The correct values only appear once you clear your cache. This problem only occurs in IE7.

Reason

It turns out that the sIFR link is not a normal link. It is essentially like hitting the enter key in the address bar of a page that is already loaded. The browser merely loads from its cache. No matter how many times you click that link!

Solution

In the code behind of your form on page load call this:

Response.Cache.SetCacheability(HttpCacheability.NoCache);

 

 

Tags: , , ,
Categories: .Net

Meta tags and Umbraco

by AnthonyDang 17. June 2009 12:01

You’d think that you could do something like this to get meta description and keywords from umbraco

 <meta name="description" content="<umbraco:Item runat='server' field='PageDescription'/>" />

   

Unfortunately umbraco will render this:

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /><meta name="description" content="&lt;umbraco:Item runat='server' field='PageDescription'/>" /> 

 

The solution is inline xslt:

<umbraco:Item ID="Item" Field="PageDescription" runat="server" Xslt="concat('<meta name=&quot;description&quot; content=&quot;',{0},'&quot;/>')" XsltDisableEscaping="true"></umbraco:Item>

 

 

Tags:
Categories: .Net | Umbraco