Develop web forms by RapidWebDev UI (2)

The series of articles introduces an innovative architect to develop business web forms in enterprise software development which has better performance, higher productivity, more configurability and easier maintainability than traditional either ASP.NET or MVC development. This is the second article in the series for the solution. Before going forward, you shall take a look at the first article for the concept and overview at The article is to introduce how "query" works and how to configure a query panel in a web form.

How "query" works

The development for a query panel is composed of xml configuration and implementation to the method Query of interface IDynamicPage as the following code snippet.

<QueryPanel HeaderText="Query Users">
    <TextBox FieldName="UserName" Label="UserName: " />
    <TextBox FieldName="DisplayName" Label="DisplayName: " />
    <CheckBoxGroup FieldName="Membership.IsApproved" 
        FieldValueType="System.Boolean" Label="Approved: " Occupation="1">
        <Item Text="Yes" Value="true" Checked="true" />
        <Item Text="No" Value="false" />

/// <summary>
/// Execute query for results binding to dynamic page grid.
/// </summary>
/// <param name="parameter">Query parameter.</param>
/// <returns>Returns query results.</returns>
QueryResults Query(QueryParameter parameter);

RapidWebDev UI framework renders UI of query panel based on the filters configured inner of xml element QueryPanel. The default supported query filter control types are CheckBox, CheckBoxGroup, ComboBox, Date, DateTime, Integer, Decimal, TextBox and RaduiGroup. When all these controls not meet your requirement, you can use xml element Custom to configure your developed query filter control which follows the specification of a custom query filter control. As the above query panel configuration, the rendered UI is as the following screenshot,

When RapidWebDev UI framework renders UI of query panel, there is JavaScript manager instance for the query panel registered into web browser which manages all query filters include their status and values. When button Query is clicked, the query panel manager instance collects user input for each query filter and assemble an asynchronous http request sending to RapidWebDev data service of dynamic page for JSON data response, seeing as ~/ObjectId/DynamicPageDataService.svc. I use Fiddler2 to track the http request and response as the following screenshot. The response data with 4 returned records is only 2.5kb.

Finally, the query panel manager renders the JSON data into grid.

Query Panel Xml Configuration

The default supported query filter control types mentioned above have common attributes as Label, FieldName, Operator, FieldValueType and Occupation.
Label is the label of the query filter in UI, E.G. "User Name:". The Label supports variable markup like $VariableName$ or "$Namespace.ClassName.StaticPropertyName, AssemblyName$". VariableName shall be setup through the method SetupContextTempVariables of interface IDynamicPage.

FieldName is used for the framework to assemble query expression by implementation of IPredicateCompiler (namespace: RapidWebDev.UI.DynamicPages) automatically. It supports properties of the associated object. E.G. we configure a dynamic page to manage users that the main entry of the page is User. The entity User references Membership. And we want to query users through properties of Membership like Membership.IsApproved in above code snippet. Linq2SQL predicate compiler (class: RapidWebDev.UI.DynamicPages.Linq2SQLPredicateCompiler) compiles the query filter to expression as:
var query = from user in dataContext.Users
    where user.Membership.IsApproved
	select user;

Operator is operator of query criteria which supports Equal, StartsWith, Like, In, NotIn, GreaterThan, GreaterEqualThan, LessThan, LessEqualThan and Between. By default, the framwork chooses operator depends on the query filter control type.

FieldValueType is the CLR type of parameter value of query expression. If FieldValueType is specified, the query filter control value will be implicitly converted into the target type when assemble query expression.

Occupation indicates how many cells the query filter control occupies in rendered query panel. E.G. the query panel layout implementation TableXColumnsQueryPanelLayout renders all query filters in html table. Occupation means how many columns are occupied for the query filter control.

Besides these common attributes, you'd better to take a look at DynamicPage.xsd for extended attributes of each query filter control.

Query Implementation

RapidWebDev data service of dynamic page converts asynchronous query request to QueryParameter which includes query and sort information. QueryParameter can be converted to query and sort expression by the implementation of interface IPredicateCompiler (namespace: RapidWebDev.UI.DynamicPages) which is configured in Spring.NET IoC. As the following implementation to query products, we only need to convert and concat the compiled query and sort expression with Linq2SQL lambda expression. And don't need to assmble query expression exlicitly. So we can handle the requirement change on query filters easily without compilation. And the returned QueryResults(int recordCount, IEnumerable results) is serialized to JSON data automatically by the framework.
/// <summary>
/// Query products by parameters.
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
public override QueryResults Query(QueryParameter parameter)
    using (ProductManagementDataContext ctx = 
        IQueryable<Product> q = from p in ctx.Products 
                                where p.ApplicationId == authenticationContext.ApplicationId 
                                select p;

        LinqPredicate predicate = parameter.Expressions.Compile();
        if (predicate != null && !string.IsNullOrEmpty(predicate.Expression))
            q = q.Where(predicate.Expression, predicate.Parameters);

        if (parameter.SortExpression != null)
            q = q.OrderBy(parameter.SortExpression.Compile());

        int recordCount = q.Count();
        var results = q.Skip(parameter.PageIndex * parameter.PageSize)
        return new QueryResults(recordCount, );

Dynamic Data

We may have the requirement needs dynamic support which cannot be configured in xml like, render different query filters to users with different permission, or the items of a combobox in query panel should be rendered from database. RapidWebDev does support such scenarios. The dynamic page xml configuration can be configured a callback to change the configuration before UI rendering, seeing Page/@ProcessCallbackType in DynamicPage.xsd. We can change the configuration at runtime in the callback. Besides, we can configure DynamicDataSource for a combobox query filter. DynamicDataSource is configured to pull items from a JSON driven external web service as the following code snippet. So in the example, when an user selects or input text into the editable combobox, the combobox refreshes the matching items from the external service.
<ComboBox FieldName="ParentHierarchyDataId" Label="Parent: " Editable="true" 
    MinChars="2" FieldValueType="System.Guid" ForceSelection="true">
    <DynamicDataSource Url="/Services/HierarchyService.svc/json/FindByKeyword?limit=999" 
	    Method="GET" TextField="Name" ValueField="Id" QueryParam="q">
        <Param Name="hierarchyType" Value="$HierarchyType$" />

Query Panel Layout

Interface IQueryPanelLayout is used to render layout of query panel. RapidWebDev implements a html table based layout as RapidWebDev.UI.DynamicPages.TableXColumnsQueryPanelLayout by version 1.51. If you have an alternative requirement, you can implement a new strategy and configure to Spring.NET IoC instead of current TableXColumnsQueryPanelLayout in RapidWebDev.Web\Spring\ui.config.

Last edited Mar 7, 2010 at 12:18 PM by eungeliu, version 4


No comments yet.