Configure WebORB with Log4Net

Posted by admin on January 17th, 2010

This will be a quick one because time is not on my side these days... If you've never worked with Log4Net, I suggest to go and read some documentation on this an try to set it up.

A while ago I was searching how I could merge the logging from WebORB with my Log4Net configuration. As it happens, I had two log files, one from WebORB and one from Log4Net. Having an overview of the logging, was difficult like this. After some initial help from Mark Piller (WebORB), I managed to merge the two loggings. However, in the beginning, some logs were still written to the WebORB log file. After some weeks I got another email from Mark explaining how it could be done so that all logging would go to the Log4Net logging.

So here's how you do it:

In the Weborb.config file, add next lines in the logging tag section:

XML:
  1. <!--<currentPolicy>Date Based Logging</currentPolicy>-->
  2. <currentPolicy>Log4NetPolicy</currentPolicy>
  3.  
  4. <loggingPolicy>
  5.   <policyName>Log4NetPolicy</policyName>
  6.   <className>Edu3.Weborb.Logging.Log4NetPolicy</className>
  7. </loggingPolicy>

The Date Based Logging is the default policy used by WebORB which I commented out. We'll implement a Log4NetPolicy (you can take another name if you wish so).

In the loggingPolicy tag you can map the policy to a className which we'll implement. This class needs to implement the interface Weborb.Util.Logging.ILoggingPolicy, which is an interface in the weborb dll.

Important is to set all the log enables to true. It's Log4Net that will handle levels. If you set, for instance, the WebORB INFO level to enable=false, then our custom Log4Net logger will not receive any INFO loggings from WebORB. Even if you then set INFO level to be logged in Log4Net, the WebORB INFO levels won't be logged.

XML:
  1. <log enable="yes">WEBORB INFO</log>
  2. <log enable="yes">WEBORB DEBUG</log>
  3. <log enable="yes">WEBORB ERROR</log>
  4. <log enable="yes">WEBORB SERIALIZATION</log>
  5. <log enable="yes">WEBORB EXCEPTION</log>
  6. <log enable="yes">WEBORB INSTRUMENTATION</log>
  7. <log enable="yes">WEBORB SECURITY</log>
  8. <log enable="yes">WEBORB MESSAGE SERVER</log>
  9. <log enable="yes">WEBORB THREADING</log>

So here's my Edu3.Weborb.Logging.Log4NetPolicy class:

C#:
  1. using Weborb.Util.Logging;
  2. using System.Collections;
  3.  
  4. namespace Edu3.Weborb.Logging
  5. {
  6.     class Log4NetPolicy : ILoggingPolicy
  7.     {
  8.         private readonly Hashtable _hashtable;
  9.         private const string PolicyName = "Log4NetPolicy";
  10.  
  11.         public Log4NetPolicy(Hashtable hashTable)
  12.         {
  13.             _hashtable = hashTable;
  14.         }
  15.  
  16.         public ILogger getLogger()
  17.         {
  18.             return new Log4NetLogger();
  19.         }
  20.  
  21.         public string getPolicyName()
  22.         {
  23.             return PolicyName;
  24.         }
  25.  
  26.         public Hashtable getPolicyParameters()
  27.         {
  28.             return _hashtable;
  29.         }
  30.     }
  31. }

getLogger() should return the logger object which will be used by WebORB
getPolicyName() should return the name of the policy. Make sure it is the same as you specified in the config file
getPolicyParameters() should return the same hashtable which was passed into your policy constructor

The Log4NetLogger is also a custom written class that looks like this:

