tsJensen

A quest for software excellence...

SharpZipLib and Kudos to Scott Galloway

I had to get an object serialized to a byte[] and then compress it using SharpZipLib and gzip and then decompress it and deserialize it to the original object. The serialization was easy but for some reason I was struggling with using the GZipOutputStream and GZipInputStream compression providers in the SharpZipLib library.

Then I found Scott Galloway's compression helper. I highly recommend it. Anyway, here's the code without the helper. Visit Scott's blog for that.

 public class ResultSerializer
 {
  public static byte[] Serialize(ResultData data)
  {
   //convert to byte[]
   IFormatter frm = new BinaryFormatter();
   MemoryStream ms = new MemoryStream(8096);
   frm.Serialize(ms, data);
   byte[] serial = ms.ToArray();
   ms.Close();
   byte[] retval = ZipUtil.Compress(serial);
   return retval;
  }
  public static ResultData Deserialize(byte[] zipData)
  {
   byte[] data = ZipUtil.DeCompress(zipData);
   //now deserialize
   IFormatter frm = new BinaryFormatter();
   MemoryStream datams = new MemoryStream(data, 0, data.Length);
   ResultData retval = (ResultData)frm.Deserialize(datams);
   return retval;
  }
 }

Note that I renamed Scott's helper "ZipUtil" for my own reasons.

ASP.NET and IPC Remoting

I'm creating a .NET 2.0 ASP.NET web service as a front end to several Windows Services (also built using .NET 2.0) and want to use IPC since the web service and the Windows Services will be running on the same machine.

I don't want to use XML configuration files. I want to do it in code. It works with a console app to the Windows Service, but the ASP.NET web service blows chunks.

Failed to connect to an IPC port:  Access Denied

Search. Search. Search. One clue about "authorizedGroup" = "Everyone" but no code. Tinker. Stumble. Search. Tinker. Finally. Here's the final result in the Windows Service server:

Dictionary<string, string> props = new Dictionary<string, string>();
props.Add("authorizedGroup", "Everyone");
props.Add("portName", "ServerPortName");
serverChannel = new IpcServerChannel(props, null);
ChannelServices.RegisterChannel(serverChannel, true);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(MarshalByRefObjectSubClass),
   "ServerAppName", WellKnownObjectMode.SingleCall);
serverChannel.StartListening(null);

With the client setup like this in the web service:

using System;
using System.Data;
using System.Configuration;
using System.Threading;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using MyRemotingInterfaces;

public class RemotingClientFactory
{
   private static Mutex mut = new Mutex();
   private static WellKnownClientTypeEntry remoteEntry;
   private static IpcClientChannel remoteChannel;
   private static string remoteUrl = "ipc://RemoteExampleRemoteServer/RemoteExampleRemote";

   static RemotingClientFactory() { }

   public static IMyRemoteObject CreateRemote()
   {
      if (remoteChannel == null || remoteEntry == null)
      {
         mut.WaitOne();
         try
         {
            if (remoteChannel == null)
            {
               remoteChannel = new IpcClientChannel();
               ChannelServices.RegisterChannel(remoteChannel, true);
            }
            if (remoteEntry == null)
            {
               remoteEntry =
                 new WellKnownClientTypeEntry(typeof(MyRemotingInterfaces.IMyRemoteObject),
                       remoteUrl);
               RemotingConfiguration.RegisterWellKnownClientType(remoteEntry);
            }
         }
         finally
         {
            mut.ReleaseMutex();
         }
      }
      try
      {
         IMyRemoteObject obj =
          
(IRemoteExampleRemote)Activator.GetObject(remoteEntry.ObjectType, remoteUrl);
         return obj;
      }
      catch(Exception e)
      {
         //TODO log then rethrow
         throw e;
      }
   }
}

And it works like a charm. It's not perfect, I'm sure. But it's a start. And it didn't seem like anyone had or wanted to post their solution to the newsgroups or anywhere else I could find.

Let me know if you find a better way or if this helps you. And good luck.

Easy Debug Windows Service

