Learning MVC 2, Workflow Foundation 4, and maybe Silverlight 3, Part I

About a year ago I wrote some software for Microsoft that included a Web application that drove workflow to create a Word document filled with specific (and dynamic) information. It was interesting combining workflow with ASP.NET as there are things you have to do in addition to the normal workflow hosting. For one thing, workflow persistence is mandatory because the workflows would be considered long-running. For another, you can't use the typical thread management as you'd be tying up IIS threads. I didn't write about this in my workflow book since it wasn't part of the typical workflow thought process at the time, which perhaps was too limiting on my part. I liked the demos I created for that book, but prior to its release, the workflow community did see workflow more related to Windows Forms or WPF applications.

Now that we have ASP.NET MVC 2, WF 4, and a host of new technologies, it's time for me to dig in a little. I also edited Dino's terrific Web architecture book, Microsoft® .NET: Architecting Applications for the Enterprise, and am editing his awesome upcoming MVC book, tentatively entitled "Programming Microsoft® ASP.NET MVC". (If you already own every MVC book out there, trust me you'll want this one too...very "internals" oriented). I'd love to work out an example prescriptive site or two just to put some of this stuff into practice.

So, open kimono time... The only way to learn this stuff is to DO this stuff. So I came up with an idea. I'd wondered about combining workflow in a Web application using SMTP to authorize things. That is, imagine an enterprise-class Web application that forwards authorization requests to a manager for approval. The request could be anything, but I'll pick....oh...vacation authorization. So you go to the HR site, place a demand for vacation time, and the application forwards your manager the request. The e-mail has an embedded link that fires up the app in the manager's browser, they click yes or no, and the system notifies you of their decision. I'm sure everyone but me has written this, but I thought it made for a good scenario to work with MVC 2 and WF 4. We'll see about working in the Silverlight once the foundational components are in place. I say that only because SL can do some really powerful UI's, and this scenario ain't it. But it might make a good seque into RIA services. (!)

What I write here is raw stuff. Maybe it's well architected and maybe things should be refactored. That's fine...I'm playing with concepts more than anything. If you see glaring omissions or errors, by all means comment! We all learn more that way.

The first thing I see I'm going to need to do is determine the difference between traditional WF persistence and something I'm seeing called "workflow instance store." Is one perferred for Web apps? I honestly don't know yet, but I'll research it a bit and report back. It'll matter because I'll create a SQL Server 2008 database and need to run the appropriate scripts (both sets of which are provided with Visual Studio 2010). I'm starting here because, to me, the app is there to serve the data, not the other way around. I'll design a rudimentary database, just enough to support my scenario, and then layer over that LINQ code to interface with the application service layer. That, then, drives the user interface, at least for this scenario.

So, next time I'll describe the differences in WF persistence and design a small database to support this application scenario. If anyone reading this has questions or comments, all are welcome. :)


Tags: , ,
Categories: .NET General | ASP.NET | Workflow

5 Comments
Actions: E-mail | Permalink | Comment RSSRSS comment feed

"The Matrix" Screen Saver

Several years ago I'd written an article about screen savers in .NET. The very detailed article has since gone to PDF form (found here), but I thought it would be good to mention some of the finer points in case anyone else out there found this and was interested in writing a C#-based screen saver. The samples you'll generally find available aren't nearly good enough as they don't provide enough code, or the right code, to do the job.

In this case, I have a screen saver that mimics the screens seen in one  of my favorite movies, "The Matrix." Here's the general idea:

Matrix Screen Image

Aside from the actual simulation, which I'll leave to you to decipher from the code, two things are critical here. First, you have to properly accept (and handle) the command line parameters. And second, you have to deal with multiple screens. Here's some detail.

As for the command line, this is the code you'll need:

string cmd = args.Length > 0 ?
    (args[0].Length > 1 ?
     args[0].ToLower(CultureInfo.InvariantCulture).Trim().Substring(0, 2) :
    args[0].ToLower(CultureInfo.InvariantCulture).Trim().Substring(0, 1)) : "";

if (cmd == "/c" || cmd == "-c"  || cmd == "c" || cmd == "" )
{
    // Options dialog.
} // if
else if (cmd == "/p" || cmd == "-p" || cmd == "p" )
{
    // "Preview" mode.
} // else if
else if (cmd == "/s" || cmd == "-s" || cmd == "s" )
{
    // Run screen saver.
} // else if
else
{
    // Sorry...don't recognize the command line parameter.
} // else

The trickiest part is the "/c" option, which requires you to accept a window handle (as a string) and render the screen output there. (That's how the options dialog shows you the preview.) The details are in the code, which you can download here, but essentially you convert the handle from a string to an IntPtr, and then create a Graphics object from that. The option will come in this form:

/c:1269802

Multiple screens are another tricky aspect. The basic approach is you iterate the screens attached to the system, which you find in Screen.Allscreens, like so:

Int32 totWidth = 0;
Int32 totHeight = 0;
for (Int32 i = 0; i < Screen.AllScreens.Length; i++)
{
   // Check the dimensions of this screen
   if ( Screen.AllScreens[i].Bounds.X == 0 )
   {
       // We simply compare the width of this screen to
       // the total width we've accumulated, and if greater,
       // use this screen's width. Otherwise, we're covered.
       if (Screen.AllScreens[i].Bounds.Width > totWidth )
           totWidth = Screen.AllScreens[i].Bounds.Width;
   } // if
   else
   {
       // The widths are additive...
       totWidth += Screen.AllScreens[i].Bounds.Width;
   } // else

   // Height
   if (Screen.AllScreens[i].Bounds.Y == 0)
   {
       // We simply compare the height of this screen, similar
       // to what we did for width.
       if (Screen.AllScreens[i].Bounds.Height > totHeight)
           totHeight = Screen.AllScreens[i].Bounds.Height;
   } // if
   else
   {
       // The heights are additive...
       totHeight += Screen.AllScreens[i].Bounds.Height;
   } // else
} // for

To install the screen saver, simply copy the Matrix.scr file to your hard drive and right-click. Then select Install from the list of available options (you can alternatively test it or configure it as well). The compiled image in the download is for all CPUs, but feel free to recompile it to match your own system. Be sure to compile a release build, however, so the streams aren't too slow!


Tags: , , , ,
Categories: .NET General

6 Comments
Actions: E-mail | Permalink | Comment RSSRSS comment feed

X-HTTP-Method-Override

While not normally an issue with thick clients, accessing full RESTful capabilities of available services via browsers often is problematic as many (if not all) browsers only allow a form to GET or POST. They don't allow for other HTTP methods, like HEAD, PUT, or DELETE. Google realized this and offers a solution, which is to add a header to the HTTP request, X-HTTP-Method-Override, that is supposed to be interpreted by the service and acted upon regardless of the actual HTTP method used.

The header syntax is as follows:

X-HTTP-Method-Override: PUT

You can learn more about it from http://code.google.com/apis/gdata/docs/2.0/basics.html#UpdatingEntry.

As it happens, ASP.NET MVC, version 2, supports this out of the box with the HttpHelper.HttpMethodOverride method. Just use that helper method in your view, and assuming the service honors the header, your Web page should be able to work with the RESTful service. I thought this blog entry was particularly interesting (he has an interest in using ASP.NET MVC for RESTful services as well).


Tags:
Categories: RESTful Services

9 Comments
Actions: E-mail | Permalink | Comment RSSRSS comment feed

Updated Nerd Score, so I'm Online!

For some reason, I decided to update my home page to fix the Nerd Score link that has been broken for a long, long time. I think I tripped on a recent page that actually had the image associated with the Nerd Score, and it gave me the idea to look for it and update my page. Turns out I did find it, but when I did, I thought to myself, "self, why not take the test again?" And so I did...

I really improved my scrore, and I wasn't trying to! I wound up with a 98%, a Nerd God, so I treated myself and bought the BBQ smock from their online store. I think I can safely say I'm the first Nerd God in my neighborhood!

I am nerdier than 98% of all people. Are you a nerd? Click here to take the Nerd Test, get geeky images and jokes, and write on the nerd forum!

As another treat, I decided it's about time I started adding to the online content and push my own electrons around, so I installed BlogEngine.Net on my server. The installation couldn't have been easier...I simply copied the "web" version to my hosted site, edited the robot text file, and granted the write permission for ASPNET to write to the data folder. I also had to give the blog folder a new IIS application (which fortunately my host allows me to do). Once I did that, created myself as a user, and edited some settings, I was able to actually post this blog item using the blog engine. I'd tried working with DasBlog, but short of recompiling it to fit into my scenario, I just couldn't get it working. This software, however, worked the first time. Oh, I still get errors...I can't edit my profile yet, I need to figure out how they're doing themes, and I can hardly believe there is no CAPTCHA support when adding comments (I'll be fixing THAT real soon, I'm sure), but I'm stoked it came up so easily.

Sorry world...you'll now be subjected to my lunatic ravings. :)

(Update: profiles and themes now working...and BlogEngine.Net has a "hidden" CAPTCHA capability...I'll go with that for the moment.)


Tags:
Categories:

1 Comments
Actions: E-mail | Permalink | Comment RSSRSS comment feed