ECO and custom services

As you are well aware, ECO is heavily modularized by use of services.

You have surely noticed that when getting an eco service with code similar to

  1. var ocl = ServiceProvider.GetEcoService<IOclService>();

As things have matured, the DefaultEcoSpace now implements simple properties for the more common built-in services;

  1. // Summary:
  2. //     The IVariableFactoryService of the EcoSpace
  3. //
  4. // Remarks:
  5. //     The IVariableFactoryService contains methods for creating free standing ECO
  6. //     elements that can be used as variables. The elements returned will implement
  7. //     IElement, and any other applicable interfaces from the Eco.ObjectRepresentation
  8. //     namespace.  This propery is equivalent to retieving the IVariableFactoryService
  9. //     from an IEcoServiceProvider using GetEcoService(typeof(IVariableFactoryService)).
  10. public IVariableFactoryService VariableFactory { get; }
  11. //
  12. // Summary:
  13. //     The IVersionService of the EcoSpace
  14. //
  15. // Remarks:
  16. //     The IVersionService is used for accessing historical values of ECO objects.
  17. //      This propery is equivalent to retieving the IVersionService from an IEcoServiceProvider
  18. //     using GetEcoService(typeof(IVersionService)).
  19. public IVersionService Versioning { get; }

and quite a few more.

What is not obvious at first glance is that anyone can register a service by means of the method DefaultEcoSpace.RegisterEcoService(Type type, object instance). As with any other service, the services you register are available from any service provider in which they are registered.

Here’s an idea I probably got from Peter Morris; add your own ICurrentUserService.

The idea is to have a globally available service that can tell you who – if anyone – is logged in.

My suggestion for an interface looks like:

  1. public interface IUserService<T>
  2. {
  3.   bool Login(string userName, string password);
  4.   void Logout();
  5.   T CurrentUser { get; }
  6.   bool IsLoggedIn { get; }
  7. }

The reason for a generic interface is to avoid linking it to the specific model.

The implementation is fairly straight forward. Note that there is a hard coded OCL expression that may or may not be suitable for you. It’s easy to change that to be set by a parameter. One of those famous exercises for the reader.

  1. public class CurrentUserService<T>: IUserService<T>
  2. {
  3.  private IEcoServiceProvider ServiceProvider { get; set; }
  4.  public CurrentUserService (IEcoServiceProvider serviceProvider)
  5.  {
  6.    ServiceProvider = serviceProvider;
  7.  }
  8.  public bool Login(string userName, string password)
  9.  {
  10.    var variables = ServiceProvider.GetEcoService<IVariableFactoryService>().CreateVariableList("var_username",  userName);
  11.    variables.AddConstant("var_password", password);
  12.  
  13.    var ocl = ServiceProvider.GetEcoService<IOclService>();
  14.    IList<T> users = ocl.Evaluate("User.AllInstances->select((username = var_username) and (password = var_password))->First", variables).GetAsIList<T>();
  15.    if (users.Count == 1)
  16.    {
  17.      currentUser = users[0];
  18.      return true;
  19.    }
  20.    return false;
  21.  }
  22.  
  23.  public void Logout()
  24.  {
  25.    currentUser = default(T);
  26.  }
  27.  private T currentUser;
  28.  public T CurrentUser
  29.  {
  30.    get
  31.    {
  32.       if (IsLoggedIn)
  33.          return currentUser;
  34.       return default(T);
  35.    }
  36.  }
  37.  public bool IsLoggedIn
  38.  {
  39.    get { return ServiceProvider != null &amp;&amp; currentUser != null; }
  40.  }
  41. }

Add this to the pool of services in the constructor of your ecospace

  1. public EcoProject1EcoSpace(): base()
  2. {
  3.   InitializeComponent();
  4.   this.RegisterEcoService(typeof(IUserService<User>), new CurrentUserService<User>(this));
  5. }

Make it a first class citizen by adding a property for it

  1.  public IUserService UserService { get { return GetEcoService<IUserService<User>>(); } }

After that, you can login, check for current user and what you may need.

Here’s the OK event on my login form

  1. private void btnOk_Click(object sender, EventArgs e)
  2. {
  3.   var userService = EcoSpace.GetEcoService<IUserService<User>>();
  4.   if (!userService.Login(tbxUsername.Text, tbxPassword.Text))
  5.   {
  6.     DialogResult = DialogResult.None;
  7.     MessageBox.Show("Invalid user name or password.");
  8.   }
  9. }

I use the logged in state to block some menus on the application;

  1. private void mnuFile_DropDownOpening(object sender, EventArgs e)
  2. {
  3.   mnuLogin.Enabled = !EcoSpace.UserService.IsLoggedIn;
  4.   mnuLogout.Enabled = EcoSpace.UserService.IsLoggedIn;
  5.   mnuChangePassword.Enabled = EcoSpace.UserService.IsLoggedIn;
  6. }

Some objects need to relate to the current user. Add that to the Created method of the class

  1. public partial class SomeModeledClass
  2. {
  3.  partial void Created()
  4.  {
  5.    CreatedByUser = AsIObject().ServiceProvider.GetEcoService<IUserService<User>>().CurrentUser;
  6.    CreatedDate = DateTime.Now;
  7.  }
  8. }

There are many a neat things that can be plugged in as services. I hope this gives you an idea of what is possible.

–Jesper Hogstrom

  • Share/Bookmark

Comments (5)

guest00December 31st, 2008 at 8:56 am

Cool!
Thank you for the example!

guest00December 31st, 2008 at 12:33 pm

Hello Jesper,
Could you please answer how can I use instead of in the the constructor of my ecospace when I am registering my custom service?
Sorry for the stupid question,

Thank you,
Regards,
Alex

guest00December 31st, 2008 at 12:33 pm

“T” instead of the “User”

adminJanuary 1st, 2009 at 5:05 pm

I am afraid I don’t quite understand what kind of information you want. Please rephrase and I’ll try to help.

Peter MorrisApril 17th, 2009 at 8:05 am

@Guest

You can override the Active property of the EcoSpace.

Leave a comment

Your comment