Thoughts from Dan Miser RSS 2.0
 Monday, March 06, 2006
Here's an article from MSDN that talks about how to host your .NET Remote objects in an NT Service. Also be sure to check out the information on the ServiceController class to work with NT Services programatically and the ServiceInstaller class. Lastly, this article talks about how to debug and deploy NT Service applications.
Monday, March 06, 2006 10:12:00 AM (Central Standard Time, UTC-06:00)  #    Comments [0] -

 Friday, March 03, 2006
First things first: I hate that ASP.NET forces you to put all assemblies in a bin subdirectory. To make matters worse, there is no way to change the private probing path in an ASP.NET application. Couple this with the directory structure that VS.NET creates for projects (e.g. MyProject\bin\Debug), and you end up with the fact that you can't simply create a virtual directory that points to the location of your assemblies that were generated by doing a build in VS.NET

I couldn't find anything to easily deploy my project with remote objects and a web.config to an ASP.NET virtual directory. I did see some documentation about Visual WebDeveloper, but I don't have that installed here. Perhaps I didn't install it when I installed VS.NET. Regardless, I really don't want to go back to install this since I'm not creating aspx pages and the like, but I do want to host my remoting objects in IIS (more details on this in a later post).

What I ended up doing was using the post-build Build Event to create events to copy the files over to the IIS directory, e.g.:

copy $(TargetDir)\*.* \inetpub\wwwroot\tipnet\bin
copy $(ProjectDir)\web.config \inetpub\wwwroot\tipnet

At least this way, my IIS files stay in sync with what I just compiled. It might not be the most beautiful thing ever, but it works.

Friday, March 03, 2006 10:05:00 AM (Central Standard Time, UTC-06:00)  #    Comments [2] -

 Thursday, March 02, 2006
