Table of Contents

Reading Data

This guide covers the Forms and Submissions APIs: querying, paging, filtering, and scope.

Scope: which portal, which user

Every method accepts an optional MegaFormScope:

var scope = new MegaFormScope
{
    PortalId = 1,   // the site/portal to read from
    UserId   = 0,   // acting user (0 = anonymous/system)
    UserName = "jane",
    DisplayName = "Jane Doe",
    Roles = new List<string> { "Managers" }
};
  • Inside a MegaForm request you can usually omit it — the ambient platform context supplies the current portal and user.
  • Outside a request (a scheduled job, a different module, a CLI) you must pass it, or the call cannot know which tenant to read.
  • DNN does not register an IPlatformContext, so always pass an explicit scope on DNN.

Listing forms

IFormApi.ListFormsAsync returns a paged result:

var result = await client.Forms.ListFormsAsync(new FormQuery
{
    Status   = "published",   // or "draft"; null = all
    Search   = "contact",     // optional title/description search
    Page     = 1,
    PageSize = 20
}, scope);

Console.WriteLine($"{result.TotalCount} forms total, showing page {result.Page}");
foreach (var form in result.Items)
{
    // form.FormId, form.Title, form.Status, form.SchemaJson,
    // form.RequireAuth, form.SubmissionCount
}

Get one form

FormDto? form = await client.Forms.GetFormAsync(formId: 1, scope);
if (form is null) { /* not found, or not in this portal */ }

form.SchemaJson is the field/layout definition as JSON — parse it if you need to render field labels or types.

Querying submissions (FindData)

ISubmissionApi.FindAsync is the SDK's FindData:

var page = await client.Submissions.FindAsync(new SubmissionQuery
{
    FormId   = 1,
    Status   = null,   // optional status filter; null = all
    Page     = 1,
    PageSize = 50
}, scope);

foreach (var s in page.Items)
{
    // s.SubmissionId, s.FormId, s.Status, s.IsSpam, s.UserId,
    // s.SubmittedOnUtc, s.DataJson
}

Reading submitted values

DataJson is a JSON object keyed by form field key:

// .NET (net8+/Oqtane):
using var doc = System.Text.Json.JsonDocument.Parse(s.DataJson ?? "{}");
var name = doc.RootElement.TryGetProperty("full_name", out var v) ? v.GetString() : null;

// classic DNN (net472):
var o = Newtonsoft.Json.Linq.JObject.Parse(s.DataJson ?? "{}");
var name2 = (string?)o["full_name"];
Tip

To build a table of columns dynamically, union the property names across the page's items — different submissions may carry different optional fields.

Get one submission

SubmissionDto? sub = await client.Submissions.GetAsync(submissionId: 10, scope);

Paging pattern

int pageNo = 1;
while (true)
{
    var page = await client.Submissions.FindAsync(
        new SubmissionQuery { FormId = 1, Page = pageNo, PageSize = 100 }, scope);
    if (page.Items.Count == 0) break;
    Process(page.Items);
    if (pageNo * page.PageSize >= page.TotalCount) break;
    pageNo++;
}

Next: download the files attached to those submissions.