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

Monday, November 23, 2009

Install Silverlight 3 Tools Offline

It seems quite stupid that the Silverlight 3 Tools installation will always look to download from internet even you have installed the Silverlight SDK by yourself. More absurdly, the download and installation will fail even you have connection to internet but by using a proxy, which is common in an office. The trick here is to extract them manually into the same folder:
  1. In cmd window, uncompress Silverlight SDK: silverlight_sdk.exe /x
  2. Uncompress Silverlight tools to the above chosen directory: Silverlight3_Tools.exe /x
  3. In the extracted folder, run VS_SilverlightTools_Setup.exe
  4. In the same folder, run VS90SP1-KB967143-enu.msp as well as VS90SP1-KB967144-enu.msp (ignore this failure)
The last 2 steps take a while, but eventually you should be able to open silverlight projects in Visual studio then.

Ref: Installing SilverLight 3 Visual Studio Tools Offline

Sunday, November 8, 2009

Simple way to invalidate SqlDataSource cache programmatically

EnableCaching and CacheDuration are the normal cache-related properties of the data source controls, but they don't give you the convenience to invalidate the cache on-demand. Some people use the SqlCacheDependency, where ASP.NET worker process will poll for changes in the SqlCacheTablesForChangeNotification when a change in monitored table triggers the "notification". This measure is somewhat clumsy in that:
  1. You have to use aspnet_regsql command line to enable notifications for the database;
  2. ASP.NET uses a polling mechanism, and you have to both write code and alter your web.config
There is a simpler way though: use CacheKeyDependency, where you make the data source cache dependent on another item in the data cache (CacheKeyDependency). Details follow:
  • Add CacheKeyDependency in aspx:
<asp:SqlDataSource ID="x" EnableCaching="True" CacheKeyDependency="MyCacheDependency" />
  • Add some code in aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{ // Or somewhere else before the DataBind() takes place
  if (!IsPostBack)
  {
      ...
      if (Cache["MyCacheDependency"] == null)
      {
        Cache["MyCacheDependency"] = DateTime.Now;
      }
  }
}
  • Where you make changes to the database table and want to invalidate cache so that next time a data binding will see the changes:
// Evict cache items with an update in dependent cache:
Cache["MyCacheDependency"] = DateTime.Now;
You can use any value instead of DateTime.Now as long as they are different to trigger the refresh.
Ref: 1. ASP.NET Caching: SQL Cache Dependency With SQL Server 2000
2. Accessing and Updating Data in ASP.NET 2.0: Declaratively Caching Data

Sunday, November 1, 2009

Prevent IIS Session Timeout in ASP .NET

There are scenarios that a user may want to keep a long session alive. For example, a help desk operator logs into a web application and takes phone calls and in between submits changes to the backend systems. The phone call may last over an hour and the operator may stay in one web page and need that session to be valid when she submits the changes.
In ASP.NET, there are several common simple solutions for that. One of them is to set the session timeout attribute (minutes) in web.config.
<sessionState mode ="InProc" timeout="xxx"/>
Some people are confused at the timeout setting in web.config and another in IIS and ask which overwrites which. A simple experiment shows that the setting in web.config always overwrites the setting in IIS.
However, this is not complete for ASP .NET 2.0+. Open IIS->Application Pools->Select the Application pool for your application->Properties->Performance, set the idle timeout for "Shutdown worker processes after being idle for xxx minutes".
Otherwise, the worker process is still stopped after 20 minutes(default) and your session state will be lost.
Another way, if we do not want to rely on the settings in IIS, is to keep the session alive by ourselves in the application. Some people use an invisible frame and set auto refresh in http header, but if you are using a master page, that behavior will be propagated to all ASP pages. With .NET 2.0+ and a little bit Ajax, we have a simpler solution - add a timer in UpdatePanel. The timer will trigger a partial postback periodically, thus prods the session to be alive.
<asp:Content ID="ct" ContentPlaceHolderID="cphMain" runat="Server">
  <asp:ScriptManager ID="scriptMgr" runat="server" />

  <%-- Your content here --%>

  <%-- Heartbeat every 15min to keep session alive --%>
  <asp:UpdatePanel ID="updatePanel" runat="server">
    <ContentTemplate>
      <asp:Timer ID="timerPing" runat="server" Interval="900000">
      </asp:Timer>
    </ContentTemplate>
  </asp:UpdatePanel>
</asp:Content>
Ref:
1. Managing Session TimeOut using Web.Config
2. Preventing Session Timeouts in C# ASP .NET

Sunday, September 6, 2009

Install Cygwin SSH on Win2K3