C#:
  1. using System;
  2. using log4net;
  3. using Weborb.Util.Logging;
  4. using log4net.Core;
  5.  
  6. namespace Edu3.Weborb.Logging
  7. {
  8.     public class Log4NetLogger : AbstractLogger
  9.     {
  10.         private static readonly ILog Log = LogManager.GetLogger("WebORB");
  11.        
  12.         public override void fireEvent(string category, object eventObject
  13.             , DateTime timestamp)
  14.         {
  15.             Level activityLevel;
  16.             switch (category)
  17.             {
  18.                 case LoggingConstants.WEBORB_INFO:
  19.                     activityLevel =
  20.                         Log.Logger.Repository.LevelMap["WEBORB_INFO"];
  21.                     Log.Logger.Log(GetType(), activityLevel
  22.                         , eventObject, null);
  23.                     break;
  24.                 case LoggingConstants.WEBORB_DEBUG:
  25.                     activityLevel =
  26.                         Log.Logger.Repository.LevelMap["WEBORB_DEBUG"];
  27.                     Log.Logger.Log(GetType(), activityLevel
  28.                         , eventObject, null);
  29.                     break;
  30.                 case LoggingConstants.WEBORB_ERROR:
  31.                     activityLevel =
  32.                         Log.Logger.Repository.LevelMap["WEBORB_ERROR"];
  33.                     Log.Logger.Log(GetType(), activityLevel
  34.                         , eventObject, null);
  35.                     break;
  36.                 case LoggingConstants.WEBORB_SERIALIZATION:
  37.                     activityLevel =
  38.                         Log.Logger.Repository.LevelMap["WEBORB_SERIALIZATION"];
  39.                     Log.Logger.Log(GetType(), activityLevel
  40.                         , eventObject, null);
  41.                     break;
  42.                 case LoggingConstants.WEBORB_EXCEPTION:
  43.                     activityLevel =
  44.                         Log.Logger.Repository.LevelMap["WEBORB_EXCEPTION"];
  45.                     Log.Logger.Log(GetType(), activityLevel
  46.                         , eventObject, null);
  47.                     break;
  48.                 case LoggingConstants.WEBORB_INSTRUMENTATION:
  49.                     activityLevel =
  50.                         Log.Logger.Repository.LevelMap["WEBORB_INSTRUMENTATION"];
  51.                     Log.Logger.Log(GetType(), activityLevel
  52.                         , eventObject, null);
  53.                     break;
  54.                 case LoggingConstants.WEBORB_SECURITY:
  55.                     activityLevel =
  56.                         Log.Logger.Repository.LevelMap["WEBORB_SECURITY"];
  57.                     Log.Logger.Log(GetType(), activityLevel
  58.                         , eventObject, null);
  59.                     break;
  60.                 case LoggingConstants.WEBORB_MESSAGE_SERVER:
  61.                     activityLevel =
  62.                         Log.Logger.Repository.LevelMap["WEBORB_MESSAGE_SERVER"];
  63.                     Log.Logger.Log(GetType(), activityLevel
  64.                         , eventObject, null);
  65.                     break;
  66.                 case LoggingConstants.WEBORB_THREADING:
  67.                     activityLevel =
  68.                         Log.Logger.Repository.LevelMap["WEBORB_THREADING"];
  69.                     Log.Logger.Log(GetType(), activityLevel
  70.                         , eventObject, null);
  71.                     break;
  72.                 case LoggingConstants.WEBORB_MESSAGINGEXCEPTION:
  73.                     activityLevel =
  74.                         Log.Logger.Repository.LevelMap["WEBORB_MESSAGINGEXCEPTION"];
  75.                     Log.Logger.Log(GetType(), activityLevel
  76.                         , eventObject, null);
  77.                     break;
  78.                 default:
  79.                     throw new Exception("All LoggingConstants should " +
  80.                                         "have been catched previously.");
  81.             }
  82.         }
  83.     }
  84. }

As you'll see, I defined some custom log levels in Log4Net. You really don't need this, you could just use the existing Log4Net levels and map custom WebORB levels to one of the existing Log4Net levels.

Here's how my Log4Net configuration section looks like if you want to work with these custom levels.

XML:
  1. <log4net>
  2.   <level>
  3.     <name value="WEBORB_INFO" />
  4.     <value value="40000" />
  5.   </level>
  6.   <level>
  7.     <name value="WEBORB_DEBUG" />
  8.     <value value="30000" />
  9.   </level>
  10.   <level>
  11.     <name value="WEBORB_ERROR" />
  12.     <value value="70000" />
  13.   </level>
  14.   <level>
  15.     <name value="WEBORB_SERIALIZATION" />
  16.     <value value="40000" />
  17.   </level>
  18.   <level>
  19.     <name value="WEBORB_EXCEPTION" />
  20.     <value value="70000" />
  21.   </level>
  22.   <level>
  23.     <name value="WEBORB_MESSAGINGEXCEPTION" />
  24.     <value value="70000" />
  25.   </level>
  26.   <level>
  27.     <name value="WEBORB_INSTRUMENTATION" />
  28.     <value value="40000" />
  29.   </level>
  30.   <level>
  31.     <name value="WEBORB_SECURITY" />
  32.     <value value="40000" />
  33.   </level>
  34.   <level>
  35.     <name value="WEBORB_MESSAGE_SERVER" />
  36.     <value value="40000" />
  37.   </level>
  38.   <level>
  39.     <name value="WEBORB_THREADING" />
  40.     <value value="40000" />
  41.   </level>
  42.   <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
  43.         <file value="Logs/Log4Net/"/>
  44.     <appendToFile value="true"/>
  45.     <rollingStyle value="Date"/>
  46.         <staticLogFileName value="false" />
  47.     <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
  48.     <datePattern value="yyyy-MM-dd-HH.lo\g" />
  49.     <maxSizeRollBackups value="10" />
  50.     <maximumFileSize value="1MB" />
  51.     <layout type="log4net.Layout.PatternLayout">
  52.       <conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
  53.     </layout>
  54.   </appender>
  55.   <root>
  56.     <level value="ALL"/>
  57.     <appender-ref ref="RollingFileAppender"/>
  58.   </root>
  59. </log4net>