I know this problem has been solved many times and written about many times, but every time I go to create a new Windows Service project, I end up re-researching how to debug and step through code in a Windows Service project in Visual Studio.

I've done it now, again, building my first real set of Windows Service projects in Visual Studio 2005 and this time I took the compiler directive approach. It's been done before, sure, and many have written about it, but for my own short term memory's sake, here's my solution.

Step One
Create the Windows Service project using the New Project wizard and the Windows Service template.

Step Two
Modify the nicely created program.cs file as follows:

using System;
using System.Collections.Generic;
using System.ServiceProcess;
using System.Text;

namespace YourNameSpace
{
#if (DEBUG)
   class Program
#else
   static class Program
#endif
   {
      /// 
      /// The main entry point for the application.
      /// 
#if (DEBUG)
      static void Main(string[] args)
#else
      static void Main()
#endif
      {
#if (DEBUG)
         ServiceRunner sr = new ServiceRunner();
         sr.Start(args);
         Console.WriteLine("Started... Hit enter to stop...");
         Console.ReadLine();
         sr.Stop();
#else
         ServiceBase[] ServicesToRun;
         ServicesToRun = new ServiceBase[] { new Service1() };
         ServiceBase.Run(ServicesToRun);
#endif
      }
   }
}

Step Three
Modify the Service1.cs file as follows:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;

namespace YourNameSpace
{
   public partial class Service1 : ServiceBase
   {
      private ServiceRunner serviceRunner = null;
      public Service1()
      {
         InitializeComponent();
         serviceRunner = new ServiceRunner();
      }

      protected override void OnStart(string[] args)
      {
         serviceRunner.Start(args);
      }

      protected override void OnStop()
      {
         serviceRunner.Stop();
      }
   }

   internal class ServiceRunner
   {
      public void Start(string[] args)
      {
         //TODO: Add code that will execute on start.
      }
      public void Stop()
      {
         //TODO: Add code that will execute on stop.
      }
   }
}

Step Four
Change the output type (in properties page of the project) to console application.

Now debug away!

OpenNLP for .NET

I recently ran into Richard Northedge's excellent article and C# rendition of the OpenNLP libraries as posted on Code Project. It's a fascinating toolset that presents common, ordinary coders like me with the opportunity to explore and build solutions previously the exclusive domain of guys with thick black plastic frames and lab coats.

I just wish I'd had this tool back in high school when the English teacher was having us waste our time diagramming sentences. But I doubt one could have stuffed this sort of code into a Commodore PET with 32K of RAM and a 4Khz 8 bit 6502 processor. Ah, those were the days. Life was simple. But not nearly so much fun as now.

I don't pretend to understand everything in the OpenNLP library, but I'm learning. Currently I'm exploring how this library might help me in search and content analysis for an ongoing project. As I learn more, I'll post more. For now, I'd love to hear from you if you've had any experience in building real-world applications using this library (even if it was the original java incantation).

WSDL.EXE Problem in .NET 2.0

I wanted to play with the Amazon Alexa Web Search Platform (AWS) web service, so I fired up Visual Studio 2005 and created a new Windows Forms project. I then tried to add a web reference to the AWS url. The GUI interface to wsdl.exe threw up all over it, so I tried it manually after running the trusty sdkvars.bat to make sure my environment variables were set. Here's the result (not pretty):

------------------------------------------------------------------------------------------------------
c:\>wsdl /o:test.cs http://awis.amazonaws.com/AlexaWebSearchPlatform/2005-12-01/AlexaWebSearchPlatform.wsdl
Microsoft (R) Web Services Description Language Utility
[Microsoft (R) .NET Framework, Version 2.0.50727.42]
Copyright (C) Microsoft Corporation. All rights reserved.
Error: There was an error processing 'http://awis.amazonaws.com/AlexaWebSearchPlatform/2005-12-01/AlexaWebSearchPlatform.wsdl'.
- The document at the url http://awis.amazonaws.com/AlexaWebSearchPlatform/2005-12-01/AlexaWebSearchPlatform.wsdl was not recognized as a known document type.