There has been an excellent post on how to install Cygwin SSH on Win2K3 . However, there are still some tricks to get that working properly. Luckily, we could alwasy refer to Window's EventViewer to get the details of what happened.
  • mkpasswd does not generate correct group number for domain users
mkpasswd -d <domain-name> -p /home -u <username> >> /etc/passwd
This will add one line of the domain user in /etc/passwd. But be careful the group number may not be correspondent with /etc/group. So the following error will likely be seen when ssh -v localhost:
sshd: PID 2584: fatal: initgroups: <username> : Invalid argument.
After manually correcting the group number in /etc/passwd, we should be able to use ssh locally.
  • hosts.allow - enable remote users
The default hosts.allow after ssh-host-config looks like:
ALL : localhost 127.0.0.1/32 : allow
ALL : PARANOID : deny
sshd: ALL
However, this won't get us through if we connect from another machine.
sshd: PID 3904: refused connect from 10.8.8.8.
We could modify hosts.allow and make it look like:
sshd: ALL : spawn (echo "Attempt from %h %a to %d at `date` by %u" | tee -a /var/log/sshd.log)
This will allow connections and add 1 line in sshd.log for each connection.
or simply:
sshd: ALL : allow
or more restrictive:
sshd: 10.8.0.0/255.255.0.0 : allow
  • /etc/hosts - if sshd cannot verify hostname
We still may see a warning "sshd: PID 3904: warning: /etc/hosts.allow, line 11: can't verify hostname: gethostbyname(<hostname>) failed."
This slows SSH client's connection. One work around is to add the host in /etc/hosts file which speeds connection up:
10.8.8.8     <hostname>

Monday, April 27, 2009

Run Glassfish v2 EJB3 example on JBoss 5

  • JBoss 5 with Derby as DataSource
There are some really good blogs about how to use derby as JBoss DataSource like Alistair Israel's, but still things to be noticed.
After copy ${JBOSS_HOME}/docs/examples/jca/derby-ds.xml to ${JBOSS_HOME}/server/default/deploy, several items should be adjusted according to the sample, like:
<jndi-name>jdbc/sample</jndi-name>
<connection-url>jdbc:derby://localhost:1527/sample</connection-url>
<driver-class>org.apache.derby.jdbc.ClientXADataSource</driver-class>
And the following to specify the database:
<mbean code="org.jboss.jdbc.DerbyDatabase" name="jboss:service=Derby">
<attribute name="Database">sample</attribute>
</mbean>
Then, Copy ${JBOSS_HOME}/docs/examples/varia/derby-plugin.jar and the ${DERBY_HOME}/lib/derby.jar and derbyclient.jar to ${JBOSS_HOME}/server/default/lib.

Next is workaround of JBoss JMX if using JBoss 5.01GA(fixed in 5.1.0GA), add -Djboss.platform.mbeanserver at the end of line in ${JBOSS_HOME}/bin/run.bat(or run.sh):
set JAVA_OPTS=...
  • JBossXBRuntimeException
You won't have it in this example, but say if you try to run the entity demo, you probably get:
DEPLOYMENTS IN ERROR:
Deployment "vfszip:.../server/default/deploy/lab-entity-demo4.jar/" is in error due to the following reason(s): org.jboss.xb.binding.JBossXBRuntimeException: Failed to resolve schema nsURI= location=persistence

This is due to the persistence.xml missing schema namespaces:
<?xml version="1.0" encoding="UTF-8"?>
<persistence>
<persistence-unit name="lab-entity-demo4">
<jta-data-source>java:/DefaultDS</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
</properties>
</persistence-unit>
</persistence>

To correct it, the following should be put in persistence element:
version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
  • org.jboss.deployers.spi.DeploymentException:
Required config property RequiredConfigPropertyMetaData@f1770a[name=destination descriptions=[DescriptionMetaData@7f0b4e[language=en]]] for messagingType 'javax.jms.MessageListener' not found in activation config [ActivationConfigProperty(destinationType=javax.jms.Queue)] ra=jboss.jca:service=RARDeployment,name='jms-ra.rar'

Need to add "destination" property in ActivationConfigProperty. See next step.
  • Modify MessageBean, add JBoss specific annotation:
import org.jboss.ejb3.annotation.Depends;

@MessageDriven(mappedName = "jms/NewsMsg", activationConfig = {
// JBoss by default uses AUTO_ACKNOWLEDGE:
// @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName="destination", propertyValue="jms/NewsMsg")
})
@Depends ("jboss.mq.destination:service=Queue,name=ejbfoo")
public class NewsMessageBean implements MessageListener {
...

