Novulo
  • Login
  • |
  • Try Now!

  • Product
  • Interactions
  • Services
  • Purchase
  • Support
  • My Novulo
  • Company
Navigation

Navigation

  • Overview
  • Library
  • Tutorials
  • Sample projects
  • Forums
  • Releases


Library

  • Novulo Library
  • About Novulo
  • Getting Started
  • Application Development in Novulo
  • Novulo Architect
  • Novulo Application Server
    • Manual
    • Samples
      • Text input with validation
      • External interfacing
      • Custom image element
      • Layout customization
      • Custom grid columns
      • Sample WebFiles
      • Sample Facebook
      • Sample Dynamic Forms
    • Reference
  • Novulo Course
  • Novulo Network
  • Terminology
  • What's new in 3.2-RC2
  • What's new in 3.3 CTP?

Library

  • Home
  • »
  • Support
  • »
  • Novulo Application Server
  • »
  • Samples
  • »
  • Sample WebFiles

Sample WebFiles

In this article you will find a step-by-step example, instructing you on how to realize a specific piece of functionality.

Example system:
Sample WebFiles

Architect version:
3.0

Custom components:
Yes

Level:

  • GUI: low
  • Expressions: medium
  • Process: medium
  • Coding: medium

System description

The WebFiles library example is a simple system designed to demonstrate how to add files to a Novulo system from custom code.
The example has one module, one grid and one details page. On the WebFiles details page a URL can be entered, causing a "get file" button to appear. The process behind this button contains a custom activity, which will be the focus of this example.

System specifics:

  • Auto-incrementing unique number for each WebFile
  • URL is not adjustable once file has been downloaded
  • "Get file" button saves the record from any page type and retrieves the file (if possible)

Designing the system

This example is related to a public system. To open this system choose Start->open, then select the "LE WebFiles" example from the public systems and press duplicate.
LE webfiles 1

If you would like to create the system from scratch, simply add a module, grid and details page construction. On the details page add a form with the following fields:

  • Number - add a text field, change the text field type to number and select "never editable" from the editability menu. We will be using this field to assign a unique auto-incrementing number to each WebFile in the system.
  • Description - add a text field, this text field can be used to enter a descriptive text about the file.
  • URL - add a text field, change the text field type to url . We will be using this field allow the user to specify what the location for the file to be downloaded.
  • Get file - add a form button and rename it to "Get file", this button will start the process that is the focal point of this article. (optional: specify an icon for the button using the "settings" from the "home" section of the ribbon)
  • File - add an upload field and set editability to "never editable", we do not want the user to upload anything, we will download the file in our custom activity and then set it as the value for the file field. Now set "file.isnull()" as editability condition for the URL field (use "IsNull" from the pallette and drag the newly added file field from the context panel onto the placeholder); This way the URL can no longer be changed once a file has been downloaded.

Once you are done, the canvas should look like this:
LE webfiles 2
and the system tree should look like this:
LE webfiles 3

With this part done, let's focus on the "Get file" Process.

The Process

So what exactly should happen when the user presses the "Get file" button? First of all, we need to decide what should happen when the user presses the button while editing/adding the record. Do we respond with a message telling the user to save the record first using the "OK" button? Should we disregard any changes the user made? Do we first save changes and then attempt to get the file?

The easiest option to implement would of course be alerting the user, but for the purpose of this example I have chosen to save any new values entered by the user before attempting to get the file. This means that in the process we first need to detect what page mode the process was started from.
Secondly we should attempt to retrieve the file in a custom activity.
If that activity succeeds, set the newly added file as value for the "file" upload field of the WebFiles object.
Finally, reload the page so the user is presented with the result.

Let's look at the process step by step:

  • Step 1: Detect page mode and if neccesary, save the changes to the WebFile
  • Step 2: Add a custom activity to the process and specify arguments and return values
  • Step 3: Set the newly added file as value for the "file" property of the WebFile
  • Step 4: Present the user with the results