In this section you can configure not to log all levels. For more information on this see the Log4Net documentation.

Maybe that some of the Log Levels values (the integers) should be changed to meet your expectations. See Log4Net Levels for more information.

That's about it. If I forgot something, I'll update the post. If you have any question, please feel free to ask.

<

Allow Port on Windows Server to enable WebORB Messaging

Posted by admin on March 6th, 2009

Had a problem starting the WebORB RTMPServer (in global.asax) today which was solved after adding the port as an exception in the Windows FireWall.

Log from WebORB:

[Thread-11] WEBORB INFO:6/03/2009 11:26:37:shutting down WebORB Message Server
[Thread-11] WEBORB EXCEPTION:6/03/2009 11:26:37:System.Net.Sockets.SocketException: A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
at System.Net.Sockets.Socket.Shutdown(SocketShutdown how)
at Weborb.Messaging.RTMPServer.shutdown()
[Thread-15] WEBORB EXCEPTION:6/03/2009 11:26:37:System.Net.Sockets.SocketException: A blocking operation was interrupted by a call to WSACancelBlockingCall
at System.Net.Sockets.Socket.Accept()
at Weborb.Messaging.RTMPServer.run()
[Thread-11] WEBORB EXCEPTION:6/03/2009 11:26:37:System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.
at System.Net.Sockets.Socket.Disconnect(Boolean reuseSocket)
at Weborb.Messaging.RTMPServer.shutdown()

Adding an exception in windows firewall is done in the "Windows FireWall Settings". Choose tab Exceptions and Add port... There you enter the port that you use for the RTMPServer (default 2037), give a name and choose TCP.

thx, Lieven Cardoen

<

Peformance issues IIS7, WebORB, Network, …

Posted by admin on February 21st, 2009

Two weeks ago I had a lot of problems in a project of mine. Often some clients couldn't connect to weborb.aspx (actually 0.01% of the times). After a lot of searching we weren't really able to find the problem. It seemed to me that maybe it was a network issue. The customer had just changed a lot of servers and improved their network. What previously worked didn't seem to work anymore now.

We changed some things after which everything started to work smoothly again:

- When an error is thrown from the server or there's a network problem we invoke the server call again with Credentials. We use authentication, so if at a certain moment in time IIS decides to recycle, the next calls to the server will fail. So we implemented a fallback system. If a fault occurs we authenticate again and try the call a second time. If the second time would also fail, then we give the user an Alert with some information what to do.

- When profiling SQLServer2008 we saw that there were millions of logs being written to the database by WebORB. We had configured WebORB logging with Log4Net and set the Filter in Log4Net on INFO. Basically everything that was logged was written to the database. This meant a lot of overhead. After having put the Filter on Warning connections to database reduced by a factor 100.

Configuring WebORB Logging with Log4Net (in global.asax):

C#:
  1. void Application_Start(object sender, EventArgs e)
  2.     {
  3.         log4net.Config.XmlConfigurator.Configure();
  4.         log4net.ILog log = log4net.LogManager.GetLogger("Global.asax");
  5.         log.Info("Application_Start(" + sender.ToString() + ", " + e.ToString() + ")");
  6.  
  7.         //Configuring WebORB Logging with Log4Net
  8.     try
  9.     {
  10.         Weborb.Util.Logging.Log.addLogger("log4NetLogger", new Edu3.Util.Logger())
  11.                 Weborb.Util.Logging.Log.removeLogger("default");
  12.     }
  13.     catch (Exception exception)
  14.     {
  15.         log.Error("Application_Start", exception);
  16.     }
  17.     }

