Skip to main content
Home  ›  Blog

Recipe: Form Files SaveInADAM in Your Custom WebAPI

You can save files of an item/entity to ADAM (automatic digital asset manager) using new APIs in 2sxc 9.30. Here's how.

Background

This recipe helps you understand how to leverage the new SaveInAdam(...) command in 2sxc 9.30. It's already in use in Mobius Forms 2 - so you can learn from that, but this recipe will show you more about what you must do, incl. how to get files from the HTML-form to be submitted to your WebAPI.

Story: Showcase Directory

In this example we are creating a public directory of showcases, where people can submit websites they made with DNN. Each website has a title, link, description and some files for the logo and many screenshots. We'll assume that there is a custom form to submit new applications, and this form also has some upload fields to select a logo and up to 5 screenshots.

Overview Uploading to ADAM

To use this in your own apps, you'll do the following:

  1. Create a content-type which will hold the data - in this example we'll call it "Showcase"
  2. Create File/Hyperlink fields to store the logo and all the screenshots
  3. Design the public input Form using standard HTML / JavaScript
  4. Create the WebAPI to save the data which is submitted
  5. Test everything
  6. Publish

1. Create your Content-Type and Basic Fields

This is standard 2sxc-work and will not be explained in this recipe.

2. Defining Fields for Storing Files

ADAM works by providing files for a field. So the field "Logo" can contain one or more files, and the field "Screenshots" works the same way. To define these fields, we must:

  1. Create the field as a hyperlink-library field
  2. It is recommended that you also specify what files are allowed to be uploaded (like *.png, *.jpg) to ensure that you really only get these files. This is also done in the settings of hyperlink fields

Important: In this scenario you should NOT set content-type permissions or field permissions, as they are not checked when your code (in the C# WebAPI) adds data. These permissions are for the public REST API. If you give users write permissions, this would allow people to create data or upload files bypassing your WebAPI.

3. Design your HTML/JS Form

Now you can design the public input Form using standard HTML / JavaScript, JavaScript validators etc. to guide the user adding showcases. This is normal HTML work and not explained in this recipe.

When this form submits the data to your WebAPI, it must include the files in the submission. This is typically done by encoding the files to base64 and placing it in your json, and also including information like the file name. Here's a snippet of how it's done from the Mobius Forms 2

Convert File Fields To Base64 for Upload

// note: example taken from more complex code
// https://github.com/2sic/app-mobius-forms/blob/master/dist/form-send.js
// this just shows the base64 encoding bits

var deferred = $.Deferred();
var file = e.get(0).files[0];
if (!file)
  return;
var reader = new FileReader();

reader.addEventListener("load", function () {
  data.Files.push({
    Encoded: reader.result,
    Name: file.name,
    Field: propName
  });
  deferred.resolve();
}, false);
reader.readAsDataURL(file);
return deferred.promise();

4. Create your Save WebAPI

Finally we'll create the WebAPI to save the data which is submitted, typically marking it as draft so the items are not shown till they are reviewed. Here's what you must do (note: you can also steal some code from Mobius Forms 2 API, but that does way more, so take only what you need):

  1. Create a new web-api file (a cshtml-file in the api folder inheriting from SxcApiController)
  2. Write code to create a dictionary-object containing all the values you want to save…
  3. …then write the code to save the new entity using App.Data.Create(…) save-new-entity code, ideally marking the new item as draft (so public users don't see it until released by an admin)
  4. Write the save files code

The specifics of how you will do this will vary, but basically it's something along these lines:

Example Web-API code (taken from Mobius Forms 2)

using ...;
public class MyFormController : SxcApiController
{
  [HttpPost]
  [DnnModuleAuthorize(AccessLevel = SecurityAccessLevel.Anonymous)]
  [ValidateAntiForgeryToken]
  public void ProcessForm([FromBody]Dictionary<string,object> contactFormRequest)
  {
    var typeName = "Showcase";
  var screenshotsField = "Screenshots";
  var guid = Guid.NewGuid();
  
    // make dictionary case-insensitive
    var values = new Dictionary<string, object>(contactFormRequest, 
    StringComparer.OrdinalIgnoreCase);

    values.Add("EntityGuid", guid);
    App.Data.Create(typeName, values);
  
    // Save files to Adam
    var files = ((Newtonsoft.Json.Linq.JArray)contactFormRequest["Files"])
      .ToObject<IEnumerable<Dictionary<string, string>>>()
    foreach(var file in files)
    {
      var data = Convert.FromBase64String((file["Encoded"]).Split(',')[1]);
      SaveInAdam(stream: new MemoryStream(data), fileName: file["Name"], 
        contentType: typeName, 
        guid: guid, 
        field: screenshotsField);
    }
  }
}

5. Test

We've included testing in this recipe, to ensure that you don't forget common issues. So we recommend you try the following things to be sure everything works:

  1. Submit some data and verify that it's draft when saving (assuming you wanted the draft-mode)
  2. Submit some data, omitting some expected files - like not passing in a logo or screenshot
  3. Submit some data with invalid files (like a .exe or a .doc when only expecting images)
  4. Submit some data with unexpected file names - like a file name containing a hash (#) character

6. Publish

That's it - enjoy. We hope you loved this - if yes, please leave a comment.
Love from Switzerland,
iJungleboy

 


Daniel Mettler grew up in the jungles of Indonesia and is founder and CEO of 2sic internet solutions in Switzerland and Liechtenstein, an 20-head web specialist with over 800 DNN projects since 1999. He is also chief architect of 2sxc (see github), an open source module for creating attractive content and DNN Apps.

Read more posts by Daniel Mettler