Silverlight RIA Services - What is the best way to handle client session timeouts?

I created an application with Silverlight4, RIA Services, and I use ASP.NET membership for authentication / authorization.

My web.config has the following:

<system.web> <sessionState timeout="20"/> <authentication mode="Forms"> <forms name="_ASPXAUTH" timeout="20"/> </authentication> 

I read several different strategies on how to deal with client-side auth / session timeout. That is: if the client is idle for x minutes (20 here), and then they do something with the user interface that launches the RIA / WCF call, I want a trap on this event and deal with it accordingly (for example, return them back to the login screen) - in a nutshell: I need a way to distinguish from a bona fide DomainException server on the auth failure side because the session was disconnected.

AFAIK: There is no typed exception or property that can define this. The only way I could figure this out was like a hack: check the line with the error message and look for something like "Access denied" or "denied". For example: something like this:

 if (ex.Message.Contains("denied")) // this is probably an auth failure b/c of a session timeout 

So, this is what I am doing now and it works if I run and debug either with the built-in server from VS2010, or I run in the local IIS. If I set the timeout to 1 minute, log in, wait more than a minute and call another call, I will focus on the exception and enter the if code code above, and everything will be fine.

Then I deploy the application to the remote IIS7 server and I try the same test and it does not work. So, I added a log trace, and here an event occurred in which an exception occurred:

 <E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent"> <System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system"> <EventID>131076</EventID> <Type>3</Type> <SubType Name="Error">0</SubType> <Level>2</Level> <TimeCreated SystemTime="2011-10-30T22:13:54.6425781Z" /> <Source Name="System.ServiceModel" /> <Correlation ActivityID="{20c26991-372f-430f-913b-1b72a261863d}" /> <Execution ProcessName="w3wp" ProcessID="4316" ThreadID="24" /> <Channel /> <Computer>TESTPROD-HOST</Computer> </System> <ApplicationData> <TraceData> <DataItem> <TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Error"> <TraceIdentifier>http://msdn.microsoft.com/en-US/library/System.ServiceModel.Diagnostics.TraceHandledException.aspx</TraceIdentifier> <Description>Handling an exception.</Description> <AppDomain>/LM/W3SVC/1/ROOT/sla-2-129644844652558594</AppDomain> <Exception> <ExceptionType>System.ServiceModel.FaultException`1[[System.ServiceModel.DomainServices.Hosting.DomainServiceFault, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType> <Message></Message> <StackTrace> at System.ServiceModel.DomainServices.Hosting.QueryOperationBehavior`1.QueryOperationInvoker.InvokeCore(Object instance, Object[] inputs, Object[]&amp; outputs) at System.ServiceModel.DomainServices.Hosting.DomainOperationInvoker.Invoke(Object instance, Object[] inputs, Object[]&amp; outputs) at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp; rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp; rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc&amp; rpc) at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet) </StackTrace> <ExceptionString>System.ServiceModel.FaultException`1[System.ServiceModel.DomainServices.Hosting.DomainServiceFault]: (Fault Detail is equal to System.ServiceModel.DomainServices.Hosting.DomainServiceFault).</ExceptionString> </Exception> </TraceRecord> </DataItem> </TraceData> </ApplicationData> </E2ETraceEvent> 

The problem is that I don't have a line in the error message that says "denied" or "Access denied" - and I'm not sure why this solution works on the local IIS or VS2010 host, but not on the remote IIS7. Are there any obscure configuration settings that I am missing here? Is there a better way to do this overall?

+8
silverlight wcf-ria-services asp.net-membership
source share
1 answer

You've probably come to that, but this article describes using DomainOperationException and checking for error codes.

 dex.ErrorCode == ErrorCodes.NotAuthenticated || dex.ErrorCode == ErrorCodes.Unauthorized 

For easy access (and if you don’t have access to the blog) here is a blog post by Josh Eastburn:

The question that often arises for developers working with Silverlight and WCF RIA Services is: why does the Silverlight application throw an exception when it has been idle for some time? As expected, this is due to the end of the authentication session. But it is not so simple. Because Silverlight uses a client / server architecture, the client can operate independently of the server for an indefinite period of time. Only when the Silverlight client makes a call to the server does the server timeout occur. There are several options for handling the client-server timeout problem (and you can come up with a few more): if you are not sure of the security associated with deleting the session timeout, you can either increase the timeout setting in web.config or create a DispatcherTimer in the Silverlight client , which calls a simple method on the server to act as a "Keep Alive". Add a DispatcherTimer to the Silverlight client, which synchronizes with the server-side timeout and warns / requests that the user save the session before the time runs out or re-authenticate it if it has already expired. However, this requires additional efforts to synchronize timers when creating new server requests. Allow the server to process the timeout as usual and correctly handle the timeout on the Silverlight client. This means that the timeout is determined by the activity of the server call, and NOT by the activity of the Silverlight client (i.e., it refers to client data in context). Of these three options, I believe that the third is the best balance of security and usability, while at the same time not adding unnecessary complexity to the application. To handle these server-side timeouts around the world, you can add the following logic either to the Application_UnhandledException method in App.xaml.cs, or to your global ViewModel load construct, if any:

  // Check for Server-Side Session Timeout Exception var dex = e.ExceptionObject as DomainOperationException; if ((dex != null) && (dex.ErrorCode == ErrorCodes.NotAuthenticated || dex.ErrorCode == ErrorCodes.Unauthorized) && WebContext.Current.User.IsAuthenticated) { // A server-side timeout has occurred. Call LoadUser which will automatically // authenticate if "Remember Me" was checked, or prompt for the user to log on again WebContext.Current.Authentication.LoadUser(Application_UserLoaded, null); e.Handled = true; } 

The following constants are defined in the ErrorCodes class:

 public static class ErrorCodes { public const int NotAuthenticated = 0xA01; public const int Unauthorized = 401; } 

When the server-side session expires, any subsequent calls will return a DomainOperationException. By checking the returned ErrorCode, you can determine if this is an authentication error and handle it accordingly. In my example, I call WebContext.Current.Authentication.LoadUser (), which will try to re-authenticate the user, if possible. Even if the user cannot be automatically authenticated again, he will return to my Application_UserLoaded method. There I can check WebContext.Current.User.IsAuthenticated to determine whether to continue the previous operation or whether I need to redirect back to the home page and re-enter to log in. The following is an example of some code in the Appliation_UserLoaded callback that shows the login dialog if the user is not authenticated:

 // Determine if the user is authenticated if (!WebContext.Current.User.IsAuthenticated) { // Show login dialog automatically LoginRegistrationWindow loginWindow = new LoginRegistrationWindow(); loginWindow.Show(); } 

To test your code, you can set the timeout value in web.config to a small value, so timeouts occur quickly:

 <authentication mode="Forms"> <forms name=".Falafel_ASPXAUTH" timeout="1" /> </authentication> 

If you like to see all of this code in a working solution, check out the Silverlight RIA Template on CodePlex .

+10
source share

All Articles