Connecting to the LemonEdge platform
This article explains how to create a .Net application that can directly connect to the LemonEdge platform through the LemonEdge API.
This is simply to connect to the LemonEdge platform from a 3rd party app, or stand-alone app, utilising our APIs. It is not to integrate functionality into LemonEdge such as new classes or algorithms. To do that see our Designing Entities walkthrough.
Tip
This article assumes you are familiar with the following LemonEdge concepts:
- Creating An AddIn: How to create a .net dll referencing the LemonEdge dlls.
- IEntityRetriever: The interface used to query all items in the LemonEdge platform using LINQ style functionality. These interfaces abstract away whether the connection is directly to the database or via a web service, using these APIs you do not need to care.
- IEntityUpdater: The interface used to create, insert or delete any item in the LemonEdge platform. Permissions are always enforced when this functionality is used.
Note
You can follow along with this article by downloading the API Examples projects which provide the code examples discussed here.
To start you need to create a new .Net application and reference the following LemonEdge dlls:
- API.dll
- Utils.dll
- Entities.dll
Depending how you would like to connect to the LemonEdge platform you will need the following dlls as well if your connection is directly to the SQL Database:
- Service Connection:
- ClientService.dll
- Direct Database Connection:
- ClientDB.dll
- DatabaseUtils.dll
- DatabaseConnector.dll
- InternalAPI.dll
Connection Classes
In order to use either the Database or Service connection we'll create a couple of wrapper classes to deal with the different types:
public abstract class Connector
{
public abstract LemonEdge.Client.Core.CommonUI.ConnectionType Type { get; }
public abstract string ServiceConnection { get; }
public virtual string Alias => "";
}
If we are connecting through a service connection, we can use the following:
public class ServiceConnector : Connector
{
public ServiceConnector()
{
var service = new LemonEdge.Client.Service.ConnectionTypeHandler();
service.AddFactory(LemonEdge.Client.Core.CommonUI.Connector.Instance);
}
public override LemonEdge.Client.Core.CommonUI.ConnectionType Type => LemonEdge.Client.Core.CommonUI.ConnectionType.Service;
public override string ServiceConnection => "http://localhost:61596/odata";
public override string Alias => "FinancialServices";
}
If we are connecting directly via a database connection we can use the following instead:
public class DBConnector : Connector
{
public DBConnector()
{
var dbService = new LemonEdge.Client.DB.ConnectionTypeHandler();
dbService.AddFactory(LemonEdge.Client.Core.CommonUI.Connector.Instance);
}
public override LemonEdge.Client.Core.CommonUI.ConnectionType Type => LemonEdge.Client.Core.CommonUI.ConnectionType.Database;
public override string ServiceConnection => "Data Source=.;Initial Catalog=FinancialServices;Persist Security Info=True;Trusted_Connection=True;Connection Timeout=120;ConnectRetryCount=3;ConnectRetryInterval=30";
}
Obviously these connection strings will need to be replaced with your own service or sql connection strings.
Connecting & Logging In
To connect to the LemonEdge platform using our connector class, we just need the following:
private static async Task<bool> Connect(Connector connector, string userName, string password)
{
LemonEdge.Client.Core.CommonUI.Connector.Instance.UseFactory(connector.Type);
//also needs typeof(LemonEdge.Connections.Database.DataUpdater).Assembly, typeof(LemonEdge.Utils.Database.Helper).Assembly if using direct db connector
LemonEdge.Utils.ReflectionHelper.Init(new Assembly[] { typeof(LemonEdge.Entities.User).Assembly });
LemonEdge.API.AddInLoaderHelper.Type = LemonEdge.API.FrameworkType.Core;
Console.WriteLine("Connecting...");
await LemonEdge.Client.Core.CommonUI.Connector.OnUpdateServiceConnection(connector.ServiceConnection);
Console.WriteLine("Logging in...");
var userLogin = await LemonEdge.Client.Core.CommonUI.Connector.Login(connector.Alias, userName, password);
using (var cn = await LemonEdge.Client.Core.CommonUI.Connector.Create())
await LemonEdge.API.AddInLoaderHelper.Init(connector.Alias, cn);
return userLogin != null;
}
Lets break this down into steps. This line tells the Connector to use the connection type provided:
LemonEdge.Client.Core.CommonUI.Connector.Instance.UseFactory(connector.Type);
This line tells the system to load all the specified assemblies into the reflection helper for performance, and so the system knows what dlls are being used by the system by default:
LemonEdge.Utils.ReflectionHelper.Init(new Assembly[] { typeof(LemonEdge.Entities.User).Assembly });
Equally, if you are connecting directly to the database you will need to reference additional LemonEdge assemblies, and thus need the following Init call:
LemonEdge.Utils.ReflectionHelper.Init(new Assembly[] { typeof(LemonEdge.Entities.User).Assembly, typeof(LemonEdge.Connections.Database.DataUpdater).Assembly, typeof(LemonEdge.Utils.Database.Helper).Assembly });
The next line indicates that we are using this client to only load the core configuration from the LemonEdge platform. We do not need to load any specific UI components that may have been added as part of a custom AddIn Module:
LemonEdge.API.AddInLoaderHelper.Type = LemonEdge.API.FrameworkType.Core;
If instead you were actually wanting to load UI configuration as well from the platform you could use the following:
LemonEdge.API.AddInLoaderHelper.Type = LemonEdge.API.FrameworkType.WPF
See AddIn Modules for more information.
The next line indicates which connection string we will be using to login to the application through the API:
await LemonEdge.Client.Core.CommonUI.Connector.OnUpdateServiceConnection(connector.ServiceConnection);
This is an operation that returns a task, as in the case of a web service connection it connects to the web service, validate it, and also downloads a complete model of the OData web service API.
Important
Next we can login to the application using our credentials:
var userLogin = await LemonEdge.Client.Core.CommonUI.Connector.Login(connector.Alias, "root@lemonedge.com", "!ltroot");
If you are connecting using windows authentication, you can use the following Connector overload instead:
var userLogin = await LemonEdge.Client.Core.CommonUI.Connector.LoginWindows(connector.Alias);
If the userLogin == null, then the login failed.
Note
If you do not know the AddIns that have been created in the LemonEdge system you are connecting to the next line downloads and dynamically loads/integrates those AddIns to the application you are running. If you know the custom AddIns that would be downloaded, then you can just reference them directly as DLLs in your project and you do not need to download anything. This also means you don't have to dynamically interrogate all the entities in the system, you will actually have the direct classes/interfaces to use. If you do not have the dlls to reference statically then you need the following line:
using (var cn = await LemonEdge.Client.Core.CommonUI.Connector.Create())
await LemonEdge.API.AddInLoaderHelper.Init(connector.Alias, cn);
Using Connected API
Once you've connected to the LemonEdge platform and logged in, you have full access via the API to everything you would through the client applications and more. Everything you perform through the API is still validated, and run through our permission system according to the user you are logged in as. You can not do anything through the API that the same user logged in to the application would be unable to do, because at the end of the day the all the client applications are built using the API too.
Important
To get an Updater Context to query, and update all entities, in the entire LemonEdge platform you simply need the following line:
using var context = await LemonEdge.Client.Core.CommonUI.Connector.Create();
For instance, you can use that to enumerate a list of all users:
using (var context = await LemonEdge.Client.Core.CommonUI.Connector.Create())
{
foreach(var user in await context.ExecuteQuery(context.GetItems<LemonEdge.API.Entities.IUser>()))
Console.WriteLine("User: " + user.EmailLogin);
}
If you want to enumerate objects that have been dynamically added through loaded AddIn modules, you can refer to them as follows:
var desc = LemonEdge.Core.Descriptors.EntityDescriptorFactory.GetDescriptors().FirstOrDefault(x => x.SetName == "Funds");
using (var context = await LemonEdge.Client.Core.CommonUI.Connector.Create())
{
foreach (var fund in await context.ExecuteQuery(context.GetItems(desc.EntityType)))
Console.WriteLine("Fund: " + fund.ToString());
}
You can also use functionality in our Utils dll to dynamically access their properties, or query them.
If you know the dll being referenced, you can link that statically to your program and use the following instead:
using (var context = await LemonEdge.Client.Core.CommonUI.Connector.Create<LemonEdge.AssetManagement.Entities.IFund>())
{
foreach (var fund in await context.ExecuteQuery(context.GetItems<LemonEdge.AssetManagement.Entities.IFund>()))
Console.WriteLine("Fund: " + fund.Name());
}
See our Updater Context documentation for more information on creating, updating, deleting and querying all entities in the system.
Complete Program
Putting all the above together, we get the following very simply program to connect, login and query the system using the API:
class Program
{
const bool USE_SERVICE_CONNECTION = true;
static async Task Main(string[] args)
{
//references simple.odata.v4.client oackage
//references clientservice dll, and entities dll
var connector = USE_SERVICE_CONNECTION ? (Connector)new ServiceConnector() : null; //new DBConnector();
var loggedIn = await Connect(connector, "root@lemonedge.com", "!ltroot");
if(!loggedIn)
Console.WriteLine("Invalid Login");
else
{
Console.WriteLine("Loading users...");
using (var context = await LemonEdge.Client.Core.CommonUI.Connector.Create())
{
foreach(var user in await context.ExecuteQuery(context.GetItems<LemonEdge.API.Entities.IUser>()))
Console.WriteLine("User: " + user.EmailLogin);
}
Console.WriteLine("Loading Funds");
var desc = LemonEdge.Core.Descriptors.EntityDescriptorFactory.GetDescriptors().FirstOrDefault(x => x.SetName == "Funds");
using (var context = await LemonEdge.Client.Core.CommonUI.Connector.Create())
{
foreach (var fund in await context.ExecuteQuery(context.GetItems(desc.EntityType)))
Console.WriteLine("Fund: " + fund.ToString());
}
}
}
private static async Task<bool> Connect(Connector connector, string userName, string password)
{
LemonEdge.Client.Core.CommonUI.Connector.Instance.UseFactory(connector.Type);
//also needs typeof(LemonEdge.Connections.Database.DataUpdater).Assembly, typeof(LemonEdge.Utils.Database.Helper).Assembly if using direct db connector
LemonEdge.Utils.ReflectionHelper.Init(new Assembly[] { typeof(LemonEdge.Entities.User).Assembly });
LemonEdge.API.AddInLoaderHelper.Type = LemonEdge.API.FrameworkType.Core;
Console.WriteLine("Connecting...");
await LemonEdge.Client.Core.CommonUI.Connector.OnUpdateServiceConnection(connector.ServiceConnection);
Console.WriteLine("Logging in...");
var userLogin = await LemonEdge.Client.Core.CommonUI.Connector.LoginWindows(connector.Alias);
using (var cn = await LemonEdge.Client.Core.CommonUI.Connector.Create())
await LemonEdge.API.AddInLoaderHelper.Init(connector.Alias, cn);
return userLogin != null;
}
}
public abstract class Connector
{
public abstract LemonEdge.Client.Core.CommonUI.ConnectionType Type { get; }
public abstract string ServiceConnection { get; }
public virtual string Alias => "";
}
public class ServiceConnector : Connector
{
public ServiceConnector()
{
var service = new LemonEdge.Client.Service.ConnectionTypeHandler();
service.AddFactory(LemonEdge.Client.Core.CommonUI.Connector.Instance);
}
public override LemonEdge.Client.Core.CommonUI.ConnectionType Type => LemonEdge.Client.Core.CommonUI.ConnectionType.Service;
public override string ServiceConnection => "http://localhost:61596/odata";
public override string Alias => "FinancialServices";
}
//public class DBConnector : Connector
//{
// public DBConnector()
// {
// var dbService = new LemonEdge.Client.DB.ConnectionTypeHandler();
// dbService.AddFactory(LemonEdge.Client.Core.CommonUI.Connector.Instance);
// }
// public override LemonEdge.Client.Core.CommonUI.ConnectionType Type => LemonEdge.Client.Core.CommonUI.ConnectionType.Database;
// public override string ServiceConnection => "Data Source=.;Initial Catalog=FinancialServices;Persist Security Info=True;Trusted_Connection=True;Connection Timeout=120;ConnectRetryCount=3;ConnectRetryInterval=30";
//}