2001, A Space Oddity

I'm sorry, but I just had to link this (requires Shockwave):

It's so awful I laughed the entire time it was playing. Smile I've been considering showing this movie to my kids, but I hazard a guess they'll understand it no better than I did the first few times I saw it. (In fact, I almost hate to admit that I didn't understand it until I saw a 2001 parody backed by 2010...what did apes beating up each other with bones have to do with spaceships to the moon? Doh! So, tell me again, exactly who's evolved?)

Nah, the kids won't get it, and probably wouldn't enjoy it. Not enough weaponry. Best to stick to Transformers. They are part of the iPod generation, after all. Smile


Tags:
Categories: General

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

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

Moving along with my example MVC/workflow application (see Part I and Part II), for this post I thought I'd share some of the architecture and show a first, rough-cut at the workflow.

The solution is broken down as you see here:

 

The Common library is shared by the presentation layer as well as the logic/data layers. From a project perspective, it looks like this:

 

Here you see I have interfaces for data access and services (although there is only one service for this example). I have a "data transfer object," which I'll use to pass employee information between the layers. And I have factories that will create instances of the data access layer (DAL) and services. This allows me to make changes to the DAL or services without breaking existing code/tests, assuming I don't modify existing interface method signatures (I can add methods, just not change existing ones). It also allows me to use a strategy pattern for loading the appropriate assembly.

For example, here is the employee service factory:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Reflection;
using KoozKooz.Common.Interfaces;

namespace KoozKooz.Common.Services
{
    public sealed class EmployeeServiceFactory
    {
        private static IEmployeeService _instance = null;

        static EmployeeServiceFactory()
        {   
            // TODO: create custom section
            // TODO: refactor code to generic loader
            string asm = ConfigurationManager.AppSettings["EmpSvs-Assembly"];
            string cls = ConfigurationManager.AppSettings["EmpSvs-Type"];

            // Dynamically load the assembly and instantiate the type  
            Assembly a = Assembly.Load(asm);
            _instance = a.CreateInstance(cls) as IEmployeeService; 
        }
        
        public static IEmployeeService GetEmployeeService()
        {
            return _instance;
        }
    }
}

The assembly information is read from the configuration file:

<add key="EmpSvs-Assembly" value="KoozKooz.Logic"/>
<add key="EmpSvs-Type" value="KoozKooz.Logic.Services.EmployeeService"/>

A quick unit test would look like this:

///<summary>
/// A test for retrieving the employee service
///</summary>
[TestMethod()]
public void GetEmployeeServiceTest()
{
    IEmployeeService svc = EmployeeServiceFactory.GetEmployeeService();
    Assert.IsTrue(svc != null);
}

The DAL code is very similar.

I've not completed the service layer, but my unit tests for loading the DAL and requesting an employee are passing. I'm now turning to the workflow. WF 4 is a very different animal than WF 3.5, and I think once I understand the changes, I'm going to like them. Two things stand out--the flow of information to and from the workflow when executed within an application seems to have improved, and the persistence model appears greatly enhanced.

With WF 3.5, if you wanted to pass information into the workflow, you could do so when the workflow was initiated (and you had to pass in a Dictionary object). If you wanted to communicate with the hosting application, you had to add a service and something I called a "bridge," which was glorified "glue" code that married the particular activity with events the host application could monitor. With WF 4, the story has improved through the use of InArgument and OutArgument. I still have more to learn, but I'll be digging into this aspect soon for this learning application. As for persistence, WF 4 has the concept of a "bookmark." Instead of adding a Delay activity to kick off workflow persistence, you now add a bookmark to your (native) activity. When the bookmark is acted upon, WF will persist the workflow and wait for some external force to re-activate the workflow. Once it is re-activated, execution resumes in an event handler you provide.

There is a slight down-side with bookmarks at present, however. Bookmarks are available only to NativeActivity-based activities. NativeActivity is a form of CodeActivity, which is how you write custom workflow activities. If using CodeActivity as your activity's base class, you can still use the designer. However, when using NativeActivity, you lose all designer support. Your workflow is then entirely code-based. Ah well. It is a beta after all. Smile

My activity will not be very complex, and I reserve the right to refactor as required. This is my first rough-cut... The activity, which I named SendManagerVacationApprovalRequestActivity, merely sends an e-mail to the employee's manager:

