# TXTextControl.DocumentServices.Plugin.Abstractions

- **Product:** DS Server
- **Section:** Documentation
- **Kind:** Topic
- **Path:** DS Server > API Reference > .NET API > TXTextControl.DocumentServices.Plugin.Abstractions
- **5915 words**
- **Web URL:** https://docs.textcontrol.com/ds-server/reference/dotnet-api/txtextcontrol-documentservices-plugin-abstractions/
- **LLMs URL:** https://docs.textcontrol.com/ds-server/reference/dotnet-api/txtextcontrol-documentservices-plugin-abstractions/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/ds-server/reference/dotnet-api/txtextcontrol-documentservices-plugin-abstractions/llms-full.txt

---

**TXTextControl.DocumentServices.Plugin.Abstractions** defines the shared interface and plugin lifecycle for building external plugin assemblies that extend the functionality of [Text Control DS Server](https://www.dsserver.io/).

This package allows developers to build `.dll` plugins that:

- Register custom ASP.NET Core API controllers
- Add middleware or route handlers
- Access DS Server configuration and services via **Dependency Injection (DI)**
- Execute startup/shutdown logic

---

### ✨ Features

- **Controller-based plugins**: Add custom API endpoints
- **Lifecycle hooks**: Initialize and clean up plugin logic
- **Service registration**: Register your own services into the DI container
- **Dependency Injection access**: Use built-in DS Server services such as `IDocumentProcessingService` or `IDocumentEditorSessionService`
- **Middleware support**: Add request interceptors, metrics, logging, etc.

---

### 📦 NuGet

```shell
dotnet add package TXTextControl.DocumentServices.Plugin.Abstractions
```

If you want to see a complete plugin implementation, refer to the [TXTextControl.DocumentServices.SamplePlugin](https://github.com/TextControl/TXTextControl.DocumentServices.SamplePlugin)example project, which demonstrates how to use this package in a real DS Server plugin.

---

### 1️⃣ Basic Plugin Structure

#### 📜 Interface Overview

```csharp
namespace TXTextControl.DocumentServices.Plugin.Abstractions;

public interface IPlugin {
    string Name { get; }
    string Description { get; }
    string Version { get; }

    string UIBasePath => null; // Optional, for plugins with a web UI (e. g. /plugin-ui/config)

    void ConfigureServices(IServiceCollection services, PluginContext context) { }
    void ConfigureMiddleware(WebApplication app, PluginContext context) { }
    void OnStart(IServiceProvider services, PluginContext context) { }
    void OnStop() { }
}
```

`PluginContext` provides metadata about the DS Server environment:

```csharp
public class PluginContext {
    public string DsServerVersion { get; set; } = default!;
    public string BaseDirectory { get; set; } = default!;
    public IConfiguration Configuration { get; set; } = default!;
}
```

#### 🚀 Getting Started

To create a basic plugin with a controller and custom middleware, follow these steps:

##### 1. Create a new class library project

```shell
dotnet new classlib -n MyFirstPlugin
cd MyFirstPlugin
```

##### 2. Add the abstraction package

```shell
dotnet add package TXTextControl.DocumentServices.Plugin.Abstractions
```

##### 3. Define a service to hold config state

```csharp
public class GreetingState {
    public string Greeting { get; set; } = "Hello (default)";
}
```

##### 4. Create a controller

This controller will respond to requests at `/plugin/hello`:

```csharp
using Microsoft.AspNetCore.Mvc;

namespace MyFirstPlugin;

[ApiController]
[Route("plugin/[controller]")]
public class HelloController : ControllerBase {
    private readonly GreetingState m_state;

    public HelloController(GreetingState state) {
        m_state = state;
    }

    [HttpGet]
    public string Get() => m_state.Greeting;
}
```

##### 5. Implement the plugin class

This class implements the `IPlugin` interface, reads the greeting text from the configuration and registers a middleware to log requests:

```csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using TXTextControl.DocumentServices.Plugin.Abstractions;

namespace MyFirstPlugin;

public class HelloPlugin : IPlugin {
    public string Name => "MyFirstPlugin";
    public string Description => "Adds a /plugin/hello endpoint and logs requests.";
    public string Version => "1.0.0";

    public void ConfigureServices(IServiceCollection services, PluginContext context) {
        // Retrieve the greeting from the configuration and register it as a singleton service.
        // This is just an example. Implementing ConfigureServices is optional.
        var greeting = context.Configuration["MyFirstPlugin:Greeting"] ?? "Hello (default)";
        services.AddSingleton(new GreetingState { Greeting = greeting });
    }

    public void ConfigureMiddleware(WebApplication app, PluginContext context) {
        // Register a middleware to log requests to the /plugin/hello endpoint.
        // This is also just an example. Implementing ConfigureMiddleware is optional.
        app.Use(async (ctx, next) => {
            if (ctx.Request.Path.StartsWithSegments("/plugin/hello")) {
                var logger = ctx.RequestServices.GetRequiredService<ILogger<HelloPlugin>>();
                logger.LogInformation("MyFirstPlugin intercepted request to /plugin/hello");
            }
            await next();
        });
    }

    public void OnStart(IServiceProvider services, PluginContext context) {
        // This method is called when the plugin is started. You can use this to 
        // initialize resources or perform startup logic. Implementing OnStart is optional.
        var logger = services.GetService<ILogger<HelloPlugin>>();
        var state = services.GetService<GreetingState>();
        logger?.LogInformation("Plugin started. Greeting: {Greeting}", state?.Greeting);
    }

    public void OnStop() {
        // Cleanup logic if needed. This is also optional.
    }
}
```

##### 6. Optional plugin settings

If your plugin expects config settings, add them to `appsettings.json`:

```json
"MyFirstPlugin": {
  "Greeting": "Howdy from DS Server!"
}
```

##### 7. Deploy and test the plugin

1. Build your plugin:

    ```bash
    dotnet build
    ```
2. Create a subfolder inside the `Plugins/` directory of your DS Server installation (e.g. `Plugins/SamplePlugin/`)
3. Copy the resulting `.dll` file (e.g. `bin/Debug/net10.0/MyFirstPlugin.dll`) into that subfolder:

    ```plaintext
    Plugins/
    └── SamplePlugin/
        └── MyFirstPlugin.dll
    ```
4. Restart DS Server.
5. Access the endpoint:

    ```perl
    GET http://<your-server>/plugin/hello
    ```

---

### 2️⃣ Accessing DS Server Services via Dependency Injection

Starting with DS Server **v5.0**, several core services are exposed to plugins through **Dependency Injection (DI)**.

These can be injected into controllers, services, or middleware. Typical use cases include:

- Converting and merging documents
- Manipulating or querying live Document Editor sessions
- Generating barcodes or analyzing PDF forms

---

#### 2.1 `IDocumentProcessingService`

Provides access to all **document processing capabilities** of DS Server.

##### Example: Convert and Merge Documents, extract PDF form fields and generate barcodes in a plugin controller

```csharp
using Microsoft.AspNetCore.Mvc;
using TXTextControl.DocumentServices.DocumentProcessing.Abstractions;
using TXTextControl.DocumentServices.DocumentProcessing.Models;

[ApiController]
[Route("plugin/[controller]/[action]")]
public class DocumentProcessingController : ControllerBase {
    private readonly IDocumentProcessingService m_processing;

    public DocumentProcessingController(IDocumentProcessingService processing) {
        m_processing = processing;
    }

    [HttpPost]
    public async Task<IActionResult> Convert([FromBody] byte[] document, [FromQuery] string format = "PDF") {
        ReturnFormat returnFormat = Enum.Parse<ReturnFormat>(format, true);
        byte[] result = await m_processing.ConvertAsync(document, returnFormat, true);
        return returnFormat switch {
            ReturnFormat.PDF => File(result, "application/pdf", "converted.pdf"),
            ReturnFormat.HTML => File(result, "text/html", "converted.html"),
            ReturnFormat.DOCX => File(result, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "converted.docx"),
            ReturnFormat.RTF => File(result, "application/rtf", "converted.rtf"),
            _ => File(result, "application/octet-stream", "converted.dat"),
        };
    }

    [HttpPost]
    public async Task<IActionResult> MergeExample([FromBody] byte[] template) {
        MergeBody mergeBody = new() {
            Template = template,
            MergeData = new[] {
                new { Name = "Alice" },
                new { Name = "Bob" }
            }
        };
        byte[][] merged = await m_processing.MergeAsync(mergeBody, ReturnFormat.PDF, append: true);
        return File(merged[0], "application/pdf", "merged.pdf");
    }

    [HttpPost]
    public async Task<IActionResult> GetAcroFormFields([FromBody] byte[] pdfDocument) {
        FormField[] formFields = await m_processing.PDF.AcroForms.GetFieldsAsync(pdfDocument);
        return Ok(formFields);
    }

    [HttpGet]
    public async Task<IActionResult> CreateBarcode([FromQuery] string text = "https://www.textcontrol.com") {
        byte[] image = await m_processing.Barcodes.CreateAsync(new BarcodeSettings(text));
        string base64 = System.Convert.ToBase64String(image);
        return Ok(new { ImageDataUrl = $"data:image/png;base64,{base64}" });
    }
}
```

##### Common Operations

| Operation | Method | Description |
|---|---|---|
| Merge | `MergeAsync` | Mail merge using JSON or object data |
| Convert | `ConvertAsync` | Convert between document formats |
| Find/Replace | `FindAndReplaceAsync` | Replace text |
| Append | `AppendAsync` | Combine multiple documents |
| Thumbnails | `GetThumbnailsAsync` | Generate image previews |
| Document Info | `GetDocumentInfoAsync` | Extract metadata and merge fields |

##### Sub-APIs

| API | Interface | Description |
|---|---|---|
| **PDF** | `IPdfApi` | Create PDFs, extract metadata, embedded files |
| **AcroForms** | `IAcroFormsApi` | Read and analyze PDF form fields |
| **Barcodes** | `IBarcodesApi` | Generate and validate barcode images |

---

#### 2.2 `IDocumentEditorSessionService`

Provides access to active **Document Editor sessions** managed by DS Server.

This allows you to manipulate open documents, retrieve fields, or change formatting in real time.

##### Example: Working with Sessions

```csharp
using Microsoft.AspNetCore.Mvc;
using TXTextControl.DocumentServices.DocumentEditor.Abstractions;
using TXTextControl.DocumentServices.DocumentEditor.Enums;
using TXTextControl.DocumentServices.DocumentEditor.Options;

[ApiController]
[Route("plugin/[controller]/[action]")]
public class DocumentEditorController : ControllerBase {
    private readonly IDocumentEditorSessionService m_sessions;

    public DocumentEditorController(IDocumentEditorSessionService sessions) {
        m_sessions = sessions;
    }

    [HttpPost]
    public async Task<IActionResult> LoadDocument([FromQuery] string connectionId, [FromBody] string base64, [FromQuery] string format = "html") {
        IDocumentEditorSession session = m_sessions[connectionId];
        byte[] content = Convert.FromBase64String(base64);
        DocumentFormat documentFormat = Enum.Parse<DocumentFormat>(format, true);
        LoadOptions options = LoadOptions.FromDocumentFormat(documentFormat, content);
        await session.LoadAsync(options);
        return Ok(new { message = "Document loaded successfully." });
    }

    [HttpPost]
    public async Task<IActionResult> SetParagraphColor([FromQuery] string connectionId, [FromQuery] string color = "#FFFF00") {
        IDocumentEditorSession session = m_sessions[connectionId];
        IParagraphFormat paragraph = session.Selection.ParagraphFormat;
        await paragraph.SetBackColorAsync(color);
        return Ok(new { message = $"Paragraph color set to {color}." });
    }

    [HttpGet]
    public async Task<IActionResult> GetFieldInfo([FromQuery] string connectionId) {
        IDocumentEditorSession session = m_sessions[connectionId];
        IApplicationField appField = await session.ApplicationFields.GetItemAsync();
        if (appField == null) return NotFound();
        string name = await appField.GetNameAsync();
        string typeName = await appField.GetTypeNameAsync();
        string text = await appField.GetTextAsync();
        return Ok(new { name, typeName, text });
    }
}
```

##### Common Operations

| Operation | Description |
|---|---|
| `LoadAsync` / `SaveAsync` | Load or save documents in a session |
| `SetUserNamesAsync` | Manage user tracking info |
| `FormFields.GetElementAsync()` | Access form fields and set values |
| `Selection.SaveAsync()` | Retrieve selected content as HTML or RTF |
| `ApplicationFields.GetItemAsync()` | Retrieve merge fields at the current input position |

---

#### 2.3 Namespaces Overview

| Interface | Namespace | Description |
|---|---|---|
| `IDocumentProcessingService` | `TXTextControl.DocumentServices.DocumentProcessing.Abstractions` | Full document processing API |
| `IPdfApi` / `IAcroFormsApi` / `IBarcodesApi` | dto. | Sub-APIs of the processing service |
| `IDocumentEditorSessionService` / `IDocumentEditorSession` | `TXTextControl.DocumentServices.DocumentEditor.Abstractions` | Access to live editor sessions |

---

### 📝 Notes

- All plugins must contain at least one public class implementing `IPlugin`
- Controllers must be decorated with `[ApiController]` and route attributes
- Middleware is registered per plugin via `ConfigureMiddleware`
- Services are injected using standard ASP.NET Core DI
- DS Server will invoke each lifecycle method (`ConfigureServices`, `ConfigureMiddleware`, `OnStart`, `OnStop`) at the appropriate phase

---

### 🛡 License

This package is provided under the MIT License. See [LICENSE.md](https://www.nuget.org/packages/TXTextControl.DocumentServices.Plugin.Abstractions/5.0.1/License) for details.

---

### 📣 About Text Control DS Server

[Text Control DS Server](https://www.dsserver.io/) is a powerful on-premise backend for generating, viewing, editing, and signing documents — complete with extensive mail merge and reporting capabilities — accessible via REST APIs or integrated custom logic through plugins like this one. [Try it out today](https://www.dsserver.io/getting-started/) and see how it can enhance your document processing workflows!

---

## Nearby

- **Previous:** [TXTextControl.DocumentServices.Admin](https://docs.textcontrol.com/ds-server/reference/dotnet-api/txtextcontrol-documentservices-admin/llms-full.txt)
- **Next:** [JavaScript API](https://docs.textcontrol.com/ds-server/reference/javascript-api/llms-full.txt)
