All posts by admin

Model, View Model, View – No way (for now)…

I get all the Model <—> ViewModel <—> View stuff.  It’s great theory, but come on! A View Model class that has the same exact properties as the stinkin’ Model that it is wrapping, just so we can say “I used MVVM”.

My little Asp.Net CRUD app is binding the UI controls directly the data properties on a BusinessObject.Entity, where the Entity is a Typed class from a LinqToSql query. (My BO’s are based on the West Wind wwLinqToSql Business Object Wrapper from the West Wind Web Tools for Asp.Net ).  And guess, what… It works! It loads and saves data when the user clicks the buttons.  Imagine that. I’ll be darned if I’m gonna wrap a ViewModel class around that data Entity so I can bind my UI controls to that ViewModel, rather than hooking straight to the Entity properties.  Just too much stinkin’ code required.

I’ve also added a few additionally needed "presentation properties" into my Business Objects to *supplement* the Entity properties that came from the data base row. And, yes, when working with my BO’s, you have to access some properties right off the BO (the custom presentation properties I added) and some come from the main BO.Entity (the real data from the database row). So, you do have to know where to get the data you are after. By doing this, most of my UI binding is against the BusinessObject.Entity properties, and a few UI bindings go against the supplemental presentation properties I’ve added right on the BO.

So, I don’t mind some bit of a hybrid ViewModel approach, but not a separate class where I have to re-host every single property that is on the Entity. And, since this is done on the Business Object class level, all these supplemental  "presentation properties" can still be accessed by other UI apps that work with the same Business Object wrapper classes.

From a theoretical standpoint, sure, it breaks a few rules. But from a real world impact, we are talking about only a handful of supplemental properties. In all the BOs I’ve built (Customer, Invoice, Quote, Shipper, User, Employee, etc.), maybe I’ve added 3 to 5 additional properties on each one to serve what is usually one view, but sometimes two or three different views at the most. If things really get crazy, there might be as many as 10 presentation properties to handle all the views. It still seems like less of an overall burden on the application as a whole to add a few presentation properties right on the BO, rather than dropping an entire Model-to-ViewModel Mapper implementation on my app (homegrown or commercial). Talk about a burden.

Now look, these additional properties will be implemented somewhere. Why not stick them onto something that already exists (the BO) as little light-weight tag-a-longs, rather than create an entirely free-standing ViewModel object, where I put these innocent properties and then I have to REPLICATE all the real properties from the Model too. Is that how this magic ViewModel character makes things "cleaner"? Yuck! Oh, wait, I almost forgot… but look how clean my BO is! No thanks.

Here’s a use case from my app… I want to bind a UI control to the Customer Name for an Invoice Object that I have pulled from the database. Well, rather than attempting to bind through the main Invoice Entity and into the Customer sub-Entity (which LinqToSql handles nicely for me BTW) I’ve added a presentation property on the BusinessObject to access the Customer Name easily, and also guard against several null object cases that can arise.

Example: Attempting to bind a UI control to directly to this property (see below) could crash the UI generation if the Entity object or Customer Entity is null:

busInvoice.Entity.CustomerEntity.Name

Since it’s possible that the busInvoice object’s .Entity property is not even saturated yet, or that the CustomerEntity is null, this could cause problems generating the UI.  And, I certainly don’t want to test for all the potential problems in my UI pages every time I want to display that property. So, I added a property on the busInvoice object to host that value and deal will all the required testing.

Something like:

public string CustomerName
{
get
   {
     if (this.Entity != null && this.Entity.CustomerEntity != null)
       return this.Entity.CustomerEntity.Name;
     else
       return "";
   }
}

Anyway, back to my main rant about going overboard with ViewModels…