namespace KoozKooz.Logic.Workflow
{
    internal sealed class SendManagerVacationApprovalRequestActivity :
                                                                 NativeActivity
    {
        // Manager's employee DTO
        public InArgument<EmployeeDTO> Manager { get; set; }

        // Employee's employee DTO
        public InArgument<EmployeeDTO> Requestor { get; set; }

        // Days requested...this should aleady be filtered against the
        // employee's available days, but we'd be remiss not to check
        // here too.
        public InArgument<Int32> RequestedDays { get; set; }

        // If your activity returns a value, derive from CodeActivity<TResult>
        // and return the value from the Execute method.
        protected override void Execute(NativeActivityContext context)
        {
            // Pull runtime values
            string fname = this.Requestor.Get(context).FirstName;
            string lname = this.Requestor.Get(context).LastName;
            Int32 requestedDays = this.RequestedDays.Get(context);
            Int32 availableDays = this.Requestor.Get(context).RemainingVacation;
            string callbackUrl = String.Format("{0}&InstanceId={1}",
                          ConfigurationManager.AppSettings"VacationCallback"],
                          context.WorkflowInstanceId.ToString());

            // Format the request message body:
            //
            // 1) Requesting employee first name
            // 2) Requesting employee last name
            // 3) Number of days requested
            // 4) Number of days available
            // 5) Callback URL, with workflow instance ID
            string messageBody =
                 String.Format(Properties.Resources.VacationRequestMessage,
                     fname, lname, requestedDays, availableDays, callbackUrl);

            // Pull manager's e-mail address
            string managerEMail = this.Manager.Get(context).EMail;

            // Mail request notification
            MailHelper mailer = new MailHelper();
            mailer.From =
                  ConfigurationManager.AppSettings["SystemEMailAccount"];
            mailer.To = managerEMail;
            mailer.Subject = Properties.Resources.VacationRequestSubject;
            mailer.SendMail(messageBody, true);

            // Create named bookmark
            context.CreateBookmark("VacationApproval",
                     new BookmarkCallback(this.OnApproval),
                     BookmarkOptions.NonBlocking);
        }

        private void OnApproval(NativeActivityContext context,
                                Bookmark bookmark, object obj)
        {
            // Do nothing...allow completion
        }
    }
}

I may, for example, return the SMTP result code if the SendMail method fails rather than allow it to simply crash (which is what it'll do without any exception handling code...at least that's what would happen using WF 3.5). Something else to learn about WF 4.

In any case, the workflow will create an e-mail message and forward that to the manager. Inside the e-mail message is a hyperlink for a "callback page" I specify (in the configuration file for now, for lack of a better place to store a value I'd like to reconfigure dynamically). Once the message is sent, the workflow instance will suspend. The page the manager accesses will then re-activate the workflow, allowing it to run to completion.

Something else to note is when I created the bookmark, I used the BookmarkOptions.NonBlocking option. This allows the workflow execution engine to run past the bookmark. I'll probably play with this a little once I get the workflow hosted. Is it better to block or not block? I might find that the workflow isn't persisted if I don't block, in which case I'll revise the code. It needs to be persisted, of course, since the manager could take a long, long time to authorize the vacation, making this a long-running workflow.

Now, I realize this workflow isn't very complex, but the point of this exercise is to marry a workflow to ASP.NET MVC. The complexity of the workflow isn't the point, so I'm fine with my custom activity merely sending an e-mail. Yes, using a workflow for this at all is probably overkill. Undecided But, again, the point is to get WF 4 working with ASP.MVC 2... Once you get the plumbing in place, you can create whatever workflows you like.

The next post should be interesting as I'll have the workflow invocation code working (or so I hope...if a lot of time passes between posts, you'll know I either got swamped with work or couldn't figure it out!). I've not seen a lot regarding threading models with WF 4, so I'm curious to dig into how WF 4 handles threading, or if it parallels what we used to have to do with WF 3.5.


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

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

When Legos and "The Matrix" Collide

I've mentioned in this blog that "The Matrix" is one of my favorite movies (others being "The Mummy", "Tremors", and "Twister"). I also have a fondness for Legos, having helped my children assemble many, many kits. Heck, I had them when I was their age, only the kits weren't as cool. Smile

Imagine my surprise when I stumbled across this (requires Shockwave):

 

This brilliant piece of stop-action animation was put together by Trevor Boyd and Steve Ilett, who took their own favorite scene from the Matrix and recreated it using Legos, frame by frame. I understand it took them 440 hours. Truly incredible. And I thought I had no spare time. Embarassed


Tags: , ,
Categories: General

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

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

In my previous post, I mentioned designing a small database to support a learning application I'd like to write. I also mentioned I'd discern the differences in the two workflow persistence models I see that are available in Workflow Foundation 4. Let's start with the latter.

It turns out there isn't really much to say. WF 3.5 persisted workflows using a "persistence provider model." WF 4, on the other hand, uses persistence according to an "instance store." The two models are incompatible, and the persistence provider is shipped with WF 4 only for backwards compatibility. All new WF 4 workflows should use the instance store, so mystery solved. We'll use the instance store when we get to that point.

As for the database, my goal isn't to design the be-all, end-all of databases for HR (as you may recall, the task will be to authorize vacation/holiday time off, which is an HR function). I just need some basic information:

  • The empoloyee's name, both requestor and manager
  • E-mail addresses
  • Amount of remaining vacation
  • An employee ID, used to uniquely identify everyone in the database

For my sample application, this data should suffice. There is always more we could add, like amount of vacation authorized by the manager but not yet taken, or the amount of vacation rolled over from last year--that sort of thing. For my needs here, however, I'll keep it simple. I'm much more interested in the workflow for vacation authorization and connecting that to an MVC application.

With that information in mind, I created this database scheme:

It's somewhat normalized, but I tend to design database that way. I say "somewhat" because the RemainingVacation column is stuck in the EmployeeData table, which isn't really where I'd probably put it in a true HR database design, but it's better than adding a third table just for this little sample application. So I'll live with that bit of denormalization. Smile I created some test data, which you see in this script (I'll swap out the e-mail addresses for valid ones later):