- We profiled IIS7 with some tools that were proposed on StackOverflow. These tools were very interesting, but still I thought to get much more information. Strange that there's not a professional profiling tool for IIS7. We used Administration Pack for IIS 7.0, the stackoverflow question is at link. The strange thing was that in 0.01% of the requests a 404 was returned. Even after having enabled Failed Request Tracing in IIS7, I couldn't find the reason for the 404.

- Recycling happens automatically @ 23 hours. (this was allready done earlier when I had problems in November).

After these tweaks everything is working fine again. Those 404's remain a mystery...

Ciao, Lieven Cardoen

<

POD component – Dashboard

Posted by admin on January 10th, 2009

Yesterday I was looking for a way to show multiple statistics next to each other. I had a component in mind that could contain Panels. The Panels would have to be divided over the available space. If there was one Panel, it would get all the space, with two Panels the space would be divided in two, ... Also you need to maximize, restore and minmize the Panels.

Thx to Tom Van den Eynde from VDE Projects I found a very nice example of such a component.

Here is the link: http://www.adobe.com/devnet/flex/samples/dashboard/dashboard.html. The Panels are also draggable.

I haven't begun to use it but I'm sure this will be a great example to start from.

Thx, Lieven Cardoen

<

Rounding Up 2008

Posted by admin on December 24th, 2008

I started this year by taking over the lead of a big project for the Belgian government. The project is an e-learning environment created mainly with Flex, WebORB, .NET, MSMQ and MSSQLServer 2005. Daily hundreds of candidates go to Brussels were they are being tested by our software. Typically some 300 candidates start off at the same time to take a test.

So what have I learned this year (some of the things ;-) ):

Database

  1. Indexes are very important because they can speed up things a lot. However they can also be misused!!! So read about them.
  2. Stored Procedures made it easy to quickly write logic (transaction scripts). However it's hard to maintain these Stored Procedures and Cache dependencies don't work with complex Stored Procedures.
  3. MetaData was a very usefull mechanism to add new logic in Flex without having to change table designs.
  4. We also used MetaData for tags which wasn't the best choice.

.NET

  1. I didn't have a lot of experience in the beginning of this year so things kind of moved in the direction of Transaction Scripts. They aren't a bad choice but as the project gets complexer, transaction scripts are difficult to maintain.
  2. SubSonic (o/r mapping tool) did it job very good but I'm not very pleased with the lack of documentation, tutorials and clear explanations. I will certainly look into nHibernate and Entity Framework and see how they work with some of the patterns described in 'Patterns of Enterprise Application Architecture' by Fowler. In the future the project will certainly need to be scalable so things will have to change.
  3. Visual Studio is a great IDE.

IIS and ASP.NET

  1. By default IIS recycles application pools every 29 hours (will come back to that later because this caused a lot of problems).
  2. HttpHandlers are great.
  3. Cache is a very important feature if you want to speed up your application.

Flex

  1. Very good choice for our client side development. Application development however is far more complex than writing web pages in .NET. If you need your code to be maintainable you need to know about design patterns, frameworks, refactoring, architecture, ... Those things are mainly things you learn after having used them a couple of years.
  2. We now work with modules but in the future we will have to check out those shared libraries as well. Our application is now 2mb big so some kind of intelligent caching will be needed.
  3. Prana is great to configure your application externally. Check it out!
  4. The Flexbuilder Eclipse Plugin is a waste of memory and I hope Adobe tries to improve this in the future. Building our project takes far too long.
  5. Resource bundles could be made easier.
  6. Designing a Flex application is a hard thing because you really need a designer who knows some basic things about Flex.
  7. Implementing Pessimistic Concurrency with Messaging was a very hard one this year!
  8. Looking forward to create a desktop application version of our project.

WebORB

  1. Great product. FluorineFX is the open source alternative, but WebORB has a lot more features. Without a support plan however some things are really hard to debug.
  2. Authentication and Authorization is worth to take a look at, but it's important to fully understand it.
  3. WebORB messaging integration with MSMQ is great to let other applications know what's happening.

Other tools that have been very usefull are CvsDude, Trac, Mylyn, SubVersion, Charles, SQL Compare, SQL Data Compare, ant, cruisecontrol, Linq, SilverLight (very promising), Spring,...

Ciao!

<

Stress Testing with WebORB

Posted by admin on November 19th, 2008

