🚀 Welcome to MDriven Learn –  MDriven is now on Discord!  Don’t miss the latest Release Notes.
Calling your own c - sharp .net things from Turnkey–server side
This page was created by Alexandra on 2018-10-28. Last edited by Wikiadmin on 2026-07-29.

You can implement model methods in your own C# assembly when a MDriven Turnkey application needs server-side logic that is not practical to express in the model, such as advanced cryptography or a call to an external web API.

When to use an external late-bound method

An external late-bound method is a model operation whose implementation is supplied at runtime by an assembly in the Turnkey deployment. Turnkey routes a call to the operation to an implementation of IExternalLateBoundService.

Use this extension point when the operation needs C# or another .NET library. For example:

  • Generate a key with a cryptographic algorithm.
  • Send a SiteAsset to an external service and return a status message.
  • Call an external web API, wait for its response, and store or return the result.

Keep the model responsible for the application structure and use external code for the specific work that requires it. For guidance on C# in MDriven, see Documentation:C-Sharp. If the requirement is specifically to post data to TurnkeyRest, use Documentation:Use c-sharp code to post to TurnkeyRest instead.

How the call is routed

Turnkey supplies your implementation with the classifier, the object that owns the operation, the model method, and the operation arguments. Your Execute method identifies the requested operation by checking the owning class and method name, performs the work, and returns an IElement.

For example, a model operation named SendAsset on SiteAsset is routed by checking:

theobject.UmlClass.Name == "SiteAsset" && method.Name == "SendAsset"

The class name and method name in the C# routing code must match the names in the model.

Implement the extension assembly

1. Create the class library

  1. Create a .NET 4.5 class-library project.
  2. Add a reference to the assembly Eco.Interfaces.
  3. Set the output assembly name to TurnKey_ExternalLateBound.dll. This name is required.
  4. Add a class that implements Eco.Services.IExternalLateBoundService.

The interface is:

namespace Eco.Services
{
  public interface IExternalLateBoundService
  {
    IElement Execute(
      IClassifier classifier,
      IObject theobject,
      IMethod method,
      IModifiableVariableList variableList);
  }
}

2. Route operations in Execute

The following example shows two routes. SiteAsset.SendAsset returns a text result, while RuntimeKey.GenerateKey delegates to a separate method.

using Eco.ObjectRepresentation;
using Eco.Services;
using Eco.UmlRt;

public class ExternalLateBoundService : IExternalLateBoundService
{
  public IElement Execute(
    IClassifier classifier,
    IObject theobject,
    IMethod method,
    IModifiableVariableList variableList)
  {
    if (theobject == null || method == null)
      return null;

    if (theobject.UmlClass.Name == "SiteAsset" && method.Name == "SendAsset")
    {
      string result = "Sending asset: " +
        SendSiteAssetToTurnkeySite(theobject, variableList);

      return EcoServiceHelper
        .GetVariableFactoryService(theobject.ServiceProvider)
        .CreateConstant(result);
    }

    if (theobject.UmlClass.Name == "RuntimeKey" && method.Name == "GenerateKey")
      return RuntimeKey_GenerateKey(theobject, variableList);

    string noLogic = "No logic for " + theobject.UmlClass.Name + "." + method.Name;
    return EcoServiceHelper
      .GetVariableFactoryService(theobject.ServiceProvider)
      .CreateConstant(noLogic);
  }

  // Implement these methods for your model operations.
  private string SendSiteAssetToTurnkeySite(
    IObject theobject,
    IModifiableVariableList variableList)
  {
    return "";
  }

  private IElement RuntimeKey_GenerateKey(
    IObject theobject,
    IModifiableVariableList variableList)
  {
    return null;
  }
}

A route that is not explicitly handled should return an appropriate result for the operation, or null where that is valid for the operation. Do not rely on the example's No logic for ... text as an error-handling policy; it is only an illustration of how to create a constant return value.

Read operation inputs and model data

variableList contains the arguments passed to the model operation. Read an argument by its model parameter name. For an operation parameter named vStartPart:

string startPart = variableList["vStartPart"].Element.GetValue<string>();

Use theobject to access the object that owns the method. For example, read its PageStyle property:

string pageStyle = theobject.Properties["PageStyle"].GetValue<string>();

Navigate an association through the owner's properties. For example, obtain the associated Product object:

IObject product = theobject.Properties["Product"].Element as IObject;

These names are model names. If vStartPart, PageStyle, or Product is renamed in the model, update the extension code to match.

Define the model operation

For every operation that the assembly implements:

  1. In MDriven Designer, define the method on the model class that owns it. For example, define SendAsset on SiteAsset.
  2. Define the method parameters and return type required by the C# implementation. Parameter names are the keys used in variableList.
  3. Leave the method implementation body empty.
  4. Add the tagged value Eco.ExternalLateBound=True to the method.
  5. Build and deploy the model with the Turnkey application.

After this configuration, you can call the operation from an action or a button. You can also use it from a derivation when the method is marked as a query.

Deploy the assembly

  1. Build the class library and verify that its output is named TurnKey_ExternalLateBound.dll.
  2. Copy TurnKey_ExternalLateBound.dll to EXT_LateBoundAssembly under the root folder of the Turnkey site.
  3. Copy every assembly on which the extension depends to the same deployment location.
  4. Deploy the files using the AssetsTK strategy used by the Turnkey site.

The extension must be deployed with the Turnkey application, not only on a development machine. For hosting and deployment guidance, see HowTos:Install MDriven Server and Turnkey on Microsoft Azure, Documentation:Set up MDriven Turnkey on premise, or Documentation:Deploying MDriven Server & Turnkey Core on IIS.

CodeDress behavior

When you run with CodeDress, leave the body of an external late-bound method empty. If the body is not empty, that body is executed instead of the external late-bound implementation.

An empty body causes code generation to create a stub. The late-bound mechanism ignores that stub, but the generated code may still need return statements or other changes required for compilation.

Design and troubleshooting guidance

Keep synchronous operations small

An external late-bound operation can have side effects and can still be marked as a query. However, do not place a large amount of processing in one UI-triggered call. Split complex work into smaller modelled steps where possible.

For example, instead of compressing every uploaded image during the upload action, model a state change that triggers a server-side job to create a thumbnail. The UI operation can complete while the job performs the longer-running processing. This divide-and-conquer approach reduces the amount of work held in memory at one time and makes the process easier to inspect and debug.

Check the deployment and runtime versions

If an extension does not load or CodeDress behaves unexpectedly, confirm that the Turnkey installation and the MDriven Framework used in Visual Studio are the same version. Old framework versions in the GAC can also be loaded by CodeDress. See HowTos:Debug Turnkey Generic Code for debugging guidance, including the distinction between .NET Framework and .NET Core binaries.

See also