Tag Archive for 'XAF'

Developer Express has announced DXperience 2008 vol 1 beta

There are quire a few breaking changes for this one, although they seem to be just minor things.

List of changes in this version is available as well.

A couple of remarks on the changes:

  • Rich Text Editor for ASP.NET 2.0 (Desktop version is probably lurking around somewhere as well)
  • TreeView-Grid Hybrid for ASP.NET 2.0
  • Some unit tests have been made available. That’s the step towards improving development experience of customers. One can feel himself more safe while making changes in the code with test coverage.
  • Desktop UI has got cute apple skin. Additionally ASP.NET controls have got consistent theming support.
    DevExperience apple skin
  • Linq Server Mode has been mentioned a few times.
  • eXpress Application Framework changes are surprisingly limited. It feels like the development team has been assigned away from the project.

One more usage of the XtraLayoutControl - cross-platform UI designer

DevExperience has a nice control called XtraLayoutControl. Basically it allows you to have your own form designer at run-time.

XtraLayoutControl in action

But it can easily do more than just reshuffling of existing items for the Desktop UI. You can design forms that will be rendered on Desktop and Web alike.

eXpressAppFramework team has started using its capabilities of the design management, but I believe they can go even further if they:

  • Forget about pseudo-groups with custom orientation flags and keep positioning and size information of the design elements.
  • Add a couple of simple layout elements that are stored in the layout only (i.e. LayoutLabel, LayoutImage).
  • Use full design information for rendering detail views on the Web.
  • Forget about the model and persist the design in the DB.
  • Actually it is quite easy to go even further on this read and push all view schemas, data schemas and even form storage schema (if they implement Forms) to the database (thus allowing to change all that on-the-fly).

All the above items are quite easy to implement. I know that for sure since they constitute logically separate module in xLim 2 - “Record and Form Management” (Flexible Grids + Details + Forms) and that has already been done more than once.

There’s even more of that. I believe that the information generated by the XtraLayoutControl is enough to create similar interfaces not only for Web and Desktop, but for WPF and GTK# also (would not you want to have the perspective of reusing your nicely crafted forms on Linux platforms?)

Desktop UI Form produced by XtraLayout designer

Web UI Form produced by Xtra Layout designer

One more usage of scopes and micro-controllers in composite applications

This post does not belong to the primary body of knowledge within autofac or xLim series.

It expands on the last article about IoC scopes and application composition and attempts to provide quick proof of concept answer (POC) to one question from the DevExpress Forum on XAF about implementing security scenarios.

Let’s talk code:

public sealed class ContextSecurityController : ICommand
{
  private readonly GridParameters _parameters;
  private readonly IIdentityObject _parentObject;
  private readonly IGuidIdentity _user;

  public ContextSecurityController(GridParameters parameters,
    IIdentityObject parentObject, IGuidIdentity user)
  {
    _parameters = parameters;
    _user = user;
    _parentObject = parentObject;
  }

  public void Execute()
  {
    string s = _parameters.CriteriaString;
    if (!string.IsNullOrEmpty(s) && s.Contains("#{"))
    {
      _parameters.CriteriaString = s
        .Replace("#{AccountId}", _user.Id.ToString())
        .Replace("#{ActorId}", _user.Owner.ToString())
        .Replace("#{ParentObjectId}", _parentObject.Oid.ToString());
    }
  }
}

In this scenario this controller should be resolved in the view scope and executed once (yes, it has the ICommand interface, since it is just a command). Upon execution it attempts to parse the XPO criteria string and modify it a little bit.

Here are the steps to make this work within the current xLim concept:

  • Add a comma-delimited list of start-up command names to the base ViewParameter object
  • Add 3 lines of code to the base view object when it loads the parameters (string.Split(Current.StartupCommands) - foreach - ResolveByName - Execute)
  • Configure the views to call this command/controller on startup.
  • Make sure that the views, dealing with the data, pass the instance of the parent object to the scope
  • Make sure that all the BOs inherit from IIdentityObject (I always do this, since this helps to provide ability to bind memos, documents, forms etc to any object in the system)

Then you could use criteria strings like:

  • Document.CreatedByOid=#{AccountId}
  • Employer.Manager.Oid=#{ParentObjectId}

Side effects:

  • Any desktop or web view will get the ability to have configurable commands executed on the start-up (commands normally do not care about the UI)
  • Since any application already has a huge list of commands in the library, you could re-use these, too.