  • Add ejbfoo-queue-service.xml in src/conf. Netbeans will pack this file in META-INF when build the jar fiel.
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="org.jboss.mq.server.jmx.Queue"
name="jboss.mq.destination:service=Queue,name=ejbfoo">
<attribute name="JNDIName">jms/NewsMsg</attribute>
<depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
</mbean>
</server>
  • Modify persistence.xml as following:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="EjbFoo-ejbPU" transaction-type="JTA">
<!-- Toplink is default for Glassfish
<provider>oracle.toplink.essentials.PersistenceProvider</provider>
<jta-data-source>jdbc/sample</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="toplink.ddl-generation" value="create-tables"/>
</properties>
-->

<!-- Hibernate for JBoss -->
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/jdbc/sample</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>
</persistence>

  • Modify PostNews servlet, which is the messageProducer and send the message through queue:
public class PostNews extends HttpServlet {
// For Glassfish:
//@Resource(mappedName = "jms/NewsMsgFactory")
// For JBoss:
@Resource(mappedName = "ConnectionFactory")
private ConnectionFactory connectionFactory;
@Resource(mappedName = "jms/NewsMsg")
private Queue queue;
...
  • Deploy and run as you would under Glassfish.

Thursday, April 23, 2009

Play with JBoss 5: ejb3.deployer not found

Like all other open source stuffs, you have to pull the scattered pieces together before you can actually get like a simple tutorial working. Recently I downloaded JBoss 5.0.1 AS and wanted to play with the ejb3. So I downloaded the EJB3Labs from JBoss community and just as I expected, it won't run without some tweaking. Here are the tricks:
  • In build.bat, comment out set ANT_HOME=..\..\..\ant-dist and set the variable in the environment.
  • Then run build runejb, and there you get:
JBossWorldBerlinLabs\lab-slsb-demo3\src\build\build.xml:44: jboss-5.0.1.GA\server\default\deploy\ejb3.deployer not found.
  • In build.xml, you have to change the classpath as it was restructured in JBoss AS5:
deploy/ejb3.deployer -> deployers/ejb3.deployer
deploy/jboss-aop-jdk50.deployer -> deployers/jboss-aop-jboss5.deployer


Then add:
<fileset dir="${jboss.home}/common/lib">
  <include name="**/*.jar">
  </include>
</fileset>

  • Last, in Client.java
calculator = (Calculator) ctx.lookup("TODO:insert name");
should be changed to
calculator = (Calculator) ctx.lookup("CalculatorBean/remote");
Ref: JBoss EJB3 Tutorial

Thursday, April 2, 2009

Change Oracle XE default HTTP and DB ports

  • Stop listener in command window:
lsnrctl stop
  • Modify ORACLE_HOME/app/oracle/product/10.2.0/server/NETWORK/ADMIN/listener.ora
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))
(ADDRESS = (PROTOCOL = TCP)(HOST = myhost)(PORT = 1521))
)
)
Change the PORT to the number wanted. Also modify PORT in tnsnames.ora and save.
  • Start listener:
lsnrctl start
  • Run SQL Plus to add local listener for that port, then change HTTP listening port:
conn system/password;
alter system set local_listener = "(ADDRESS=(PROTOCOL=TCP)(HOST=your.com)(PORT=1522))";
exec dbms_xdb.sethttpport(nnnn);
alter system register;
disc;
If "set local_listener" is omitted, you probably will get get "ORA-12514: TNS:listener does not currently know of service requested when openning SQL Plus with sqlplus system@xe

alter system register" is also important as it reregisters the DB and all services with the listener. Otherwise you can find the port is not listening with netstat -an. Also you can verify with lsnrctl status, and a line like following should be there:
...
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=your.com)(PORT=8090))(Presentation=HTTP)(Session=RAW))

  • Confirm:
select dbms_xdb.gethttpport as "HTTP Port",
dbms_xdb.getftpport as "FTP Port" from dual;
Ref: http://download.oracle.com/docs/cd/B25329_01/doc/admin.102/b25107/network.htm#BHCCDEIH

Saturday, March 28, 2009

Change locale and date format of Oracle XE in SQL*Plus

Want to change the default locale and date format in SQL*Plus with Oracle XE Universal to US english. The easiest way is to add two environment variables in Windows XP:
NLS_DATE_FORMAT=DD-MON-YYYY
NLS_LANG=AMERICAN_AMERICA.AL32UTF8
Then start SQL*Plus:
C:\>sqlplus / as sysdba
SQL> select sysdate from dual;
SYSDATE
--------------------
28-MAR-2009