Showing posts with label asp.net. Show all posts
Showing posts with label asp.net. Show all posts

Saturday, June 16, 2012

Time-outs

IIS Management Console

  • Application Pool
    • Advanced Settings
      • Idle Time-out
        One way to conserve system resources is to configure idle time-out settings for the worker processes in an application pool. When these settings are configured, a worker process will shut down after a specified period of inactivity. The default value for idle time-out is 20 minutes.

  • Web Site
    • Advanced Settings
      • Connection Limits
        • Connection Time-out
          Specifies the time (in seconds) that IIS waits before it disconnects a connection that is considered inactive. Connections can be considered inactive for the following reasons:
          • The HTTP.sys Timer_ConnectionIdle timer expired. The connection expired and remains idle.
          • The HTTP.sys Timer_EntityBody timer expired. The connection expired before the request entity body arrived. When it is clear that a request has an entity body, the HTTP API turns on the Timer_EntityBody timer. Initially, the limit of this timer is set to the connectionTimeout value. Each time another data indication is received on this request, the HTTP API resets the timer to give the connection more minutes as specified in the connectionTimeout attribute.
          • The HTTP.sys Timer_AppPool timer expired. The connection expired because a request waited too long in an application pool queue for a server application to dequeue and process it. This time-out duration is connectionTimeout.
          The default value is 00:02:00 (two minutes).
    • Features View
      • Configuration Editor
        • Section = system.web/httpRuntime
          • executionTimeout
            Specifies the maximum number of seconds that a request is allowed to execute before being automatically shut down by ASP.NET.

            This time-out applies only if the debug attribute in the compilation element is False. Therefore, if the debug attribute is True, you do not have to set this attribute to a large value in order to avoid application shutdown while you are debugging.

            The default is 110 seconds.