Step 1: Detecting page mode and saving changes

The first process element is a decision, named "viewpage". The decision returns true if the button was pressed from a page in view mode. In that case we do not need to save changes, because the user cannot have changed the record before pressing the button.
The following image displays the start of the process and the decision as shown in the expression editor:
LE webfiles 4

So what happens if the user pressed the button from the edit or add page modes?

  • save_context - Save the context (using a "changeRecordValues" activity).
  • editpage - Detect if the process was started from an editpage (using a decision process element).
  • set_webfile_number - If the process was not started from the editpage (it must be an addpage), set the new webfile number (using a "changeRecordValues" activity).
  • commit_webfile - Commit the record to the database so the information is stored (using a "commitRecord" activity).
  • unlock_webfile - After commit, unlock the record (using an "UnlockRecord" activity).

This part of the process simply ensures that the button will work as (most likely) expected by the user from any page mode. As you can see in the process overview, the process continues with the same activity for any page mode after step 1.

The following image highlights some of the important components of Step 1.
LE webfiles 5

Step 2: Custom activity

In step 1 the process handles storing the correct information from any page mode. Now that we can be sure that the information is stored in the database (or an error has been handled), it is time to attempt to retrieve the file from the url. To do this we need a "Custom" activity. Custom activities allow the developer to execute code at any point in the process. All that needs to be done is specifying parameters and return values for the activity.

The custom activity in the process is named "download_webfile". Since all we need to do in the custom activity is getting the file from the url and presenting it, setting parameters and returnvalues is pretty straightforward. In the activity's properties dialog we can set "trigger.record.url" as a parameter of type URL. For the return values we specify "success" (boolean), "error" (Message) and "file" (File). If the file can be succesfully downloaded the "file" returnvalue will be a Novulo file type record, if unsuccessful, error will contain a message that can be directly presented to the user using a showmessage activity.

The following image shows the properties dialog for the custom activity.
LE webfiles 6

Step 3: Set the new file as value for the webfile "file" property

If the custom activity "download_webfile" was successful, we should set the returned file as value for the current WebFile's "file" property.
To do this, the process contains a "changeRecord" activity, which is used to modify the previously saved "trigger.record".

The following image shows how the new value is set.
LE webfiles 7

Step 4: Present the user with the results

Finally we need to show the result to the user. In this case we choose to simply reload the page with the updated record, which will present the user with a clickable link, allowing download of the file that is now available from the system. For this a "LoadPage" activity is used, calles "to_viewpage". We choose to return the user to the page in view mode.

The following image shows how the loadpage activity is specified.
LE webfiles 8

Custom coding

After we ensure the system is complete and no problems exist in the model, the system needs to be built and committed to a code repository, so it can be opened for custom development.

For more information on building to a repository click here.
For more information on setting up Visual Studio click here.

After opening the project in Visual studio, open the generated code for the custom activity. It will be located in the "App_Code\custom" section.
LE webfiles 9

We will be adding code to the Execute function of the generated download_webfile156345Action class (156345 is a generated internal ID, it may vary for your system).
The generated code initially looks like this:

   1:      public override Dictionary<string, NObject> Execute( Dictionary<string, NObject> parameters, TaskHandler taskHandler) {
   2:        Dictionary<String, NObject> returnValues = new Dictionary<string, NObject>();
   3:        
   4:        NObject no_url = parameters["url"];
   5:   
   6:        returnValues["success"] = new NObject(true, NSingleType.BOOLEAN);
   7:        returnValues["error"] = new NObject(null, NovuloDataHandler.MESSAGES);
   8:        returnValues["file"] = new NObject(null, new NRecordType("file"));
   9:        
  10:        return returnValues;
  11:      }



