Tuesday, December 27, 2016

Simplest F# Asynchronous Workflow Sample


Can't nobody tell me F# async is easy; it seems hard to me. I wanted to put together the simplest sample (but different from all the samples I've seen) so I could get a better understanding. Maybe thistle help someone else. I'm searching a file line by line to see if I can find a match. In this case there are only 4 lines in the file so I'm splitting the file into 2 chunks.  Each... async... thing (after watching a long video on C# async lately and ending up hopelessly confused about when actual new threads are created I've given up guessing) gets 2 lines. In this sample, it's pretty handy how it stops looking after finding a match.

open System.IO
open System

// So we don't just print "null" to console when not found.
let OptionToStr o =
  match o with
  | None -> "not found"
  | Some(o) -> o

// Because our line gets wrapped into an option twice (once in Seq.tryPick and again in Seq.tryFind).
let UnwrapOption o =
  match o with
  | None -> None
  | Some(o) -> o

// Some(matching line) if the current chunk contains our id
let ChunkContains (id:string) (chunk:string seq) =
  chunk
  |> Seq.tryPick ( fun line -> 
                   // Notice how it doesn't process all lines when it finds a match.
                   printfn "Current: %s" line
                   if line.Contains id then Some(line) else None )

// Skip n lines and call our search method for the current chunk
let ProcessFileChunkAsync (lines:string seq) skip (func: string seq -> string option) =
  async {         // Note: async is cranky.  You have to format the curly braces a certain way or compiler will complain with strange error.
    return lines  // return keyword required.
    |> Seq.skip skip
    |> Seq.truncate 2
    |> func       // 2nd parameter applied to previous partial application of ChunkContains below.
   }

[]
let main argv = 
  let lines = File.ReadAllLines @"c:\temp\4LinesOfTrash.txt"  // one of the lines is "hi mom"
  seq { 0 .. 1 }
  |> Seq.map ( fun i -> let chunkFun = ChunkContains "hi"   // find the line with "hi"; partial func application
                        ProcessFileChunkAsync lines (i * 2) chunkFun
             )
  |> Async.Parallel          // Fork
  |> Async.RunSynchronously  // Join: Take the async results and wait for them to complete.
  |> Seq.tryFind ( fun item -> Option.isSome item )
  |> UnwrapOption
  |> OptionToStr
  |> printfn "Result: %A"
  |> Console.ReadLine
  |> ignore
  0

Thursday, October 13, 2016

URL Redirecting in an OWIN Self-Hosted Web Application

Perhaps this will get old quick; I don't know. Had a small research task for this. In this case I'm using a couple WebAPI controllers along with OWIN to demo.

  1. Create new console application.
  2. Install nuget packages Microsoft.Owin.SelfHost, Microsoft.AspNet.WebApi.Owin
  3. Create RedirectMiddleware.cs like below (source)
  4. Create Startup.cs like below
  5. Make Program.cs (self-host starter) like below.
  6. Add a couple controller classes, I added AController and BController.

 public class RedirectMiddleware : OwinMiddleware
 {

  public RedirectMiddleware(OwinMiddleware next) : base(next)
  {
  }

  public async override Task Invoke(IOwinContext context)
  {
   var url = context.Request.Uri;
   var shouldRedirect = ShouldRedirect(url.AbsoluteUri);
   if (shouldRedirect.Item1)
   {
    // permanent redirect
    context.Response.StatusCode = 301;
    context.Response.Headers.Set("Location", shouldRedirect.Item2);
   }
   else
   {
    await Next.Invoke(context);
   }
  }

  private Tuple<bool, string> ShouldRedirect(string uri)
  {
   if (uri.EndsWith("A"))
   {
    return Tuple.Create(true, "/B");
   }
   else
   {
    return Tuple.Create(false, "");
   }
  }

 }

 class Startup
 {

  public void Configuration(IAppBuilder appBuilder)
  {
   // Setup WebAPI configuration
   var configuration = new HttpConfiguration();

   configuration.Routes.Add("API Default", new HttpRoute("{Controller}"));

   /// Register our middleware
   /// Order of registration is the order the middleware will execute in.
   appBuilder.Use();

   // Register the WebAPI to the pipeline
   appBuilder.UseWebApi(configuration);

   appBuilder.Run((owinContext) =>
   {
    owinContext.Response.ContentType = "text/plain";
    return owinContext.Response.WriteAsync("Controllers are /A and /B.  http://localhost:5000/A will take you to B");
   });
  }

 }

 class Program
 {
  static void Main(string[] args)
  {
   const string baseUrl = "http://localhost:5000/";
   using (WebApp.Start<Startup>(baseUrl))
   {
    Console.WriteLine("Hit me up @ http://localhost:5000.  Press Enter to shut down.");
    Console.ReadKey();
   }
  }
 }

Thursday, October 06, 2016

Powershell Tray Icon Sample

The powershell samples for popping a tray icon weren't complete.  Here is a simple example (pops for 5 seconds) that I'm using to regularly remind me to stand/stretch/focus my eyes on distant objects. I've wrapped it in a scheduled task that calls powershell passing this script as the arg starting every weekday at about the time I start work repeating every 20 minutes.

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

$m = (Get-date).Minute

<# This is multi-line comment syntax #>
# Console.Write equivalent:
#Write-Host $m

$objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon
$objNotifyIcon.Icon = "C:\Someplace\YourTrayIcon.ico"
$objNotifyIcon.BalloonTipIcon = "Warning"
$objNotifyIcon.BalloonTipTitle = "Hocus Focus"

if ($m -lt 30)
{
$objNotifyIcon.BalloonTipText = "Focus your eyes distant and blink frequently"
}
else
{
$objNotifyIcon.BalloonTipText = "Focus eyes & stretch too"
}

$objNotifyIcon.Visible = $True
$objNotifyIcon.ShowBalloonTip(1) #Not sure what the heck this millisecond param is even for; it stays until you hide it.

Start-Sleep -Seconds 5
$objNotifyIcon.Visible = $False