Friday, November 09, 2007

So, WPF is the technology that is finally going to realize the vision of allowing developers and designers to work on the same project, using the same assets, at the same time, and have everyone be happy.  I posted quite a ways back that WPF was cool, and posted pictures of my first two efforts as evidence that WPF will also make it easy for developers to do ridiculous and confusing things.  In my "spare time" at work, which right now means "When I get sick of the things I need to be doing"  I am actually working in WPF, with Orcas and the Expression Blend September preview, on a real application that is going into production next year, with assets supplied by real designers.  Real designers with talent, who are used to specific non-MSFT tools, who are windows-hating Mac users who wouldn't fire up Expression Blend if it came with a free puppy and a pound of gold.  It's very early yet, but I think it's going to work because tools are appearing that will export Adobe Illustrator to XAML, and Expression Design can import vector graphics from Illustrator files.  If WPF and Silverlight gain enough traction is it too much to hope that Illustrator (on the Mac, no less) will be able to understand my VS2008 solution file?  Is it too much furthur to hope that maybe a VSS or Subversion plug-in could be written to let them check the assets right in to my source control?

In the past we've often had one of two situations:

  1. The designer jumps into the asp/jsp/<yourTemplateEngineHere> code to design it up.  Code is accidentally broken, or the designer is unsure of which parts can be edited.
  2. You receive a .TIFF or .PNG graphic depicting insane things and the unenviable task of "Turn this into a web page or windows form".  Hilarity ensues.

If we can get to the point where the UI with insane things going on is an Illustrator file that you import and it "just works", we will have accomplished something.  If the black turtleneck Mac using artist can just check in the XAML skin for my programs, life will be good. 

WPF
Friday, November 09, 2007 3:22:08 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, November 07, 2007

I still can't officially blog about what we have going on, but obviously I'm trying to hire people into my department and am traveling.  We've beenn working quite a bit at the 'ole CarSpot lately to make some things happen and over time that takes its toll.  I've been in more meetings than is healthy (by USRDA standards) the past three days, culminating with giving a brief talk to 600 people in Atlanta today.  I'm back home and feeling a little bit recharged mentally.  No matter how much work has to be done inside Visual Studio, or MS-Project, or Power Point, or Thawte, or Expression Blend, it's very good to escape into the real world and spend some time interacting with entities who don't respond to Ctrl+S or CTRL-SHIFT-B

Wednesday, November 07, 2007 11:55:47 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, November 05, 2007

It is, if I am not mistaken, the year 2007.  Why is it that my fancy-pantz hotel room in downtown Atlanta does not just come with Internet access?  Why, further, do they outsource to these companies who's systems seem unerringly to not work the first time?  I don't travel a lot, but I have yet to have Internet access work in a room without calling the front desk or "iBahn" or whatever.  Business travelers flying business class staying in business hotels asking for the corporate rate are highly likely to expect to plug their laptops into the wall and have it work.

Monday, November 05, 2007 9:24:30 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Thursday, November 01, 2007

There are various little gotchas writing software for Vista.  I've posted before about ridiculous things like logging not working.  You must use the Admin token to write to the Program Files directory so in some cases your program will silently fail and create no logs.  I've also been looking for a way to elevate a single action from .NET: an application that can run without elevation but has a button with the cute shield icon that invokes an action that requests elevation from the user.  At any rate, I just switched to Enterprise Library from log4net and had to get it to produce log files in a User location rather than \program files\myprogdir and the configuration (though the tools are nice) do not support this.  Luckily Enterprise Library 3.1 comes with the source so I dug around and found what to do.  To save you the trouble.

I'm using RollingFlatFileTraceListener.  This class only has one constructor:

public class UserScopeRollingFileListener : Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.RollingFlatFileTraceListener
{
public UserScopeRollingFileListener(string fileName, string header, string footer, ILogFormatter formatter, int rollSizeKB, string timeStampPattern, RollFileExistsBehavior rollFileExistsBehavior, RollInterval rollInterval)
: base(GetUserScopedFilePath(fileName), header, footer, formatter, rollSizeKB, timeStampPattern, rollFileExistsBehavior, rollInterval)
{
}

protected static string GetUserScopedFilePath(string logFileName)
{
string path = logFileName;
if (Environment.OSVersion.Version.Major > 5)
{
string homeDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
path = System.IO.Path.Combine(homeDir, logFileName);
}

return path;
}
}

So, in the constructor call the GetUserScopedFilePath().  If the OS is Vista, it takes the log file name from the app.config file and maps it into My Documents.  It could just as easily be Local Application Data or something else.  The Logging configuration uses a "Data" class associated with each listener to build to the listener class.  This seems odd since this Data class explicitly invokes the constructor of the Listener even though the configuration requires the Type of the listener to be present in the app.config.


/// <summary>
/// Represents the configuration data for a <see cref="RollingFlatFileTraceListenerData"/>.
/// </summary>    
[Assembler(typeof(UserScopedRollingTraceListenerAssembler))]
public class UserScopedRollingTraceListenerData : Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.RollingFlatFileTraceListenerData
{
public UserScopedRollingTraceListenerData()
{
}
}