Building on my last post on .NET Remoting Sinks, you may notice that when you define a serverProvders block in the config file, you no longer are able to reference the WSDL from your remote object (e.g. http://localhost/tipnet/MyAppServer.rem?wsdl). The reason for this is that when there is no serverProviders block, .NET creates a few default sinks, including the sink that generates WSDL output of your object. However, when you define sinks manually, .NET expects you to explicitly list all of the sinks that you want to use. The WSDL output is generated by the SdlChannelSink class. So to get WSDL back with your custom sinks, simply use a block like this:
<serverProviders>
   <formatter ref="binary" />
   <provider ref="wsdl" />
   <provider type="LoggingSink.ServerSinkLoggerProvider, LoggingSink" />
</serverProviders>

The ref syntax is a shorthand way of referencing the SdlChannelSink class. You could use the full type name by specifying the strong name of the SdlChannelSink class if you wish, but this is much easier.

Thursday, March 02, 2006 8:11:00 AM (Central Standard Time, UTC-06:00)  #    Comments [0] -

 Tuesday, February 28, 2006
When writing server-side sinks, it's important to remember that order matters when declaring your sinks. For example, consider the following block in a config file:

<serverProviders>
	<provider type="LoggingSink.ServerSinkLoggerProvider, LoggingSink" />
	<formatter ref="binary" typeFilterLevel="Full" />
</serverProviders>

The problem here is that if ServerSinkLoggerProvider is a class that implements IServerChannelSink, the requestMsg parameter will be null in the ProcessMessage method. If you reverse the ordering of the 2 lines (i.e. put the formatter first), everything works fine.

This is by design, and due to the chaining of sinks that occurs in .NET Remoting. In the first case, the formatter has not yet deserialized the message, so we can't easily get to the IMessage that was passed to us. In the second case, the formatter takes care of the deserialization first, and can then pass the IMessage to the DispatchChannelSinks for further processing and investigation. The overview of .NET Remoting layers from MSDN is lacking a lot of detail, but hints at what causes the differences. Once I went back to Ingo Rammer's book, the technical reason for this behavior became obvious.

Tuesday, February 28, 2006 9:02:00 AM (Central Standard Time, UTC-06:00)  #    Comments [0] -
.NET
 Monday, February 27, 2006
I use OutputDebugString (ODS) a lot when trying to trace through a problem with an application. Coupled with using DebugView from SysInternals, you can easily get a real good idea of where things are going wrong.

In .NET, you use Debug.WriteLine() to write ODS messages. This requires that your assemblies be built with DEBUG information to see the ODS messages. When working with ASP.NET pages, you have a some options to achieve this (the easiest couple are listed here):

  1. Include the Debug attribute in the Page tag for the aspx page. For example:
    
    <%@ Page language="c#"  Debug="true"%>
    Testing:<br>
    <%
    System.Diagnostics.Debug.Write("Testing");
    %>
    
  2. Include the debug attribute in the web.config file. For example, put this in a section underneath the <configuration> node. You can also do this by changing the config file when running the IIS Manager, selecting Properties for the Virtual Directory, going to the ASP.NET page, selecting Edit Configuration, going to the Application tab, and selecting Enable Debugging.
    
      <system.web>
        <compilation debug="true" defaultLanguage="c#" />
      </system.web>
    

Monday, February 27, 2006 2:17:00 PM (Central Standard Time, UTC-06:00)  #    Comments [1] -

 Tuesday, February 21, 2006
Someone on the newsgroups posted a linke to SourceMonitor. It is a tool that analyzes source code (Delphi, C++, C#, Java, VB, C, and HTML) and reports on various code metrics, like the number of lines of code, average statements per method, methods per class, depth of method, global routines and variables, cyclomatic complexity of a method and tons more. The charts are incredible (Kiviat graphs that are configurable with tolerance levels), and you can drill down and sort by any criteria. By doing this, you can identify methods that need to be refactored. In addition, you can View Source on the details and get buttons to take you straight to various offending code metrics (max depth, max complexity method, etc.). The detail view also shows graphs and more information about each unit. Lastly, you can take multiple snapshots so you can monitor progress of your source code's health over time.

This tool is listed as being freeware, but this is one instance where you get WAY more than you pay for.

Tuesday, February 21, 2006 1:04:00 PM (Central Standard Time, UTC-06:00)  #    Comments [3] -
Delphi
 Monday, February 20, 2006
This entry is a quick one, pointing out a couple of ADO.NET related links that I came across today.

Blog entry showing how to add Primary Keys to GetSchema in SqlClient - you could also extend this logic to add other database-specific metadata to any ADO.NET provider

Introduction to Visual Studio Data Designer Extensibility (DDEX) - this shows how you can add/customize functionality to the ServerExplorer in VS.NET.

Monday, February 20, 2006 1:16:00 PM (Central Standard Time, UTC-06:00)  #    Comments [0] -
ADO.NET
 Friday, February 17, 2006
SmartInspect is a new logging tool published by Gurock Software. This tool works with Delphi (including BDS2006), .NET and Java applications.

By adding some simple code to your application, you can get SmartInspect to keep track of the logging in a meaningful way (by process, thread, method, session, etc.). Log events that are "children" of other events can be rolled up and grouped to allow you to focus precisely on what you're interested in. Logging can be done via file or TCP/IP, so you can coordinate log messages from multiple machines. Source code is included for the objects that SmartInspect uses, and you can extend the objects to do whatever you dream up (filter packets, automatically colorize certain events, etc.). You can even install Code Snippets/Templates into the IDE that you use. There are many more features than this, but those are the ones that really stood out for me.

I would highly recommend this product. This company has gone from nothing to having one of the most professional product experiences I have ever seen. They have a very complete, nice-looking, and easily navigable web site; incredibly great documentation (both in general and for developers); trial versions; multiple support options (forum, knowledge base, and email); a blog; walk through samples; and an extremely well-polished user interface. I wish all companies came on to the scene with such a thorough attention to detail.

In short, great job guys. I look forward to using this product more as time passes.

Friday, February 17, 2006 2:33:00 PM (Central Standard Time, UTC-06:00)  #    Comments [4] -
Delphi
 Thursday, February 16, 2006
There are times when you get painted into a corner. Some times, you paint yourself in, and some times, you get painted in by others. If you do it to yourself, it is much easier to get out by just changing all of the things needed to get out of the jam. Other times, your hands are tied and you can only make changes to specific areas of code, like the implementation section. A couple of reasons for this would be to preserve binary compatbility of a published interface for your framework, or a 3rd party component relies on that dcu compatibility of another 3rd party. Given all of the above, what do you do if you want to add a property to an existing class without changing the interface section of that unit? I came up with the following hack to get this done, but be cautioned, this is definitely not for the squeamish! :)

Let's say you have a setup like the following:


unit uExtenderTypes;

interface

type
  TType = class
  private
    FID: integer;
  public
    procedure Display;
    property ID: integer read FID write FID;
  end;

function GetType: TType;

implementation

uses
  SysUtils, Dialogs;

var
  gblType: TType = nil;

function GetType: TType;
begin
  if gblType = nil then
    gblType := TType.Create;
  Result := gblType;
end;

procedure TType.Display;
begin
  ShowMessage(IntToStr(ID));
end;

finalization
  if Assigned(gblType) then
    FreeAndNil(gblType);
end.

As time passes, you realise you want to only do the ShowMessage some of the time, and to do this you think a CanDisplay property would be perfect on the TType class. But remember, you can't change the interface section. You can add code like this to get things ready (only the changed section is listed here):


{$M+}
type
  TDerivedType = class(TType)
  private
    FCanDisplay: boolean;
  published
    property CanDisplay: boolean read FCanDisplay write FCanDisplay;
  end;
{$M-}

function GetType: TType;
begin
  if gblType = nil then
    gblType := TDerivedType.Create;
  Result := gblType;
end;

procedure TType.Display;
begin
  if (Self is TDerivedType) and TDerivedType(Self).CanDisplay then
    ShowMessage(IntToStr(ID));
end;

Note that the main changes are to add the new class - derived from the base class - in the implementation section; update the singleton TType return function; and update the Display method to conditionally display the message.

In order to set this property, we will rely on RTTI since callers outside the scope of this unit will have no idea what the TDerivedType is. The code for this would look similar to this:


procedure SetCanDisplay(t: TType; Value: boolean);
begin
  if IsPublishedProp(t, 'CanDisplay') then
    SetOrdProp(t, 'CanDisplay', ord(Value));
end;

procedure TForm3.btnDerivedClick(Sender: TObject);
var
  t: TType;
begin
  t := GetType;
  t.ID := 30;

  SetCanDisplay(t, true);
  try
    t.Display;
  finally
    SetCanDisplay(t, false);
  end;
end;

Obviously, this technique should only be used as a last result. However, it can get you out of that tight spot for a little while, and the changes are pretty well self-contained so you can do it right when building the next version.

Thursday, February 16, 2006 8:57:00 PM (Central Standard Time, UTC-06:00)  #    Comments [2] -

Navigation
Archive
<March 2006>
SunMonTueWedThuFriSat
2627281234
567891011
12131415161718
19202122232425
2627282930311
2345678
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2008
Dan Miser
Sign In
Statistics
Total Posts: 306
This Year: 21
This Month: 0
This Week: 0
Comments: 604
All Content © 2008, Dan Miser
DasBlog theme 'Business' created by Christoph De Baene (delarou)