Quantcast
Channel: eXpandFramework RSS
Viewing all 861 articles
Browse latest View live

BLOG by Manuel Grundner: XAF Dependency Injection - bring the stuff together

$
0
0

XAF Dependency Injection - bring the stuff together

Somebody of you know that we actually use FunnelWeb. Don't get me wrong, it is a good blog engine, but it's buggy, and it is a playground.

I like opensource projects, and i like to contribute to FunnelWeb to make it a better blog engine. But my spare time is really, ...hmm rare? I try to make the best out of this problem and try to write a blog engine (oh no, not another one) that uses all the XPO/XAF/WebApi/WebMvc/Unity/DI/async/await features i blogged about earlier and get the thing into a real working application.

Some facts i want to keep in mind when i implement this thing:

  • I like to import (or even better, reuse) the existing database of funnelweb
  • I will create this in TDD (from the first to the last line of code)
  • I will create a full blown XAF/XPO/WebApi/WebMvc application
  • I like to manage the whole thing out of XAF
  • I like to create a API that allows me easily to import (or communicate) with other engines
  • I will follow clean-coder
  • I will share this code open-source
  • I have to use TFSService or TFS with GIT or TFS-SCC
  • I like to use Continious deployment
  • I like that other XAF users can contribute, and are able to learn from my experiences
  • I like code kata's& I like trains ;)

In the next weeks i will try to code every WE till this thing is done.

Your help, thoughts, meanings and other ideas are wellcome!

Thanks, Manuel


Fast creating icons in XAF format

$
0
0

XAF image formatter

Introduction

Almost anyone, who use XAF knows how add or override images in XAF. For this we should create images of four standard sizes:
Image sizeImage suffixDescription
12x12"12x12"Used by ASP.NET Web Property Editors.
16x16noneStandard-sized images.
32x32"32x32"Large images.
48x48"48x48"Used in dialog windows.
With the following convention: MainCategory[_AdditionalCategories]_SizeSuffix.extension

To make it easier, I made simple tool, which make all XAF formats from one icon file.

Description

Supported formats: 

*.ico;*.icl;*.dll;*.exe;*.ocx;*.cpl;*.src



Features: 

  • Drag supported and "open with" supported. (just drag icon on application file(exe) or drag on applications form)
  • Program creates icons, which are not exists in icon file. (if exists icon larger than icon, which does not exist)
  • Supported selection formats for export. (just click on required image for select/deselect)



Required:

.net framework 3.5

Screenshot

Video



Download



BLOG by Robert Anderson: Load Testing XAF: Overview

$
0
0

Over the next few posts, I will demonstrate how to load test XAF web applications.

History

Performance testing has traditionally been difficult and expensive. A few years ago, to do it well required a powerful piece of dedicated load testing software such as HP LoadRunner (typical cost back in 2007: USD 50,000-100,000 or more per year!). This software was capable of simulating multiple virtual users via the use of recorded scripts and providing detailed performance statistics. Usually the cost was increased further increased by the need for powerful hardware to be able to run the application.

In 2007 we were required by a big customer (a global bank) to provide load testing statistics for our expressApp Framework application. We could not afford anything as sophisticated as LoadRunner so we went with a cheaper alternative (NeoLoad, which was still several thousand per year). It was extremely painstaking work to produce a test. The approach was to record the http requests (as a stream of text values) and write a script to check the http response. Since there was no real browser involved, it was very difficult to determine if our test was really representative. Several machines in the office had to be dedicated to simulating virtual users. Nobody was allowed to use the internet for fear of skewing the results during a test. If an error occurred, it was almost impossible to determine what went wrong. We wrestled with it and managed to fulfill our requirements, but it was all a lot of effort for no real return.

Part of the problem was certainly that XAF is complex to test. The user interface is rich and makes use of complex controls. Most of these load testing tools work better when targetting a simple <INPUT type="button"> rather than an image of a button that sometimes is not even clickable until the mouse has hovered over it. DevExpress have made it easy to run tests via their EasyTests, but no load testing tool supports them yet. (They have informed me it’s in their plans…)

Enter the cloud

The basic idea is this: instead of simulating users with specialised software, why not fire up a virtual machine and test with a real browser instance which is ‘remote controlled’ via a script.

The increased availability of cheap cloud-based virtualised machines has revolutionised load testing. The rental of the virtualised machines is not free, but it is very cheap. In about 2008, I started using the Amazon cloud to perform load tests. Our basic test costs us about USD 10.00 per run. We probably run this a dozen times a year, so our total cost is about USD 120.00 per year.

We get better statistics than we ever got out of NeoLoad. We are confident that the test is realistic and we can compare with the actual performance of our production environments. We have been able to find and solve memory leak problems and various tricky multi-user problems with these tests.

Load testing is still a complex business. There are a lot of pieces to put together, but with the cloud, each piece is relatively simple and cheap.

The solution

  • In Part 1, we install the DevExpress MainDemo on an Amazon EC2 instance.
  • In Part 2, we use Selenium to write a script which will run on the client machines to control a real browser instance.
  • In Part 3, we create a NeuStar Web Performance test and validate the script.
  • In Part 4, we launch a performance test and monitor the server.
  • In Part 5, we analyse the results of the clients.
  • In a bonus part, we learn how to run multiple simultaneous EasyTests as an alternative method of isolating performance and concurrency problems.

If you follow all the steps, expect to pay a handful of dollars in Amazon EC2 costs and a few more in Neustar costs. You could alternatively skip step 1 and target one of your own development machines instead.

BLOG by Manuel Grundner: Performance and XAF-Bootstrapping

$
0
0

How to speed-up bootstrap time:

Its all about reflection. Don't do it if you haven't.

Look at your modules:

Here is an excerpt of our main module:

ctor:

public sealed partial class ModelDefinitionModule : ModuleBase, IUnityModule
{
    InitializeComponent();

    snip..
}

ModulesTypes:

Important although its a .Net 1.1 List, but there you should expose everything you need. Not exposing the modules will kick in refelection, what are trying not do do..