This controller is extremely simple to extend with the support for more complex tokens (i.e.: #{DateTime}, #{CurrentOfficeId}, #{SecurityHash} etc), you just need to make sure that the values do not mess up the syntax of XPO. Or you could implement more complex parser that takes the named object from the current scope and evaluate some property of it. You’ll get the simplified scripting in that case.

One more option is to use the DSLs to express complex business requirements (although, I would not advise to do that).

PS: This approach seems to be simple and flexible, and yet it is not recommended for the xLim 2 implementations. Too much of flexibility in the wrong spot is not a good thing for the project in the long term (been there, done that). This post serves POC purpose only.

X is for “eXtensible” - inversion of control container in xLim

That’s how views are handled within the Web and Desktop clients according to the xLim 2 approach.

The views are declared in the code like this

// web module
public sealed class WebFormView : WebViewBase<FormParameters>
public sealed class WebGridView : WebViewBase<GridParameters>
...
// desktop module
public sealed DesktopFormView : DesktopViewBase<FormParameters>
public sealed DesktopGridView : DesktopViewBase<GridParameters>

Views (along with the workflow controllers, commands, translators, etc) are registered in the appropriate module when it is being hooked up by the IoC. Normally they have container scope and ownership (unless they are reusable, thread-safe and do not have any context-specific dependencies).

Here’s real-life example of such registration:

public class CoreWebModule : Module
{
   protected override void Load()
   {
      RegisterWebView<WebCommentsView>(CommentsParameters.HandlerName);
      RegisterWebView<WebAdminView>(AdminView.ComponentName);
      RegisterWebView<WebDocumentView>(DocumentParameters.HandlerName);
      RegisterWebView<WebFormView>(FormParameters.HandlerName);
      RegisterWebView<WebGridView>(GridParameters.HandlerName);
      ...

Interface-specific base classes for views (WebViewBase, DesktopViewBase, WapViewBase etc) inherit from the core ViewBase class that could have the following declaration:

public abstract class ViewBase<T> : IView
{
   ...
   protected Container ViewContext { get { return _viewContext; } }
   protected abstract void OnLoad(T properties);
   protected abstract void OnUnload();
   ...
}

Views are displayed by the IWorkspace implementations (i.e.: tabbed workspace, panel workspace, window workspace, composite web workspace etc) like this:

IWorkspace space = container.ResolveByName<IWorkspace>(workspaceName);
space.ShowViewByName(viewName, info);

Each workspace knows how to handle its views. In addition it manages the container scopes for the view. Simple implementation for the “ShowViewByName” of the desktop panel workspace could be like this:

public void ShowViewByName(string name, IViewInfoReader info)
{
   IView view;
   if (!_views.TryGetValue(name, out view))
   {
      view = _workspaceContainer.ResolveByName<IView>(name);
      _views.Add(name , view);
   }
   Show(view, info);
}

and the actual “void Show(IDesktopView view, IViewInfoReader info)” method simply deserializes the information (which is securely stored and passed behind the scenes) to the view-specific property type, does some maintenance and calls the “abstract void OnLoad(T properties)” of the view.

Simple XAF-related examples of this are WebGridView and DesktopGridView implementations. They do what their names imply - display some data in grid format, while allowing it to be edited (just like XAF does). The specific behavior is determined by the GridParameters object and the controllers that get loaded. Here are some self-explanatory properties of this object:

public string EditSchemaName { get; set; }
public string ViewSchemaName { get; set; }
public string Criteria { get; set; }
public string CriteriaManagerName { get; set; }
public string WorkflowControllerName { get; set; }

Note, that when the view is initially created by the workspace, it is being passed some context-specific container via the DI. Normally the workspace passes its own container, that is the child of shellContainer, but could have same useful overrides (i.e. window workspace overrides the BarManager by providing window-specific bar manager to extend to; or, if the every view is opened in a new window, then there’s new view scope for every view).

Since scope creation is a cheap operation, the view might want to create one more scope within the OnLoad method, and then use it to resolve specific controllers while optionally registering some objects that are specific to this operation (commands usually rely on these). Note, that in this case all new objects with container scope and lifestyle will be disposed along with the owner container (and that should happen in “ViewBase.OnUnload”).

Here’s some imaginary implementation for the WebFormView (reality is a bit more complicated):

protected override void OnLoad(FormParameters parameters)
{
   _loadContext = ViewContext.CreateInnerContainer();

   IDocumentSecurity security =
   _loadContext.ResolveByName<IDocumentSecurity>(parameters.SecurityWorkflow);

   DocumentPolicy policy = security.GetPolicyForDocument(parameters.FormId);
   LoadCommands(_loadContext, policy);
   UpdateControls(policy);

   Form form = _session.LoadByKey<Form>(parameters.FormId);
   LoadForm(form);
   ...
   // validating form when needed
   IFormValidator validator =
      _loadContext.ResolveByName<IFormValidator>(form.ValidatorName);
   var result = validator.Validate(form);
   ...
}

Note how:

  • we use the local scope to resolve workflow controllers hidden behind “IDocumentSecurity” and “IFormValidator”. Specific implementations of the IDocumentSecurity might ask for the IIdentiyInfo or ISecurityLevel instances and these shall be passed down to them from the appropriate context.
  • we use typed property object instead of the property bags.
  • we implement form-specific named validation policy to handle business logic, while leveraging the generic (yet named and thus replaceable) IDocumentSecurity to handle the security; names are defined in the properties/objects and thus the associated behavior be changed easily.
  • All items that are created in the _loadContext will get local objects in their constructors. If these are not found, then the upper scope will provide them.
  • workflow controllers, commands, parameter objects are not UI-dependent and thus they are reused and shared between all UI clients.

These posts extend this article:

eXpressApp Framework and Resharper conflicts

When installed, eXpressApp Framework 7.3.5 brings “DXCore for Visual Studio .NET” along with it.

I didn’t ask for it.

Not only that slows down the Visual Studio 2005 IDE, but also messes up the Resharper integration.

Fortunately the DXCore went away without any problems (XAF installation stayed intact).

Landor Information Management architecture

In my last post I’ve talked about the eXpressApp framework by DevExpress. Let’s continue from there.

Despite all the limitations (there are no universal solutions in the world), the eXpressApp Framework is a great product. And what’s more important its development has made the DXperience suite even better (some changes had to be made there to aid the XAF development). I’m surely glad to have those, since in Landor one of our research and development focuses is the Landor Information Management (“Lim” for short) architecture that currently relies on all this great DX & XPO functionality.

I’ll keep talking about Lim as we go further down the road, but as a short summary: Lim is not an actual framework, or library or the piece of software. It is rather a set of development principles, architectural solutions and component preferences that help us to efficiently deliver small and medium sized information management solutions. Basically that’s just our evolving recipe of building such systems efficiently. It reuses ideas or solutions from:

Current specs for the current Lim recipe (that’s version 2 actually) are:

.NET application with the ASP.NET web UI (provides basic information access and management capabilities), Data Server (over any DB engine supported by the XPO) and flexible modular Windows.Forms Smart Client applications with rich UI. Every module is highly customizable and swappable by default (were it is appropriate and efficient).

DevExpress releases eXpressApp Framework

DevExpress has finally announced the delivery of their eXpressApp Framework. That’s quite a powerful business framework that utilizes the flexibility provided by the DXperience component suite v. 7.3.5 (pro-looking Windows.Forms and ASP.NET components) and eXpress Persistent Objects library. You should see the “Outlook done quickly” demo for yourself.

Basically it lets you create your first functional .NET Web Application or Desktop Client Application in a matter of minutes (I’m not kidding). You just need to code in the domain objects and the relationships between them, and the framework will try to do the rest.

On its first run the application by default will use the information from the domain objects to:

  1. Create database structure (it is done by the XPO)
  2. Create customizable layout for the table and detail views (this is done by the layout functionality, grid controls and some hardcoded magic) and all the relations. There also is domain model editor that lets you edit the intermediate configuration.
  3. Then the application will be launched using the default modules to display all the UI (either in Web or WinForms)

Additionally the application by default provides default implementations for such things as security/permissions, logging, customization, printing, validation and reports.

The disadvantage of this approach is that everything is coded quite highly and only DevExpress pieces are to be used. Additionally there is no client-server separation of concerns (the application talks right to the database and we do not have server-enforced security, workflows, logging etc), no DI, IoC, CAB/SmartClient approaches. So basically the XAF is just a reference implementation that’s used to advertise the capabilities of the DevExpress products. Well, that’s natural.

PS: That’s no ad of DevExpress here, but rather the acknowledgment of the capabilities of their products. However they are not even close to being flawless. The problems that we have faced recently include those:

  • XPO is promised to have full compatibility with the Mono compiler, yet it throws errors if analyzed with the MoMA and does not run well under Mono. What’s the point in compatibility, then?
  • XPO’s distributed caching (good thing on its own) has to be wrapped with some hacks in order to be able to work through WebServices.
  • Using DXperience components in the modular desktop applications (CAB and SmartClient principles) is not natural at all and requires quite a number of hacks.