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:
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:
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.
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:
Once you are done, the canvas should look like this:and the system tree should look like this:
With this part done, let's focus on the "Get file" 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:
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:
So what happens if the user pressed the button from the edit or add page modes?
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.
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.
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.
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.
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.
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:
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!
For more examples about custom coding, check the "Novulo application server -> samples" section of the library.