The error message from each known type may help you fix the problem:
- Report from 'DISCO Document' is 'Discovery document at the URL http://awis.amazonaws.com/AlexaWebSearchPlatform/2005-12-01/AlexaWebSearchPlatform.wsdl could not be found.'.
- The document format is not recognized.
- Report from 'WSDL Document' is 'There is an error in XML document (140, 3).'.
- The element was not expected in this context: ... Expected elements: http://www.w3.org/2001/XMLSchema:include, http://www.w3.org/2001/XMLSchema:import, http://www.w3.org/2001/XMLSchema:redefine, http://www.w3.org/2001/XMLSchema:simpleType, http://www.w3.org/2001/XMLSchema:complexType, http://www.w3.org/2001/XMLSchema:annotation, http://www.w3.org/2001/XMLSchema:notation, http://www.w3.org/2001/XMLSchema:group, http://www.w3.org/2001/XMLSchema:element, http://www.w3.org/2001/XMLSchema:attribute, http://www.w3.org/2001/XMLSchema:attributeGroup.- Report from 'XML Schema' is 'The root element of a W3C XML Schema should be and its namespace should be 'http://www.w3.org/2001/XMLSchema'.'.

If you would like more help, please type "wsdl /?".
------------------------------------------------------------------------------------------------------

So I wondered how VS .NET 2003 would do with Amazon's WSDL. Changed directories to make sure I was running 1.1 of wsdl.exe and ran the same command line. It ran flawlessly. Here's the output:

------------------------------------------------------------------------------------------------------
c:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\Bin>wsdl /o:test.cs http://awis.amazonaws.com/AlexaWebSearchPlatform/2005-12-01/AlexaWebSearchPlatform.wsdl
Microsoft (R) Web Services Description Language Utility
[Microsoft (R) .NET Framework, Version 1.1.4322.573]
Copyright (C) Microsoft Corporation 1998-2002. All rights reserved.

Writing file 'test.cs'.
------------------------------------------------------------------------------------------------------

Opened VS .NET 2003 and created a little test project and it created the proxy just fine. I noticed that the WSDL file it created in the project was slightly different from the one downloaded directly from the Amazon URL. Specifically, the nodes with no namespace designation such as <definitions> and <types> now had a namespace prefix <wsdl:definitions> and <wsdl:types> along with the namespace declaration in the <definitions> node changed from xmlns="http://schemas.xmlsoap.org/wsdl/" to xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/".

I closed VS .NET 2003 and opened VS 2005. Now I used the "Add Web Reference" and referenced the local AlexaWebSearchPlatform.wsdl file that VS .NET 2003 had created. Now I have a proxy that at least compiles, but of course it does not reference the Amazon URL directly so update web reference will not work.

I'll start testing using the 2003 to 2005 proxy generated class and report back tomorrow on how well it worked. Meantime, if anyone can tell me how to get the wsdl.exe for .NET 2.0 to behave, I'd appreciate it.

DotNetNuke 4.0 Go To Definition

I spent a few hours this week exploring DNN 4.0 and the team's effort to transform the successful 3.x version into the ASP.NET 2.0 mold. I congratulate the team. They had a lot of work to do and I found the installation and setup easy and the module template is a joy.

Of course, I wish they had chosen C# but that's my own bias. The beauty is that you can add a C# module using the module template right into the DNN web application. Everything seems to work as advertised, EXCEPT...

Open the C# module code generated by the template and right-click on an class name that's part of the DNN source code and select the "Go to Definition" menu option. Hey, where did the code go. I get a C# [meta data] file just like I would with a BCL class rather than the object browser. EXCEPT there is really code available but it's VB.NET.

So I have my first complaint about VS 2005. I'm hoping a reader can help me find the solution. In a mixed language solution, why doesn't the real code open up? Is this a bug or am I missing some configuration thing? First person to help me find the solution get's a $20 Amazon gift certificate, unless I post the solution here first.