Yesterday and today I worked on a performance issue where 350 candidates had to wait more than a minute before their data was loaded. The 350 candidates start their exam simultaenously so the server is heavily loaded at that time. I had a couple of ideas in mind like caching certain things but how was I going to test this. I haven't got 350 computers at my desk, I just have one laptop (and a development server).

A first tool I got from an answer on StackOverflow. AB is a tool for benchmarking apache server, but it can be used to benchmark any url(in my case local IIS). To do this I created an aspx page that loaded the same data that was loaded by one candidate. I then used AB to call that page multiple times. With this tool I already got a good idea how good my caching was working but I didn't know if WebORB was also causing performance problems.

Since the last update we put on the development server of the customer, candidates had to wait much longer to get started. My guess was that it had to do with WebORB authentication. I now had to find a way to test my services by using the WebORB gateway. Asynchronous Unit Testing with FlexUnit had to be one of the answers. So I got started and two hours later I had my test. I did however had to try three different things.

In the first try I created a Test and added it a hundred times to the TestSuite. This wasn't so usefull because the next Test starts only if the previous had ended. I needed simulteanously remote calls, parallel, not serial.

In the second try I created a Test that does a remote call a hundred times and is added only once to the TestSuite. This second try looks like this:

Actionscript:
  1. package {
  2.     import flexunit.framework.Assert;
  3.     import flexunit.framework.TestCase;
  4.    
  5.     import mx.rpc.AsyncToken;
  6.     import mx.rpc.Fault;
  7.     import mx.rpc.IResponder;
  8.     import mx.rpc.Responder;
  9.     import mx.rpc.remoting.mxml.RemoteObject;
  10.    
  11.     public class LoadExamSessionTest extends TestCase  {
  12.        
  13.         private var remoteObject:RemoteObject;
  14.        
  15.         override public function setUp():void {
  16.             remoteObject = new RemoteObject("GenericDestination");
  17.             remoteObject.source = "Edu3.ApplicationTestServices.LoadExamSessionBenchMarkTestService";
  18.             remoteObject.endpoint = "http://localhost/edumatic3/local/weborb.aspx";
  19.             // This is needed because the weborb authentication is enabled on the server side.
  20.             remoteObject.setCredentials("credentials", "credentials");
  21.            
  22.         }
  23.        
  24.         public function testLoadExamSessionTest():void {
  25.             for(var i:int ; i <200 ; i++){     
  26.                 loadExamSession();
  27.             }
  28.         }
  29.        
  30.         public function loadExamSession():void{
  31.             var token:AsyncToken = remoteObject.LoadTest();
  32.             var responder:IResponder = new Responder
  33.             (
  34.                 addAsync(onLoadExamSessionResult, 1000000),
  35.                 null
  36.             );
  37.             token.addResponder(responder);
  38.         }
  39.        
  40.         public function onLoadExamSessionResult(data:Object):void {
  41.             assertNotNull(data.result);
  42.         }
  43.     }
  44. }

This worked like a charm, but Authentication on the server side is only done once with the frist call because I'm using the same Remote Object every time. You should also check Charles to see what happens because it's very interesting. Apparently the there are only two calls to weborb.aspx. The first call is the one that will trigger my custom authentication handler, the next call has packages 199 calls to the service... I won't put a screenshot here because testing it is so much cooler. You can actually see in Charles that the server has started 199 threads and you can follow how much of the amf package is downloaded.

But this wasn't what I needed because all 350 candidates are authenticated seperately. To simulate this I just create a new remote object for each call. Class now looks like this:

Actionscript:
  1. package {
  2.     import flexunit.framework.Assert;
  3.     import flexunit.framework.TestCase;
  4.    
  5.     import mx.rpc.AsyncToken;
  6.     import mx.rpc.Fault;
  7.     import mx.rpc.IResponder;
  8.     import mx.rpc.Responder;
  9.     import mx.rpc.remoting.mxml.RemoteObject;
  10.    
  11.     public class LoadExamSessionTest extends TestCase  {
  12.        
  13.         private var remoteObject:RemoteObject;
  14.        
  15.         override public function setUp():void {
  16.         }
  17.        
  18.         public function testLoadExamSessionTest():void {
  19.             for(var i:int ; i <200 ; i++)
  20.             {         
  21.                 loadExamSession();
  22.             }
  23.         }
  24.        
  25.         public function loadExamSession():void{
  26.             remoteObject = new RemoteObject("GenericDestination");
  27.             remoteObject.source = "Edu3.ApplicationTestServices.LoadExamSessionBenchMarkTestService";
  28.             remoteObject.endpoint = "http://localhost/edumatic3/local/weborb.aspx";
  29.             // This is needed because the weborb authentication is still enabled on the server side.
  30.             remoteObject.setCredentials("credentials", "credentials");
  31.            
  32.             var token:AsyncToken = remoteObject.LoadTest();
  33.             var responder:IResponder = new Responder
  34.             (
  35.                 addAsync(onLoadExamSessionResult, 1000000),
  36.                 null
  37.             );
  38.             token.addResponder(responder);
  39.         }
  40.        
  41.         public function onLoadExamSessionResult(data:Object):void {
  42.             assertNotNull(data.result);
  43.         }
  44.     }
  45. }