INSERT INTO [Koozkooz].[dbo].[Employees]
           ([EmployeeID])
     VALUES
           ('5001')
GO

INSERT INTO [Koozkooz].[dbo].[Employees]
           ([EmployeeID])
     VALUES
           ('10001')
GO

INSERT INTO [Koozkooz].[dbo].[EmployeeData]
           ([EmployeeDataID]
           ,[EmployeeID]
           ,[FName]
           ,[LName]
           ,[EMail]
           ,[RemainingVacation]
           ,[ManagerID])
     VALUES
           ('CEBB9D6F-9B50-4C8E-BAC7-B8E03377E5EB'
           ,'5001'
           ,'Tonya'
           ,'Manager'
           ,'tonya@koozkooz.com'
           ,20
           ,'0')
GO

INSERT INTO [Koozkooz].[dbo].[EmployeeData]
           ([EmployeeDataID]
           ,[EmployeeID]
           ,[FName]
           ,[LName]
           ,[EMail]
           ,[RemainingVacation]
           ,[ManagerID])
     VALUES
           ('A57152B2-D4F3-4A5E-8F74-C734C3B5C9A2'
           ,'10001'
           ,'Aimee'
           ,'Employee'
           ,'aimee@koozkooz.com'
           ,5
           ,'5001')
GO

The image depicting the database is from Visual Studio, and you've probably already noted I'm using LINQ to SQL. I've started framing the application in Visual Studio 2010 (Beta 2). I settled on the name "KoozKooz," if only because a quick Web search didn't turn up a lot of hits on the name:

Something in the beta I believe needs to be addressed is the ability to name things. When creating new projects, for example, you tell Visual Studio 2010 where you want the code located, but it names the project. At least the solution is named according to the location, as you'd expect. Anyway, in my case, I created an MVC 2 Web application, but Visual Studio named it "MvcApplication2" for me. I'll probably rename it to be "KoozKooz.Web," but you get the idea. Another limitation in the beta is deciding where Web apps should be hosted. With Visual Studio 2008, you can choose to use Cassini or IIS (locally or remotely). That functionality is not present in the current beta, but clearly it's needed. I'm sure it'll be in the next beta, or whatever release Microsoft intends.

In the next post, I'll start rigging up the data access and application layers, as well as their unit tests.