Service Configuration Editor (system.serviceModel)

  • Bindings 
    • closeTimeout
      A TimeSpan value that specifies the interval of time provided for a close operation to complete. This value should be greater than or equal to Zero. The default is 00:01:00.
    • openTimeout

      A TimeSpan value that specifies the interval of time provided for an open operation to complete. This value should be greater than or equal to Zero. The default is 00:01:00.
    • receiveTimeout
      A TimeSpan value that specifies the interval of time provided for a receive operation to complete. This value should be greater than or equal to Zero. The default is 00:10:00.
    • sendTimeout
      A TimeSpan value that specifies the interval of time provided for a send operation to complete. This value should be greater than or equal to Zero. The default is 00:01:00.

 BizTalk Server Administration Console

  • BizTalk Group
    •  Platform Settings
      • Hosts
        • Settings
          • General
            • Response Time [see also]
              Specify the default timeout for request response messages.
              When an adapter submits a request-request message, it needs to specify the time-out of the request message on the IBTTransportBatch.SubmitRequestMessage Method (COM) API. A response message will be delivered to the adapter only within this time-out period. After the time-out expires, a negative acknowledgment (NACK) will be delivered to the adapter instead of the response message. If the adapter does not specify a time-out value, the engine uses the default value of 20 minutes.
      • Applications
        • [Application]
          • Send Ports/Receive Locations
            • [Send Port/Receive Location]
              • Properties
                • Type = Any WCF Adapter > Configure...
                  • Binding

    Wednesday, April 27, 2011

    ASP.NET MVC View Engine with FreeMarker

    FreeMarker is a quite success template engine in Java world. It is used with Apache Struts, an MVC framework, as a view engine. ASP.NET MVC is using Web Form as the default view engine. The problem is the view become a spaghetti of HTML and C# snippets fairly quickly, just like classic ASP and PHP. FreeMarker.Net is a project that ports the FreeMaker as an ASP.NET MVC view engine

    The idea is compiling FreeMarker to .Net assembly with IKVM and create a wrapper to wrap .Net objects so that FreeMarker can understand.

    Compiling FreeMarker
    It is a strength forward process. It can be done with one command:
    ikvmc freemarker.jar -target:library

    Separating Necessary IKVM Libraries
    Only the following libraries is required for development:
    • IKVM.OpenJDK.Beans.dll 
    • IKVM.OpenJDK.Charsets.dll
    • IKVM.OpenJDK.Core.dll
    • IKVM.OpenJDK.SwingAWT.dll
    • IKVM.OpenJDK.Text.dll
    • IKVM.OpenJDK.Util.dll
    • IKVM.Runtime.dll

    Wrapping .Net Object
    FreeMarker does not directly deal with the objects. Instead, it deals with the TemplateModel objects. There are a few template models to be implemented:
    • TemplateBooleanModel
    • TemplateDateModel
    • TemplateHashModel
    • TemplateMethodModelEx
    • TemplateNumberModel
    • TemplateScalarModel
    • TemplateSequenceModel
    FreeMarker provides an ObjectWrapper interface to wrap the raw objects into TemplateModel.

    The NetObjectModel is actually is a TemplateHashModel
    public class NetObjectModel : StringModel, 
                                  TemplateModel, 
                                  TemplateHashModel {
            Dictionary<string, PropertyInfo> props = 
                new Dictionary<string, PropertyInfo>();
            Dictionary<string, MethodModel> methods = 
                new Dictionary<string, MethodModel>();
            Dictionary<string, ExtensionMethodModel> extensionMethods = 
                new Dictionary<string, ExtensionMethodModel>();
    
            public NetObjectModel(object data, 
                                  NetObjectWrapper wrapper)
                : base(data, wrapper){
                var type = data.GetType();
                foreach (var p in type.GetProperties()) {
                    props.Add(p.Name, p);
                }
                foreach (var m in type.GetMethods()) {
                    if (!methods.ContainsKey(m.Name)) {
                        methods.Add(m.Name, 
                                    new MethodModel(data,  
                                                    wrapper, 
                                                    m.Name));
                    }
                }
            }
    
            public virtual TemplateModel get(string key) {
                if (props.ContainsKey(key)) {
                    return wrapper.wrap(props[key].GetGetMethod()
                                                  .Invoke(data, null));
                }
                else if (methods.ContainsKey(key)) {
                    return methods[key];
                }
                else if (wrapper.ExtensionTypes.Count > 0) {
                    if (!extensionMethods.ContainsKey(key)) {
                        extensionMethods[key] = 
                            new ExtensionMethodModel(data, 
                                                     wrapper, 
                                                     key);
                    }
                    return extensionMethods[key];
                }
                else {
                    return TemplateModel.__Fields.NOTHING;
                }            
            }
    
            public virtual bool isEmpty() {
                return props.Count == 0;
            }
        }
    

    To adapt the ASP.NET objects, three more template model are created:
    • HttpApplicationStateModel
    • HttpRequestModel
    • HttpSessionStateModel
    They are similar but not in the same interface, all of them are like this:
    public class HttpApplicationStateModel : NetObjectModel, 
                                             TemplateModel, 
                                             TemplateHashModel {
    
            public HttpApplicationStateModel(
                 object data, 
                 NetObjectWrapper wrapper)
                : base(data, wrapper) {
                
            }
    
            public override TemplateModel get(string key) {
                HttpApplicationStateBase dic = 
                    data as HttpApplicationStateBase;
                if (dic.Keys.Cast<string>().Contains(key)) {
                    return wrapper.wrap(dic[key]);
                }
                else {
                    return base.get(key);
                }
            }
    
            public override bool isEmpty() {
                IDictionary<string, object> dic = 
                    data as IDictionary<string, object>;
                return dic.Count == 0 && base.isEmpty();
            }
        }
    View Engine
    The view engine is fairly simple, it simply initialize the FreeMarker configuration.
    public class FreemarkerViewEngine : VirtualPathProviderViewEngine {
            Configuration config;
            public FreemarkerViewEngine(string rootPath, 
                                        string encoding = "utf-8") {
                config = new Configuration();
                config.setDirectoryForTemplateLoading(
                    new java.io.File(rootPath));
                AspNetObjectWrapper wrapper = 
                    new AspNetObjectWrapper();
    
                config.setObjectWrapper(wrapper); 
                base.ViewLocationFormats = 
                    new string[] { "~/Views/{1}/{0}.ftl" };
                config.setDefaultEncoding(encoding);
                base.PartialViewLocationFormats = 
                    base.ViewLocationFormats;
            }
    
            protected override IView CreatePartialView(
                ControllerContext controllerContext, 
                string partialPath) {
                return new FreemarkerView(config, partialPath);
            }
    
            protected override IView CreateView(
                ControllerContext controllerContext, 
                string viewPath, 
                string masterPath) {
                return new FreemarkerView(config, viewPath);
            }
        }
    

    View
    FreemarkerView implements IView to render the content. It simply create the dictionary as variable bindings and invoke the FreeMarker.
    public class FreemarkerView : IView{
        public class ViewDataContainer : IViewDataContainer {
            private ViewContext context;
            public ViewDataContainer(ViewContext context) {
                this.context = context;
            }
    
            public ViewDataDictionary ViewData {
                get {
                    return context.ViewData;
                }
                set {
                    context.ViewData = value;
                }
            }
        }
    
        private freemarker.template.Configuration config;
        private string viewPath;
        public FreemarkerView(freemarker.template.Configuration config, string viewPath) {
            this.config = config;
            this.viewPath = viewPath;
        }
    
        public void Render(ViewContext viewContext, 
                            System.IO.TextWriter writer) {
            Template temp = config.getTemplate(viewPath.Substring(2));
                
            Dictionary<string, object> data = 
                            new Dictionary<string, object>{
                {"model", viewContext.ViewData.Model},
                {"session", viewContext.HttpContext.Session},
                {"http", viewContext.HttpContext},
                {"request", viewContext.HttpContext.Request},
                {"application", viewContext.HttpContext.Application},
                {"view", viewContext},
                {"controller", viewContext.Controller},
                {"url", new UrlHelper(viewContext.RequestContext)},
                {"html", new HtmlHelper(viewContext, 
                                new ViewDataContainer(viewContext))},
                {"ajax", new AjaxHelper(viewContext, 
                                new ViewDataContainer(viewContext))},
            };
    
            Writer output = new JavaTextWriter(writer);
            temp.process(data, output);
            output.flush();
        }
    }
    
    Configuration
    Configuration is as simple as adding the view engine to the view engine collections.
    protected void Application_Start() {
        AreaRegistration.RegisterAllAreas();
    
        // ****** Optionally, you can remove all other view engines ******
        //ViewEngines.Engines.Clear();
        ViewEngines.Engines.Add(new FreemarkerViewEngine(this.Server.MapPath("~/")));
    
        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }
    

    Extension Methods
    ASP.NET MVC relies on extension method quite heavily. In the NetObjectWrapper, the following code is added to find the extension methods:
    public virtual void AddExtensionNamespace(string ns) {
        var types = this.ExtensionTypes;
        foreach (var a in AppDomain.CurrentDomain.GetAssemblies()) {
            try {
                foreach (var t in a.GetExportedTypes()) {
                    if (!types.Contains(t) && 
                        t.IsClass && 
                        t.Name.EndsWith("Extensions") && 
                        t.Namespace == ns && 
                        t.GetConstructors().Length == 0) {
                        types.Add(t);
                    }
                }
            }
            catch { }
        }
    }
    
    In the view engine's constructor, it reads the namespaces specified under system.web/pages sections in web.config:
    PagesSection section = 
        (PagesSection)WebConfigurationManager
                          .OpenWebConfiguration("~/")
                          .GetSection("system.web/pages");
    if (section != null) {
        foreach (NamespaceInfo info in section.Namespaces) {
            wrapper.AddExtensionNamespace(info.Namespace);
        }
    }
    
    An ExtensionMethodModel class is created to find the appropriate method to invoke:
    foreach (var type in wrapper.ExtensionTypes) {
        MethodInfo method = type.GetMethod(
            methodName, 
            BindingFlags.Public | BindingFlags.Static, 
            Type.DefaultBinder, 
            argTypes, null);
        if (method != null) {
            cache.Add(key, method);
            return wrapper.wrap(method.Invoke(target, args.ToArray()));
        }
    }
    
    Localization
    ResourceManagerDirectiveModel (a TemplateDirectiveModel) and ResourceManagerModel are created so that we could do something like this:
    <@resource type="Freemarker.Net.MvcWeb.App_GlobalResources.PersonResource, Freemarker.Net.MvcWeb"/>
    

    ${res.Title}

    ResourceManagerDirectiveModel is getting the ResourceManager from the resource and put it into res template variable:
    public void execute(freemarker.core.Environment env, java.util.Map parameters, TemplateModel[] models, TemplateDirectiveBody body) {
        if (parameters.containsKey("type")) {
            TemplateScalarModel scalar = 
                (TemplateScalarModel)parameters.get("type");
            var type = Type.GetType(scalar.getAsString());
            env.setVariable("res", 
                env.getObjectWrapper()
                    .wrap(type.GetProperty("ResourceManager", 
                                            BindingFlags.Static | 
                                            BindingFlags.NonPublic | 
                                            BindingFlags.Public)
                            .GetGetMethod(true)
                            .Invoke(null, null)));
        }            
    }
    
    Adding More Directives
    To all more directives can be added in the future, MEF is used. The directive implementation only needs to export and implement the ImportableDirective interface.
    [Export(typeof(ImportableDirective))]
        public class ResourceManagerDirectiveModel : TemplateDirectiveModel, ImportableDirective {
    
    The view engine will import them in the constructor:
    public class FreemarkerViewEngine : VirtualPathProviderViewEngine {
            Configuration config;
            [ImportMany]
            IEnumerable<ImportableDirective> directives;
            public FreemarkerViewEngine(string rootPath, 
                                        string encoding = "utf-8") {
                // initialize the config 
                // ...
                // import the extension methods' namespaces
                // ...
                // import the directives
                var dir = new DirectoryInfo(
                    Path.Combine(rootPath, "bin"));
                var catalogs = dir.GetFiles("*.dll")
                    .Where(o => o.Name != "freemarker.dll" && 
                               !(o.Name.StartsWith("IKVM.") || 
                               o.Name.StartsWith("Freemarker.Net")))
                    .Select(o => new AssemblyCatalog(
                                 Assembly.LoadFile(o.FullName))
                );
                var container = new CompositionContainer(
                    new AggregateCatalog(
                        new AggregateCatalog(catalogs),
                        new AssemblyCatalog(
                          typeof(ImportableDirective).Assembly)
                ));
                container.ComposeParts(this);
            }
    

    The source code is available in CodePlex. Please visit http://freemarkernet.codeplex.com/.

    P.S.: The bonus of this project is we have not only a new view engine in ASP.NET MVC, but also a new template engine in .Net Framework. Maybe someday we could use FreeMarker to generate code instead of T4 in Visual Studio SDK.

    Friday, March 25, 2011

    PHP-Azure Migration - Part 4

    Up to the last post of the migration, we have done all data and file migration. How about the new files being uploaded from the CMS?

    PHP
    We are using a very old version of FCKEditor as our rich text editor. Since FCKEditor supports uploading file from the editor, we need to change the code in editor/filemanager/connectors/php/command.php. Here is an example of getting the folder and files for the file browser.
    function GetFoldersAndFiles( $resourceType, $currentFolder ) {
            $sServerDir = MapAzureFolder( $resourceType, $currentFolder);
            $blobs = $blobStorageClient->listBlobs($ContainerName, $sServerDir, '/');
     $aFolders = array();
     $aFiles = array();
     $folders = GetSessionFolders($resourceType, $currentFolder);
     foreach($blobs as $blob){
      $name = GetName($blob->Name);
      if ($blob->IsPrefix){
       $folders[$name] = 0;
      } else {     
       $iFileSize = $blob->Size;
       if ( !$iFileSize ) {
        $iFileSize = 0 ;
       }
       if ( $iFileSize > 0 ) {
        $iFileSize = round( $iFileSize / 1024 ) ;
        if ( $iFileSize < 1 ) $iFileSize = 1 ;
       }
        $aFiles[] = '<File name="' . ConvertToXmlAttribute( $name ) . '" size="' . $iFileSize . '" />' ;
      }
     }
     foreach($folders as $name => $value){
      $aFolders[] = '<Folder name="' . ConvertToXmlAttribute( $name ) . '" />' ;
     }
    }
    
    It is worth to mention the GetSessionFolders() function. Azure Storage does not have concept of folder. All folders are actually derived by the paths of the files. So, when listing the blobs, we can use $blob->IsPrefix to distinguish the derived folders and the files.

    If a user want to create a folder and upload the file to the folder, we need to put the folder into the session. That is how GetSessionFolders() function come from.

    When upload a file, we have to handle the Flash format. It seems that modern browsers are intelligent enough to recognize image files like JPEG, GIF, PNG without the content type. When it comes to Flash file, it could not be played properly.
    function FileUpload( $resourceType, $currentFolder, $sCommand ) {
    ...
     $sFileName = 'uploadedfiles/'. strtolower($resourceType).$currentFolder.$sFileName;
     $result = $blobStorageClient->putBlob($ContainerName, $sFileName,  $oFile['tmp_name']);
    
     if(strtolower($resourceType) == 'flash') {
      $contentType = 'application/x-shockwave-flash';
      $blobStorageClient->setBlobProperties($ContainerName,  $sFileName, null, array('x-ms-blob-content-type' => $contentType));
     }
     $sFileUrl = $currentFolder.$sFileName;
    ...
    }
    

    ASP.NET
    For the ASP.NET portal, we have to do the same. Under /editor/filemanager/connectors/aspx/connector.aspx, we changed the first line to
    <%@ Page Language="c#" Trace="false" Inherits="FCKAzureAdapter.Connector" AutoEventWireup="false" %>
    

    The connector is simply extending FredCK.FCKeditorV2.FileBrowser.Connector and override the GetFiles(), GetFolders(), and CreateFolder() methods with Azure API. Here is an example of GetFolders():
    protected override void GetFolders(System.Xml.XmlNode connectorNode, string resourceType, string currentFolder) {
        string sServerDir = this.ServerMapFolder(resourceType, currentFolder);
    
        // Create the "Folders" node.
        XmlNode oFoldersNode = XmlUtil.AppendElement(connectorNode, "Folders");
    
        CloudBlobContainer container = GetCloudBlobContainer(containerPath);
        var dir = container.GetDirectoryReference(folder);
    
        var items = dir.ListBlobs();
        List<string> dirList = new List<string>();
        foreach (var x in items.OfType<CloudBlobDirectory>())
        {
            dirList.Add(x.Uri.ToString());
        }
        var dirs = dirList.Select(o => o.Substring(o.LastIndexOf('/', o.Length - 2)).Replace("/", "")).ToArray();
    
        Dictionary<string, List<string>> folderList = 
                HttpContext.Current.Session["Folders"] as Dictionary<string, List<string>>;
        foreach (var dir in dirs)
        {
            // Create the "Folder" node.
            XmlNode oFolderNode = XmlUtil.AppendElement(oFoldersNode, "Folder");
            var dirName = dir.Uri.GetName();
            XmlUtil.SetAttribute(oFolderNode, "name", dirName);
            if (folderList != null && 
                folderList.ContainsKey(resourceType) 
                && folderList[resourceType].Contains(dirName))
            {
                folderList[resourceType].Remove(dirName);
            }
        }
    
        if (folderList != null && folderList.ContainsKey(resourceType))
        {
            foreach (var folder in folderList[resourceType].Where(o => o != currentFolder && o.StartsWith(currentFolder)))
            {
                var folderName = folder.Substring(currentFolder.Length).Trim('/');
                if (!folderName.Contains('/')) {
                    // Create the "Folder" node.
                    XmlNode oFolderNode = XmlUtil.AppendElement(oFoldersNode, "Folder");
                    XmlUtil.SetAttribute(oFolderNode, "name", folderName);
                }
            }
        }
    }
    Then, we do the same for editor/filemanager/connectors/aspx/upload.aspx.

    Next time, we will discuss what other problems we have encountered.

    Thursday, March 03, 2011

    PHP-Azure Migration - Part 3

    In the previous post, we have fixed all database queries to make the web site start working in SQL Server. The next task is tackling the file I/O without the file system. The file system is not a permanent storage in Windows Azure. We need to copy all resource files (file attachments of articles) from the local file system to Azure Storage.

    File Migration
    The migration seemed quite straight forward. We can just copying the file to Azure Storage. However, there is no FTP or any batch utilities from Microsoft for batch upload. Given we have 4GB of files with some hierarchical directories, it is infeasible to the files one by one. We used Cloud Storage Studio for the migration.

    URL Redirection
    The web site and the resource files are now in different servers. We can no longer use relative path. However, since the database is storing the relative path of the resource files, we either change the data (as well as semantics) to store the absolute URIs of the resource files; or redirect the browser to get the files from the correct URLs.

    As changing the data would involve a lot of testings in business logics, we decided to create a ASP.NET Module to redirect the requests. Given that
    1. IIS (as well as Windows Azure) allow us to call ASP.NET Module in any web site (including PHP web site)
    2. All files were stored in a particular folder so we could derive the redirect pattern easily
    Now, all existing files have been migrated and will be redirected to new URL. Next time, let's take a look how to deal with new uploaded files.

    Monday, November 15, 2010

    Jeans - Running Java Servlet and JSP Webapp in ASP.NET/IIS - Part 4

    Retrieving a database connection is one of the most popular problem in software development. Usually, we specify the connection string in a configure file and create the database connection with the connection string. The Java way is wrapping connection string in a javax.sql.DataSource interface and put in the application server config. The application server will put the DataSource instance into a JNDI context. So, this is what should be supported.

    Bring in the Unity
    Microsoft has a Dependency Injection container called Unity. Even though I am not doing dependency injection, I'd like to configure how to instantiate the data source in web.config. Instead of writing my own configuration classes, Unity is a good alternative as an object builder.

    Before doing any configuration, the JDBC driver has to be compiled into .Net assembly since it will be loaded by Unity instead of the Java class loader.

    Method Injection
    When configuring Unity, we could specify the methods to be called during the instance initialization. The first attempt:
    <method name="setURL">
        <param name="url" value="..." />
    </method>

    However, Unity was smart enough to know there is no such parameter name. I fired-off the object explorer to look the actual parameter name. It seemed that IKVM compiled all parameter name with str, str1, str2, etc. The configuration has to be like this:

    <method name="setURL">
        <param name="str" value="..." />
    </method>


    JNDI Context
    Having known that a data source with the name jdbc/testDS is the same as java:comp/env/jdbc/testDS, I tried to mimic the behavior with the reference of this article. It turned out the result is an exception:
    javax.persistence.PersistenceException: Exception [EclipseLink-7060] (Eclipse Persistence Services - 2.0.2.v20100323-r6872): org.eclipse.persistence.exceptions.ValidationException
    Exception Description: Cannot acquire data source [jdbc/testDS].
    Internal Exception: javax.naming.NameNotFoundException: Name jdbc is not bound in this Context
        at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:399)

    So, I reverted to the simpliest way by just creating the jdbc subcontext in the initial context.

    Password
    The configuration was set. Time to run the test. It did not work:
    javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.2.v20100323-r6872): org.eclipse.persistence.exceptions.DatabaseException
    Internal Exception: com.microsoft.sqlserver.jdbc.SQLServerException: Login failed for user 'jsptest'.
    Error Code: 18456
        at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:399)


    Well, the password was copied from persistence and very simple:
    <method name="setPassword">
        <param name="str" value="passw0rd" />
    </method>

    Not sure what happened but when the user and password were put in the URL, it worked.

    The new source code has been checked-in in http://jeans.codeplex.com/. The persistence.xml has changed to use the <non-jta-data-source>jdbc/testDS</non-jta-data-source>.

    Note: sqljdbc4.jar has been removed from the source repository. Please download it from Microsoft and compile it with IKVM to run the JSP demo site.

    Jeans - Running Java Servlet and JSP Webapp in ASP.NET/IIS - Part 3

    Developing Java webapp, we use of Filter for cache control, compression, database connection and transaction handling. So, Filter is another feature I need to support.

    Original Thought
    In ASP.NET, IHttpModule is like a filter while IHttpHandler is like a servlet. It seemed obvious to modify the existing ServletModule to execute the filter.

    Platform Mismatch
    The first problem I found is the async design of ASP.NET. The IHttpModule is an event sink and need to implement the event handlers for events like BeginRequest, EndRequest. In contrast, Servlet Filter is using FilterChain to call the filter one by one. I tried to execute the filter chain in BeginRequest event. However, I won't be able to gain the access of Session. Having google around, I found the comprehensive events execute sequence in IHttpModule (http://msdn.microsoft.com/en-us/library/ms178473.aspx):
    • BeginRequest
    • AuthenticateRequest
    • PostAuthenticateRequest
    • AuthorizeRequest
    • PostAuthorizeRequest
    • ResolveRequestCache
    • PostResolveRequestCache
    • PostMapRequestHandler
    • AcquireRequestState
    • PostAcquireRequestState
    • PreRequestHandlerExecute
    • PostRequestHandlerExecute
    • ReleaseRequestState
    • PostReleaseRequestState
    • UpdateRequestCache
    • PostUpdateRequestCache
    • EndRequest
    • PreSendRequestHeaders
    • PreSendRequestContent
      To get the session, the module needs to implement an event handler for PostRequestHandlerExecute event. In order to get the Session, HttpContext.Current.Handler has to be implementing IRequiresSessionState as well.

      There is code to wrap the HttpContext.Current.Handler around (http://stackoverflow.com/questions/276355/can-i-access-session-state-from-an-httpmodule). It worked fine but it does not solve the async problem.

      From Module to Handler
      I managed to run the filter chain in PreRequestHandlerExecute event. It turned out that not only it run the JSP code, but also the source code of the JSP was also append to the result by the default handler. Response.End() has to be invoked. And then some checking for the whether it is my own servlet handler, etc. The code is a bit weird.

      Since it does not matter where the filter chain is executed, I moved to code to ServletHandler and revert the changes in ServletModule, it compiled and seemed working with the Hello World JSP. No more Response.End() and checking. Async problem is solved since executing the filter and servlet are in one place. It matched the semantics of Java webapp.

      Testing
      The simplest way to test is to get a filter that GZIP the output and use fiddler to see if the response is compressed. I grabbed filter from http://onjava.com/pub/a/onjava/2003/11/19/filters.html. Added the setting in web.xml. Somehow it does not work. It turned out it's because the default XML namespace in web.xml generated by Eclipse caused the problem. Removing the namespace made enabled the support of filter.

      XML Namespace
      The default XML namespace is quite annoying. I am not sure why it is there as it is meaningless. I tried a few way to remove it with the .Net XML API but the namespace somehow stayed there. The final resort was invoking string.Replace() to get rid of it.

      The latest source code has been checked-in in http://jeans.codeplex.com/.

      Saturday, November 13, 2010

      Jeans - Running Java Servlet and JSP Webapp in ASP.NET/IIS - Part 2

      One of my mentors said, "If you do not write SQL, you cannot do application development." Even though the statement is not quite true as there are ORM frameworks handling the database communication, the statement emphasizes the importance of database. So, running a pure Hello World JSP is a poor proof of concept to ASP.NET. Running a database connected JSP is more meaningful.

      Preparation
      The following components were gathered in this phase:
      • JPA - the current standard of doing ORM in Java.
        •  EclipseLink is the reference implementation. It should serve the purpose well.
      • SQL Server 2008 Express - As ASP.NET is being used anyway, why don't we work in the whole Microsoft ecosystem?
        • SQL Server JDBC Driver - Yes, I need a JDBC Driver in .Net...
      • AdventureWorksLT - Microsoft used to provide sample databases that works with SQL Server. AdventureWorksLT is the simplified version.
      One bottleneck I have is I have no JPA experience. I used Hibernate before but JPA is a standard. The problem of being standard is there are many implementations. The only way to understand it is to read the specification. Otherwise, it's hard to understand how it works in general so that it works for most (if not all) implementations.

      META-INF/persistence.xml
      One of the challenges encountered was loading the persistence.xml. Luckily, IKVM can load the resource files with by specifying -classloader:ikvm.runtime.ClassPathAssemblyClassLoader when the compiling the class files and JAR files into .Net assembly. However, since all files were compiled into a single DLL. Only the first persistence.xml IKVM read can managed to be the resource.

      META-INF/orm.xml
      The problem of compiling everything into .Net assembly is losing all annotations in the classes. In the other words, you must use META-INF/orm.xml and initialize it in an IHttpModule.

      Rework
      The limitation of loading the two XML files is quite nasty. It would not feasible for medium size application that might have a few JAR files containing persistence.xml. Creating orm.xml manually is quite a pain as you know the information is in the classes already. To increase the flexbility, ClassPathAssemblyClassLoader is is wrapped by an URLClassLoader with the following classpaths:
      1. WEB-INF\classes 
      2. All JAR files in WEB-INF\lib directory
      Then, it is invoked to the current thread's context class loader to load the JAR and the precompiled JSP classes directly. It works!

      Dual Mode
      Now, Jeans support two ways to run a Java webapp:
      1. Native mode - With everything compiled into a single DLL
      2. WAR mode - Run a standard Java webapp directory whose structure is the same as in WAR file given:
        1. JSP are precompiled into servlet and put into WEB-INF/classes folder.
        2. JSP Servlet mappings are stored in jspweb.xml to complement the original web.xml.
      The consequence is quite obvious. In native mode, it takes around 50MB of memory to load the Hello World page. In WAR mode, it takes around 100MB of memory the run the same page. No benchmark for the application performance but I believed native mode should run faster.

      Friday, November 12, 2010

      Jeans - Running Java Servlet and JSP Webapp in ASP.NET/IIS - Part 1

      There are two main camps in enterprise server technology market, Java and .Net Framework. Java side has Servlet, JSP, and Java ServerFace. .Net Framework side has ASP.NET (WebForm and MVC). Both sides are not compatible with each other. This article will describe how to run JSP in IIS natively without connecting to a Java web container.

      IKVM
      Mr. Jeroen Frijters has implemented an JVM in .NET, IKVM.NET. It seems to be a good start.

      Jetty vs. Tomcat
      The first attempt was compiling Jetty to execute web applications directly. Digging into the source code and after a few trials, I found that Jetty is using Jasper library, which is Tomcat's JSP engine, to run JSP. Given that .Net does not have the concept of class file, it is unlikely .NET is able to load the create new class and load it into memory in runtime.

      JSP Precompiler
      Jasper not only is the runtime engine of JSP, it also includes a JSP precompiler to compile JSP into Servlet. Using it is not hard but type the Java command is tedious. It makes sense to use IKVM to create a .Net executable. The Jasper library from Tomcat 5.5 is used:

      • ant.jar
      • catalina-ant.jar
      • commons-el.jar
      • commons-logging-api-1.1.1.jar
      • jasper-compiler-jdt.jar
      • jasper-compiler.jar
      • jasper-runtime.jar
      • jsp-api.jar
      • naming-factory-dbcp.jar
      • naming-factory.jar
      • naming-resources.jar
      • servlet-api.jar

      Then compile the precompiler with this command:
      ikvmc -classloader:ikvm.runtime.ClassPathAssemblyClassLoader -target:exe -main:org.apache.jasper.JspC -out:bin\jspc.exe *.jar

      JSP Compilation
      The command-line arguments of JspC is the same as the Java version. The following command can be used (%1 is the directory of the target web application):
      jspc -uriroot "%1" -d out -compile -v -webxml "%1\WEB-INF\jspweb.xml" -trimSpaces -source 1.5 -target 1.5

      The JSP
      The first JSP is a simple Hello World page to test out the JSTL EL:
      Hello ${param.name}!

      Web Application Compilation
      Everything are still in JARs and classes. However .Net Framework needs DLLs. The following command is executed to get everything in .Net assembly:
      ikvmc -classloader:ikvm.runtime.ClassPathAssemblyClassLoader -recurse:%1\WEB-INF\classes -out:%1\bin\jsp.dll -reference:%1\bin\jspc.exe %1\WEB-INF\lib\*.jar

      Servlet API, in .Net
      Before running the DLL, the following classes are necessary in the Servlet API to run the JSP:
      • HttpServletRequest/Response
      • ServletInputStream/OutputStream
      • ServletRequestDispatcher
      • ServletContext
      • ServletConfig
      and a few more adapters to implement Java I/O.

      ASP.NET IHttpModule and IHttpHandler
      The final bit is the ASP.NET module to initiate the configuration and the handler to execute the servlets/JSP.

      I have made the source code available so you don't need to go through the whole process. Please visit http://jeans.codeplex.com/.

      Saturday, March 14, 2009

      Secure WCF Services with Authentication Service

      We can use WCF Authentication Service to authenticate users with ASP.NET membership provider. However, other WCF services are not protected by the authentication service out-of-the-box. That is, WCF services is not using ASP.NET forms authentication.

      Fortunately, it is not hard to enable it. The magic point is set the HttpContext.Current.User in Global.asax
      public class Global : System.Web.HttpApplication
      {
      // other methods snipped...
      protected void Application_AuthenticateRequest(object sender, EventArgs e)
      {
      HttpCookie ticketCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
      if (null == ticketCookie)
      {
      return;
      }

      FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(ticketCookie.Value);
      if (null != ticket)
      {
      HttpContext.Current.User = new GenericPrincipal(new FormsIdentity(ticket), null);
      }
      }
      }
      In the service you want to protect, set the requirement mode to allowed or required.
          [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
      public class PrimeService : IPrimeService
      Then, throw in the following checking at the beginning of the method.
                  if (!HttpContext.Current.User.Identity.IsAuthenticated)
      {
      throw new FaultException<SecurityAccessDeniedException>(new SecurityAccessDeniedException());
      }
      That would be good enough for Silverlight client. For .Net WCF client, you need to handle the HTTP cookies by yourself (Authentication Service is using the authentication ticket in cookies). Detail discussion can be found in the article in Shane's Shelf.

      Saturday, November 01, 2008

      Improving ASP.NET Web Performance with Local SMTP Server

      Implementing public web site, we usually need an SMTP server for registration verification, reset password notification, etc. We usually utilize existing email infrastructure to send the email. However, we may not have the control of the infrastructure. The SMTP server may locate overseas or may go down sometime. In these cases, the response of the web server seems slow. We can setup the SMTP in local server to resolve the problem.

      How does SMTP works?
      There is a special record in DNS called MX record (Mail eXchange record). Using a@b.com as an example. The SMTP server inquires the MX record of b.com to resolve the SMTP server that will receive the email.

      SMTP Setup in Windows
      Windows comes with SMTP service in XP, 2003, Vista, and 2008. It can be configured with the following steps
      1. In IIS Manage, right click Default SMTP Virtual Server, choose Properties
      2. Choose Access tab and click the Relay button at the bottom in Relay restriction section. An SMTP relay lets an SMTP client use an SMTP server to forward e-mail messages to a remote domain. By default, it is disabled so you cannot send any email.
      3. Add your local host address to allow your local application to send email. You can even add your internal network address so your other machine can use this as the SMTP relay.
      4. Optionally, you can prohibit the external connection by configuring the Connection control section.

      Since SMTP will queue the email and return, it responses instantly. The web performance also improves instantly, too.