So look at this sample I found from a notable Asp.Net guru.  It is a ProductView class that returns a ProductView object from a passed in Product (that you got from your DAL somewhere), and it can return a Product object from a passed in ProductView object, basically by unwrapping the ProductView object and casting the string properties back to the original data types. Look at all this code! Especially look at the ToProduct() method. Wow!  ( code from http://weblogs.asp.net/craigshoemaker/archive/2009/11/03/vm-workshop-model-view-viewmodel-mvvm-and-the-presentation-model-pattern-in-5-ui-platforms.aspx )

It looks like a maintenance nightmare.  I need more convincing that this is the way the pros do it. Perhaps I’ll be a rookie just a little bit longer.

    public class ProductEditView : IUrlSerializer
    {
        public string ProductId { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string QuantityOnHand { get; set; }
        public string Price { get; set; }
        public string ReleaseDate { get; set; }

        public string SerializeToUrlString()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("productId={0}&", this.ProductId);
            sb.AppendFormat("title={0}&", this.Title);
            sb.AppendFormat("description={0}&", this.Description);
            sb.AppendFormat("quantityonhand={0}&", this.QuantityOnHand);
            sb.AppendFormat("price={0}&", this.Price);
            sb.AppendFormat("releasedate={0}", this.ReleaseDate);
            return sb.ToString();
        }

        public static ProductEditView ToProductEditView(Product product)
        {
            ProductEditView view = new ProductEditView();
            view.ProductId = product.ProductId.ToString();
            view.Title = product.Title;
            view.Description = product.Description;
            view.Price = string.Format("{0:c}",product.Price);
            view.QuantityOnHand = product.QuantityOnHand.ToString();
            view.ReleaseDate = product.ReleaseDate.ToShortDateString();
            return view;
        }
        public static Product ToProduct(ProductEditView view)
        {
            double db;
            int num;
            DateTime dt;

            Product product = new Product();
            product.Title = view.Title;
            product.Description = view.Description;

            if (double.TryParse(view.Price.TrimStart(‘$’), out db))
            {
                product.Price = db;
            }
            else
            {
                throw new ArgumentException("Price is malformed or not a valid value.");
            }

            if (int.TryParse(view.ProductId, out num))
            {
                product.ProductId = num;
            }
            else
            {
                throw new ArgumentException("ProductId is malformed or not a valid value.");
            }

            if (int.TryParse(view.QuantityOnHand, out num))
            {
                product.QuantityOnHand = num;
            }
            else
            {
                throw new ArgumentException("QuantityOnHand is malformed or not a valid value.");
            }

            product.ProductId = Convert.ToInt32(view.ProductId);
            product.QuantityOnHand = Convert.ToInt32(view.QuantityOnHand);

            product.ReleaseDate = Convert.ToDateTime(view.ReleaseDate);
            if (DateTime.TryParse(view.ReleaseDate, out dt))
            {
                product.ReleaseDate = dt;
            }
            else
            {
                throw new ArgumentException("ReleaseDate is malformed or not a valid value.");
            }

            return product;
        }

Adobe Acrobat PDF Printer output filename on 64-bit OS…

Now that I’ve moved over to Windows 7 64-bit on my primary workstation, I’m in a new world of IT support that I didn’t expect from those extra 32 bits of OS horsepower. My MicroTek scanner is not supported, my HP 2800 Business Inkjet is not supported, and I recently discovered that a technique I use in my Visual FoxPro business application to pre-define the PDF output filename when using the Adobe Acrobat PDF printer driver mysteriously does not work on Windows 64-bit. So, I want to show the remedy in case others encounter this same problem. I’m explaining this from the perspective of a Visual FoxPro application, but the issue applies to all Windows applications, and the remedy can come from many programming languages.

Background… It’s well know that you can prevent the Adobe PDF printer driver from prompting the user to choose a path and filename for the output file by programmatically setting a certain registry key with a string value that contains the desired path and filename of PDF file you want to output. I use this technique to automatically set the path and filename for my users for the various PDF reports we generate to send out to our customers and vendors.

This magic registry key is located at: HKEY_CURRENT_USER\Software\Adobe\Adobe Distiller\PrinterJobControl.  So, you create a string value under that key with the path and name of the *application* that is printing the PDf, and then you set the value of that string value to the path and filename of the PDF you want to create.

Now, the path and filename of the application that is doing the printing is not always easy to figure out, so I can’t solve that mystery here for any given app that you may be using, but I do know (and I forget where I learned this) that for a Visual FoxPro application (.exe), the path and application name can be discovered from the VFP variable “_VFP.ServerName”. Of course, it’s up to you to decide the path and filename of the PDF output file you’re want to create.

So, to bring it all together, you add a string value named after the app that is doing the printing (for instance) “C:\Program Files\Microsoft Visual FoxPro 9\vfp9.exe” and you set the value of that string value to the filename you want the PDF to be called; i.e. “C:\TEMP\JMC_PO_MS2741C.pdf”

Well, that’s how it works on good ‘ole 32-bit OS.  Now, enter into the 64-bit world…

The issue is that the *application* name that the 64-bit OS sees as doing the printing is no longer the actual exe the user is running,  but rather some odd Windows exe named “splwow64.exe” (some spooler-like thingy that actually handles the printing which I learned about here http://www.acrobatusers.com/forums/aucbb/viewtopic.php?pid=57794#p57794 ). So that’s the application name you have to use, and you do have to include the path. Since this spooler thingy exe runs from C:\Windows, the actual registry key that must therefore be created is “C:\Windows\splwow64.exe”.

PDF_Reg

So, with the PrinterJobControl registry key all programmatically setup as described above, when you actually fire off the Adobe PDF printer, the output name is already set and the user will not see the prompt dialog to choose the output path and filename.

Also, be aware that after *you* programmatically create and set the registry value, the Adobe PDF driver will actually delete that string value from the key right after the file is printed. Perhaps this is so the next app that prints won’t use the same name.

Finally, here’s the VFP code I use to set the values for both 32-bit and 64-bit OS’s. (This code uses an instance of the Registry class from the FoxPro FFC classes to work on the Windows registry). Again, this all works the same way whether you are using .Net, VFP, VB, or whatever. The main thing is to setup the registry value the right way.

   oRegTools=createobject(‘registry’)

        m.lcKeyPath = "Software\Adobe\Acrobat Distiller\PrinterJobControl"

       *– This RegKey setting works on 32-bit OS…
        oRegTools.OpenKey(@lcKeyPath, HKEY_CURRENT_USER , .T.)
        lcPrintingApplicationName = _VFP.ServerName
        oRegTools.SetKeyValue(lcPrintingApplicationName, “C:\TEMP\JMC_PO_MS2741C.pdf”)
        oRegTools.CloseKey()

        *– This is the "Application" name that the OS sees as doing the printing when running on a 64-bit OS…
        oRegTools.OpenKey(@lcKeyPath, HKEY_CURRENT_USER , .T.)
        lcSplWow64ProcessName = ‘C:\Windows\splwow64.exe’ && <— This is what the OS sees as what’s doing the printing…
        oRegTools.SetKeyValue(lcSplWow64ProcessName, “C:\TEMP\JMC_PO_MS2741C.pdf”)
        oRegTools.CloseKey()

 

Hopefully, this insight will save someone out there a little headache when working with the Adobe PDF printer driver on these super-duper 64-bit OS’es.

LINQ to SQL, Lazy Loading and Prefetching

I want to recommend this interesting article that explains times when LinqToSql’s native behavior of “Lazy Loading” is not a good thing (from a database performance standpoint), and explains a pre-fetching technique that you can can use when you want to avoid lazy loading hits to SQL Server.

It’s from the the great Rick Strahl. See his blog post at:

http://west-wind.com/Weblog/posts/38838.aspx

I also recommend that you review his LinqToSql Business Object wrapper framework and sample app that he created to show a real-world working app using the framework.

Original article and download, September 27, 2007 (read this first):

http://www.west-wind.com/WebLog/posts/160237.aspx

He also posted an update article on February 05, 2008:

http://www.west-wind.com/Weblog/posts/246690.aspx

And, Rick has continued to update the LinqToSql Business Object wrapper framework since those articles were written, and you can download the latest version which is included as part of the WestWind Web Toolkit for Asp.Net (tons of other goodies are in the entire Toolkit, so check out the free license details, which is a full working version) :

http://www.west-wind.com/westwindwebtoolkit/

 

In closing… You know, they’ve said that LinqToSql was kind of dead, but at least they did do a little work on it for .Net 4 framework. That’s encouraging to me. I think a LOT of people use LinqToSql, and I personally think it will pick up even more, rather than die off. It has a fine place in small-to-mid sized apps, and I frequently hear plenty of notables in the community speak of it.

Here’s is an article on the updates to LinqToSql that included in the .Net 4 framework:

http://damieng.com/blog/2009/06/01/linq-to-sql-changes-in-net-4

Uninstalling Visual Studio 2010 Beta 2

Why am I writing about Un-installing Visual Studio Beta 2 when it was just released yesterday, October 19, 2009? (video announcement can be seen at this link). Well, in the past whenever I’ve used the beta versions of some of Microsoft’s developer tools, I’ve found that it was impossible to uninstall them properly (or fully) when the RTM version was finally released.

Now, I know that VM’s can be used to test out beta software, and I do use VM’s on my machine, as I did when I installed VS2010 Beta 1 on a Windows 7 Beta VM running on VirualBox VM.  But sometimes I still like running right on the bare metal so I will have access to the rest of the tools I need in a full dev environment. Especially now that it’s Beta 2, I’d feel pretty good running it on my live dev machine. But, I was unsure about being able to easily remove it later when the RTM version comes out on March 22, 2010.

So, I posted a question on the Visual Studio 2010 Install and Setup forum of the newly restyled  http://www.msdn.com/forums to see if anyone could address this issue.

My question is titled Will we be able to un-install VS2010 Beta 2, when final version is released?.

Fortunately, I got a very quick reply from a MSFT moderator named Aaronru who claims a very easy and successful uninstall of VS2010 Beta 2 has been tested and WILL allow for an easy upgrade path to VS2010 RTM.

The exact reply was…

For helpful instructions on how to install Visual Studio, we’ve published some detailed instructions for installing and maintaining Visual Studio 2010 Beta 2.

If you evaluated Visual Studio 2010 Beta 1, you will be happy to hear that no reformatting is required. Additionally, simple path exists to appraise Beta 2 on the same machine. It involves uninstalling your Visual Studio 2010 Beta1 product and then installing one of the Visual Studio 2010 Beta2 offerings.  Please refer to the following blog post for more details.

As part of our Beta 2 testing, we did test the uninstall of Beta 2 to ensure that the Beta 2 could be uninstalled sufficiently to the end that you could uninstall Beta 2 and install RTM with as seamless UX as possible.

You can read the entire thread here.

So go for it! The download of VS2010 Beta 2 will be available to the public on October 21, 2009, with final RTM to be released on March 22, 2010.

To Blog or to Forum Post, that’s the question…

I’m not really sure why I’m so driven to do this, but I’ve always been a spread-the-news kind of guy for the VFP community. Any time I see something cool, or that I think others may be interest in, I make a post here-and-there to all the most popular FoxPro sites to spread the word.  So, about a month ago I cranked up this blog for the purpose of doing just that, thinking this would be a good way to go.  Now, I don’t want to compete with the existing forums, because it’s easy enough to go there and make announcements, but I have to visit UniversalThread, and  Foxite, and the ProFox and VFUG lists too, oh, and even Fox.Wikis.com, oh, and sometimes use my FoxCentral.net account. I usually have to hit all those sites with a bunch of cut-and-paste to work all the places I want to reach. Plus, after posting to forums and lists, if I need to tweak the info (corrections, add details, etc), it’s too late to edit or just too much work. And, any conversations (comments) about the topic are now spread out across all the different places and there’s no one place other readers can visit to take it all in. Plus, the formatting and image posting in a blog is much better.

So, I’m trying to decide whether it really adds any value to put this info in a blog post and try to get an audience following the blog, or just keep it old school and post in multiple places.

Your opinions please.

Crash Course to Web Development for FoxPro and Web Connection Developers

I just received an e-mail announcement for what looks like an awesome jump start class for Visual FoxPro developers to get their feet wet in the .Net Web development arena. Super-smart web maven Rick Strahl plans to give you 3 days of quick start how-to teaching on the .Net / Web development train.

You can attend live or watch on GoToMeeting. It’s a 3-day class, November 5, 2009 through November 7, 2009.

Here is a link with all the details: http://eps-software.com/EventDetail.aspx?id=37d20fbb-6632-4264-8db5-b1665904b00a

(P.S. – Does anyone want to sponsor me?)

The color of your comments

Recently I had a thought that the comments in my code may be getting in the way of me actually seeing the code itself while I’m coding. There seems to be two camps in the code commenting world: (1) Write good code and you should not need comments and (2) Write comments or else you are being lazy and no one will ever be able to work with your code. Well, I’m not here to settle that debate (I fall somewhere in the middle).

So, I had this idea of changing the COLOR of my comments from GREEN to GREY, so that I could still see them, but they would kind of fade away into the background, but would still be there if I took a harder look. I suppose the default VFP comment color must be that classic green color that I’ve been looking at for years, so I’ve changed mine to grey to help me focus better on my code, and not the comments.

Who knows, maybe one day I’ll be a real programmer and won’t even need to write comments at all.

Also, the smart one, Bo Durban, posted this hint on UT (in response to this blog post) about how you are not limited to the base 16 colors:

Did you know…If you set it programmatically, you are not limited to the base 16 colors?:

oReg = NEWOBJECT("FoxReg",HOME(2)+"classes\registry.prg")
oReg.SetFoxOption("EditorCommentColor","RGB(80,140,80,250,250,170),NoAuto,NoAuto")
SYS(3056,1)

So, here are a few screenshots to compare… Give it a try and see what you think.

Grey Comments: Green Comments:

Ruby on Birmingham

In case you’re interested, here is a link to the RubyHam users group in Birmingham, Alabama. They have monthly meetings, usually meeting on the first non-holiday Monday of the month. The meetings are around lunch time, rather than at night. I’ve never been to one the meetings, and I’ve never used Ruby, but I did see a presentation about it once and it seemed cool enough to make me want to learn more about it. I plan to go to the next meeting on September 14, 2009 just to see what it’s all about. Will I see you there?

http://tech.groups.yahoo.com/group/rubyham/

Ruby is a (non-Microsoft) language that seems to have reasonable popularity among the kids. Microsoft is working on a version for .NET called IronRuby: http://www.ironruby.net Since I am indeed a Microsoft fanboy, that will probably win my first dance.

Get involved. Enjoy. The choices are endless.

West Wind Client Tools for VFP

Note: This post if part of a complete series on the West Wind wwBusiness library.


Introducing wwBusiness

An object oriented data access library for Visual FoxPro

I recently got interested in converting my company’s main Visual Foxpro CRUD application to a Business Object model, rather than old-school free .dbf tables with a bunch of procedural code stuck in all the button clicks and textbox valid() events. I’m sure none of you have ever done such hack-work, but back in the beginning (I started with FPD in 1992, then FPW, then VFP as each was released) that’s how I started. I was a solo developer and had no formal training or access to mentors. It took me a long time to get the vision of how real programming should be done, but I finally learned some of these core fundamentals a few years back, and I’m really enjoying the process of refactoring my app into this BO pattern. I began by reading about the topic in all the usual places, and posted a few questions here and there on several VFP sites (like http://www.foxite.com/ and http://www.universalthread.com/), then I finally hacked out my own basic BO class, after I learned about the SCATTER approach that is widely used to capture data from a table row into an object.

Then, at a pair programming session with a Foxpro developer friend of mine, he showed me Rick Strahl’s West Wind Web Connection for VFP that he’s used for years. Turns out that package has a nice BO class library, called wwBusiness, which is also available as part of a client app tool set from West Wind (called the West Wind Client Tools for VFP http://www.west-wind.com/wwClientTools.asp ). So the Web Connection package and the Client Tools package both have the same wwBusiness BO class library.

Now, the West Wind Client Tools package also has a TON of stuff besides just the BO classes (like SMTP, HTTP, FTP, SQL, XML, JSON, SOAP, blah, blah). You can read all about them at the Client Tools page link I listed above.

One cool thing about the wwBusiness BO class is that it has one single property (nDataMode) to switch between VFP dbf tables and SQL Server, so it’s very helpful if you want to migrate your application’s data to a SQL Server backend and flip the switch once you are ready to move away from dbf tables. And the cool thing is that your app will never know where the data comes from, it just uses the wwBusiness BO to request data, and it comes back as an object that you can work with, then you call the .Save() method on the BO object to write the changes back to the DBF or Sql Server. I tested it, and it actually does work very well.

The wwBusiness.vcx class library has two class types:

  • wwBusiness – a single BO class (for fetching a parent record or a single line item)
  • wwItemList – a class which will fetch and hold a set of records (like line items on a Sales Order)

Together, these classes can model just about any Parent-Child data set you might have in your app.

Introducing wwBusinessPro

I found the two base classes in wwBusiness be good starting points for basic Object Oriented data access, but I have written my own wrappers around them and extended their functionality greatly, and I’ve named my enhanced library “wwBusinessPro”.

Download

You can download wwBusinessPro from the project hosted on BitBucket.org.

Features:


The wwBusinessPro library extends the base features of wwBusiness by adding these new features:

Here are the primary two ways I extended the classes:

  1. The wwBusiness (single BO class) expects an integer PK to do lookups and fetches. I indeed have Integer PKs on my tables, but I sometimes also have a unique lookup string for each parent record, and I wanted the option of using that for fetching a Parent record (and related child records too). So, I created a Get() method which will accept either an Integer or a String. It then calls the native wwBusiness.Load(tnPk) for Integer PK lookups or it will call my extension method LoadByRef(tcLookupString) for string based lookups. The wwBusiness class already had cPKfield out of the box, and I added a cLookupField property to handle string-based lookups. I also enhanced the Save() method to apply the Parent Key to all the Child collection records so that the relational structure required for Parent-Child PK/FK would be automatically handled for me.
  2. Out of the box, the wwItemList class requires YOU to write a method to fetch the desired child records into a cursor, then it loads that data from your cursor into an array when you call the wwItemList.LoadFromCursor() method. Well, that array would work fine for procedural processing, but for my application I needed to host the child records in a grid, so I needed to service the child records from that local cursor (rather than working on the array items). I wrapped the wwItemList Save() method to get the local records back into the real table from which they came. For my app design, this cursor-based functionality was the biggest missing part from the basic toolkit. I had to write about 3 or 4 methods to handle this workflow in an abstract way so I could have a generic solution for all my child item collections. The main methods I wrote were LoadLineItems() and a wrapper around SaveToCursor() which was needed to handle records that had been deleted from the local working cursor.

You can see a code sample of working with my extended wwBusiness classes here: http://codepaste.net/aascee
Here is a screenshot of the object model that I created with my extended wwBusiniess and wwItemList to create a Job object with several associated child collections: Line Items, Material Items, and Labor Items that are all from child tables related to the Parent record via PK/FK relationship.

wwBusinessObjectModel

Lastly, note that using a BO tool in general not only brings you data handling in an object-based manner with support for various back end data stores, but that same Business Object now becomes *THE* place to put business logic for each of your business objects. Like adding a method for CloseSalesOrder() or AssignJobPriority() or SetDefaultPropertiesForNewJob(), or PrintShippingTicket() etc. With all this properly in place on your Business Objects, creating a UI form becomes a much simpler task of just calling methods on the Business Object. Using this technique, I was able to reduce the code in my CRUD forms by more than 50%!! And now, I have a bunch of cute BOs I can instantiate in code or even right in the command window to work on them without even having a UI screen. Not only that, the same BO can easily support a web-based UI to your same exact data and business logic. It is truly beautiful!

So, as you can see, I did a lot of work on the West Wind classes to prepare them for my app, but two things: 1. It was VERY fun to work all this out, and 2. It works like a charm, and I now have a completely BO-based CRUD app where all the Business logic is nicely tucked away in the BOs and not in my forms or form controls.

Also, FoxPro veteran Kevin Cully is a long-time West Wind user, and he made a presentation on the wwBusiness classes to the Atlanta FoxPro User Group (AFUG) several years ago and prepared a nice 20-page introductory paper here: http://cullytechnologies.com/presentations/wwbusiness/cully_technologies_wwbusiness_presentation.pdf

Man, I wish I had this thing 10+ years ago when as I first began the VFP version of my app. Since I didn’t have a clue what I was doing at the time I started, it wound up a little bit messy, until this came along. I began my own BO efforts around May 2009, and the I abandoned my version in favor of wwBusiness around August 2009.

So go check it out for yourself… You can read the help file online and the package is only $199, and has 10% during August 2009, so about $179 gets you on his customer list and into the surf over at West Wind. You can download a working version with the full source code right from the site. The site also has a reasonably active discussion forum, and Rick is generally very responsive himself.

Note: This post if part of a complete series on the West Wind wwBusiness library. Click here to see the full index.