(Update: I found the KoozKooz domain was available, so I bought the rights. It's nice to be legal. Smile)


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

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

Implementing an Asynchronous HttpModule

When I was researching REST and writing my part of Scott's and my book on REST (Effective REST Services via .NET: For .NET Framework 3.5), on page 234 I mentioned that the authentication/authorization module I'd written should be asynchronous and that someday I'd write an asynchronous version. Thanks to reader Carl asking me to come through on my promise, I've completed the asynchronous version. Actually, I refactored the synchronous version as well so that both implementations can share the code that actually deals with authentication and authorization. If you've read the book and have downloaded the source (which I updated, downloadable from here), you can download the AuthModule.cs files themselves for Chapters 6-8 here.

I noticed a distinct lack of example implementations on the Web while deciding how I wanted to implement my version of the asynch module. Jeff Prosise has the most-referenced version (available here), but this wasn't complete enough for my needs. Jeff's version uses FileStream.BeginWrite to generate the necessary IAsyncResult object. In my case, I couldn't use that (of course) since my module is performing authentication and authorization for RESTful services.

Jeff still provides a hint, though. In his article he shows an asynchronous HttpHandler, and the code for that handler implements IAsyncResult. I wanted a touch more functionality--a boolean return value and exception support--so I modified his work to look like the following:

/// <summary>
/// A class containing an IAsyncResult implementation
/// that wraps a ManualResetEvent. Note this is  relatively
/// simple implementation. A more complete (generic)
/// implementation is available by Jeffrey Richter, found at
/// http://msdn.microsoft.com/en-us/magazine/cc163467.aspx.
/// My thanks to Jeff Prosise for the basis of this
/// implementation.
/// </summary>
internal class AsyncAuthResult : IAsyncResult
{
    private AsyncCallback _callback;
    private object _state;
    private ManualResetEvent _event;
    private bool _completed = false;
    private bool _result = false;
    private object _lock = new object();
    private Exception _ex = null;

    public AsyncAuthResult(AsyncCallback callback,
            object state)
    {
        _callback = callback;
        _state = state;
    }

    public Object AsyncState
    {
        get { return _state; }
    }

    public bool CompletedSynchronously
    {
        get { return false; }
    }

    public bool IsCompleted
    {
        get { return _completed; }
    }

    public WaitHandle AsyncWaitHandle
    {
        get
        {
            lock (_lock)
            {
                if (_event == null)
                    _event = new ManualResetEvent(IsCompleted);
                return _event;
            }
        }
    }

    public void CompleteCall(bool result, Exception exception)
    {
        // Passing null for exception means no error occurred
        _ex = exception;

        // Cache result
        _result = result;

        lock (_lock)
        {
            _completed = true;
            if (_event != null)
                _event.Set();
        }

        if (_callback != null)
        {
            // Invoke callback...
            _callback(this);
        }
    }

    public bool EndInvoke()
    {
        // Operation is done...if an exception occured, throw it
        if (_ex != null) throw _ex;

        return _result;
    }
}

I then created an "authentication manager" that implements the "begin" and "end" methods I'd need in my module:

internal sealed class AuthenticationManager
{
    const string BasicAuthProtocol = "basic";
    HttpContext _context = null;

    public AuthenticationManager(HttpContext currentContext)
    {
        _context = currentContext;
    }

    public bool AuthenticateUser()
    {
        return InternalAuthenticateUser();
    }

    public IAsyncResult BeginAuthenticateUser(AsyncCallback callback,
                                              Object state)
    {
        // Create IAsyncResult object identifying the 
        // asynchronous operation.
        AsyncAuthResult ar = new AsyncAuthResult(callback, state);

        // Create a new thread to perform the operation...note we can't
        // use a thread from the thread pool as this defeats the purpose
        // of the asynchronous implementation (we're trying to leave
        // *those* threads alone for ASP.NET to use to service incoming
        // requests).
        Thread worker = new Thread(this.InternalAuthenticateUserAsync);
        worker.Start(ar);

        return ar;  // Return the IAsyncResult to the caller
    }

    public bool EndAuthenticateUser(IAsyncResult asyncResult)
    {
        // We know that it's really an AsyncAuthResult object
        AsyncAuthResult ar = asyncResult as AsyncAuthResult;
        return ar.EndInvoke();
    }

    private void InternalAuthenticateUserAsync(Object asyncResult)
    {
        // We know that it's really an AsyncAuthResult object
        AsyncAuthResult ar = asyncResult as AsyncAuthResult;

        // Perform the operation..if successful set the result. If
        // not, record the exception.
        try
        {
            bool authorized = this.InternalAuthenticateUser();
            ar.CompleteCall(authorized, null);
        }
        catch (Exception ex)
        {
            ar.CompleteCall(false, ex);
        }
    }

    private bool InternalAuthenticateUser()
    {
        // Authorize the user (using HttpContext for Authorization
        // header access) and return success/failure.
    }
}

The module itself then performs the typical asynchronous event connections. In the "begin" authentication event, I create an instance of my authentication manager, call its "begin" method (which spins up a new thread...more in a moment on that), and waits for authentication to complete. Upon completion, it calls the authentication manager's "end" method to retrieve success/failure and proceeds from there:

public class AsyncAuthModule : IHttpModule
{
    #region Fields

    // We *must* cache the context. When the "end" method is
    // invoked, a CLR thread will be executing (versus an IIS
    // thread), so there is no "current" context available
    // for the thread to use. That is, HttpContext.Current
    // will return null. We can cache the context in this manner
    // even though three different threads will eventually
    // use this object since the runtime suspends this module
    // invocation entirely and restarts it in the "end" 
    // method.
    HttpContext _context = null;

    // We'll cache this as well so we can call its "end"
    // method.
    AuthenticationManager _authMgr = null;

    #endregion

    #region IHttpModule Members

    public void Dispose()
    {
    }

    public void Init(HttpApplication application)
    {
        // Hook authentication
        application.AddOnAuthenticateRequestAsync(
            new BeginEventHandler(BeginAuthenticateRequestHandlerExecute),
            new EndEventHandler(EndAuthenticateRequestHandlerExecute)
        );
    }

    #endregion

    #region Event handlers

    IAsyncResult BeginAuthenticateRequestHandlerExecute(Object source,
        EventArgs e, AsyncCallback cb, Object state)
    {
        // Pull the current context
        HttpApplication application = source as HttpApplication;
        _context = application.Context;

        // Create an instance of the authentication manager and invoke
        // its asynchronous method.
        _authMgr = new AuthenticationManager(_context);
        return _authMgr.BeginAuthenticateUser(cb, state);
    }

    void EndAuthenticateRequestHandlerExecute(IAsyncResult ar)
    {
        // Collect authentication/authorziation result...if true, the
        // user is good to go. If false, the context will contain the
        // appropriate response code and headers.
        bool authorized = _authMgr.EndAuthenticateUser(ar); // can throw...

        // If the context contains anything but "OK" we know
        // to terminate the request. The appropriate headers
        // will already be set up by the authentication manager
        // object.
        if (!authorized ||
            _context.Response.StatusCode != (Int32)HttpStatusCode.OK)
        {
            // End the request
            _context.Response.End();
        }
    }

    #endregion
}

As far as I can tell, this is the only example of a complete asynchronous HttpModule that fully implements IAsyncResult for a custom processing workflow that you can search (at least that I could find). I'm not sure why it's so hard to find others, but hopefully this helps someone else. Laughing With this example, and with Jeff's you should be able to get a working asynchronous HttpModule up and running.

One "gotcha" I'd mention is don't fall into the trap I fell into, which is using the wrong callback. That is, ASP.NET provides you with an instance of AsyncCallback as a parameter to the module's "begin" method. That callback is the one your processing should invoke so that ASP.NET knows your workflow is complete. It then will call the module's "end" method for you. Initially I created a new instance of AsyncCallback and passed that in, bypassing ASP.NET entirely. That resulted in the server hanging the page since I broke the HTTP pipeline. (In my best Homer Simpson voice, "Doh!"). In code, the following is correct:

return _authMgr.BeginAuthenticateUser(cb, state);

The following is most assuredly NOT correct:

return _authMgr.BeginAuthenticateUser(
        new AsyncCallback(this.EndAuthenticateRequestHandlerExecute), state);

Now, as for threading. A good question to ask is "why spin up your own thread and not use the thread pool?" The reason is asynchronous modules (and handlers/pages as well) all are assigned CLR threads from the AppDomain's thread pool when IIS hands off the request. If we were to consume one of the AppDomain's pooled threads, we're defeating the purpose of the asynchronous implementation entirely. This means you should not only avoid queueing a thread pool task but also should not use Delegate.BeginInvoke (a trick I often use to gain asynchronous behavior in other apps). Spinning up a new thread is the only alternative you have when you create your own custom asynchronous module/handler/page workflow objects. I've not cracked open other CLR implementations (like FileStream.BeginWrite), but hopefully if I did I'd find those aren't using the AppDomain's thread pool as well.


Tags: , , , ,
Categories: .NET General | ASP.NET | RESTful Services

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