William's profile.Net ZoneBlogLists Tools Help

Blog


    March 02

    Obama Bow

     

    image

     

    "King.  May I tie your shoe?"

    February 20

    ReportViewer with nested tables

    Sometimes you may need a report that can not be done easily with standard grouping in a table.  Say you want to a repeatable data region that is repeated by an outer group, but contains two other tables an maybe an image.  I can't think of a good way to do that with standard row grouping using a tablix.  However, the List control makes this easy.  In short, here is what is needed.  A List control that contains all other elements and is grouped by some value.  The List gets repeated for each unique group value.  Put two Tables in the List and toss in any other controls you need such as Textboxes or Images.

    Here is the controls layed out in Visual Studio report designer:

    image

     

    We get our data from the database using anything such as Linq or other.  However, we "flatten" it because reports do not understand nested data.

    We can make developing the report simplier by skipping the DB step and making our own objects like:

    public class Offers
    {
        public string OfferID { get; set; }
        public string Offerer { get; set; }
        public bool IsProgram { get; set; }
        public string ProgramName { get; set; }
        public int ProgramHours { get; set; }
        public bool IsPrereq { get; set; }
        public string PrereqName { get; set; }
        public int PrereqCode { get; set; }
        public byte[] Image { get; set; } 
    
        public static List<Offers> GetData()
        {
            byte[] im = File.ReadAllBytes(@"C:\Users\William\Pictures\MarkTwain.jpg");
            byte[] im2 = File.ReadAllBytes(@"c:\users\william\pictures\captain_john_smith.jpg"); 
    
            // Offer1
            Offers of1 = new Offers(){ OfferID="03453", Offerer="John Smith", IsProgram=true, ProgramName="admission", ProgramHours=1};
            of1.Image = im2;
            Offers of2 = new Offers(){ OfferID="03453", Offerer="John Smith", IsProgram=true, ProgramName="actual crisis", ProgramHours=10};
            of2.Image = im2;
            Offers of3 = new Offers(){ OfferID="03453", Offerer="John Smith", IsProgram=true, ProgramName="discussion", ProgramHours=5};
            of3.Image = im2;
            Offers of4 = new Offers(){ OfferID="03453", Offerer="John Smith", IsProgram=true, ProgramName="final notes", ProgramHours=2};
            of4.Image = im2; 
    
            Offers of5 = new Offers(){ OfferID="03453", Offerer="John Smith", IsPrereq=true, PrereqName="Macro econ II", PrereqCode=3463};
            of5.Image = im2;
            Offers of6 = new Offers(){ OfferID="03453", Offerer="John Smith", IsPrereq=true, PrereqName="Finance", PrereqCode=34634};
            of6.Image = im2;
            List<Offers> offers = new List<Offers>() {of1, of2, of3, of4, of5, of6}; 
    
            // Offer2
            of1 = new Offers(){ OfferID="80345", Offerer="Mark Twain", IsProgram=true, ProgramName="admission2", ProgramHours=2};
            of1.Image = im;
            of2 = new Offers(){ OfferID="80345", Offerer="Mark Twain", IsProgram=true, ProgramName="actual crisis2", ProgramHours=3};
            of2.Image = im;
            of3 = new Offers(){ OfferID="80345", Offerer="Mark Twain", IsProgram=true, ProgramName="discussion2", ProgramHours=4};
            of3.Image = im;
            of4 = new Offers(){ OfferID="80345", Offerer="Mark Twain", IsProgram=true, ProgramName="final notes2", ProgramHours=7};
            of4.Image = im; 
    
            of5 = new Offers(){ OfferID="80345", Offerer="Mark Twain", IsPrereq=true, PrereqName="Macro econ II2", PrereqCode=3466};
            of5.Image = im;
            of6 = new Offers(){ OfferID="80345", Offerer="Mark Twain", IsPrereq=true, PrereqName="Finance2", PrereqCode=34638};
            of6.Image = im;
            List<Offers> offers2 = new List<Offers>(){of1, of2, of3, of4, of5, of6};
            offers.AddRange(offers2);
            return offers;
        }
    }
    

     

    Now in the Report load event of your report Form do something like:

    private void Offers_Load(object sender, EventArgs e)
    {
        var list = Offers.GetData();
        this.OffersBindingSource.DataSource = list;
        this.reportViewer1.LocalReport.EnableExternalImages = true;
        this.reportViewer1.RefreshReport();
    }

     

    Now you have a report that has grouped "regions" and inside each region can contain other lists and/or other elements related to the group.

    Output:

    image

    February 01

    Astoria query Cheat Sheet

    Samples Data Model:

    image

    Query Samples:

    Below are some samples of using Astoria to query against the model.  I tried to hit the most popular that will hit most of the features, but far from complete.  Please let me know others you would like to see and I will keep adding.

    var db = SocialEntities.GetDB();  // Get the DataContext.

    Navigation1

    public void Test()
    {
        var q = from u in db.Users
                where u.UserID == 2
                from en in u.Entries
                select en;
        //http://localhost:7777/RestService.svc/Users(2)/Entries()
    }

    Navigation2

    public void Test()
    {
        var q3 = (from u in db.Users
                  where u.UserID == 2
                  from e in u.Entries
                  where e.EntryID > 1
                  select e).Take(10);
        //http://localhost:7777/RestService.svc/Users(2)/Entries()?$filter=EntryID gt 1&$top=10
    }

    String filter

    public void Test()
    {
        var q2 = from u in db.Users
                 where u.Tag.Contains("will") || u.Tag.EndsWith("ne")
                 select u;
        //http://localhost:7777/RestService.svc/Users()?$filter=substringof('will',Tag) or endswith(Tag,'ne')
    }

    Reverse Navigation

    public void Test()
    {
        var q4 = from e in db.Entries
                 where e.EntryID == 85 // Must be 1 primary key. Range not supported.
                 select e.Users1; // Get the user that owns this entry.
        // http://localhost:7777/RestService.svc/Entries(85)/Users1
    }

    Date filter

    public void Test()
    {
        var q5 = (from u in db.Users
                  where u.Created >= DateTime.Parse("10/1/05") && u.Created <= DateTime.Parse("11/1/09")
                  select u).Take(5);
        //http://localhost:7777/RestService.svc/Users()?$filter=(Created ge datetime'2005-10-01T00:00:00') and (Created le datetime'2009-11-01T00:00:00')&$top=5
    }

    Using Expand on Service operation

    This example shows a couple concepts. It shows how one can use Expand on a service operation, and it shows how we can continue to "compose" over query.  Here we use a service operation that takes 1 parameter, but we could use more or none.  Linq is used to "build" the uri query, which is then executed by the .Net client stack, which is sent to the server.  The servers gets the IQueryable from the method and composes over it (i.e. adds the filters and the Expand) using the client's query and returns the results.

    private void Test()
    {
        // Using Expand on a service operation proxy.
        var db = SocialEntities.GetDB();
        var q3 = from u in db.GetUsers("").Expand("Entries")
                 where u.Tag == "william"
                 select u;
        Console.WriteLine(q3.ToString());
        // URI: http://localhost:7777/RestService.svc/GetUsers()?$filter=Tag eq 'william'&$expand=Entries&pattern=''
        var user = q3.First();
        Console.WriteLine("{0} {1}", user.Tag, user.Entries.Count() );
    }
    
    // Client proxy method.
    public DataServiceQuery<Users> GetUsers(string pattern)
    {
        var q = this.CreateQuery<Users>("/GetUsers").AddQueryOption("pattern", "'" + pattern + "'");
        return q;
    }
    
    // Service operation
    [WebGet]
    public IQueryable<Users> GetUsers(string userPattern)
    {
        if (userPattern == null || userPattern.Length == 0)
            return this.CurrentDataSource.Users;
        userPattern = userPattern.Replace('*', '%');
        userPattern = userPattern.Replace('?', '_');
        string filter = string.Format("it.Tag LIKE '{0}'", userPattern);
        var q = this.CurrentDataSource.Users.Where(filter).Select(u => u);
        return q;
    }
    
    

    Limit number of "Expanded" items on the many side (rSide)

    TMK, you can't use Expand to limit the number items on the many side.  However, you can reverse the query to get the same effect.

    public void Test()
    {
        // Take X from many side and expand the 1 side.
        var q2 = (from en in db.Entries.Expand("Users")
                  where en.Users.Tag == "william"
                  orderby en.Created descending
                  select en).Take(1);
        foreach (var en in q2)
            Console.WriteLine("{0} {1} {2}", en.EntryID, en.Created, en.Users.Tag);
    }

     

    Return "partial" types from server using Service Operation and EFExtentions to "hide" data:

    Using the Entity Framework Extentions (http://code.msdn.microsoft.com/EFExtensions), you can materialize entities using all or some of the fields. Here we just return ID and Firstname from the database. One drawback here is you can not use Expand on the client side when using Materialize this way. Not sure why yet, but I assume it has something to do with the way it creates Entity Collections (or not).

    [WebGet]
    public IQueryable<Employees> GetEmployee(string empID)
    {
        // Note we create a partial employee with only selected columns, so we can return
        // just the data we need.  The rest will be the default values of the types.
        string sql = string.Format("select EmployeeID, FirstName from Employees where EmployeeID='{0}'", empID);
        var cmd = this.CurrentDataSource.CreateStoreCommand(sql);
        var q = cmd.Materialize<Employees>();
        return q.AsQueryable();
    }

     

    Update entity without query first:

    You can skip the initial query to download the object just to update it by attaching a client-side object and setting the key property.

    MyDataServiceContext ctx = new MyDataServiceContext(myServiceRoot);
    Customer cust = new Customer();
    cust.ID = 1;                    // Set primary key for object tracking.
    ctx.AttachTo("Customer", cust); // Attache customer to context.
    cust.Name = "Bill";             // Update members of object.
    ctx.UpdateObject( cust );       // Set for update.
    ctx.SaveChanges();

    January 28

    Use MicrosoftReportViewer and a Dymo LabelWriter to create a really nice and 3of9 barcode label

    I have to say, I had fun coding this feature.  I wanted to print some 3of9 bar code labels for employee badges in a WinForms app I am rolling out. I was thinking this was going to involve some custom api and buying some font package (some are big $$). It turned out this was surprisingly simple and a fun report to build. Here is a sample label (extra points for first person to discover what is the barcode:

      image  

    What you need:

    1. SqlServer or some other data source.  I am using Linq and Entity Framework. You could you XML, csv or memory objects as you need.
    2. Visual Studio and the MicrosoftReportViewer control. Not sure if this is included in Express addition or not. Let me know.
    3. A Dymo LabelWriter 400 or other such printer that can print single labels in a stream. I really like the Dymo for its ease of use, simple loading, and it is well made.  Also it is a thermal printer, so you don't need to change any ribbons - ever.  About $100.  Order the label sizes you need - remember you need to order their special labels as they are thermal. I am using 3.5" x 1".  I also like this, because you don't waste a lot of labels like trying to print 8.5"x11" sheets.  You always end up with half a sheet you don't know what to do with.  So get a Dymo, you can use it for other things too.
    4. A 3of9 TrueType font. I use the Free3of9 ttfs here: http://www.squaregear.net/fonts/free3of9.shtml.  Hats off to Matthew Welch for his nice font package he is sharing!
      Just download and install the two fonts from the Control panel.

    Steps to create the label report.  I am using 3.5" x 1" labels, but same steps apply for other sizes:

    1. Install the Free3of9 fonts and logout and back in to get the fonts loaded.
    2. Create a VS WinForms project. You could do the same with WPF, but I used WinForms.
    3. Add a new Form to hold your report control.
    4. Add a MicrosoftReportViewer control to the form. I have to give props to MS for this control. It is a great control that puts a lot of power in your hands.
    5. Create a new report from the drop down on the top right of the control.
    6. Once your in the designer, change the report properties Layout to 3.4in wide and .9in high.  I set it just a tad smaller then the label so as not to get strange page breaks.  Set all four margins to 0.
    7. Change the Body of the report surface to 3.4 x .9in or smaller. Just don't make it larger then the page layout or you will get page breaks
    8. Now your surface is your "label".  Add your Table and other controls as needed for your label within this surface.
    9. Change the font family to 3of9 Extended for the field that you want to show as a barcode.
    10. Add as many Detail rows to your table as you need vertically.  I used 2 rows to show Employee name on top and EmployeeID as Barcode under it.
    11. Select the last row and right-click "Edit Group..." and group on some unique field such as employee id.  Also Check "Page break at end." so that your page will break to a new label after each employee.
    12. In the load event of the form, get your data as a list and set the DataSource property of the report control to the list and RefreshReport() after that.
    13. Run your report and adjust things as needed.  Fast, clean and professional barcodes in a snap right from your next windows application.

    Misc:

    • Set the Dymo Advanced properties on the printer driver to "Barcodes and images" to get really clean quality. Set the Color to black and white, not sure why they have a Color option, but you can play with output as needed.
    • Can also use this same method to make a production receipt printer application with the Dymo with full graphics abilities.  Just get the Receipt paper they offer and change the report size.
    • Not sure how to make it print directly to a printer without user intervention yet.  Say you wanted a receipt to print after clicking a button and not show the print dialog.  If anyone knows how to make ReportViewer do this, please let me know.
    • Have fun with your new 3of9 labels!  I will try to add some pictures here and a sample project soon.
    • When I get my USB barcode scanner with Serial simulation driver, I hope to post back with some code showing how to use the Serial class so we can scan our new labels.

    --William

    December 23

    Tips to deploy an application (or ClickOnce) using the Griaule Fingerprint SDK 2009

    The Griaule fingerprint SDK is good and works well.  However sometimes the documentation is lacking.  After some trial and error and hair pulling I finally figured out the correct steps.


    1) Install the Griaule USB driver: Griaule_FingerCap_USB_Driver_1.2_Installer.exe from http://www.griaulebiometrics.com/page/en-us/downloads
       You must use this driver and not the driver supplied with the reader hardware. If vender driver already installed, remove it first.  Your instructions for your application should have users
       install this first before your application.  I am not sure if it is possible to include this in the app setup (or ClickOnce) or not.  If it is, please let me know how to do it.

    2) Add GrFinger.dll, GrFingerLicenseAgreement.txt, pthreadVC2.dll and CapPluginFingercap.dll to the project and mark them "Content" and "Copy if newer".
       Note: The GrFingerLicenseAgreement.txt license file is at C:\ProgramData\Griaule on Vista. You can use the Trial license for testing your deployment.

    3) Create a new Project. Add a Reference to the .Net library GriauleFingerprintLibrary.dll to your project. This is from the 2009 sdk.
       On my system it is located at C:\Program Files\Griaule\Fingerprint SDK 2009\bin\GriauleFingerprintLibrary.dll
       If creating a managed C# or VB app, I recommend using this managed .Net library instead of the ActiveX control.  You *do not need to add the ActiveX control to your toolbox.  Just add the
       reference and add your using statements such as:

    using GriauleFingerprintLibrary;
    using GriauleFingerprintLibrary.Exceptions;
    using GriauleFingerprintLibrary.DataTypes;

    4) If using ClickOnce, make sure all the above files are "Included" as Application Files. If not using ClickOnce, the same files must be deployed with your application in the application directory.
       Application Files to include:
       ============================
       GrFinger.dll
       pthreadVC2.dll
       GrFingerLicenseAgreement.txt
       CapPluginFingercap.dll
       GriauleFingerprintLibrary.dll


    5) Compile or publish your app.

     

    Hope this helps someone else.  I will publish a minimalist WinForm's app showing all this working with ClickOnce.  Maybe even a console app.

    I see that DigitalPersona has a free sdk if you use there hardware.  Have not tried it.  If you have, please let me know how good it works.  Thanks.

    William

    November 16

    Return total count of query plus paging with Data Services

    ...And in the same reply.  I racked my brain for a few days trying to figure out a way to return the count of a query in the same reply with the results for my client paging control.  I started with making two queries, one for the count and one for the records.  There is a couple of issues with that. First, your sending two queries. Second, before you get the results of the second query, your count has probably changed.  On a CRUD table, count is a point in time anyway, so you can't "count" on it being accurate.  The other issue was I had to maintain two queries, one for the count and one for the results; which was difficult to maintain, so using a Batch was not really helping. 

    It finally occured to me that I might be able to stuff the count in the HTTP reply header.  As it turned out, it worked, and worked pretty well.  I was able to send one query and get results and the count in same reply.

    Service WebGet method

    /// <summary>
    /// Returns the entries using the predicate.
    /// The total count of records matching the predicate is returned in
    /// Http header "EntryCount".
    /// </summary>
    /// <param name="predicate"></param>
    /// <param name="skip"></param>
    /// <param name="take"></param>
    /// <returns></returns>
    [WebGet]
    public IEnumerable<Entries> GetEntries(string predicate, string orderKeys, int skip, int take)
    {
        // TODO: Security check.
        if (orderKeys == null || orderKeys.Length == 0)
            throw new DataServiceException("orderKeys required.");
        // Get the records using skip and take.
        IEnumerable<Entries> q = null;
        int count = 0;
        if (predicate == null || predicate.Length == 0)
        {
            q = this.CurrentDataSource.Entries.OrderBy(orderKeys).Skip(skip).Take(take);
            count = this.CurrentDataSource.Entries.Count();
        }
        else
        {
            q = this.CurrentDataSource.Entries.Where(predicate).OrderBy(orderKeys).Skip(skip).Take(take);
            count = this.CurrentDataSource.Entries.Where(predicate).Count();
        }
    
        // Get the count all records matching predicate and add to HTTP header.
        HttpContext.Current.Response.AppendHeader("EntryCount", count.ToString());
        return q;
    }

     

    Client side Proxy method

    /// <summary>
    /// Get entries using a string predicate and read the total count in the reply header.
    /// </summary>
    /// <param name="predicate"></param>
    /// <param name="skip"></param>
    /// <param name="take"></param>
    /// <returns></returns>
    public IEnumerable<Entries> GetEntries(string predicate, string orderBy, int skip, int take, out int count)
    { 
        // Why this work around? We have to pass an eSql string for the predicate instead of composing over IQueryable,
        // because at the server side we need to "know" the full predicate in order to get the count.
        // This also allows us to use the same query for the count and the select.
        if (predicate == null) predicate = "";      // Empty predicate on server side equals all rows.
        if (orderBy == null) throw new ArgumentNullException("orderKeys"); // order clause required.
    
        predicate = predicate.Replace("'", "''");   // Must add another single quote as these will be inside a single quote pair.
        string request = string.Format("GetEntries?predicate='{0}'&orderKeys='{1}'&skip={2}&take={3}", predicate, orderBy, skip, take);
        request = Uri.EscapeUriString(request);     // Escape spaces and other.
        var q = this.Execute<Entries>(request.ToRelativeUri()); // Have to Execute (not CreateQuery) so we can inspect the header here.
    
        // Get full record count in header.
        var qReply = (QueryOperationResponse)q;     // Downcast to get the Headers in the reply.
        Debug.WriteLine("Request URI: " + qReply.Query.RequestUri);
        string cs = qReply.Headers["EntryCount"];
        count = int.Parse(cs);
        return q;
    }

     

    Test

    One down side here is that we have to send our query as an entity Sql string, so we don't get the help of linq expressions or designer support.  If there was a way to get the user's query inside a service operation, we could use that query and append .Count() to it.  TMK, there is not a way to do that with Astoria.  If anyone has ideas on that, please let me know.

    // Get all entries > 1.  Take 10 and skip 0. The count of all entries > 1 will be returned so you can set your paging buttons (i.e. Next, Prev) as needed.

    int count;
    string pred = "it.EntryID>1";
    var q = db.GetEntries(pred, "it.IsSticky desc, it.Created desc", 0, 10, out count);
    Console.WriteLine("Count: {0}", count);

    November 13

    Back to CSV - Convert CSV text to Objects; via JSON

    As Json is easier to read and write then Xml. It follows that CSV (comma seperated values) is easier to read and write then Json. CSV also has tools such as Excel and others that make it easy to work with and create. So if you ever want to create a config or data file for your next app, here is some code to convert CSV to JSON to POCO objects.

    Control Method

    public void ConvertCsvToObjects()
    {
        string csv = File.ReadAllText(@"c:\temp\mycsv.txt");
        /* mycsv.txt - Note the doube quotes around strings are required by json.
        ID, Name, Price
        1, "ABC", 1200.00
        2, "Zip Co.", 1400
        3, "Contoso", 5000
         */
    
        // Step 1: Reshape csv to a json array format.
        string json = csv.CsvToJson();
        Console.WriteLine(json);
        /* JSON text
        [ 
        {ID: 1, Name: "ABC", Price: 1200.00},
        {ID: 2, Name: "Zip Co.", Price: 1400},
        {ID: 3, Name: "Contoso", Price: 5000}
        ]
        */
    
        // Step 2: Convert json to objects.
        List<Customer> customers = json.FromJson<List<Customer>>();
        foreach(var cust in customers)
            Console.WriteLine("{0}\t{1}\t{2:c}", cust.ID, cust.Name, cust.Price);
        /* Output.
        1    ABC    $1,200.00
        2    Zip Co.    $1,400.00
        3    Contoso    $5,000.00
         */
    }
    public class Customer
    {
        public int ID {get;set;}
        public string Name { get; set; }
        public decimal Price { get; set; }
    }

    CsvToJson extention method

    /// <summary>
    /// Converts a CSV string to a Json array format.
    /// </summary>
    /// <remarks>First line in CSV must be a header with field name columns.</remarks>
    /// <param name="value"></param>
    /// <returns></returns>
    public static string CsvToJson(this string value)
    {
        // Get lines.
        if (value == null) return null;
        string[] lines = value.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
        if (lines.Length < 2) throw new InvalidDataException("Must have header line.");
    
        // Get headers.
        string[] headers = lines.First().SplitQuotedLine(new char[] { ',' }, false);
    
        // Build JSON array.
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("[");
        for (int i = 1; i < lines.Length; i++)
        {
            string[] fields = lines[i].SplitQuotedLine(new char[] { ',', ' ' }, true, '"', false);
            if (fields.Length != headers.Length) throw new InvalidDataException("Field count must match header count.");
            var jsonElements = headers.Zip(fields, (header, field) => string.Format("{0}: {1}", header, field)).ToArray();
            string jsonObject = "{" + string.Format("{0}", string.Join(",", jsonElements)) + "}";
            if (i < lines.Length - 1)
                jsonObject += ",";
            sb.AppendLine(jsonObject);
        }
        sb.AppendLine("]");
        return sb.ToString();
    }

    FromJson extention method

    public static T FromJson<T>(this string json)
    {
        JavaScriptSerializer ser = new JavaScriptSerializer();
        return ser.Deserialize<T>(json);
    }
    October 27

    Social Rest

    Almost complete with my new social service codenamed "Social Rest".  Still needs a name.

    image

    October 19

    LINQ-a-fi your file system and create a neat little Grep tool

    After watching this Channel9 video http://channel9.msdn.com/shows/Going+Deep/Erik-Meijer-and-Bart-De-Smet-LINQ-to-Anything/

    I was inspired to try out writing my own domain specific language (DSL) for the file system.  I started with writing my own Where and Select in a class, but soon discovered I did not need that.  All a really needed was a method to return IEnumerable and an abstraction to make using FileSystemInfo a bit easier to use with linq.  So I created LFileInfo (Linq FileInfo) for lack of a better name, and a StreamIndexer as a simple wrapper around a StreamReader to give me an Indexer (i.e. char c = file[12]) over a file.  The indexer was not really required and has nothing to do with linq-ing my LFileInfo class, but it make searching the file easier in Like() algo.  In effect, what we have here is another way to Grep (e.g. search) using Linq.  So we created our own DSL without writing any parser code or coming up with some new syntax.  We leverage the power of linq to build something fairly useful.

    Sample usage of LFileInfo below. Other Test methods given in the LFileInfo class:

    Console.WriteLine("\nGet number of files and total size under a dir.");
    long totSize = 0;
    long totFiles = 0;
    var q = (from f in new LFileInfo(@"c:\temp").Children(true)
             let x = totSize += f.Length
             let y = totFiles++
             select f);

    var list = q.ToList(); // Run the query.

    Console.WriteLine("Total Size:{0:N} Total Files: {1}", totSize, totFiles);

     

    // LFileInfo. Wraps a FileSystemInfo object to allow us to more simply "linq-a-fi" directory operations.
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    using System.Diagnostics;

    namespace WJS.Utils
    {
        public class LFileInfo
        {
            private FileSystemInfo fi;
            private int level;
            private LFileInfo parent;
            private List<LFileInfo> children;

            public LFileInfo(string path)
            {
                if ((File.GetAttributes(path) & FileAttributes.Directory) == FileAttributes.Directory)
                    fi = new DirectoryInfo(path);
                else
                    fi = new FileInfo(path);
            }

            private LFileInfo(FileSystemInfo item)
            {
                fi = item;
            }
            public LFileInfo Parent
            {
                get { return this.parent; }
            }
            public FileSystemInfo FileSystemInfo
            {
                get { return this.fi; }
            }

            IEnumerable<LFileInfo> Children()
            {
                foreach (var c in Children(false))
                    yield return c;
            }

            IEnumerable<LFileInfo> Children(bool recurse)
            {
                if (!this.IsDirectory)
                    yield break;

                if (this.children != null)
                {
                    // enum from from cache.
                    foreach (var f in this.children)
                    {
                        yield return f;
                        if (recurse && f.IsDirectory)
                        {
                            foreach (var l in f.Children(true))
                                yield return l;
                        }
                    }
                    yield break;
                }
                else
                {
                    // Build cache from disk. Note, this is still lazy. We only
                    // continue searching FAT, after yielding. GetFileSystemInfos()
                    // is not lazy, so a directory read returns all fileinfos in that dir.
                    this.children = new List<LFileInfo>();
                    DirectoryInfo di = (DirectoryInfo)fi;
                    //if (di.FullName.StartsWith(@"c:\temp\system", StringComparison.OrdinalIgnoreCase))
                    //    Debugger.Break();
                    var infos = di.GetFileSystemInfos();
                    foreach (var f in infos)
                    {
                        LFileInfo lfi = new LFileInfo(f);
                        lfi.level = this.level + 1;
                        lfi.parent = this;
                        this.children.Add(lfi);
                        yield return lfi;
                        if (recurse && f is DirectoryInfo)
                        {
                            DirectoryInfo di2 = (DirectoryInfo)f;
                            if (di2 != null)
                            {
                                LFileInfo nfi = new LFileInfo(di2);
                                nfi.level = this.level + 1;
                                nfi.parent = this;
                                var children = nfi.Children(recurse);
                                foreach (var f2 in children)
                                    yield return f2;
                            }
                        }
                    }
                }
            }

            public string Name
            {
                get { return fi.Name; }
            }

            public string Extension
            {
                get { return fi.Extension; }
            }

            public string FullName
            {
                get { return fi.FullName; }
            }

            public int Level
            {
                get { return this.level; }
            }

            public long Length
            {
                get
                {
                    if (IsDirectory)
                        return 0;
                    return ((FileInfo)fi).Length;
                }
            }

            public bool IsFile
            {
                get { return !IsDirectory; }
            }

            public bool IsDirectory
            {
                get
                {
                    return (fi is DirectoryInfo);
                }
            }

            private bool CanRead
            {
                get
                {
                    try
                    {
                        using (var f = File.OpenRead(fi.FullName))
                        {
                            return true;
                        }
                    }
                    catch
                    {
                        return false;
                    }
                }
            }

            public string ReadAllText()
            {
                if (IsFile)
                    return File.ReadAllText(fi.FullName);
                else
                    return null;
            }

            public string[] ReadAllLines()
            {
                if (IsFile)
                    return File.ReadAllLines(fi.FullName);
                else
                    return null;
            }

            public byte[] ReadAllBytes()
            {
                if (IsFile)
                    return File.ReadAllBytes(fi.FullName);
                else
                    return null;
            }

            public bool Like(string pattern, bool caseSensitive)
            {
                StreamIndexer si = new StreamIndexer(this.fi.FullName);
                int matchIndex = 0;
                bool result = Like(si, pattern, caseSensitive, ref matchIndex);
                return result;
            }

            /// <summary>
            /// Uses a stream wrapper that exposes an iterator to allow reading a file by index.
            /// </summary>
            private static bool Like(StreamIndexer input, string pattern, bool caseSensitive, ref int startIndex)
            {
                if (input == null) throw new ArgumentNullException("input");
                if (pattern == null)
                    return false;

                // Setup case function.
                Func<char, char, bool> equal;
                if (caseSensitive)
                    equal = (char c1, char c2) =>
                    {
                        bool r = c1 == c2;
                        return r;
                    };
                else
                    equal = (char c1, char c2) =>
                    {
                        bool r = char.ToLower(c1) == char.ToLower(c2);
                        return r;
                    };

                // Do pattern matching.
                int i = 0;
                int j = 0;
                while (i < input.Length && j < pattern.Length && pattern[j] != '*')
                {
                    if ( (!equal(pattern[j], (char)input[i])) && (!equal(pattern[j], '?')) )
                    {
                        return false;
                    }
                    i++;
                    j++;
                }

                // If we have reached the end of the pattern without finding a wildcard,
                // the match must fail if the string is longer or shorter than the pattern.
                if (j == pattern.Length)
                    return input.Length == pattern.Length;

                int cp = 0;
                int mp = 0;
                while (i < input.Length)
                {
                    if (j < pattern.Length && pattern[j] == '*')
                    {
                        if (++j >= pattern.Length) //Nothing more in pattern so we match.
                        {
                            startIndex = i-1;
                            return true;
                        }
                        mp = j;
                        cp = i + 1;
                    }
                    else if (j < pattern.Length && ( equal(pattern[j], (char)input[i]) || pattern[j] == '?'))
                    {
                        j++;
                        i++;
                    }
                    else
                    {
                        j = mp;
                        i = cp++;
                    }
                }

                while (j < pattern.Length && pattern[j] == '*')
                {
                    j++;
                }

                startIndex = i;
                return j >= pattern.Length;
            }
            public static int IndexOfAny(string source, string ofAny)
            {
                if (source == null || ofAny == null) return 0;
                for(int i=0; i<source.Length; i++)
                {
                    char c = source[i];
                    foreach (char c2 in ofAny)
                    {
                        if (c == c2) return i;
                    }
                }
                return -1;
            }

            /// <summary>
            /// Return true if input string matches pattern.
            /// </summary>
            public static bool Like(string input, string pattern, bool caseSensitive)
            {
                if (pattern == null && input == null)
                    return true;
                if (pattern == null || input == null)
                    return false;

                // Convert both string and pattern to lower case for comparison.
                if (!caseSensitive)
                {
                    pattern = pattern.ToLower();
                    input = input.ToLower();
                }

                // If pattern doesn't actually contain any wildcards, use simple equality.
                if (IndexOfAny(pattern, "*?") == -1)
                    return input == pattern;

                // Otherwise do pattern matching.
                int i = 0;
                int j = 0;
                while (i < input.Length && j < pattern.Length && pattern[j] != '*')
                {
                    if ((pattern[j] != input[i]) && (pattern[j] != '?'))
                    {
                        return false;
                    }
                    i++;
                    j++;
                }

                // If we have reached the end of the pattern without finding a wildcard,
                // the match must fail if the string is longer or shorter than the pattern.
                if (j == pattern.Length)
                    return input.Length == pattern.Length;

                int cp = 0;
                int mp = 0;
                while (i < input.Length)
                {
                    if (j < pattern.Length && pattern[j] == '*')
                    {
                        if (++j >= pattern.Length)
                        {
                            return true;
                        }
                        mp = j;
                        cp = i + 1;
                    }
                    else if (j < pattern.Length && (pattern[j] == input[i] || pattern[j] == '?'))
                    {
                        j++;
                        i++;
                    }
                    else
                    {
                        j = mp;
                        i = cp++;
                    }
                }

                while (j < pattern.Length && pattern[j] == '*')
                {
                    j++;
                }

                return j >= pattern.Length;
            }

            // Some sample tests. Remove Test methods from final code.
            public static void Test1()
            {
                // Get all directories under a root.
                Console.WriteLine("\nAll directories under a root.");
                var q = from f in new LFileInfo(@"c:\temp").Children()
                        where (f.IsDirectory)
                        select f;
                foreach(var f in q)
                    Console.WriteLine(f.FullName);
            }

            public static void Test2()
            {
                // Get directories that don't have any files. The power of linq really shows here.
                Console.WriteLine("\nAll directories with no files.");
                var q = (from f in new LFileInfo(@"c:\temp").Children(true)
                        where f.IsDirectory && !f.Children().Any(e=>e.IsFile)
                        select f);

                foreach(var f in q)
                    Console.WriteLine("{0} {1} Level:{2}", f.IsDirectory, f.FullName, f.Level);
            }

            public static void Test3()
            {
                // Get number of files and total size under a dir.
                Console.WriteLine("\nGet number of files and total size under a dir.");
                string dir = @"c:\temp";
                long totSize = 0;
                long totFiles = 0;
                var q = (from f in new LFileInfo(dir).Children(true)
                         let x = totSize += f.Length
                         let y = totFiles++
                         orderby f.Name, f.IsFile, f.Level
                         select f);

                foreach (var f in q)
                    Console.WriteLine("{0} {1} Level:{2}", f.IsDirectory, f.FullName, f.Level);

                Console.WriteLine("Total Size:{0:N} Total Files: {1}", totSize, totFiles);
            }
            public static void Test5()
            {
                Console.WriteLine("\nAll files over 1MB:");
                var q = from f in new LFileInfo(@"c:\temp").Children(true)
                        where f.Length > 1024 * 1024
                        select f;
                foreach(var f in q)
                    Console.WriteLine("{0}\t\t\tLen: {1:N}", f.FullName, f.Length);
            }

            // Print a dir tree to the console.
            public static void Test6(string path)
            {
                //string currDir = System.AppDomain.CurrentDomain.BaseDirectory;
                //string pDir = new DirectoryInfo(currDir).Parent.Parent.FullName;

                LFileInfo dir = new LFileInfo(path);
                PrintTree(dir);
            }

            // Use Like pattern matching to search files.
            public static void Test7()
            {          
                var q = from f in new LFileInfo(@"c:\temp").Children(true)
                        where LFileInfo.Like(f.Name, "*.txt", false)
                        where f.Like("* where *", true)
                        select f;

                var list = q.ToList();
                Console.WriteLine("\nFile matching pattern: {0}", list.Count());
                foreach (var f in list)
                    Console.WriteLine("{0} Ext:{1}", f.Name, f.Extension);
            }

            /// <summary>
            /// Print a dir tree starting from entry.
            /// </summary>
            private static void PrintTree(LFileInfo entry)
            {
                string pad = "";
                if (entry.Level > 0) pad = new string('.', (entry.Level) * 2);
                if (entry.IsDirectory) pad += "+";
                Console.WriteLine(pad + entry.Name);

                if (entry.IsDirectory)
                {
                    var children = entry.Children().OrderBy(e => e.IsDirectory);
                    foreach (LFileInfo lf in children)
                        PrintTree(lf);
                }
            }
        }
    }

     

    // StreamIndexer class to wrap a StreamReader and expose an indexer.
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;

    namespace WJS.Utils
    {
        public class StreamIndexer
        {
            private StreamReader sr;
            public StreamIndexer(string path)
            {
                sr = new StreamReader(path);
            }

            public long Length
            {
                get { return sr.BaseStream.Length; }
            }

            public void Close()
            {
                sr.Close();
            }

            public IEnumerable<Char> Characters()
            {
                int ch = 0;
                while ((ch = sr.Read()) >= 0)
                {
                    yield return (char)ch;
                }
            }

            public int this[int index]
            {
                get
                {
                    sr.BaseStream.Seek(index, SeekOrigin.Begin);
                    return sr.Read();
                }
            }
        }
    }

    October 09

    Fiddler with Ado.Net Data Services

    To get Fiddler 2.1.8.2 to work with Visual Studio Development server and using Ado.Net Rest services, I found only 1 thing that actually works:

    1) Add a new host to your \etc\hosts file:

    127.0.0.1 local

    The name is not important, but local works. localhost does not work for some reason with Fiddler.

    2) Set Fiddler to filter on host name "local".  Just to filter out public traffic on your machine.

    3) Change your client library URL to use the new URL.  If you have Application settings in the client project, change the ServiceUri. If you use Client Application services, also change those locations in the application Properties / Services tab.  Use your service name below.

    Example: http://local:7777/RestService.svc/

    4) Change your Rest service's web.config to listen on "local" name. Use Specific Port instead of Auto-assign port in Web tab of application Properties.

    <services>
      <service name="MyRestService">
        <endpoint address="http://local:7777/RestService.svc/" binding="webHttpBinding" bindingConfiguration="higherMessageSize" contract="System.Data.Services.IRequestHandler">
        </endpoint>
      </service>
    </services>

    5) Verify service starts and listens on URL from a brower and point to http://local:7777/RestService.svc/ to see the service meta data.

    Other solutions on the net such as adding a dot to localhost http://localhost.:7777/Service.svc/  Do not seem to work for me (at least on Vista).

    The solution above works from .Net client app and IE.

    September 13

    OpenID and CardSpace

    OpenID and CardSpace are both complementary and competing technologies.  An interesting thing about OpenID it that it allows you to "attach" a Card to your OpenID account (create an openid at myopenid.com if you have not already).  That is interesting as it allows you to logon to your OpenID account using your InfoCard on your desktop.  That is pretty powerful because that means you can logon to any OpenID site using your InfoCard.  So the web designer that enables OpenID logins will also get CardSpace for free without writing a single line of additional code - that is pretty cool.

    In a previous post, I wrote on the need of a Proxy that would allow me to get my Card easily when on a public pc.  OpenID with cardspace support does not get us there, because I still have to have the card on the machine I am at in order to authenticate to OpenID using my card.  However, OpenID does allow me to login using name/pwd pair, so that is always a good last resort.  However this can be made better I think.

    What if the OpenID provider also "stored" my Card in encrypted form?  Then I could download that card and use it.  To make this process simple, MS needs to create a temp proxy card.  So on a new machine I create a TProxy card that have my name and a URI to my OpenID provider.  Now when I try to use TProxy card, it downloads my real card from the provider and decrypts by prompting for a password.  Now that I have my real card local, I can then continue to use as normal during the session.  The provider only ever sees my card in encrypted form so it is protected from snooping.  Now the question is how to get rid of local card when done?  If I log out, the CardSpace framework and just clear card memory and be done.  But what if I just walk away and forget to logout?  I guess that is same issue as forgetting your credit card at a store and hoping nobody uses it until you cancel the card.  One option to mitigate the risk is to add a timeout on the card.

    I guess another option would be a usb smart card and a pwd pair.  Keep your smart card on your key chain and you can login anywhere.  Loose your card, and someone still needs your password.  So I need to login once (to decrypt the card on the smart card) and can use the card for remainder of my session.

    September 12

    CardSpace (InfoCard) replay and thoughts

    InfoCard (i.e. CardSpace) has been out for a bit, but does not get much joy yet. I think probably cause a lot people just don't know about it or don't care yet.  But the other day I created a OpenID and started using it for identi.ca.  identi.ca is a good example of a site that uses OpenID well and makes it easy.  That got me thinking all sites should use OpenID.  Then I rediscovered CardSpace because OpenID also always you to attach an InfoCard to your id.  So that got me thinking more about CardSpace and using it for my web site.

    In general, I am starting to think InfoCard (or the idea of InfoCard) is almost the perfect security model for the following reasons:

    1) You control your cards locally. You don't have various names and password strung out all over the INET.

    2) You can use same card on multiple sites.

    3) You only share the info you want in the card.

    4) You get to pick your card at login using a picture and named card.  This makes it easy to remember what card you used at what site. Vista actually has a nice CardSpace control for this and it works well (can download for XP).

    5) People can't hack your password on a site using normal hash tables (rainbow) or brute force.  I am not sure yet if it is possible to brute force an InfoCard.

    6) It moves the security model to a standard and tested model.  Today, each site may (or may not) protect your password with all kinds of good or no good hash and/or encryption methods.  Point it, you don't know what method is used - it could be stored in the clear!  InfoCard removes many of the server side variants and acts almost like an agent on your behalf.

    7) The framework it there where in the future you can time limit your card and revoke it from use.

    Given the upsides and the fact that I am in control of the card, I am starting to wonder if OpenID is the right model.

    That said, AFAICT, there is one primary down side - you have to have your card on each machine you use.  That means if you are on some random machine, you need to figure our how to get your card and have to worry about removing it from the machine when you done.  Maybe what we need is password protected Temp Proxy Card.  When you are at a "public" PC, you create a Proxy Card that includes the URL of your real card (stored at a public URL that is encrypted AES with your known password).  Then browse to web site that requires a card, the Card selector will popup and you select your Proxy card.  The framework will download and decrypt your real card and use that and cache it in memory only in encrypted form using your same password as your proxy card.  Maybe it also has a time limit on it.

    Make your web site InfoCard enabled.  I have looked at a couple solutions, but found Dominick's control the best fit and ease of use.  It also supports non-SSL mode, as many web sites (i.e. blogs) do not use SSL.  Having the option is nice.

    Dominick Baier's IC Selector at: http://www.codeplex.com/InfoCardSelector/Release/ProjectReleases.aspx?ReleaseId=12626

    August 23

    Transaction is not allowed error using ADO.Net Entities.

    Doing some ADO.Net Entity queries and updates the other day, I kept getting this exception:

    "New transaction is not allowed because there are other threads running in the session."

    foreach (Users u in db.Users.Include("Queries"))
    {

          // A db.SaveChanges() here will throw the error.
    }

     

    The reason is we have an open Reader in our foreach and we can't nest trasactions like that.  The solution is to read everything we need first so we close the reader.  The simple solution here is to append .ToArray() like:

    foreach (Users u in db.Users.Include("Queries").ToArray())
    {

          // A db.SaveChanges() here should work.
    }

    August 20

    ADO.Net Data Services after Silverlight Tools sp1

    After installing Silverlight VS Tools SP1 beta, not only did SL designer not work, but it somehow messed up my ADO.Net REST services.  Was getting strange exceptions.  I uninstalled SL Tools and reinstalled VS SP1 (not sure if that was needed) and ADO.Net data services seem to be back working again.  Short story, don't install SL tools yet.  I should say, don't install beta software - but I could not follow my own advice.

    August 15

    Turn off feed reading view to debug your ADO.Net

    If your trying to expose a new ADO.Net dataservice and work some samples, you may get some strange output in your IE that looks like a feed page and wonder why you can't see the XML as the samples show.  Just turn off the feed reading view in IE.

     

    image

    image

    Silverlight Streaming Service

    If you have not looked at in a while, the new SL service allows you to directly upload you .wmv files.  So you don't need to use Encoder anymore to encode a SL video into a SL application.  This makes it really simple to public videos for your blogs, etc.  After uploading your video, the service gives you chance to do a quick preview and gives you the html you need to embed the video in your blog.  Simple and elegant - nice.

    http://silverlight.live.com

    August 14

    Microsoft Response Point PBX

    Man, I am really excited about the new small business PBX system MS released - Response Point.

    It seems like one of those no brainers - Create a platform that can be extended and programmed against easily using .Net, have a blue button and voice commands, connect the phone via Ethernet and IP, and make it super easy to hookup,manage, and buy.  That is a formula for success IMO.  I am looking forward to seeing the SDK.  I can already envision a wave of social apps for this thing.  Now I just need to figure out how to get one to experiment with...

    http://www.microsoft.com/responsepoint/

    January 09

    Enterprise Framework LINQ Queries failing - MSDN Forums

    Good Linq post from Colin Meek below:
    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2078990&SiteID=1 

    To give a sense of what is shared and what isn’t between LINQ to SQL and LINQ to Entities (both in terms of modules and behavior) I’ll repeat some information that’s probably familiar to most people on this thread…

    LINQ providers support integrated query via the IQueryable and IQueryProvider interfaces. The provider’s job is basically to translate LINQ expression trees into native queries. LINQ to SQL and LINQ to Entities accomplish this translation in roughly the same way, though nothing is shared beyond the System.Linq components in System.Core.dll.

    Matt Warren’s IQueryable series gives a more detailed overview (http://blogs.msdn.com/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx) but I’ll include the highlights here to provide some context:

    1. At compile time, user code is translated into (or directly uses) expression builder calls.

    2. At runtime, calls to System.Linq.Queryable methods yield additional expression trees with argument expressions inline.

    3. The provider is passed a LINQ expression which it translates into a “query” expression. LINQ to SQL and LINQ to Entities use different internal representations of the expression (a variant of LINQ expressions and Canonical Query Trees respectively). This step includes the replacement of method calls with query operators and the replacement of member accesses with store function calls.

    4. Each provider then compensates for non-relational structures in the query (e.g. types, nested collections in results, etc.)

    5. Native queries are generated and executed.

    6. Query results are reshaped (basically the inverse of step 4).

    As I mentioned, there is really nothing shared between LINQ to SQL and LINQ to Entities beyond step 2. The example in this thread illustrates a couple of differences between the two stacks in the handling of step 3 and step 4.

    Implicit vs. explicit client evaluation

    LINQ to SQL is a hybrid provider in the sense that it supports evaluation of parts of the query in the client and parts in the store. As a result, the following query succeeds in LINQ to SQL but fails in LINQ to Entities:

    var query = from o in context.Orders

    where GetCutoffDate() > o.OrderDate

    select o;

    As Brian suggested, it must be rewritten as:

    DateTime cutoffDate = GetCutoffDate();

    var query = from o in context.Orders

    where cutoffDate > o.OrderDate

    select o;

    This makes the boundary between client and store evaluation explicit. There is a tradeoff between self-containment of queries and predictability of behavior for non-expert users.

    Canonical functions vs. store functions

    Of course, the sub-expression mentioned in this thread could be entirely translated into Transact-SQL function calls:

    DateTime.UtcNow.AddDays(-180)

    becomes

    DATEADD(day, -180, GETUTCDATE())

    Note that although LINQ to SQL could translate the above expression into Transact-SQL, it chooses to evaluate it on the client because it is uncorrelated. The behavior is different depending on whether results are correlated or not.

    In Beta 2, LINQ to Entities does not support the DateTime.AddDays method simply because a corresponding “canonical function” does not exist. Canonical functions are store agnostic and can be implemented by arbitrary Entity Frameworks providers. We plan on introducing a few more DateTime-related functions in the next release (the usual disclaimers apply) at which point this expression will be supported by LINQ to Entities.

    Regarding Rick’s question: Entity-SQL supports both canonical and store-specific functions. For functions not supported by LINQ to Entities, this provides the cleanest workaround. Where the gap is due to unsupported CLR methods – in either LINQ to SQL or LINQ to Entities – consider explicitly breaking up the query into client- and store- side elements. For instance, to extend the above example:

    DateTime cutoffDate = GetCutoffDate();

    var query = from o in context.Orders

    where cutoffDate > o.OrderDate

    select o;

    var hybridQuery = from row in query.AsEnumerable()

    select ShapeResult(row.Oid, row.Description, row.OrderDate);

    Recommendation:

    When working with LINQ to Entities, keep in mind that boundaries between client- and store- execution are explicit. To use a value computed on the client within a query, assign the value to a local variable before executing (see the assignment to cutoffDate above). To perform client-side processing of results, use the AsEnumerable method to yield results from the store query and then apply client-side logic (see the assignment to hybridQuery above).

    Thanks,
    -Colin

    Enterprise Framework LINQ Queries failing - MSDN Forums

    January 06

    Make existing project a Volta project - MSDN Forums

     

    Yes, this is possible, allthough you will need to modify the project file by hand. You can do this by right-clicking on the project and selecting'Unload project'. Next you will need to right-click on it again and select 'Edit ???.??proj'.

    Then in the top-level propertygroup add the VoltaProjectKind, VoltaVersion and the ProjectTypeGuids elements.

    Code Block

    <Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
         (....)

    <VoltaProjectKind>WinformsApplication</VoltaProjectKind>

    <VoltaVersion>1.0</VoltaVersion>

    <ProjectTypeGuids></ProjectTypeGuids>

        (....)

    </ProjectTypeGuids>

    If it is a C# project insert:

    {41daf090-9073-464d-9898-7bcdfc7d2642};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}

    into the ProjectTypeGuids element. If it is a VB project insert:

    {41daf090-9073-464d-9898-7bcdfc7d2642};{F184B08F-C81C-45F6-A57F-5ABD9991F28F}

    The last thing to do is to replace:

    <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

    or:

    <Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />

    with:

    <Import Project="$(VoltaInstallPath)\Microsoft.Volta.targets" />

    This should do the trick. Please let us know if it doesn't.

    Thanks,

    Danny

    Make existing project a Volta project - MSDN Forums