protected override ModuleTypeList GetRequiredModuleTypesCore()
{
    return new ModuleTypeList(
        typeof(DevExpress.ExpressApp.SystemModule.SystemModule),

	snip..
}

next

GetDeclaredControllerTypes:

    protected override System.Collections.Generic.IEnumerable<System.Type> GetDeclaredControllerTypes()
    {
        return new Type[] { };
    }

not exposing any controllers would do fine.

Its faster to expose all controllers need. But you should not expose IEnumerable via yield return.

Why?

It maybe enumerated certain times. If you know the result, expose a collection (see LINQ for that)...

The similar yields for GetModuleUpdaters and GetDeclaredExportedTypes

Cave cat of all this optimization is that you have to declare everything, modules, controllers, business classes at compile time, you will not see any of them at run time, until you do this although.

Having all under control is a task of high responsibility.

Declaring your module this way will help you to reduce bootstrap time of your XAF-Appliction

You might be still struggling with boot strap performance, so look at your xptypesinfo-table (loading types no more available), your images (loading images non more available), and broken xafml (trying to load further things not more available...)

regards

René

BLOG by Robert Anderson: Load Testing XAF: Part 1 - Deploying

$
0
0

This is the first part of a tutorial about load testing XAF applications. See the overview for a bit of background. In this post we set up the target webserver.

You can target any machine which has a publicly available web address, but for this tutorial, I’m’ deploying the MainDemo to the Amazon cloud, by following the instructions in Part 1 and Part 2 of my previous series about Amazon Web Services.

I am using version 12.2.7 of the DevExpress XAF MainDemo. There are a couple of extra changes to make to the web.config.

  • Set debug to false <compilation targetFramework="4.0" debug="false"> in the <compilation> section of <system.web>
  • Switch to Release mode before deploying.

There are a couple of differences compared to the tutorial:

  • I chose a Medium instance instead of a Micro instance for EC2 (the web server) and deployed it against IIS 8.
  • For RDS (the database), I stuck with a Micro instance.

For the load test, it is also important to disable the automatic health checks performed by the load balancer.

The reason for this is that we are trying to determine the breaking point of our application. If the elastic load balancer detects that a system is struggling, it might automatically flag it as unhealthy and replace it with a newly launched instance. While this behaviour might be desirable for a production system, it doesn’t make sense for a load test.

Make sure you can connect to your installation from a web browser before continuing. I chose to deploy to a Windows 2012 instance running IIS 8.0 (which was not available when I wrote my previous XAF AWS tutorial) and I had a little trouble with the URL. If I navigate to the application’s base URL (http://zerosharp-maindemo.elasticbeanstalk.com/ in my case), then I get forwarding problems after logging in. Instead, I navigate to the full address http://zerosharp-maindemo.elasticbeanstalk.com/MainDemo.Web_deploy/Default.aspx and everything works. I’ll try to look into it later, but it’s not important for the load testing.

BLOG by Robert Anderson: Load Testing XAF: Part 2 - Selenium

$
0
0

Writing a Selenium User Test against MainDemo

This is another post in a series about load testing XAF applications. Previously in the series:

Why not use DevExpress EasyTests?

The DevExpress recommended method of writing functional tests is to use the EasyTest functionality of the expressAppFramework. This has several advantages over other functional testing approaches.

  • It uses a domain specific language tailored for XAF making it easy to test views and actions
  • It makes it easy to interact with the DevExpress controls that are used within XAF
  • A single EasyTest can be run against both the ASP.NET and WinForms applications
  • EasyTests work against both the debug webserver and IIS

However, one feature which is not (yet) available is the ability to use EasyTests for load testing.

UPDATE: See my more recent post on how run multiple simultaneous EasyTests.

Modifications to the MainDemo

The sample script I have written assumes the MainDemo is running with Horizontal Navigation rather than vertical. You can modify the script to add support for vertical navigation or you can change Global.asax.cs Application_Start as follows:

12345678
protected void Application_Start(object sender, EventArgs e){    RenderHelper.RenderMode = DevExpress.Web.ASPxClasses.ControlRenderMode.Lightweight;    ASPxWebControl.CallbackError += new EventHandler(Application_Error);+    // Add the following line to default to horizontal layout+    WebWindowTemplateHttpHandler.PreferredApplicationWindowTemplateType = DevExpress.ExpressApp.Web.Templates.TemplateType.Horizontal;}

The Selenium script

Selenium is a powerful tool for automating browsers. It supports all of the major browsers and a Selenium test can be written in many different programming languages (C#, Java, Javascript, HTML, etc.) The load testing tool (which we will come to in part 3 of this series) uses Selenium scripts written in Javascript.

We will now create and verify a simple Selenium test. The test will open the browser, login to the MainDemo and cycle through all of the tabs before logging out. The script is extremely basic. For a more realistic load test, you want a combination of scripts running, some entering data, some triggering reports, etc.

Create a \scripts subdirectory and populate it with the following code:

MainDemo_CycleThroughTabs.js
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
/* global test */// Settings for Neustar:// replace the following with the public address of the application server,vartargetHost="http://zerosharp-maindemo.elasticbeanstalk.com/";varvirtualShare="MainDemo.Web_deploy";// Settings for debug webserver:// (local script validator doesn't always work against localhost,// so we use the excellent localtest.me instead.)//var targetHost = "http://localtest.me:58404";//var virtualShare = "";// Settings for the build server or IIS://var targetHost = "http://localtest.me/";//var virtualShare = "MainDemo.Web";// Test parametersvarthinkTimeInSeconds=3;vartimeout=60000;varstep=0;// You an optionally set the simulated bandwidth for the script// (max of 100KB/sec). A value of -1 means do not limit.// E.g., // var bandwidthLimit = 50 * 1024 * 8; // 50KB/secvarbandwidthLimit=-1;vardriver=test.openBrowser();varselenium=driver.getSelenium();// Support functionsfunctionthink(){if(thinkTimeInSeconds>0){if(!test.isValidation()){test.pause(thinkTimeInSeconds*1000);}}}functionwaitForCallbacks(){selenium.waitForCondition("(typeof selenium.browserbot.getUserWindow().xafHasPendingCallbacks === 'function') && (selenium.browserbot.getUserWindow().xafHasPendingCallbacks() === false);",timeout);}functionstepLogin(username){step=step+1;test.beginStep("Step "+step.toString()+" - Login");selenium.open(targetHost+virtualShare+"/Default.aspx");think();selenium.type("xpath=//input[contains(@id,'_xaf_dviUserName_Edit_I')]",username);selenium.type("xpath=//input[contains(@id,'_xaf_dviPassword_Edit_I')]","");selenium.click("Logon_PopupActions_Menu_DXI0_T");selenium.waitForPageToLoad(timeout);waitForCallbacks();selenium.assertElementPresent("Horizontal_VCC_VSL");selenium.waitForText("Horizontal_VCC_VSL","Contact");test.endStep();think();}functionstepLogoff(){varexpectedSubstring;step=step+1;test.beginStep("Step "+step.toString()+" - Logoff");selenium.click("//li[@class='dxm-item']/div[@class='dxm-content dxm-hasText']//a[@class='dx dxalink' and text()='Log Off']/..");selenium.waitForPageToLoad(timeout);expectedSubstring="Logout.html";test.endStep();}functionstepNavigateToTab(maintabCaption,tabCaption,viewCaption){// viewCaption is optionalviewCaption=(typeofviewCaption==="undefined")?tabCaption:viewCaption;step=step+1;test.beginStep("Step "+step.toString()+" - "+tabCaption);selenium.waitForElementPresent("//td[@class='dxtc' and text()='"+maintabCaption+"']");if(selenium.isVisible("//td[@class='dxtc' and text()='"+maintabCaption+"']")){selenium.click("//td[@class='dxtc' and text()='"+maintabCaption+"']");}selenium.waitForElementPresent("//div[@class='dxm-content dxm-hasText' and starts-with(@id, 'Horizontal_NTAC_PC_M')]//a[@class='dx dxalink' and contains(text(), '"+tabCaption+"')]/..");selenium.click("//div[@class='dxm-content dxm-hasText' and starts-with(@id, 'Horizontal_NTAC_PC_M')]//a[@class='dx dxalink' and contains(text(), '"+tabCaption+"')]/..");waitForCallbacks();selenium.assertElementPresent("Horizontal_VCC_VSL");selenium.assertText("Horizontal_VCC_VSL",viewCaption);test.endStep();think();}functioninitializetest(){selenium.setTimeout(timeout);if(bandwidthLimit>0){test.setSimulatedBps(bandwidthLimit);}}(functionmain(){initializetest();test.beginTransaction();stepLogin("Sam");//stepNavigateToTab("Default", "Contact");stepNavigateToTab("Default","Task");stepNavigateToTab("Default","Department");stepNavigateToTab("Default","Scheduler Event");stepNavigateToTab("Default","My Details","User - Sam");stepNavigateToTab("Default","Note");stepNavigateToTab("Default","Payment");stepNavigateToTab("Default","Position");stepNavigateToTab("Default","Resume");stepNavigateToTab("Default","Role");stepNavigateToTab("Default","User");stepNavigateToTab("Reports","Analysis");stepNavigateToTab("Reports","Reports");stepLogoff();test.closeBrowser();test.endTransaction();}());

Neustar

In a future post we will create multiple test runners in the Amazon cloud using the Neustar web performance tool (formerly BrowserMob). Neustar will gather statistics about each scripts reponse times and provide a load test report including details of any test failures.

For now we will verify locally that the Selenium script above works as expected.

Installing the Neustar local script validator

In order to verify that our script is supported by the Neustar framework, we need to install their local script validator. Download it and unzip it to a subdirectory of the MainDemo.

There are instructions for setting up local script validation here.

To run the script locally call the following:

> script-validator-4.8.81\bin\validator.bat CycleThroughTabs.js -keepbrowseronerror

I had some problems getting the NeuStar script validator to work in 64-bit Windows 8. The script validator instructions recommend FireFox 12 but I am using version 19. For the record I am using:

  • DevExpress MainDemo 12.2.7
  • NeuStar localscriptvalidator 4.8.81
  • Mozilla FireFox 19
  • Java 7.0.90

You need to modify your C:\Users\<Username>\.wpm\config.properties file as follows:

config.properties
1
FF=C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe

Also, for some reason, I could not get the local script validator to run against localhost. I kept getting the error:

1234
WARN 03/28 12:38:28 b.n.w.a.s.JavaScrip~ - Got script exceptionorg.mozilla.javascript.WrappedException: Wrapped biz.neustar.webmetrics.agent.api.HttpErrorException: No valid HTTP Response received while navigating to URL 'http://localhost:58404/Default.aspx' (CycleThroughTabs.js#50)

The easiest solution was to change the localhost address in the javascript file to the excellent localhost alternative localtest.me.

Now when I run the script using the local validator with

> validator cyclethroughtabs.js

I see Firefox startup after a few seconds and the script correctly cycles through all of the tabs and then exits.

We will use this scenario as the basis of a load test in the next post.

BLOG by Robert Anderson: Load Testing XAF: Part 3 - Uploading and Validating the Virtual User Script

$
0
0

This is another post in a series about load testing XAF applications. Previously in the series:

In this part, we will load test the application we set up in Part 1, using the Selenium load test we created in Part 2.

Neustar Web Performance Management

NeuStar (formerly BrowserMob) are a company specialised in web application performance monitoring. We are interested in their web performance module. It is free to create an account. To run a test with less than 25 virtual users costs only $0.15 per virtual user. Tests with more than 25 users (up to 5000) require an additional paid plan.

Create a script

In order to run a load test, we first need to create the script and validate it. Go to the scripting page and select ‘Create a new script’. Then cut and paste the Selenium code for MainDemo_CycleThroughTabs.js from the previous post.

Now change the targetHost variable near the top of the file to point to the location of your MainDemo installation. You can then validate the script. This will actually run through the Selenium test on a newly provisioned Amazon instance to ensure that it passes.

If you get a green icon, you can proceed with setting up a load test, otherwise you can see what went wrong in a video of the user session.

In the next post we will configure and launch the load test.

BLOG by Robert Anderson: Load Testing XAF: Part 4 - Launching the load test

$
0
0

This is another post in a series about load testing XAF applications. Previously in the series:

In this part, we will launch a 1 hour test with 25 virtual users using the NeuStar Web Performance Management module.

Schedule and launch a test

From the script validation screen, click on Schedule a load test with this script. The defaults are good, but you can specify in detail how to run your load test. For instance, you can coordinate multiple Selenium scripts to simulate different types of activity on your site.

Notice that the load test cost for 25 users for an hour will be only $3.75.

When you click Launch, Neustar takes 7 or 8 minutes to provision the Amazon machines and stage the test, after which you will get realtime detail information about response times, bandwidth and errors.

In the next post we’ll analyse the results of this test.


BLOG by Robert Anderson: Load Testing XAF: Part 5 - Analysis

$
0
0

This is the final post in a series about load testing XAF applications. Previously in the series:

In this part, we analyse the results of the load test we ran in Part 4.

Results

The results of the test we ran are here. The graphs are interactive and give quite interesting data about the load tests. Feel free to have a look and play around with the results.

The Performance Graphs

The above graph shows the basic information about the test. We can see there were 649 transactions (the Selenium script was run 649 times) and there were 17 errors.

You can see that the test managed to follow the planned scenario (the actual number of users follows the yellow line). You can also see information about the throughput in bytes during the test.

The Script Performance Graphs

Here we see information pertaining to the script we chose to run. Had we run multiple different scripts, we would be able to isolate each one.

It is clear that the transaction time rises quite slowly with the load until about 12:17 when there is a jump. More on that later.

First, I have removed the plot of the total transaction time, so that we can see more detail from the remaining steps. Two things seem to be clear: the response time for each individual step does not seem to be much affected by the load, but the login step rises gradually.

Now back to the spike at 12:17, if you look at the transaction data more closely (not shown here but available on the NeuStar results page, it looks like several transactions finished at the same time and that the jump coincides with several simultaneous logins.

So again, it seems that login is the ‘weakest link’, i.e., the most resource intensive step and the one that suffers the most under load.

The Errors

Lets look more closely at the errors.

The first type of error we can see from the screen-shot occurred at the login page. This error happened 6 times and was very similar to another error which occurred once. In fact, all 6 of these errors happened at the very end of the test. As such, they can be ignored, because it is likely that the load test was scaling down and interrupting sessions at this point.

One of the very nice features of NeuStar’s load testing solution is that you not only get a screenshot, but also a video which shows you exactly what the user experienced when an error occurs. By clicking on the second error, it looks like there may be a problem when the system is under load. There were 6 errors and it is clear in the video that the errors occur when attempting to navigate away from the Scheduler Event view to the My Details view. The screen-shot gives us some useful information. DevExpress? Any ideas?

There are a couple of other errors, but I think these are most likely a result of problems with the Selenium script rather than XAF. The AJAX update panels make it quite hard to detect when the page is fully ready and although we try to accommodate this with selenium.waitForCondition() my feeling is that the click() occurred before everything was properly wired up.

Further tests

This series has covered the process of load testing XAF applications in its entirety, but in some ways, it feels like only the beginning. There are many other configurations and tests which would be interesting.

For instance

  • Reduce think time which is currently set to 3 seconds per step
  • Use a smaller/larger EC2 instance
  • Increase the number of virtual users
  • Try load balancing with sticky sessions
  • Experiment with/without compression (IIS or via the web.config)
  • Experiment with/without caching (both at the http level, and via the cached data store

There are also many ways of improving XAF performance that are not in the MainDemo. These include:

  • Server mode in all grids
  • XPO Caching
  • Where possible, move any heavy operations to a separate asynchronous web service call

We have implemented all of these in our production application.

A note about concurrency

In our experience, people tend to over estimate the number of concurrent users for their application. Our application has probably upwards of 5000 users defined, but we know from our logs that there have never been more than 80 simultaneously logged in. Also, even with 80 concurrent users, they have a much longer ‘think time’ than 3 seconds on average.

For the production environment, we run at least one 25 user test for every major release and ensure the performance is at least as good as the previous release. We have occasionally run tests with up to 200 simultaneous users. The response time goes down to unacceptable levels (~30 seconds), but the application behaves. In production, the system is load balanced (with sticky sessions) and we know from previous experience that this is sufficient for our application.

Conclusion

This concludes my series on load testing. We’ve managed to get some very useful information with some very low-cost tools. The largest part of effort is the writing of the Selenium script which is certainly tricky. In the future I’d really like to harness the DevExpress EasyTests to replace the script but I haven’t yet found a way of doing this. Feel free to use my Selenium script as a starting point for testing your own XAF applications, and let us know of any interesting results!

BLOG by Robert Anderson: Load Testing XAF: Bonus - Simultaneous EasyTests

$
0
0

In my recent series on load testing XAF, I used a Selenium javascript test to run the client browser instances. This is a good and cheap method of validating the performance of XAF applications under production load.

However, if the load tests fail because of a concurrency bug or a performance bottleneck, it can still be difficult to analyse and solve. For this, we need to be able to simulate load locally against the development environment.

In this post I will demonstrate how to run multiple simultaneous XAF EasyTests against a local server. As a load test, it is not very scientific, but it can be extremely useful as a debugging tool.

The EasyTest script

First, we will create a new EasyTest which will cycle through the existing navigation tabs. Open the XAF MainDemo and create a new EasyTest as follows.

MainDemo_CycleThroughTabs.ets
123456789101112131415161718192021
#Application MainDemoWeb*FillForm User Name = Sam Password =*Action Log On*Action Navigation(Contact)*Action Navigation(Task)*Action Navigation(Department)*Action Navigation(Scheduler Event)*Action Navigation(My Details)*Action Navigation(Note)*Action Navigation(Payment)*Action Navigation(Position)*Action Navigation(Resume)*Action Navigation(Role)*Action Navigation(User)*Action Navigation(Reports.Analysis)*Action Navigation(Reports.Reports)*Action Log Off

(This test replicates the Selenium test we created in Part 2 of my previous series on load testing with NeuStar and Amazon.) It is important to note that we are only testing the web application and that we do not include a #DropDB directive.

First, ensure that you can run this test with the default settings.

The config file

Now modify the config.xml file as follows:

Config.xml
12345678910111213141516171819202122
<?xml version="1.0" encoding="utf-8" ?><Optionsxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"TestRunTimeLimit="5"><Applications><!-- Web --><ApplicationName="MainDemoWeb"Url="http://localhost:4030"SingleWebDev="True"WebBrowserType="Standalone"PhysicalPath="[ConfigPath]\..\MainDemo.Web"AdapterAssemblyName="DevExpress.ExpressApp.EasyTest.WebAdapter.v12.2, Version=12.2.8.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a"/><!-- For IIS --><!--<Application      Name="MainDemoWeb"      Url="http://localhost/MainDemo.Web/Default.aspx"      PhysicalPath=""      DontRestartIIS="True"      DontRunWebDev="True"      WebBrowserType="Standalone"            AdapterAssemblyName="DevExpress.ExpressApp.EasyTest.WebAdapter.v12.2, Version=12.2.8.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a"/--></Applications></Options>

There are a few important things to note.

I have not shown the Win section here since we are not using it. Also, I am using XAF 12.2.8. You may need to change the version number in the AdapterAssemblyName attribute. I have increased the TestRunTimeLimit attribute from 3 to 5. Everything goes a little slower when there are multiple browsers and we need to make sure the test does not time out.

With the above config, the EasyTest will no longer run from within Visual Studio.

You can choose to run the simultaneous tests against the debug web server or IIS. Uncomment the relevant section. The interesting settings are:

  • SingleWebDev="True" which instructs the EasyTest runner to run all tests against the same instance of the development webserver. Without this, the webserver would be stopped and started for each test.
  • WebBrowserType="Standalone" which causes each launched browser to be launched with its own session. (There are a few mentions of this setting in the support center, but it is not very well documented).
  • DontRestartIIS and DontRunWebDev which are self-explanatory

The launch command

Next, create the following batch file in the MainDemo.EasyTests subdirectory. ##

Launch.bat
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
:: Requires the Debug webserver to be running on port 49660:: Requires EasyTests to be enabled:: Requires NetDA to be running:: Requires admin rights:: Must be run from a command prompt:::: Usage: > launch <numberOfBrowsers>:: e.g. : > launch 21:: will launch 21 simultaneous browsers at 3 second intervals@echooff:DELETE_OUTPUTifexist *.jpeg del *.jpegifexist *.html del *.htmlifexist TestsLog.xml del TestsLog.xml:CHECK_ADMINnet session >nul2>&1if%ERRORLEVEL%equ0gotoCHECK_CONSOLEecho Must be run from an administrative command windowgotoERROR:CHECK_CONSOLEecho%CMDCMDLINE%|find/i"/c">nulifERRORLEVEL1gotoCHECK_PARAMSecho Must be run from an administrative console (not Windows Explorer)gotoERROR:CHECK_PARAMSIF [%1]==[] GOTOUSAGE:LAUNCHset/a i=0:LOOPif%i%==%1gotoOKset/a i=%i%+1start "x""C:\Program Files (x86)\DevExpress\DXperience 12.2\Tools\eXpressAppFramework\EasyTest\TestExecutor.v12.2.exe" MainDemo_CycleThroughTabs.ets:: Wait 3 secondsping 1.1.1.1 -n 1 -w 3000>nulgotoLOOP:USAGEecho Usage: %0 numberOfBrowsersecho numberOfBrowsers must be an integergotoOK:ERROR:OKpause

If you want to run your tests against the development webserver, you will need to make sure it is running before launching the batch file. The easiest way to do this is to run the application from within Visual Studio and then close the browser. You should still see the development webserver running in the task bar notification area. Against IIS, it is enough to ensure it is started.

Now, open an administrative command prompt. Note that you must run from an administrative console: it is not sufficient to ‘run as administrator’ from Windows Explorer. Navigate to the EasyTest subdirectory where the Launch.bat file is located and launch a single test with the following command:

launch.bat 1

You should see the test run without error. If this works, you can then launch 20 simultaneous test runs with 3 second intervals by running:

launch.bat 20

Conclusion

As a load test, you do not get much useful information. Even if we managed to extract accurate data for client response times and throughput, the overhead of running the multiple browsers would skew the results too much. However, this approach is extremely useful for isolating concurrency and performance problems.

BLOG by Robert Anderson: Fixing an unmanaged code AppCrash

$
0
0

This post is the result of a recent bug hunt in which I came across a tricky bug, found a debugging switch I’d completely forgotten existed and learned a little about calling extern string functions from C#.

I love bug hunting. It’s like a murder mystery: you’ve got your suspects and you try to eliminate them one at a time until, as a famous bug hunter said:

… when you have eliminated the impossible, whatever remains, however improbable, must be the truth.

Sherlock HolmesThe Sign of Four

Between about 1995 and 2006, I used a data library called Apollo almost every day. It was a bunch of C++ drivers for dBase files with some more advanced options for encryption and indexing and was a popular option for Clipper) programmers. I joined a software project which was based on Clipper and Apollo in 1995. Apollo went through many different incarnations SuccessWare, Luxent, Vista, ApolloDB. All of these companies were essentially providing wrappers for different languages (Delphi, .NET) but the core C++ drivers always remained more or less the same and it’s still going.

Fast forward to 2013 and we have a legacy console utility for migrating data from the old format, which traverses the Apollo tables and converts the data to our model (DevExpress XPO objects). This code hardly ever changes, but when I converted all our core libraries to .NET 4.5., I found I had to jump in and fix it one last time.

When I tried to run the upgraded .NET 4.5 library I got a mysterious app crash.

The application would then close without any error message or stack trace. Nothing I did was allowing me catch any exception. None of the signatures, e.g., the c0000374 exception code show up on Google. It shows up in the Windows event log, but apparently EventID 1000 is a very generic error message.

I had a suspicion the problem was something to do with the Apollo assembly and I also knew that Apollo was not all managed code. I stumbled over the Enable native code debugging in the project settings. I’ve never used this setting. (My next approach would have been to use tracing to try to pinpoint the location of the crash.)

Visual Studio really impresses with its debugging capabilities. When we run again, we get a stack trace and an error message.

Well Google didn’t seem to have much to say about ‘This may be due to a corruption of the heap’. But the problem seems to do with apolloTable.FieldName(i). With a decompiler I had a look at its definition.

123456
publicstringFieldName(shortfieldNum){//...returnApolloAPI.sx_FieldName(fieldNum);//...}

Let’s find ApolloAPI.sx_FieldName(fieldNum);

12
[DllImport("SDE7.dll", CharSet=CharSet.Ansi, ExactSpelling=true)]publicstaticexternstringsx_FieldName(shortuiFieldNum);

Now, knowing that SDE7.dll is written in C++, I guessed it might be having trouble with the return value being a string. The C++ memory management of the returned string might be getting in the way. A bit of StackOverflow gave me this trick: declare the return type as IntPtr and use Marshal.PtrToStringAnsi() to get a C# string from the pointer. (It seems that .NET 4.5 is stricter about marshalling than earlier frameworks. Perhaps someone can enlighten me why the error did not occur with .NET 4.0?) I wrote a new extension method for ApolloTable and changed the code to use apolloTable.SafeFieldName(i) instead.

12345678910111213
publicstaticclassTApolloTableExtensions{        [DllImport("SDE7.dll", CharSet = CharSet.Ansi, ExactSpelling = true)]publicstaticexternIntPtrsx_FieldName(shortuiFieldNum);publicstaticstringSafeFieldName(thisApolloTableapolloTable,shortfieldNum){//...IntPtrstrPtr=sx_FieldName(fieldNum);returnMarshal.PtrToStringAnsi(strPtr);//...}}

And bingo! The application now runs without error.

BLOG by Manuel Grundner: Intoduction to Xpand.Testing

BLOG by Marcelo Paiva: DevExpress XAF – Controle Aparência

$
0
0

Olá pessoal, vamos continuar nossa série sobre o XAF.

Se não leu ainda, veja os artigos anteriores para melhor entender o que estamos falando nos link’s: XAF – Introdução e XAF Validações.

Nos artigos anteriores apresentamos uma pequena introdução e como funciona a implementação de validações, agora vamos destacar o controle de aparência na interface do usuário.

Iremos considerar em nosso projeto inicial (conforme os artigos anteriores) a inclusão de um campo com enumerador para identificar o tipo de pessoa, poderá ser Pessoa Física ou Pessoa Jurídica.

Veja abaixo como ficou nosso modelo alterado:

Novo Enumerador:

Incluímos os campos: Tipo, CPF e CNPJ:

Se executarmos o nosso projeto, o XAF irá incluir os novos campos no banco de dados e como também definimos a propriedade ‘Tipo’ sendo o seu Type o enumerador o XAF identifica o campo no banco de dados como sendo do tipo Inteiro. Veja como ficou o banco de dados:

Executando no projeto teremos a seguinte tela de edição do nosso cadastro:

No entanto agora queremos controlar a nossa DetailView para exibir os campos CPF ou CNPJ de acordo com o valor selecionado pelo usuário no campo Tipo. Para isso a primeira coisa que precisamos fazer é incluir o módulo de controle de aparência em nosso projeto, para isso você deve abrir o arquivo ‘Module.cs’ no projeto base .Module, e através da toolbox incluir o módulo ‘ConditionalAppearanceModule’ conforme a imagem a seguir:

Após este procedimento precisamos implementar a regra na classe de nosso modelo que no caso será a classe ‘Pessoas’, veja como isso é feito:

Com isso definimos as condições para ocultar/exibir os campos na interface do usuário.

Outro item importante para que ao usuário selecionar o Tipo de pessoa tenha um reflexo imediato na interface é preciso  na propriedade ‘Tipo’ indicar o atributo ‘ImmediatePostData’ como True, veja:

Com isso temos os resultados abaixo:

Selecionando pessoa física:

Agora selecionando pessoa jurídica:

É isso aí pessoal, o próximo da série vamos falar de controle de segurança.

Até mais.

 

 

 

 

 

BLOG by Robert Anderson: Making XAF reports even better - Part 1

$
0
0

The ability to create reports using a report writer is a very powerful feature of DevExpress XAF, but there are some limitations which are particularly cumbersome to deal with in complex project.

One of the projects I work on has over 100 reports in it. Even though we make use of unit tests to ensure they are not broken, the maintenance of the code in the embedded scripts is particularly difficult to manage.

  • XafReports are .repx files which are usually loaded into the report table during the database update routine. They are a subclass of XtraReports which with some added restrictions.
  • Any scripts are stored as a string or serialized to a resources property.
  • The report writer is available only in the Windows Forms application. This must be used whenever a change is made to a report. The modified report must be exported as a repx file and then added to the module as an embedded report. The procedure is described here.

These aspects of XAF reports give rise to several development headaches.

  • While script syntax can be checked within the report writer at design time (via the Validate button in the scripts tab), the script code is still brittle.
  • Errors that result from Script syntax are sometimes only discovered at run time (you can write a unit test to check during build, but we really want to the compiler to tell us).
  • Refactoring any classes requires a considerable amount of work with the report writer in order to apply any changes to the code within the scripts.
  • There is no Intellisense in the report writer.
  • Version control diff comparisons and merging are impossible.

The aim of these posts is to provide a two-way conversion process between .repx and C# files. In order to accomplish this we’ll be relying on Visual Studio’s excellent T4 templating engine.

Installing T4Toolbox

T4 Text Transformation Toolkit is a template based code generation framework which is included with Visual Studio. On top of this Oleg Sych provides a Visual Studio extension called T4 Toolbox which adds some additional features.

Install T4 Toolbox by selecting Tools/Extensions and Updates from Visual Studio and searching for it.

The ReportSync MainDemo

Next, download the modified MainDemo application from my GitHub repository and open it in Visual Studio.

First lets look at the embedded reports which I have modified slightly so that they include scripts. I added these scripts via the MainDemo.Win application.

Let’s look at the ContactsGroupByPosition.repx file. You will find that there is a section:

12
this.ScriptsSource="\r\nprivate void xrLabel4_BeforePrint(object sender, System.Drawing.Printing.PrintE"+"ventArgs e) {\r\n\txrLabel4.Text = xrLabel4.Text + \" Test!\";\r\n}\r\n";

In this case, the script has been saved as a string. The other report, which has only slightly more complex script code looks like this:

1234567891011
privateSystem.Resources.ResourceManagerresources{get{if(_resources==null){stringresourceString=@"zsrvvgEAAACRAAAAbFN5c3RlbS5SZXNvdXJjZXMuUmVzb3VyY2VSZWFkZXIsIG1zY29ybGliLCBWZXJzaW9uPT.....5kIFtEdWVEYXRlXSA8PSAnQEN1cnJlbnREYXRlJwABEFRhc2tzU3RhdGVSZXBvcnQ=";this._resources=newDevExpress.XtraReports.Serialization.XRResourceManager(resourceString);}returnthis._resources;}}// ...this.ScriptsSource=resources.GetString("$this.ScriptsSource");

Here, the scripts are not even in plain text. They have been serialised to the resources property.

The MainDemo.Reports assembly

You will find a new assembly MainDemo.Reports which contains a T4 template RepxToCSharp.tt. This is a T4 template which will search for repx files and transform them into much more helpful plain C#.

The template will run every time it is saved. Currently, it depends on code within the MainDemo.Reports assembly, so make sure you have compiled it in Debug mode. Then open the RepxToCSharp.tt and press Ctrl+S to save (and run the T4 transformation).

The output

The template will generate two types of output. First, it generates the following report which you should find in RepxToCSharp.txt

123456789
(This is an automatically generated file which should be excluded from version control)Summary of repx transformation==============================Total repx files found                                      :  2  Total reports generated                                   :  2  Total reports skipped because unchanged                   :  0Time elapsed: 00:00:02.1762029

In addition, each repx will have been transformed into two correpsonding files. All the generated files are highlighted in yellow:

Now the scripts have been deserialized from the repx and put in a partial class and the remainder of the repx has been transformed into a corresponding XafReport descendant. See for instance, ContactsGroupedByPosition.cs (which stored its scripts as a string) is as follows:

ContactsGroupedByPosition.cs
12345678910
publicpartialclass_ContactsGroupedByPosition{// -- Start of embedded scripts -- privatevoidxrLabel4_BeforePrint(objectsender,System.Drawing.Printing.PrintEventArgse){xrLabel4.Text=xrLabel4.Text+" Test!";}// -- End of embedded scripts --    }

And TasksStateReport.cs is now like this

TasksStateReport.cs
1234567891011121314151617181920
publicpartialclass_TasksStateReport{// -- Start of embedded scripts -- privatevoidxrLabel1_BeforePrint(objectsender,System.Drawing.Printing.PrintEventArgse){// This is a testxrLabel1.Text="Hello";}privatevoidxrLabel2_BeforePrint(objectsender,System.Drawing.Printing.PrintEventArgse){xrLabel2.Text=GetLabel2Text();}publicstringGetLabel2Text(){return"Label 2!";}// -- End of embedded scripts --    }

A note about performance

The process of transforming the repx into C# is quite quick (a couple of seconds per repx), but when you have dozens of reports, it can quickly be tiresome. Therefore, there is a performance optimisation which checksums the repx and skips the transformation if it has not changed.

(In a future version, we will also use a similar checksum in the other direction to determine whether the scripts have been modified).

Already much better

Now we have much more useful source files. Versions can be compared easily. The compiler will immediately inform us of any problems with the scripts within our reports.

This is work in progress. Next up, I will be adding the ‘reverse’. That is, a new transformation template which looks for scripts which have changed and ‘injects’ them back into the original repx file.

BLOG by Robert Anderson: Making XAF reports even better - Part 2

$
0
0

Good news. The conversion is now two-way. Get the source code from GitHub. Make sure you have built MainDemo.Reports project.

You will find there are now two T4 transforms in the project. RepxToCSharp.tt is covered in the Part 1. It searches for any .repx files in the solution and converts the scripts into compilable C#.

The second transform is new. CSharpToRepx.tt copies any changes to the script part back into the original .repx files. Again, there are performance optimisations via checksums to prevent overwriting unchanged files.

12345678910
(This is an automatically generated file which should be excluded from version control)Summary of C# transformation============================Total C# files found                                        :  2  Total reports injected                                    :  1  Total reports missing                                     :  0  Total reports skipped because unchanged                   :  1Time elapsed: 00:00:02.3483264

Repx files with embedded scripts are now much more maintainable. You can correct syntax errors, refactor, version control, merge versions easily. You could even write unit tests against the code in the scripts.

Currently the easiest way of running these scripts is to open them and save them with Ctrl+S. This is because T4 templates were originally designed as a Visual Studio tool.

In the future I’m hoping to improve the integration further. There are ways of including the transformations into the build instead, most of which are covered in a blog post by Mr T4, Oleg Sych. I like the idea of it being a NuGet package that can be easily added to any XAF project, but there’s a but I’ll need some more time to work out how best to achieve this.

Basic usage summary

Until then, here are some basic usage instructions.

  • Add the T4 Toolbox extension to Visual Studio
  • Add a copy of the MainDemo.Reports project to your own solution
  • Make sure you build it before running the transforms
  • Open RepxToCSharp.tt in Visual Studio.
  • Save it with Ctrl+S to run the transform. It will search all the folders in your Solution for .repx files and add corresponding C# classes.
  • Make any changes you like to the script section (anything outside of // -- Start of embedded scripts -- and // -- End of embedded scripts --) will be ignored.
  • Open CSharpToRepx.tt and run it with Ctrl+S. The changes will be saved back to the corresponding .repx.

Even more power?

You may notice that if you reload the MainDemo.Reports project, you can now see View in Designer in the context menu when you right-click on the .repx.cs file.

Let’s click it and see what happens. It opens directly in Visual Studio (like an XtraReport).

Now, this is all highly experimental. You can see there are some warnings… Also, there is no connection with XPO, so the Preview is always empty.

That said, it doesn’t seem like too much of a stretch to eventually allow far more Visual Studio integration for XAF reports…


BLOG by Manuel Grundner: How to initialize an ObjectSpaceProvider with XPO

$
0
0

If anybody needs to initialize an ObjectSpaceProvider with XPO for UnitTesting or a ServiceApplication here is the code:

public IObjectSpaceProvider CreateObjectSpaceProvider(Assembly assembly, string connectionString)
{
	var dictionary = new ReflectionDictionary();

	dictionary.CollectClassInfos(assembly);

	var info = new TypesInfo();

	var source = new XpoTypeInfoSource(info, dictionary);

	info.AddEntityStore(source);

	foreach (XPClassInfo item in dictionary.Classes)
	    source.RegisterEntity(item.ClassType);

	return new XPObjectSpaceProvider(new ConnectionStringDataStoreProvider(connectionString), info, source);
}

This took me hours of digging in the XAF-source.

Hope this helps anyone.

Happy coding, Manuel!

BLOG by Apostolis Bekiaris: Anonymous authentication for XAF aps.net applications

$
0
0

As promised  in eXpand’s forums with next version of eXpand (13.1.5.8) you can enjoy anonymous authentication for your web applications!

The anonymous authentication functionality is embedded in Xpand.ExpressApp.Security.Web module. After installing this module you need to enable it and setup the anonymous username using XAF’s Application Model Editor.

image

It is possible and recommended to combine anonymous authentication with auto-authentication discussed in http://apobekiaris.blogspot.gr/2013/07/auto-authentication-rememberme-for-your.html. Note that the model of the previous post is refactored to allow each feature to work independently.

image

Next you need to configure XAF’s security system by setting up the Authentication and the LogonParameters as illustrated in the image bellow.

image

 

And finally you need to create the anonymous user and role in your ModuleUpdater.cs. For this and if your use XpandRole class I provided the next extensions methods (GetAnonymousRole, GetAnonymousUser).

voidCreateAnonymousSecurityObjects() {

    var anonymousRole = ObjectSpace.GetAnonymousRole("Anonymous");

    anonymousRole.GetAnonymousUser();

 

    //add project specific permissions

    anonymousRole.SetTypePermissions<Category>(SecurityOperations.ReadOnlyAccess, SecuritySystemModifier.Allow);

    anonymousRole.SetTypePermissions<Topic>(SecurityOperations.Read, SecuritySystemModifier.Allow);

The GetAnonymousRole method will create a new XpandRole (if not exists) and will add two custom permissions the MyDetailsPermission that will hide MyDetails from anonymous role and the AnonymousLoginPermission. It is also possible to do the same using XAF’s UI as in the next image.

image

Moreover I want to mention that using XpandRole is not mandatory, I used it because of the built-in support for custom permissions. You may have your own implementation following for example How to: Implement Custom Permission, Role and User Objects so feel free to use them.

Together with the MyDetailsPermission I mentioned the AnonymousLoginPermission. This one is responsible for hiding the default XAF’s Logoff action and for providing a new LoginAnonymous action. So when someone visits your site and you use Xpand.ExpressApp.Security.Web with enabled anonymous access, by default XAF will authenticate the anonymous user you created in the ModuleUpdater, and with the LoginAnonymous action will allow authentication as provided by XAF.

image

That was it my friends! I hope you find this implementation easy to use and useful. For questions, feedback etc feel free to use eXpand forums.

 

Happy XAF’ing to all!

BLOG by Apostolis Bekiaris: Poll - Which of the following eXpand modules/features do you use most?

$
0
0
Our community project (www.eXpandframework.com)
is growing fast and thanks everybody for the contribution and trust! However in order to use our limited resources better and make some plans for the future I would to ask your participation in the following survey.
I would like to ask your input one more time in the following survey: Click here to take survey

Reminder: There is also a XAF related survey going on at http://dennisgaravsky.blogspot.ru/2013/06/we-are-currently-in-process-of-13.html.

Both are our tools to get direct feedback from all of you to improve our beloved XAF.

Thanks you all for your participation!

BLOG by Apostolis Bekiaris: Runtime views created from business users

$
0
0

You all know the powerful Application Model Editor with the embedded layout control that allows view creation without any technical knowledge. However the Model Editor is so powerful that may be dangerous to allow access to everybody. A few years now in eXpand we have the XpandViewVariants module that allowed end users to build views without the model editor. This modules is based in XAF’s built-in ViewVariants module and the XAF team is constantly improving it. However eXpand resources are not so huge so our module was a bit outdated.

Today things changed, because I spend some hours to refactor the ModifyVariantsController and now can do magic. if you using eXpand you only need to install XpandViewVariants module, if not and thanks to XAF’s MVC architecture just grab the controller for eXpand’s online repository http://goo.gl/mnFR7 or even follow its history http://goo.gl/CPx5A.

Now simply watch the next video to see that this controller can do for you.http://screencast.com/t/nrELagRJBhY

P.S.: We really appreciate your input in our latest surveys we run for both XAF and eXpand. If you haven’t participate yet please see this post

http://apobekiaris.blogspot.ru/2013/07/poll-which-of-following-expand.html.

Comments as always in eXpand forums Smile, here a related thread http://goo.gl/cQ05p.

BLOG by Manuel Grundner: Introducing Para.FluentModelBuilder

$
0
0

I like to introduce a little Framework about mapping/decorating XPO/EntityFramework classes in XAF using the typesystem XAF provided without having to 'pollute' your model-assembly with DevExpress.ExpressApp assemblies:

Para.FluentModelBuilder

In the readme.md you can explore what we've build so far :)

Happy coding, and hoping for feedback from the great XAF-Community Greetz Manuel

Viewing all 861 articles
Browse latest View live