- Part 1 - FileImage_Edit FieldTemplate.
- Part 2 - FileImage_Edit FieldTemplate.
- Part 3 - FileUpload FiledTemplate.
FileUpload and FileUpload_Edit FiledTemplates
I thought this would complement the DBImage and FileImage FieldTemplates and so I thought what would you want to be able to do:
- Upload a file to a specified folder.
- Download the said file once uploaded.
- Display an image for the file.
- Control the download capability via attributes and user Roles.
- Handle errors such as wrong file type or when file is missing from upload folder.
The FileUpload Attributes
In this example I’m creating on attribute to hold all the parameters to do with FileUpload.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public sealed class FileUploadAttribute : Attribute { /// <summary> /// where to save files /// </summary> public String FileUrl { get; set; } /// <summary> /// File tyoe to allow upload /// </summary> public String[] FileTypes { get; set; } /// <summary> /// image type to use for displaying file icon /// </summary> public String DisplayImageType { get; set; } /// <summary> /// where to find file type icons /// </summary> public String DisplayImageUrl { get; set; } /// <summary> /// If present user must be a member of one /// of the roles to be able to download file /// </summary> public String[] HyperlinkRoles { get; set; } /// <summary> /// Used to Disable Hyperlink (Enabled by default) /// </summary> public Boolean DisableHyperlink { get; set; } /// <summary> /// helper method to check for roles in this attribute /// the comparison is case insensitive /// </summary> /// <param name="role"></param> /// <returns></returns> public bool HasRole(String[] roles) { if (HyperlinkRoles.Count() > 0) { var hasRole = from hr in HyperlinkRoles.AsEnumerable() join r in roles.AsEnumerable() on hr.ToLower() equals r.ToLower() select true; return hasRole.Count() > 0; } return false; } }Listing 1 – FileUploadAttribute
You will notice in the Listing 1 that all the properties are using c# 3.0’s new Automatic Properties feature less typing; just type prop and hit tab twice and there is you property ready to be filled in.
The second thing you will see is the HasRoles method on this attribute, which takes an array of roles and checks to see if HyperlinkRoles property has any matches. It does this by joining the two arrays together in a Linq to Object query and then selects true for each match in the join. I’m sure this is more readable that the traditional nested foreach loops, it’s certainly neater :D.
The FileUpload FieldTemplate
This FiledTemplate will show the filename and associated icon.
![]()
Figure 1- File and associated Icon
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="FileUpload.ascx.cs" Inherits="FileImage" %> <asp:Image ID="Image1" runat="server" /> <asp:Label ID="Label1" runat="server" Text="<%# FieldValueString %>"></asp:Label> <asp:HyperLink ID="HyperLink1" runat="server"></asp:HyperLink> <asp:CustomValidator ID="CustomValidator1" runat="server" ErrorMessage=""> </asp:CustomValidator>
Listing 2 – FileUpload.ascx file
As you can see from Listing 1 there are Image, Label and Hyperlink controls on the page. The Label and Hyperlink are mutually exclusive if the conditions are right then a Hyperlink will show so that the file can be downloaded else just a Label will show with the filename.
using System; using System.IO; using System.Linq; using System.Web.DynamicData; using System.Web.Security; using System.Web.UI; using Microsoft.Web.DynamicData; public partial class FileImage : FieldTemplateUserControl { public override Control DataControl { get { return Label1; } } protected override void OnDataBinding(EventArgs e) { base.OnDataBinding(e); //check if field has a value if (FieldValue == null) return; // get the file extension String extension = FieldValueString.Substring( FieldValueString.LastIndexOf(".") + 1, FieldValueString.Length - (FieldValueString.LastIndexOf(".") + 1)); // get attributes var fileUploadAttributes = MetadataAttributes.OfType<FileUploadAttribute>().FirstOrDefault(); String fileUrl = fileUploadAttributes.FileUrl; String displayImageUrl = fileUploadAttributes.DisplayImageUrl; String displayImageType = fileUploadAttributes.DisplayImageType; // check the file exists else throw validation error String filePath; if (fileUploadAttributes != null) filePath = String.Format(fileUrl, FieldValueString); else // if attribute not set use default filePath = String.Format("~/files/{0}", FieldValueString); // show the relavent control depending on metadata if (fileUploadAttributes.HyperlinkRoles.Length > 0) { // if there are roles then check: // if user is in one of the roles supplied // or if the hyperlinks are disabled // or if the file does not exist // then hide the link if (!fileUploadAttributes.HasRole(Roles.GetRolesForUser()) fileUploadAttributes.DisableHyperlink !File.Exists(Server.MapPath(filePath))) { Label1.Text = FieldValueString; HyperLink1.Visible = false; } else { Label1.Visible = false; HyperLink1.Text = FieldValueString; HyperLink1.NavigateUrl = filePath; } } else { // if either hyperlinks are disabled or the // file does not exist then hide the link if (fileUploadAttributes.DisableHyperlink !File.Exists(Server.MapPath(filePath))) { Label1.Text = FieldValueString; HyperLink1.Visible = false; } else { Label1.Visible = false; HyperLink1.Text = FieldValueString; HyperLink1.NavigateUrl = filePath; } } // check file exists on file system if (!File.Exists(Server.MapPath(filePath))) { CustomValidator1.ErrorMessage = String.Format("{0} does not exist", FieldValueString); CustomValidator1.IsValid = false; } // show the icon if (!String.IsNullOrEmpty(extension)) { // set the file type image if (!String.IsNullOrEmpty(displayImageUrl)) { Image1.ImageUrl = String.Format(displayImageUrl, extension + "." + displayImageType); } else { // if attribute not set the use default Image1.ImageUrl = String.Format("~/images/{0}", extension + "." + displayImageType); } Image1.AlternateText = extension + " file"; // if you apply dimentions from DD Futures var imageFormat = MetadataAttributes.OfType<ImageFormatAttribute>().FirstOrDefault(); if (imageFormat != null) { // if either of the dims is 0 don't set it // this will mean that the aspect will remain locked if (imageFormat.DisplayWidth != 0) Image1.Width = imageFormat.DisplayWidth; if (imageFormat.DisplayHeight != 0) Image1.Height = imageFormat.DisplayHeight; } } else { // if file has no extension then hide image Image1.Visible = false; } } }
Listing 3 – FileUpload.ascx.cs file
In Listing 3 you can see that everything goes on in the OnDataBinding event handler.
The FileUpload_Edit FieldTemplate
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="FileUpload_Edit.ascx.cs" Inherits="FileImage_Edit" %> <asp:PlaceHolder ID="PlaceHolder1" runat="server" Visible="false"> <asp:Image ID="Image1" runat="server" /> <asp:Label ID="Label1" runat="server" Text="<%# FieldValueString %>"></asp:Label> <asp:HyperLink ID="HyperLink1" runat="server"></asp:HyperLink> </asp:PlaceHolder> <asp:FileUpload ID="FileUpload1" runat="server" /> <asp:CustomValidator ID="CustomValidator1" runat="server" ErrorMessage=""> </asp:CustomValidator>
Listing 4 – FileUpload_Edit.ascx file
In Listing 4 the PlaceHolder control is used to hide the Image, Label and Hyperlink when in insert mode or when there is no value to be shown.
using System; using System.Collections.Specialized; using System.IO; using System.Linq; using System.Web.DynamicData; using System.Web.Security; using System.Web.UI; using Microsoft.Web.DynamicData; public partial class FileImage_Edit : FieldTemplateUserControl { public override Control DataControl { get { return Label1; } } protected override void OnDataBinding(EventArgs e) { base.OnDataBinding(e); //check if field has a value if (FieldValue == null) return; // when there is already a value in the FieldValue // then show the icon and label/hyperlink PlaceHolder1.Visible = true; // get the file extension String extension = FieldValueString.Substring( FieldValueString.LastIndexOf(".") + 1, FieldValueString.Length - (FieldValueString.LastIndexOf(".") + 1)); // get attributes var fileUploadAttributes = MetadataAttributes.OfType<FileUploadAttribute>().FirstOrDefault(); String fileUrl = fileUploadAttributes.FileUrl; String displayImageUrl = fileUploadAttributes.DisplayImageUrl; String displayImageType = fileUploadAttributes.DisplayImageType; String filePath; // check the file exists else throw validation error if (fileUploadAttributes != null) filePath = String.Format(fileUrl, FieldValueString); else // if attribute not set use default filePath = String.Format("~/files/{0}", FieldValueString); // show the relavent control depending on metadata if (fileUploadAttributes.HyperlinkRoles.Length > 0) { // if there are roles then check: // if user is in one of the roles supplied // or if the hyperlinks are disabled // or if the file does not exist // then hide the link if (!fileUploadAttributes.HasRole(Roles.GetRolesForUser()) fileUploadAttributes.DisableHyperlink !File.Exists(Server.MapPath(filePath))) { Label1.Text = FieldValueString; HyperLink1.Visible = false; } else { Label1.Visible = false; HyperLink1.Text = FieldValueString; HyperLink1.NavigateUrl = filePath; } } else { // if either hyperlinks are disabled or the // file does not exist then hide the link if (fileUploadAttributes.DisableHyperlink !File.Exists(Server.MapPath(filePath))) { Label1.Text = FieldValueString; HyperLink1.Visible = false; } else { Label1.Visible = false; HyperLink1.Text = FieldValueString; HyperLink1.NavigateUrl = filePath; } } // check file exists on file system if (!File.Exists(Server.MapPath(filePath))) { CustomValidator1.ErrorMessage = String.Format("{0} does not exist", FieldValueString); CustomValidator1.IsValid = false; } // show the icon if (!String.IsNullOrEmpty(extension)) { // set the file type image if (!String.IsNullOrEmpty(displayImageUrl)) { Image1.ImageUrl = String.Format(displayImageUrl, extension + "." + displayImageType); } else { // if attribute not set the use default Image1.ImageUrl = String.Format("~/images/{0}", extension + "." + displayImageType); } Image1.AlternateText = extension + " file"; // if you apply dimentions from DD Futures var imageFormat = MetadataAttributes.OfType<ImageFormatAttribute>().FirstOrDefault(); if (imageFormat != null) { // if either of the dims is 0 don't set it // this will mean that the aspect will remain locked if (imageFormat.DisplayWidth != 0) Image1.Width = imageFormat.DisplayWidth; if (imageFormat.DisplayHeight != 0) Image1.Height = imageFormat.DisplayHeight; } } else { // if file has no extension then hide image Image1.Visible = false; } } protected override void ExtractValues(IOrderedDictionary dictionary) { // get attributes var fileUploadAttributes = MetadataAttributes.OfType<FileUploadAttribute>().FirstOrDefault(); String fileUrl; String[] extensions; if (fileUploadAttributes != null) { fileUrl = fileUploadAttributes.FileUrl; extensions = fileUploadAttributes.FileTypes; if (FileUpload1.HasFile) { // get the files folder String filesDir = fileUrl.Substring(0, fileUrl.LastIndexOf("/") + 1); // resolve full path c:\... etc String path = Server.MapPath(filesDir); // get files extension without the dot String fileExtension = FileUpload1.FileName.Substring( FileUpload1.FileName.LastIndexOf(".") + 1).ToLower(); // check file has an allowed file extension if (extensions.Contains(fileExtension)) { // try to upload the file showing error if it fails try { FileUpload1.PostedFile.SaveAs(path + "\\" + FileUpload1.FileName); Image1.ImageUrl = String.Format(fileUploadAttributes.DisplayImageUrl, fileExtension + ".png"); Image1.AlternateText = fileExtension + " file"; dictionary[Column.Name] = FileUpload1.FileName; } catch (Exception ex) { // display error CustomValidator1.IsValid = false; CustomValidator1.ErrorMessage = ex.Message; } } else { CustomValidator1.IsValid = false; CustomValidator1.ErrorMessage = String.Format("{0} is not a valid file to upload", FieldValueString); } } } } }Listing 5 - FileUpload_Edit.ascx.cs file
In Listing 5 the OnDataBinding event handler is pretty much the same as the FileUpload.ascs.cs file. Here its the ExtractValues method that does the work of uploading and displaying errors, i.e. if the file type of the file to be uploaded does not match a file type specified in the metadata or there is an error during the upload.
Helper Class FileUploadHelper
public static class FileUploadHelper { /// <summary> /// If the given table contains a column that has a UI Hint with the value "DbImage", finds the ScriptManager /// for the current page and disables partial rendering /// </summary> /// <param name="page"></param> /// <param name="table"></param> public static void DisablePartialRenderingForUpload(Page page, MetaTable table) { foreach (var column in table.Columns) { // TODO this depends on the name of the field template, need to fix if (String.Equals( column.UIHint, "DBImage", StringComparison.OrdinalIgnoreCase) String.Equals(column.UIHint, "FileImage", StringComparison.OrdinalIgnoreCase) String.Equals(column.UIHint, "FileUpload", StringComparison.OrdinalIgnoreCase)) { var sm = ScriptManager.GetCurrent(page); if (sm != null) { sm.EnablePartialRendering = false; } break; } } } }
This is just a modified version of the Dynamic Data Futures DisablePartialRenderingForUpload method the only difference is that I’ve added support for both my file upload capable FieldTemplates FileImage and FileUpload.
Finally Some Sample Metadata
[MetadataType(typeof(FileImageTestMD))] public partial class FileImageTest : INotifyPropertyChanging, INotifyPropertyChanged { public class FileImageTestMD { public object Id { get; set; } public object Description { get; set; } [UIHint("FileUpload")] [FileUpload( FileUrl = "~/files/{0}", FileTypes = new String[] { "pdf", "xls", "doc", "xps" }, DisplayImageType = "png", DisableHyperlink = false, HyperlinkRoles=new String[] { "Admin", "Accounts" }, DisplayImageUrl = "~/images/{0}")] [ImageFormat(22, 0)] public object filePath { get; set; } } }
Listing 7 – sample metadata
The FileUpload Project
Enjoy ![]()