For a decade, the way to extend SharePoint was a farm solution: a WSP package containing assemblies deployed to the Global Assembly Cache, running with full trust inside the SharePoint worker process. It was powerful and dangerous in equal measure. With Office 365 and SharePoint Online, that model simply doesn't exist — there is no server you can deploy a DLL to. This article explains why the SharePoint Add-in model replaced it, how provider-hosted add-ins authenticate, and how to approach migrating real code.
Why full-trust had to go
Farm solutions execute in-process with SharePoint. That means a memory leak, an undisposed SPSite, or a blocking web-service call in your code degrades the entire farm — for every tenant on it. In a multi-tenant cloud, that is unacceptable. Microsoft's answer was to move custom code out of the SharePoint process entirely:
- Full-trust farm solution — your code runs inside SharePoint, with farm-wide reach. Not possible in SharePoint Online.
- Sandboxed solution — a brief, constrained middle ground; deprecated for managed code.
- SharePoint Add-in (originally "App") — your code runs somewhere else and talks to SharePoint over authenticated web APIs (CSOM/REST).
Two add-in flavours
The add-in model comes in two shapes:
- SharePoint-hosted add-in — only HTML, CSS, and JavaScript, hosted in an isolated "app web" inside SharePoint. No server-side code. Good for lightweight UI.
- Provider-hosted add-in — your server-side logic lives in an external web application (typically ASP.NET on IIS or Azure), which calls back into SharePoint using OAuth. This is the real replacement for full-trust business logic.
How provider-hosted authentication works
A provider-hosted add-in authenticates to SharePoint Online through Azure Access Control Service (ACS) using OAuth. The high-level flow:
- You register the add-in (via
AppRegNew.aspxor the Seller Dashboard) and receive a client ID and client secret. - When a user launches the add-in, SharePoint posts a context token to your remote web.
- Your code validates that token and exchanges it (with ACS) for an access token scoped to the user and site.
- You attach the access token to CSOM/REST calls back into SharePoint.
The Visual Studio add-in template ships a TokenHelper class and SharePointContext that do the heavy lifting:
// Provider-hosted add-in: get an authenticated ClientContext
protected void Page_Load(object sender, EventArgs e)
{
var spContext =
SharePointContextProvider.Current.GetSharePointContext(Context);
using (var ctx = spContext.CreateUserClientContextForSPHost())
{
ctx.Load(ctx.Web, w => w.Title);
ctx.ExecuteQuery();
lblTitle.Text = ctx.Web.Title;
}
}
CreateUserClientContextForSPHost() acts as the signed-in user (low-trust user+app token). For background jobs with no user present, use an app-only token instead — but app-only requires the permission to be explicitly granted at registration time.
Declaring permissions
An add-in has no rights by default. You request exactly the scopes you need in AppManifest.xml, and an administrator (or site owner) consents at install time. Least privilege is the rule:
<AppPermissionRequests AllowAppOnlyPolicy="true">
<AppPermissionRequest
Scope="http://sharepoint/content/sitecollection/web"
Right="Write" />
</AppPermissionRequests>
Scopes range from tenant down through sitecollection, web, and list, with rights of Read, Write, Manage, and FullControl. Request the narrowest scope and lowest right that gets the job done.
A pragmatic migration strategy
You rarely "lift and shift" a farm solution — the architecture is fundamentally different. Instead, decompose the old WSP by capability and map each to its modern equivalent:
| Farm solution feature | Add-in model replacement |
|---|---|
| Server-side event receivers | Remote event receivers / webhooks |
| Web parts (visual) | Add-in part (client web part) or, later, SPFx |
| Custom ribbon / actions | Custom actions declared in the add-in manifest |
| Timer jobs | External scheduled service (Azure WebJob / Function) |
| Feature receivers / provisioning | Remote provisioning via CSOM (PnP) |
| Full-trust business logic | Provider-hosted web app calling CSOM/REST |
Refactor in layers
- Isolate the business logic from the SharePoint plumbing in the old solution. Pure C# rules and calculations move across almost unchanged.
- Replace the data layer — swap server
SPListItemcalls for client-side CSOM/REST against the same lists. - Re-home the entry points — event receivers become remote receivers/webhooks; timer jobs become scheduled Azure jobs; UI becomes add-in parts.
- Re-implement provisioning with PnP templates rather than feature activation.
Looking ahead
The add-in model itself was a transitional architecture. By the time you read the later articles in this series, SPFx had become the recommended way to build UI, and Microsoft Graph plus Azure AD app registrations replaced ACS for authentication (ACS-based app-only auth is now on a deprecation path). But the core lesson endures: in the cloud, your code lives outside SharePoint and earns access through explicit, least-privilege permissions. Internalising that during the farm-to-add-in transition is exactly what makes the later jump to Graph feel natural.