Now you'll see 200 calls to weborb.aspx in Charles and my custom WebORB authentication handler will be called 200 times. This is somewhat the customers case I wanted to simulate.

What did I find out, well, for 200 remote calls, the third scenario (200 times weborb authentication) takes double as long as the second scenario (once weborb authentication).

The Caching on the server times now speeds up the loading of the data five times!

ps: I do need to dig in a little deeper in the addAsync from FlexUnit because when I add another addAsync for my fault event in the Reponder, things get messy... Will keep you posted on this.

Ciao! Lieven Cardoen aka Johlero

<

WebORB Authentication Issue

Posted by admin on November 16th, 2008

Imagine you have a Flex Applicatin using WebORB Authentication. When the first Remote Call is done you supply the Remote Object with credentials. The server authenticates and from then on you don't need to supply credentials anymore. The server side session will remembler who you are.

But if for some reason your server side session is ended (to to session timeout, applicatin pool recycling, ...) the next Remote Call will get a Weborb Security Error.

We have solved this by catching this error in the OnFault event from the responder and retrying the remote call again with the credentials. However, this wasn't as easy as we thought. Apparently the client side code remebers that it's been authenticated and will not re-authenticate automatically (because the client doens't know the session has ended). First we tried to call logout() on the remote object but that didn't work (we got an error saying that logging out and setting the credentials couldn't be done simultaenously). We then tried disconnect() and this worked like a charm. After the disconnect() on the remote object we resetted the credentials. If we then called a server side function, WebORB would re-authenticate again. Without the disconnect() WebORB would'nt re-authenticate again (apparently the remote object holds some flags which tell WebORB to authenticate or not). We do need to go and find out the difference between the logout() and the disconnect().

I will definetily come back to this because it isn't a hundred procent clear to me.

Ciao, Lieven Cardoen aka Johlero

<

IIS Recycling

Posted by admin on November 16th, 2008

Last week I got a call from a big customer saying that the 100 of the 200 candidates had just received an error log window in our Flex Application. I knew that this could happen someday, but what had caused this error log...?

After a lot of searching in the logs of the two servers at the customer, I found out that at a certain time on one of the two servers all sessions and application pool were ended. Why? Well, after again a lot of searching I found out that IIS recycles an application pool every 29 hours... Man, why is this default enabled???

Apparently a lot of these recycle events are nog logged by default. Only the 29 hour recycle event apparently is logged by default. As for now I haven't found this log yet, so I will have to enable all those logs to find the actual reason why the application pool recycled...

That's done by this command on IIS6:

cscript %SYSTEMDRIVE%\inetpub\adminscripts\adsutil.vbs Set w3svc/AppPools/LogEventOnRecycle 255

On IIS7 you can enable them in the Advanced Settings of the application pool.

The problem with our Flex Application was that it uses WebORB Authentication. This authentication is done by the first remote call after which the server side session remembers the credentials. After the recycle the sessions were gone and 100 candidates received a WebORB Security error... We have already solved this problem by re-authenticating when this happens but I'm also really hoping to find out why the application pool recycled in the first place... Any suggestions are welcome... (memory?, too mucht connections?, database problem?, ...).

Ciao, Lieven Cardoen aka Johlero

<

SilverLight

Posted by admin on October 18th, 2008

The last couple of days I played around with Silverlight 2.0 and it's the first time I really enjoy it! That's probably mainly because doing SilverLight in VS2008 works great. Installing all the things I needed was another thing. I had to uninstall several things, examples created in beta versions of VS2008 didn't work, ... Anyway, if you start off at http://silverlight.net/GetStarted/ and google for some blogs on installing it, you should be fine after while!

I'm currently using the book Introducing Microsoft Silverlight 2 to get started and it isn't bad. Some examples though have mistakes (never understood how one can put code in a book that has mistakes and doesn't build...). After finishing the book I'll start off with some examples on the site of silverlight.

The coolest thing for me is debugging with Visual Studio. Until a year ago I mainly programmed in Flex, which also has a great debugger, but not like VS2008. When doing Flex together with WebORB and .NET (ASP, C#) I could easily debug in Flex and in ASP.NET but still needed to IDE's. With Silverlight I only need one IDE, VS2008, where the debugger is awesome.

There are lots of discussions about Flex vs. Silverlight but I guess the truth is just that SilverLight has a lot of catching up to do. Components need to be created, bugs will need resolving, something like AMF would be great (I know WebORB is working on SilverLight support), ... I think SilverLight is finally at a point where it becomes interesting to grab a book and play around with it!

The only thing that's strange to me is the lack of sites, games, examples in silverlight on the internet. I have found some but they are just extremely simple. Would like to see some examples of silverlight sites that can be compared to business solutions in Flex.

I also installed Expression Blend and I don't like it at all. Maybe because I'm a programmer and not a designer, but still, I found Flash more intuitive. And what is all that black doing there in Blend... Hopefully it's just me feeling novice in Blend but if not, then I hope they will improve Blend a lot.

Be well! Lieven Cardoen

<

WebORB Security Flex .NET Server Side PartI

Posted by admin on September 27th, 2008

I will not do a big introduction on WebORB security because I mainly want to show the security with some examples. It would however not be bad to read the following two things at http://www.themidnightcoders.com/doc30/ :

  • Flex Integration --> Flex Remoting --> Security
  • Server Infrastructure --> Security

Beside that read the comments in the Security section in the weborb.config file.

In my example I'll work with the closed system.

From WebORB:

WebORB default authorization handler implements a powerful system for granting or denying access to the user classes, XML Web Services, CFCs or any other supported service type. The system supports 2 modes of operation: Open and Closed mode. The 'Open System' mode exposes all application classes and services to the rich client applications. Access can be restricted to individual methods, classes or packages/namespaces by creating specific access constraints. This mode is useful for development when infrastructure security has lower priority. The 'Closed System' mode is the opposite of the open mode. When running in the 'Closed System' mode, WebORB restricts access to all service types available in the application - all classes, xml services, EJBs and CFCs. Access to the individual methods, classes, packages/namespace can be granted by applying security access constraints.

The closed system is more secure and easier to manage, so I'll work with that.

On the servers side I have one Class that needs security:

C#:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace Authentication
  7. {
  8.     public class TestService
  9.     {
  10.         /**
  11.          * No access constraints should be defined for this method. In a closed system,
  12.          * this means that no one should have access to this method.
  13.          */
  14.         public void Ping() { }
  15.  
  16.         /**
  17.          * Access should be granted to all IP adresses.
  18.          */
  19.         public void AllIpPing() { }
  20.  
  21.         /**
  22.          * Access should be granted only to Admin roles.
  23.          */
  24.         public void AdminPing() { }
  25.  
  26.         /**
  27.          * Access should be granted only to User roles.
  28.          */
  29.         public void UserPing() { }
  30.  
  31.         /**
  32.          * Access should be granted to users having both
  33.          * Admin and User role.
  34.          */
  35.         public void AdminAndUserPing() { }
  36.  
  37.         /**
  38.          * Access should be granted to users having
  39.          * Admin or User role.
  40.          */
  41.         public void AdminOrUserPing() { }
  42.     }
  43. }

Default WebORB Authentication/Authorization

First we'll check the default Authentication/Authorization from WebORB. In the weborb.config check the section on Security:

XML:
  1. <security>
  2.       <deploymentMode>closed</deploymentMode>
  3.       <authenticationHandler>Weborb.Security.WebORBAuthenticationHandler</authenticationHandler>
  4.       <!--authenticationHandler>Johlero.Security.Handler.AuthenticationHandler</authenticationHandler-->
  5.       <authorizationHandler>Weborb.Security.WebORBAuthorizationHandler</authorizationHandler>
  6.       <!--authorizationHandler>Johlero.Security.Handler.AuthorizationHandler</authorizationHandlers-->
  7.       <rolesProvider>Weborb.Security.WebORBRolesProvider</rolesProvider>
  8.       <!--rolesProvider>Johlero.Security.Provider.RolesProvider</rolesProvider-->
  9. </security>

Ok, closed system is set. Now we need to define the users. This is done at the end of the Security section in the weborb.config and should be set like this:

XML:
  1. <acl>
  2.       <user>
  3.         <name>admin</name>
  4.         <password>adminpass</password>
  5.         <role>admin</role>
  6.       </user>
  7.       <user>
  8.         <name>user</name>
  9.         <password>userpass</password>
  10.         <role>user</role>
  11.       </user>
  12.       <user>
  13.         <name>adminuser</name>
  14.         <password>adminuserpass</password>
  15.         <role>user</role>
  16.         <role>admin</role>
  17.       </user>
  18. </acl>

We have defined three users each with their password and the roles they are given. The adminuser is given two roles, user and admin. This will become clear later on in the Flex Part.

Now we need to set the constraints. At this point, no function in the TestService Class is accessible because of the Closed system.

First we'll create some access constraints. You'll see that some constraints are allready defined. We'll use also one of those predefined constraints:

XML:
  1. <access-constraint action="grant">
  2.           <name>Constraint.Grant.UserRole</name>
  3.           <role>user</role>
  4.         </access-constraint>
  5.         <access-constraint action="grant">
  6.           <name>Constraint.Grant.AdminRole</name>
  7.           <role>admin</role>
  8.         </access-constraint>
  9.         <access-constraint action="grant">
  10.           <name>Constraint.Grant.AdminAndUserRole</name>
  11.           <role>admin</role>
  12.           <role>user</role>
  13. </access-constraint>

First constraint grants access to the User role. The name is just a name that will be used further on in the secure-resource tags.
Second constraint grants access to the Admin role.
Third constraint grants access to users having both Admin AND User role. Be aware, this access-contraint does not say: give access to users having the Admin OR User role.
Besides giving access to a certain role it's also possible to give access to IP adresses, IP ranges and hostnames. (See comments in weborb.config).

We will also use a IP access contraint:

XML:
  1. <access-constraint action="grant">
  2.           <name>everyone</name>
  3.           <IP>*.*.*.*</IP>
  4. </access-constraint>

Ok, so these access-constraints are like predefined security configurations that can now be used to secure resources. In the secure-resources tag in weborb.config add these lines:

XML:
  1. <secure-resource>
  2.           <resource>Authentication.TestService.UserPing</resource>
  3.           <constraint-name>Constraint.Grant.User</constraint-name>
  4.         </secure-resource>
  5.         <secure-resource>
  6.           <resource>Authentication.TestService.AdminPing</resource>
  7.           <constraint-name>Constraint.Grant.Admin</constraint-name>
  8.         </secure-resource>
  9.         <secure-resource>
  10.           <resource>Authentication.TestService.AdminAndUserPing</resource>
  11.           <constraint-name>Constraint.Grant.AdminAndUser</constraint-name>
  12.         </secure-resource>
  13.         <secure-resource>
  14.           <resource>Authentication.TestService.AdminOrUserPing</resource>
  15.           <constraint-name>Constraint.Grant.Admin</constraint-name>
  16.         </secure-resource>
  17.         <secure-resource>
  18.           <resource>Authentication.TestService.AdminOrUserPing</resource>
  19.           <constraint-name>Constraint.Grant.User</constraint-name>
  20.         </secure-resource>
  21.         <secure-resource>
  22.           <resource>Authentication.TestService.Ping</resource>
  23.           <constraint-name>everyone</constraint-name>
  24. </secure-resource>

First secure-resource secures the Authentication.TestService.UserPing function with the Constraint.Grant.User constraint. This means that access to the UserPing function is granted to users that have the user role. So when along the Flex side user credentials are set (see ACL), access will be granted. Because of the closed system, ONLY user roles will have access.

Second secure-resource is analog to previous secure-resource, but now for Admin.

Third secure-resource secures the AdminAndUserPing with the AdminAndUser constraint. Here only access will be given to users having both user and admin role!

To give access to a Function for user having user OR admin role, you need to define two secure resources (fourth and fifth secure-resource).

The last secure-resource secures the Ping function with the everyone constraint. So everyone will have access to this resource.

In next post will show you how you can configure certain things with the Weborb Console (weborbconsole.html).

<

Copyright © 2007 Johlero – Cardoen Lieven. All rights reserved.