Thursday, December 17, 2009

Sculpture generated Silverlight on IIS and Async_Exception

Sculpture is a .NET open source MDD (Model-Driven Development) code generation framework. With the same model, it can generate various UIs such as Silverlight, ASP.NET MVC and WPF for you. This article talks about tricks of Silverlight, not necessarily Sculpture related, but if people encounter the same problem that I found using Sculpture, they might found it useful.

It is quite easy to run the Silverlight application from within Visual Studio 2008, being it created by Sculpture or yourself. However, to host that application on IIS 6, there are some configuration work to do. Here are the brief steps:

1. Start->Run->inetmgr
2. Right click Default Web Site->Properties->Home Directory->Configuration->find .aspx->Edit->Executable, change to C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll
3. Under Internet Information Services, right click the Server node->Properties->MIME Types->New, add:
Extension: .xap, MIME type: application/x-silverlight
Extension: .xaml, MIME type: application/xaml+xml
4. Restart IIS service


For details, see reference 1.

Now your Silverlight baby should be beautifully running and it's time for dealing with the unhandled exceptions if you use WCF in it. With normal silverlight installed, the typical error is like:
Message: Unhandled Error in Silverlight Application [Async_ExceptionOccurred]
Arguments:
Debugging resource strings are unavailable. Often the key and arguments provide sufficient information to diagnose the problem. See http://go.microsoft.com/fwlink/?linkid=106663&Version=3.0.40818.0&File=System.dll&Key=Async_ExceptionOccurred   at System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary()
at App.Infrastructure.ServiceContracts.DatabaseServerToExcludeCrudInfoCompletedEventArgs.get_Result()
at App.Shell.ServiceReferences.DatabaseServerToExcludeCrudService.DatabaseServerToExcludeCrudService_GetAllCompleted(Object sender, DatabaseServerToExcludeCrudInfoCompletedEventArgs e)
at App.Shell.ServiceReferences.DatabaseServerToExcludeCrudService.OnGetAllCompleted(Object state)
at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)
Line: 1
Char: 1
Code: 0
URI: http://192.1.1.50/App/Silverlight.js
With silverlight_developer version installed, you could see a bit more:
Message: Unhandled Error in Silverlight Application An exception occurred during the operation, making the result invalid.  Check InnerException for exception details.   at System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary()
at App.Infrastructure.ServiceContracts.DatabaseServerToExcludeCrudInfoCompletedEventArgs.get_Result()
at App.Shell.ServiceReferences.DatabaseServerToExcludeCrudService.DatabaseServerToExcludeCrudService_GetAllCompleted(Object sender, DatabaseServerToExcludeCrudInfoCompletedEventArgs e)
at App.Shell.ServiceReferences.DatabaseServerToExcludeCrudService.OnGetAllCompleted(Object state)
at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)...

There are at least 2 things you might have to check/fix:

1. Do you have a clientaccesspolicy.xml or crossdomain.xml under the root of your application domain where the service is hosted? Either file will set rules for your Silverlight control to access a WCF/web service in another domain.

An example of allowing any client is like this:
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*">
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>
For more details of cross-domain access, see ref 3.

2. Have you set the Endpoint Address of WCF service in Silverlight client correctly?

There are several ways of doing that. For example, generate/edit ServiceReferences.ClientConfig. From Visual Studio, you can right click your service node's Service References->Add Service Reference... to generate the client configuration.

For Sculpture generated code, you can override the GetEndPointAddress() method in ServiceConfiguration.cs and set the correct URL.

There seemed to be no big difference by configuration or programming as finally they will be compiled into Silverlight binary and neither has the flexibility of modification on the fly.

Ref:
1. Developing and deploying a Visual WebGui Silverlight application
2. Configuring IIS for Silverlight Applications
3. Using Silverlight 2.0 clientaccesspolicy.xml vs. crossdomain.xml for Web-Service cross-domain access
4. Network Security Access Restrictions in Silverlight
5. Making a Service Available Across Domain Boundaries