We will be adding code right before the return statement that opens the stream, gets the file and adds it using the Novulo FileTypeHandler.
The resulting function looks like this:

   1:  public override Dictionary<string, NObject> Execute( Dictionary<string, NObject> parameters, TaskHandler taskHandler) {
   2:    Dictionary<String, NObject> returnValues = new Dictionary<string, NObject>();
   3:    
   4:    NObject no_url = parameters["url"];
   5:   
   6:    returnValues["success"] = new NObject(true, NSingleType.BOOLEAN);
   7:    returnValues["error"] = new NObject(null, NovuloDataHandler.MESSAGES);
   8:    returnValues["file"] = new NObject(null, new NRecordType("file"));
   9:   
  10:    IDataHandler dh = Framework.Current.DataHandler;
  11:   
  12:    try
  13:    {
  14:        //Create a webrequest using the url parameter
  15:        HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(no_url.StringValue);
  16:        request.Timeout = 5000; // 5 seconds in milliseconds
  17:        request.ReadWriteTimeout = 20000; // allow up to 20 seconds to elapse
  18:   
  19:        HttpWebResponse response = (HttpWebResponse)
  20:        request.GetResponse();
  21:       
  22:        //if there is a content-disposition header, get the alternative filename
  23:        String disposition = response.GetResponseHeader("Content-Disposition");
  24:        String newfilename = String.IsNullOrEmpty(disposition) ? System.IO.Path.GetFileName(no_url.StringValue) : disposition.Substring(disposition.LastIndexOf("=") + 1);
  25:        
  26:        //get mimetype from response header
  27:        String mimetype = response.GetResponseHeader("Content-Type");
  28:        if(String.IsNullOrEmpty(mimetype))
  29:        {
  30:            mimetype = "text/plain";
  31:        }
  32:   
  33:        //get the file stream
  34:        Stream fs = response.GetResponseStream();
  35:   
  36:        //copy stream to allow seeking in stream
  37:        byte[] data = new byte[response.ContentLength];
  38:        fs.Read(data, 0, data.Length);
  39:        MemoryStream ms = new MemoryStream(data);
  40:   
  41:        //get the file typehandler and add a new file using the copied stream
  42:        var fth = (FileTypeHandler) dh.GetTypeHandler(DataHandler.FILE);
  43:        NObject fileRecord = fth.AddFile(newfilename, mimetype, ms);
  44:        
  45:        //close the streams
  46:        fs.Close();
  47:        ms.Close();
  48:   
  49:        //add the file to the returnValues
  50:        returnValues["file"] = fileRecord;
  51:    }
  52:    catch(Exception e)
  53:    {
  54:        //handle exceptions
  55:        returnValues["success"] = false;
  56:        returnValues["error"] = new NObject(new TranslatedMessage(e.Message), NovuloDataHandler.MESSAGES);
  57:    }
  58:   
  59:    return returnValues;
  60:  }



The following lines are where the stream is actually added to the novulo system as a file (line 42/43). The FileTypeHandler has an addfile function that accepts a stream and simply returns the fileRecord as an NObject.

   1:  var fth = (FileTypeHandler) dh.GetTypeHandler(DataHandler.FILE);
   2:  NObject fileRecord = fth.AddFile(newfilename, mimetype, ms);



Now build the solution and test!

LE webfiles 10

More information

For more examples about custom coding, check the "Novulo application server -> samples" section of the library.

Comments

Comment
No comments yet

Article

Article added on 12 Jun.
  • Product
  • How it works
  • Tour
  • Features
  • Technical specs
  • Novulo for...
  • Roadmap
  • Try now
  • Interactions
  • BASD
  • RAD
  • Agile
  • ORM
  • Model-driven development
  • Services
  • Consultancy
  • Training & Support
  • Projects
  • Purchase
  • Buy now
  • License agreement
  • F.A.Q.
  • Contact sales
  • Support
  • Library
  • Tutorials
  • Sample projects
  • Forums
  • Releases
  • My Novulo
  • My profile
  • My tickets
  • My products
  • Start architect
  • Company
  • About Novulo
  • Customers
  • Press
  • Awards
  • Careers
  • Contact
  • © 2008-2010 Novulo | All rights reserved
  • Terms of use | Privacy policy