The Configuration
Every call your endpoint makes to the Rule Repository carries a configuration: an object that describes the current request's user and what your application allows. It says who the user is, which permissions they have, which language RR shows, which AI models are offered, how notifications reach people, and which limits apply. RR reads nothing about users, roles or settings from anywhere else.
You need it because RR has no user directory, no roles and no settings file of its own. Your application already knows who is signed in and what they may do; the configuration is how it tells RR, request by request.
One Configuration per Request
Build a new configuration for every request, from the signed-in user, and pass it to Context.GetResponse. Do not keep one in a static field or share one between users: its properties are the current user's.
Most applications use the Configuration class. An application with its own authorization service can implement the IRepositoryConfiguration interface instead (see below).
Every Property
| Property |
Type |
Default |
What it decides |
CurrentUserId |
string |
(none) |
Required. The signed-in user's ID in your application: a login, an email address, a directory object ID. Up to 256 characters. Stored against everything the user creates or changes. See Users and the Acting User. |
CurrentUserName |
string |
null |
The user's display name, shown in RR. Optional; a name stored earlier is kept when you leave it out. |
CurrentUserType |
UserType |
User |
What the caller is: a person (User), an AI agent acting on its own (Agent) or automation (Service). Only a person can make versions live, approve or delete. |
CurrentAgentId, CurrentAgentName |
string |
null |
The AI agent acting for the person in CurrentUserId, when there is one. Set only from your own authentication of the caller. |
AccessMode |
ActionPermissionMode |
ViewOnly |
How ActionList is read: ViewOnly (no permissions), AllowAllExcept (every permission but those listed) or AllowOnly (only those listed). See Permissions. |
ActionList |
ISet<ActionPermissionType> |
empty |
The permissions withheld (AllowAllExcept) or granted (AllowOnly). |
CanPerform(action) |
method |
from the two above |
Whether the user has a permission. Configuration answers from AccessMode and ActionList; your own implementation can answer any way you like. |
UiXml |
XmlDocument |
null |
A translated or reworded user interface text document. See User Interface Text and Themes. |
UiXmlFile |
string |
null |
The full physical path to a file holding that document; its parsed text is cached by content. Ignored when UiXml is set. |
EditorHelpXml |
XmlDocument |
null |
The rule editors' Help XML in another language: their menus, operators and Help String. See Help XML and Multilingual Support. |
EditorHelpXmlFile |
string |
null |
The full physical path to a file holding that document. Ignored when EditorHelpXml is set. Unreadable: CE10262. |
SourceLabelsXml |
XmlDocument |
null |
Source labels: your source objects' field, method and action names and descriptions in another language, laid over every source version on display. |
SourceLabelsXmlFile |
string |
null |
The full physical path to a file holding that document. Ignored when SourceLabelsXml is set. Unreadable: CE10263. |
TypeResolver |
GetTypeDelegate |
null |
Finds a .NET type by name when the runtime cannot: needed only when a type a stored source definition names has moved to another assembly or been renamed. |
Notify |
NotificationDelegate |
null |
Called after approvals are requested, granted or declined and after versions go live or offline, so your application can tell the right people. See Notifications. |
Assistant |
AssistantSettings |
null |
The AI models for the AI Assistant and the AI Rule Editor. Null or no models: neither feature appears. See AI Assistant and AI Rule Editor. |
Agents |
AgentSettings |
defaults |
What AI agents may do beyond their permissions: test limits and data source access. See AI Agents. |
Limits |
RequestLimits |
defaults |
Request and payload sizes, filter and option counts, test runs at once (below). |
Building It from the Signed-In User
Put the mapping from your users and roles to RR in one class of your own, and use it from your endpoint. A typical one:
using System.Security.Claims;
using CodeEffects.Rule.Common.Models;
using CodeEffects.Rule.Repository;
using CodeEffects.Rule.Repository.Common;
public sealed class RepositoryConfigurationFactory
{
// What each of your roles may do in the Rule Repository
private static readonly ISet<ActionPermissionType> Authors = new HashSet<ActionPermissionType>
{
ActionPermissionType.RuleCreate, ActionPermissionType.RuleUpdateDetails,
ActionPermissionType.RuleVersionCreate, ActionPermissionType.RuleVersionUpdateDetails,
ActionPermissionType.RuleVersionRequestApproval,
ActionPermissionType.DraftView, ActionPermissionType.DraftCreate, ActionPermissionType.DraftUpdate,
ActionPermissionType.DraftConvert, ActionPermissionType.DraftDelete,
ActionPermissionType.TestView, ActionPermissionType.TestRun, ActionPermissionType.TestCreate,
ActionPermissionType.TestUpdate, ActionPermissionType.TestDelete, ActionPermissionType.TestRunBatch,
ActionPermissionType.ValueTemplateCreate, ActionPermissionType.ValueTemplateUpdate,
ActionPermissionType.ActivityView, ActionPermissionType.NoteView, ActionPermissionType.NoteCreate
};
private readonly NotificationDelegate notify;
private readonly AssistantSettings assistant;
public RepositoryConfigurationFactory(NotificationDelegate notify = null, AssistantSettings assistant = null)
{
this.notify = notify;
this.assistant = assistant;
}
public Configuration Create(ClaimsPrincipal user)
{
var config = new Configuration
{
CurrentUserId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value,
CurrentUserName = user.FindFirst(ClaimTypes.Name)?.Value,
Notify = this.notify,
Assistant = this.assistant
};
if (user.IsInRole("RuleManager"))
{
// Everything except reading other people's AI conversations
config.AccessMode = ActionPermissionMode.AllowAllExcept;
config.ActionList = new HashSet<ActionPermissionType> { ActionPermissionType.AiConversationViewAll };
}
else if (user.IsInRole("RuleAuthor"))
{
config.AccessMode = ActionPermissionMode.AllowOnly;
config.ActionList = new HashSet<ActionPermissionType>(Authors);
}
else
{
config.AccessMode = ActionPermissionMode.ViewOnly; // sees sources and rules, changes nothing
}
return config;
}
}
Register it once (builder.Services.AddSingleton<RepositoryConfigurationFactory>(), or with a notification handler and AI settings) and call Create(http.User) in the endpoint, as The Server Endpoint does.
A role mapping is easy to get subtly wrong (granting DraftUpdate without DraftView, for instance), and an incomplete set fails every request with CE10218. Check each of your role sets in a unit test:
var problems = Context.ValidatePermissions(new RepositoryConfigurationFactory().Create(TestUsers.Author));
Assert.Empty(problems); // each problem is one English sentence, such as "DraftUpdate (52) requires DraftView (50)."
ValidatePermissions reads no database.
The Context Class
Context is the whole server-side API of the Rule Repository. It is static: nothing to create, set up or dispose of. Each method takes the database provider and, where a user is involved, a configuration.
| Method |
When you call it |
GetResponse(config, db, requestJson) |
In your endpoint, for every request from the browser. |
SyncSources(db, settings) |
At startup, at deployment or on demand, to put your source objects into the repository. See Source Sync and Versioning. |
Reindex(db, aliases) |
After an upgrade or a bulk import, when SyncSources reports source objects to reindex. |
GetAliasNames(db) |
To see which source objects the repository already holds. |
GetRules(db, query) |
In production code that evaluates live rules without Audit. See Live Versions and Approvals. |
CheckDatabase(db) |
Once at startup. See The Database. |
ValidatePermissions(config) |
In your tests of role mappings. |
GetDefaultUiXml() |
Once, to get the English text document you translate. |
GetDefaultEditorHelpXml() |
Once, to get the rule editors' English Help XML you translate. |
GetRequestToken(config, db) |
Only when your own server code builds repository requests. |
Implementing the Interface Yourself
If your application already has an authorization service (policies, a permissions table, an external policy engine), implement IRepositoryConfiguration and answer CanPerform from it. RR asks CanPerform once for every permission on every request, so keep it fast (cache the user's permissions for the request).
using System.Xml;
using CodeEffects.Rule.Common.Models;
using CodeEffects.Rule.Repository;
using CodeEffects.Rule.Repository.Common;
public interface IMyPermissions { bool Allows(string userId, string permission); }
public sealed class PolicyConfiguration : IRepositoryConfiguration
{
private readonly IMyPermissions permissions;
public PolicyConfiguration(IMyPermissions permissions, string userId, string userName)
{
this.permissions = permissions;
this.CurrentUserId = userId;
this.CurrentUserName = userName;
}
// Answered by your own service; RR only asks
public bool CanPerform(ActionPermissionType action) =>
this.permissions.Allows(this.CurrentUserId, "rules:" + action);
// Not used when CanPerform answers by itself, but part of the interface
public ActionPermissionMode AccessMode { get; set; } = ActionPermissionMode.ViewOnly;
public ISet<ActionPermissionType> ActionList { get; set; } = new HashSet<ActionPermissionType>();
public string CurrentUserId { get; set; }
public string CurrentUserName { get; set; }
public UserType CurrentUserType { get; set; } = UserType.User;
public string CurrentAgentId { get; set; }
public string CurrentAgentName { get; set; }
public XmlDocument UiXml { get; set; }
public string UiXmlFile { get; set; }
public XmlDocument EditorHelpXml { get; set; }
public string EditorHelpXmlFile { get; set; }
public XmlDocument SourceLabelsXml { get; set; }
public string SourceLabelsXmlFile { get; set; }
public GetTypeDelegate TypeResolver { get; set; }
public NotificationDelegate Notify { get; set; }
public AgentSettings Agents { get; set; }
public AssistantSettings Assistant { get; set; }
public RequestLimits Limits { get; set; }
}
Your answers must form a complete set: a permission granted without one it requires fails every request with CE10218. Test them with Context.ValidatePermissions.
Request Limits
Every request is held to limits that protect your server. The defaults suit most sites; change them with Limits:
config.Limits = new RequestLimits { LookupOptions = 5000, TestRunsAtOnce = 4 };
| Property |
Default |
What it limits |
RequestLength |
3 MB (characters) |
The longest request accepted (CE10205). An AI Assistant file upload has its own limit, AssistantSettings.MaxAttachmentBytes. |
PayloadLength |
1 MB (characters) |
The longest stored payload: a draft's rule, a test's values and last run, a value template (CE10207). |
Filters |
50 |
Filters on one grid request (CE10206). |
LookupOptions |
1,000 |
Options returned for one drop-down list. |
TestRunsAtOnce |
8 |
Test runs under way at once in the whole process, for all users together (CE10209). |
Your endpoint's own body-size limit should be a little larger than RequestLength, and larger still if you allow AI attachments (see AI Assistant and AI Rule Editor).