One way or the other, I like DNN 4.0 a lot. Sure there's more comprehensive portal and content management systems available, but definitely not for the price. I'm sure I'll run into more trouble as I roll down the .NET 2.0 road, but so far, it's been a lot of fun. Here's to more of it.

Pick Up the Scissors and Run

I've had VS.NET 2005 and SQL Server 2005 installed for a couple of days now. Thanks to the MSDN subscription site. So far, I'm very impressed. The question remains how and when do we make the move. I say, run with the scissors.

The cutting edge, if you can define this as cutting edge, is not quite as sharp as one might think given we've been through beta one and two and the community technology previews (CTP). But for those of you who did install the betas (and by what I've read and heard there are thousands of you), be warned! The SQL Server install is a pain if it detects any whiff of beta. I was finally successful after uninstalling even the previous .NET frameworks.

That said, I'm still recommending running with the scissors. Okay, well, walk quickly anyway. Plan to migrate as quickly as possible without totally disrupting your current development paths. Here's my list of reasons to do it. I'm sure there's many more, but it's a start.

ADO.NET

  • Bulk updates: 1,000,000 row insert for 1.1: 30 minutes; for 2.0: 45 seconds
  • Dataset binary serialization in remoting: faster DS over the wire (up to 6 times smaller)
  • DataTable now supports XML read, write, schema, merge, load
  • DataView.ToTable method allows creation of a new DataTable from a view

C# 2.0

  • Generics: generic class later cast to a specific type. Collections are the best example: a list of some type: List<someType>
  • Anonymous methods: allows code to be passed as a parameter rather than requiring a delegate
  • Partial classes: allows a class to be defined and worked on in two or more files

ASP.NET

  • AJAX: direct support for asynchronous javascript calls to the server with javascript generation automated and easy event handling in the code-behind code of the page.
  • Master pages: allows visual inheritance or a base class page
  • DataSource & ObjectDataSource allow easier binding to data aware controls

Visual Studio .NET 2005

  • Click-Once deployment of smart client
  • Editor: improved color coding and intellisense
  • Debugger will suggest potential problem areas
  • Warnings suggesting specific replacements for code that uses deprecated or obsolete framework objects
  • Debugger allows data visualization: view a dataset in a grid while debugging
  • Conversion of previous VS.NET projects easy, automated, informative reports

SQL Server 2005

  • PIVOT/UNPIVOT allows rows and column rotation
  • APPLY allows use of a UDF in a FROM clause to create a result set with calculated columns
  • TRY/CATCH allows more granular exception handling
  • CTE (Common Table Expressions) allow the creation of a recursive query to produce a hierarchical resultset
  • CLR integration allows stored procedures to be written in C#

ASP.NET is NOT ASP

I enjoy reading Fawcette publications online as one source of industry information, but sometimes for plain old amusement. A recent article with an author byline that begins "by by" did a relatively decent job of comparing J2EE and .NET with a fair bit of praise for ASP.NET, especially in the much anticipated 2.0 incarnation.

The amusement part began with the author's constant reference to ASP.NET as ASP. This is a clear and dead give away that the author has either never used both or has absolutely no pride. I will not pretend to make a comparison of ASP.NET and JSP because I really don't have any real experience with JSP. I have friends that do, and they like it well enough, and that's good enough for me to assume that you can get done what you need to get done in JSP, JSF, etc.

And there have been reams of paper and billions of bytes wasted on enumerating the differences between what is now generally referred to, by those who have been there, as "classic ASP" and ASP.NET. Let me just waste the following words for the author and my Java friends: ASP.NET IS NOT ASP. The only real thing shared between the two is the <% %> tag markers. And just for the record, ASP 2.0 was a long time ago.

ASP.NET is like the guy with Jr. following his name who just knows he turned out so much better than his dad and wonders to himself why the old man thought so much of himself that he had to go and give him the same name.

And the real ASP.NET 2.0 is just days away. I'm like a kid looking in at the candy store, just waiting for doors to open.

And no, I'm not going to give you a link to the story. Like the byline suggested, the story should go bye bye.