/// <summary>
/// This type supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
/// Represents the process to build a <see cref="RollingFlatFileTraceListener"/> described by a <see cref="RollingFlatFileTraceListenerData"/> configuration object.
/// </summary>
/// <remarks>This type is linked to the <see cref="RollingFlatFileTraceListenerData"/> type and it is used by the Custom Factory
/// to build the specific <see cref="TraceListener"/> object represented by the configuration object.
/// </remarks>
public class UserScopedRollingTraceListenerAssembler : RollingTraceListenerAssembler
{
public UserScopedRollingTraceListenerAssembler()
{
}

/// <summary>
/// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
/// Builds a <see cref="FlatFileTraceListener"/> based on an instance of <see cref="FlatFileTraceListenerData"/>.
/// </summary>
/// <seealso cref="TraceListenerCustomFactory"/>
/// <param name="context">The <see cref="IBuilderContext"/> that represents the current building process.</param>
/// <param name="objectConfiguration">The configuration object that describes the object to build. Must be an instance of <see cref="FlatFileTraceListenerData"/>.</param>
/// <param name="configurationSource">The source for configuration objects.</param>
/// <param name="reflectionCache">The cache to use retrieving reflection information.</param>
/// <returns>A fully initialized instance of <see cref="FlatFileTraceListener"/>.</returns>
public override TraceListener Assemble(IBuilderContext context, TraceListenerData objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
{
UserScopedRollingTraceListenerData castObjectConfiguration
= (UserScopedRollingTraceListenerData)objectConfiguration;

ILogFormatter formatter = GetFormatter(context, castObjectConfiguration.Formatter, configurationSource, reflectionCache);

UserScopeRollingFileListener createdObject
= new UserScopeRollingFileListener(
castObjectConfiguration.FileName,
castObjectConfiguration.Header,
castObjectConfiguration.Footer,
formatter,
castObjectConfiguration.RollSizeKB,
castObjectConfiguration.TimeStampPattern,
castObjectConfiguration.RollFileExistsBehavior,
castObjectConfiguration.RollInterval
);

return createdObject;
}
}

Now, if you used the Enterprise Library configuration tool to create the RollingFlatFileListener configuration, you need to make two changes:

<listeners>

<add fileName="MyLogFileName.log" rollSizeKB="0" timeStampPattern="yyyy-MM-dd"

rollFileExistsBehavior="Overwrite" rollInterval="None" formatter="Text Formatter"

header="" footer=""

listenerDataType="MyNS.MyNS.UserScopedRollingTraceListenerData, MyAssembly.Name"

traceOutputOptions="None"

type="MyNS.MyNS.UserScopeRollingFileListener, MyAssembly.Name"

name="Rolling Flat File Trace Listener" />

</listeners>

One other thing I wanted to change about the logging, is that I like the log4net syntax for different log levels.  You would get an ILog implementation and call log.Debug(message) or log.Error(message) or log.Fatal(message).  With the joy of Extension Methods you can create your own on-the-fly facade with the compiler doing most of the work:

    public static class LogExtensions

    {

        static void Debug(this LogWriter l, string message)

        {

            LogEntry entry = new LogEntry();

            entry.Message = message;

            entry.Severity = System.Diagnostics.TraceEventType.Verbose;

            l.Write(entry);

        }

 

        static void Error(this LogWriter l, string message)

        {

            LogEntry entry = new LogEntry();

            entry.Message = message;

            entry.Severity = System.Diagnostics.TraceEventType.Error;

            l.Write(entry);

        }

    }

So extension methods now allow me to say Logger.Writer.Error("An error has occurred: value was null").  I am now happy with the Logging application block.

Thursday, November 01, 2007 8:36:15 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback

I'm enjoying Enterprise Library right now, especially the unexciting yet very useful Logging and Caching application blocks.  In the past I have used things like log4net, but the configuration tool that comes with Enterprise Library 3.1 is enough reason to use EL by itself. 

Thursday, November 01, 2007 3:55:06 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, October 31, 2007

One of my co-workers has decided to get with the 00s and start blogging.  Introducing David Snopek!  He is not a .Net developer, yet: silverlight+mono+DLR will win over even some diehard Microsoft haters.  David is my favorite sparring partner at CarSpot, so hopefully we can take our disagreements into the blogosphere for your entertainment.

Wednesday, October 31, 2007 1:06:09 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, October 21, 2007

I'm sitting at my kitchen table tonight burning about a dozen podcasts for my commute.  For a while I stuck to Dot Net Rocks but I've been throwing in the occasional Hanselminutes and Audioholics into the mix as well.  Tonight is the first time in a while I donn't truly have to do anything right now.  I still can't make any public announcements on the work situation but suffice to say my typical day is go to work --> pick up daughter --> put kiddo to bed at 8pm --> work till 12pm; throw in some required travel and marathon meetings and I'm more than a little tired.  I have two solid, relevant articles I need to complete and just haven't had the time.  In the next two weeks I'll be getting our new WPF based product into a demoable state and preparing for a talk in front of 600 people in Atlanta.

Tonight shall be spent catching up on Netflix night with my friend M. Chateauneuf du Pape and little else. 

Some people I know personally got an invitation to see Bram Stoker's Dracula on BD this weekend as one of my two Halloween movie nights this month.  I would encourage Milwaukee area nerds to try to make this one, in addition to the screening of one of my favorite films someone has promised to bring over a Halo edition 360 for some 106" front projection large and loud H3 action. 

Sunday, October 21, 2007 7:31:16 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, October 15, 2007

In previous articles I've shown how to host the Windows Forms designer outside of Visual Studio, which can be very useful in some sitations.  I had some down time before catching a plane (read: didn't want to start something bigger) so I started looking into the WPF designer.  The WPF designer, code-named "Cider", will not be hostable outside Visual Studio in the first release.  I will be providing feedback through the appropriate channels...

I'm going to go back and finish my ClickOnce thoughts next.

Monday, October 15, 2007 11:32:28 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback