Code On Time web applications perform automatic handling of binary large objects (BLOB). Thumbnails of images are displayed in grids and forms, such as in the screenshot below.
Users can clear or replace the field with files of their own choosing. This functionality is available out-of-the-box and requires no extra programming when the data is stored in the database. It can be extended by adding utility fields to store the file name, size, and extension.
An alternative to database-stored data is use an external storage location. The data can be placed in online storage systems such as Amazon S3 or Microsoft Azure Storage. These systems provide many benefits, such as easy scalability and content delivery networks. The data can also be stored on a local Network Attached Storage (NAS).
Let’s implement a column in the Categories table of the sample Northwind database in order to store data on the local hard drive.
Start SQL Server Management Studio and connect to your database. In the Object Explorer, right-click on Databases / Northwind / Tables / dbo.Categories and press Design.
Add the following columns:
Column Name | Data Type | Allow Nulls |
ExternalDocFileName | nvachar(150) | yes |
ExternalDocLength | int | yes |
ExternalDocContentType | nvarchar(150) | yes |
Save the changes to the table.
Start Code On Time web application generator. Click on the project name, and select Refresh. Check the box next to Categories controller and continue to refresh the web app.
Start the Project Designer. In the Project Explorer, right-click on Categories / Fields node, and press New Field.
Assign the following values:
Property | Value |
Name | ExternalDoc |
Type | Byte[] |
Allow null values. | yes |
The value of this field is computed at run-time by SQL expression. | yes |
Value is retrieved on demand | yes |
Source Fields | CategoryID |
On Demand Handler | CategoriesExternalDoc |
On Demand Style | Thumbnail |
Label | External Doc |
Save the field.
We will need to bind the field to grid1 and editForm1 views and prevent the user from editing the utility fields. In the Project Explorer, drag Categories / Fields / ExternalDoc (Byte[]) field node onto Categories / Views / grid1.
Drag ExternalDoc (Byte[]) field node onto Categories / Views / editForm1 node.
Let’s prevent users from editing the utility fields in editForm1 or grid1. Right-click on Categories / Views node, and press List.
Upload of binary content is currently only supported for existing records. Let’s remove the utility fields from createForm1. Click on Categories / Views / createForm1 / ExternalDocFileName data field node. Hold Shift key, and click on ExternalDocContentType. Right-click and press Delete.
At the top of the Project Browser, switch to Data Fields tab. A grid of data fields will be displayed. Make the following changes to Format and Text Mode properties:
Field Name | View | Format | Text Mode |
ExternalDocFileName | editForm1 | Static | |
ExternalDocLength | editForm1 | n0 | Static |
ExternalDocContentType | editForm1 | Static | |
ExternalDocFileName | grid1 | Static | |
ExternalDocLength | grid1 | n0 | Static |
ExternalDocContentType | grid1 | Static |
If you try to upload files in the ExternalDoc field, an error will be displayed. File upload and download will have to be handled with custom business rules, which will do the following:
The folder that blobs will be saved to must exist before they will be saved. Navigate to your My Documents folder and create another folder with the name “My External Doc Files”.
In the Project Explorer, right-click on Categories / Business Rules node, and press New Business Rule.
Assign the following properties:
Property | Value |
Type | C# / Visual Basic |
Command Name | UploadFile |
Command Argument | ExternalDoc |
Phase | Execute |
Save the business rule. Create another business rule with the following properties:
Property | Value |
Type | C# / Visual Basic |
Command Name | DownloadFile |
Command Argument | ExternalDoc |
Phase | Execute |
Create a third rule:
Property | Value |
Type | C# / Visual Basic |
Command Name | Select |
Phase | Execute |
On the toolbar, press Browse to generate the business rule files. When complete, right-click on Categories / Business Rules / UploadFile (Code / Execute) – r100 node, and press Edit Rule in Visual Studio.
Replace the code base with the following. Note that a Stream parameter has been added to the method definition in order to handle the uploaded file.
C#:
using System; using MyCompany.Data; using System.IO; namespace MyCompany.Rules { public partial class CategoriesBusinessRules : MyCompany.Data.BusinessRules { [Rule("r100")] public void r100Implementation(int? categoryID, string categoryName, string description, string externalDocFileName, int? externalDocLength, string externalDocContentType, Stream externalDoc) { PreventDefault(); string fileName = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), String.Format(@"My External Doc Files\{0}.bin", categoryID)); Stream output = File.Create(fileName); externalDoc.CopyTo(output); output.Close(); } } }
Visual Basic:
Imports MyCompany.Data Imports System Imports System.IO Namespace MyCompany.Rules Partial Public Class CategoriesBusinessRules Inherits MyCompany.Data.BusinessRules <Rule("r100")> _ Public Sub r100Implementation(ByVal categoryID As Nullable(Of Integer), ByVal categoryName As String, ByVal description As String, ByVal externalDocFileName As String, ByVal externalDocLength As Nullable(Of Integer), ByVal externalDocContentType As String, ByVal externalDoc As Stream) PreventDefault() Dim fileName As String = Path.Combine( _ Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), _ String.Format("My External Doc Files\\{0}.bin", categoryID)) Dim output As Stream = File.Create(fileName) externalDoc.CopyTo(output) output.Close() End Sub End Class End Namespace
Save the file. In the Project Explorer, right-click on Categories / Business Rules / DownloadFile (Code / Execute) – r101 node and press Edit Rule in Visual Studio.
Replace the code:
C#:
using System; using MyCompany.Data; using System.IO; namespace MyCompany.Rules { public partial class CategoriesBusinessRules : MyCompany.Data.BusinessRules { [Rule("r101")] public void r101Implementation(int? categoryID, string categoryName, string description, string externalDocFileName, int? externalDocLength, string externalDocContentType, Stream externalDoc) { PreventDefault(); string fileName = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), String.Format(@"My External Doc Files\{0}.bin", categoryID)); Stream input = File.OpenRead(fileName); input.CopyTo(externalDoc); input.Close(); } } }
Visual Basic:
Imports MyCompany.Data Imports System Imports System.IO Namespace MyCompany.Rules Partial Public Class CategoriesBusinessRules Inherits MyCompany.Data.BusinessRules <Rule("r101")> _ Public Sub r101Implementation(ByVal categoryID As Nullable(Of Integer), ByVal categoryName As String, ByVal description As String, ByVal externalDocFileName As String, ByVal externalDocLength As Nullable(Of Integer), ByVal externalDocContentType As String, ByVal externalDoc As Stream) PreventDefault() Dim fileName As String = Path.Combine( _ Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), _ String.Format("My External Doc Files\\{0}.bin", categoryID)) Dim input As Stream = File.OpenRead(fileName) input.CopyTo(externalDoc) input.Close() End Sub End Class End Namespace
Save the file. Finally, right-click on Categories / Business Rules / Select (Code / Execute) – r101 node and press Edit Rule in Visual Studio.
Replace the code with the following:
C#:
using System; using MyCompany.Data; namespace MyCompany.Rules { public partial class CategoriesBusinessRules : MyCompany.Data.BusinessRules { [Rule("r102")] public void r102Implementation(int? categoryID, string categoryName, string description, string externalDocFileName, int? externalDocLength, string externalDocContentType) { if (!String.IsNullOrEmpty(externalDocFileName)) UpdateFieldValue("ExternalDoc", categoryID); else UpdateFieldValue("ExternalDoc", String.Format("null|{0}", categoryID)); } } }
Visual Basic:
Imports MyCompany.Data Imports System Namespace MyCompany.Rules Partial Public Class CategoriesBusinessRules Inherits MyCompany.Data.BusinessRules <Rule("r102")> _ Public Sub r102Implementation(ByVal categoryID As Nullable(Of Integer), ByVal categoryName As String, ByVal description As String, ByVal externalDocFileName As String, ByVal externalDocLength As Nullable(Of Integer), ByVal externalDocContentType As String) If Not String.IsNullOrEmpty(externalDocFileName) Then UpdateFieldValue("ExternalDoc", categoryID) Else UpdateFieldValue("ExternalDoc", String.Format("null|{0}", categoryID)) End If End Sub End Class End Namespace
Save the file.
On the Project Designer toolbar, press Browse. When complete, navigate to the Categories page. The utility fields will be present in the grid.
Start editing a record, and upload a file to External Doc field. The file will be uploaded successfully, and the utility fields will be updated with the correct information.
Clicking on the thumbnail will download or open the file with the correct format. The file is stored in the folder My Documents/My External Doc Files with a file name of the CategoryID and extension of “.bin”.