Monday, February 25, 2013

Run Chai based tests with PhantomJs


PhantomJs is installed at C:\Program Files (x86)\phantomjs-1.8.1-windows
then add it to the path
i had to put chai.js in the target directory of the phantom script which makes me sad, but perhaps I'll figure that out next.

at the command prompt:

C:\Projects\mine\phantomjs>phantomjs payerportal.js>phantomjs hellophantom.js
phantom.injectJs("chai.js");

var assert = chai.assert;
var pageToTest= 'http://localhost/helloworld/';
var url = pageToTest;
page.open(url, function(status) {
 try{
       assert.typeOf('test','string','test is a string');
       
      } catch(err) {console.log('Test failed:'+err);}
        
});

Monday, February 11, 2013

What did you do this weekend?


Well it's been quite a full weekend!

During the work week:

  • Learned about WebAPI's IQueryable possibilities
  • Found out they changed the ruling on Entity Framework
    • We can now select straight into POCOs instead of only anonymous types or EF types
    • Still can't find any articles, blog posts, or announcements about this change.
  • Forced EF to allow me to do queries that span linked databases.
  • Used Knockout to consume the OData (or WebApi IQueryable)
    • complete with a user friendly search form
  • Explored PhantomJs for headless browser automation and testing
  • Updated my win forms tool for scraping data from our Stash and Crucible
  • Explored some SpecFlow

What did you do?

MyModelMetadataProvider

So I was tired of not having any inheritance on Attributes in Mvc for scaffolding, column order, display names and the rest. Here's some code to Allow an attribute called ParentsAttribute to allow you to inject parental metadata for another class that Mvc's DisplayFor will listen to.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MyMvc.Models
{

  public class ParentsAttribute:Attribute
  {
    public Type[] Values { get; set; }
    public ParentsAttribute(params Type[] parents)
    {
      Values = parents;
    }
  }


  public class MyModelMetadataProvider:DataAnnotationsModelMetadataProvider
  {

    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
      //called once for each property of the viewmodel

      var attrs =attributes.ToArray(); // for possible multiple enumeration
      
      var modelMetadata=base.CreateMetadata(attrs, containerType, modelAccessor, modelType, propertyName);

      if (containerType == null) return modelMetadata;
      var parents =(ParentsAttribute) containerType.GetCustomAttributes(typeof(ParentsAttribute),false).FirstOrDefault(); //search all parents for display attributes that we can inherit
      if(parents==null)
        return modelMetadata;

      var props = from metdataParents in parents.Values
                  from mProp in metdataParents.GetProperties()
              where mProp.CustomAttributes.Any() && mProp.Name == propertyName
                  select new { parent = metdataParents, mProp };
      var sample=props.ToArray();


      var q = from metdataParents in parents.Values
            from mProp in metdataParents.GetProperties()
            where mProp.CustomAttributes.Any() && mProp.Name == propertyName
            
            let da = mProp.GetCustomAttributes(typeof(DisplayAttribute),true).OfType<DisplayAttribute>().FirstOrDefault()
            let dna = mProp.GetCustomAttributes(typeof(DisplayNameAttribute),true).OfType<DisplayNameAttribute>().FirstOrDefault()
            //don't copy down required, may not be required for the current class or viewmodel
            //let ra = mProp.GetCustomAttributes(typeof(RequiredAttribute), true).OfType<RequiredAttribute>().FirstOrDefault()
            where da !=null || dna !=null
            
              select new { mProp,da,dna };
      foreach (var modifier in q)
      {
        if (modifier.da != null)
        {
          //http://aspnetwebstack.codeplex.com/SourceControl/changeset/view/1b78397f32fc#src/System.Web.Mvc/DataAnnotationsModelMetadataProvider.cs
          if (string.IsNullOrEmpty(modelMetadata.Description)) modelMetadata.Description = modifier.da.GetDescription();
          if (string.IsNullOrEmpty(modelMetadata.ShortDisplayName)) modelMetadata.ShortDisplayName = modifier.da.GetShortName();
          if (string.IsNullOrEmpty(modelMetadata.Watermark)) modelMetadata.Watermark = modifier.da.GetPrompt();
          modelMetadata.Order = modifier.da.GetOrder() ?? modelMetadata.Order;
          if (string.IsNullOrEmpty(modifier.da.GetName()) == false) //only set current object if it is overriding the display
          {
            modelMetadata.DisplayName = modifier.da.GetName();  
          } else if (modifier.dna != null)
          {
            modelMetadata.DisplayName = modifier.dna.DisplayName;
          }
          
        }
        
      }

      return modelMetadata;

    }
  }
}
And don't forget to hook it up in your Global.asax! ModelMetadataProviders.Current = new MyModelMetadataProvider();

Friday, February 8, 2013

LinkedServerDatabase Query with CodeFirst Entity Framework

So you have a Model or Poco (or ViewModel) and you want to populate it via EF code first. However, the Entity Framework refuses to let you run a simple query against the connection when it involves a table that's linked. Here's the Poco Model of the linked db
[Table("Customer", Schema="LinkedDatabaseName].dbo")]
  public class Customer
  {
    [Key]
    [Column("Customer_Id")]
    public int CustomerId { get; set; }
    [Column("Company_Name")]
    [Display(Name="CustomerName")]
    public string CompanyName { get; set; }
    public string CustomerAlias { get; set; }
  }
Here's the Context Method that consumes it:
public IEnumerable<LandingViewModel> GetTrackingFiles()
    {
      var q = from tf in TrackedFiles
              join lfs in FileStatuses on tf.FileStatusId equals lfs.FileStatusId into lfsg
              from fs in lfsg.DefaultIfEmpty()
              join lc in Customers on tf.CustomerId equals lc.CustomerId into lcg
              from c in lcg.DefaultIfEmpty()
              select
                new
                  {
                    tf.FileGuid,
                    tf.FileName,
                    tf.FileId,
                    tf.CustomerId,
                    tf.ExpectedTrxCount,
                    tf.ActualTrxCount,
                    tf.ExpectedTrxPaidAmount,
                    tf.ActualTrxPaidAmount,
                    tf.ExpectedClaimCount,
                    tf.ActualClaimCount,
                    tf.FileRecieved,
                    tf.FileCompleted,
                    fs.FileStatusName,
                    tf.FilePath,
                    c.CompanyName,
                    c.CustomerAlias
                  };
      var sql = q.ToString();
      var fixedSql = sql.Replace("[LinkedDatabaseName]].dbo]", "[LinkedDatabaseName].[dbo]");
      Trace.WriteLine(fixedSql); // look at the result in the trace output
      
      var result=this.Database.SqlQuery<LandingViewModel>(fixedSql);

      

      return result;
    }

Wednesday, February 6, 2013

AutoScaffold Index.cshtml tabular view site-wide

I was tired of generating the index.cshtml list over and over again everytime the model or viewmodel changes. So how could I get that to be runtime generated? Enter Haacked's article on Mvc Tabular Display Template Updated to work with Razor and with IEnumerable First the DisplayTemplate
@using System
@using MyMvc.Models
@model IEnumerable<dynamic>
@{
    //http://haacked.com/archive/2010/05/05/asp-net-mvc-tabular-display-template.aspx
    var items = Model.ToArray();
    var metadata = ModelMetadata.FromLambdaExpression(m => m.ToArray()[0], ViewData);
    var properties = metadata.Properties.Where(pm => TableViewHelper.ShouldShow(pm, ViewData)).OrderBy(pm => pm.Order);
}

<table>
    <thead>
        <tr>
            @foreach (var property in properties)
            {
                <th>@property.GetDisplayName()</th>
            }
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            var itemMetadata = ModelMetadata.FromLambdaExpression(m => item, ViewData);
            <tr>
               
                @foreach (var property in properties)
                {
                    var propertyMetdata = itemMetadata.Properties.Single(m => m.PropertyName == property.PropertyName);
                    <td>
                        @Html.DisplayFor(m => propertyMetdata.Model)
                    </td>
                }
            </tr>
        }
    </tbody>
    
</table>

<span>Showing @Model.Count() items</span>
Then the helper
@using System
@using MyMvc.Models
@model IEnumerable<dynamic>
@{
    //http://haacked.com/archive/2010/05/05/asp-net-mvc-tabular-display-template.aspx
    var items = Model.ToArray();
    var metadata = ModelMetadata.FromLambdaExpression(m => m.ToArray()[0], ViewData);
    var properties = metadata.Properties.Where(pm => TableViewHelper.ShouldShow(pm, ViewData)).OrderBy(pm => pm.Order);
}

<table>
    <thead>
        <tr>
            @foreach (var property in properties)
            {
                <th>@property.GetDisplayName()</th>
            }
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            var itemMetadata = ModelMetadata.FromLambdaExpression(m => item, ViewData);
            <tr>
               
                @foreach (var property in properties)
                {
                    var propertyMetdata = itemMetadata.Properties.Single(m => m.PropertyName == property.PropertyName);
                    <td>
                        @Html.DisplayFor(m => propertyMetdata.Model)
                    </td>
                }
            </tr>
        }
    </tbody>
    
</table>

<span>Showing @Model.Count() items</span>
Then add a Views/Shared/Index.cshtml
@model System.Collections.Generic.IEnumerable<dynamic>
@{
    ViewBag.Title = "Index";
}

@Html.DisplayForModel("Table")

Change your Mvc AddView template

I didn't like that the AddView template ignored the DisplayAttribute(Order=0). So I adjusted it following http://blogs.msdn.com/b/webdev/archive/2009/01/29/t4-templates-a-quick-start-guide-for-asp-net-mvc-developers.aspx I added the following to my CodeTemplates/AddView/CSHTML/List.tt file
IEnumerable<PropertyInfo> SortProperties(IEnumerable<PropertyInfo> props)
    {
      var pl = props.ToList();
      var length = pl.Count;
      var q = from p in pl
            let da = p.GetCustomAttribute<DisplayAttribute>()
            where da != null
            let o = da.GetOrder()
            where o.HasValue
            orderby o
            select new { p, o.Value };

      var ordered = q.ToList();
      var remainder = pl.Except(ordered.Select(o => o.p).ToArray()).ToArray();
      var destination = new PropertyInfo[length];

      foreach (var o in ordered)
      {
        destination[o.Value] = o.p;
      }

      if (ordered.Count == length)
        return ordered.Select(o => o.p).ToArray();

      var remainderCount = 0;
      for (int i = 0; i < pl.Count; i++)
      {
        if (destination[i] != null)
          continue;
        destination[i] = remainder[remainderCount];
        remainderCount++;

      }
      return destination;


    }
then updated GetEligibleProperties to call it in the property loop. Here's the unit test:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

using Microsoft.VisualStudio.TestTools.UnitTesting;


namespace MyMvc.Tests.CodeTemplates.AddView.CSHTML
{
  [TestClass]
  public class ListTests
  {
    class SortTester
    {
      public Guid FileGuid { get; set; }

      [Display(Order = 0)]
      public string FileName { get; set; }

      public int CustomerId { get; set; }

      [Display(Order = 1)]
      public int? ExpectedTrxCount { get; set; }
    }
    IEnumerable<PropertyInfo> SortProperties(IEnumerable<PropertyInfo> props)
    {
      var pl = props.ToList();
      var length = pl.Count;
      var q = from p in pl
            let da = p.GetCustomAttribute<DisplayAttribute>()
            where da != null
            let o = da.GetOrder()
            where o.HasValue
            orderby o
            select new { p, o.Value };

      var ordered = q.ToList();
      var remainder = pl.Except(ordered.Select(o => o.p).ToArray()).ToArray();
      var destination = new PropertyInfo[length];

      foreach (var o in ordered)
      {
        Console.WriteLine("ordering:" + o.p.Name);
        destination[o.Value] = o.p;
      }

      if (ordered.Count == length)
        return ordered.Select(o => o.p).ToArray();

      var remainderCount = 0;
      for (int i = 0; i < pl.Count; i++)
      {
        if (destination[i] != null)
          continue;
        destination[i] = remainder[remainderCount];
        remainderCount++;

      }
      foreach (var d in destination) Console.WriteLine(d.Name);
      return destination;


    }
    [TestMethod]
    public void Sort_DisplayOne_IsSecond()
    {
      var type = typeof(SortTester);
      
      var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
      var expected = props.First(p => p.Name == LinqOp.PropertyOf(()=>new SortTester().FileName).Name);
      var sorted = SortProperties(props);
      var actual = sorted.First();
      Assert.AreEqual(expected, actual);

    }
    [TestMethod]
    public void Sort_DisplayZero_IsFirst()
    {
      var type = typeof(SortTester);

      var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
      var expected = props.First(p => p.Name == LinqOp.PropertyOf(() => new SortTester().ExpectedTrxCount).Name);
      var sorted = SortProperties(props);
      var actual = sorted.Skip(1).First();
      Assert.AreEqual(expected, actual);

    }
  }
}

Here's the source of LinqOp

Tuesday, February 5, 2013

Mvc4 fresh site 'simplemembershipprovider' with existing user login table(s)

So there are a few requirements to using WebMatrix.WebData.SimpleMembershipProvider. One of these is that your PasswordHash must be stored in a column called Password. Argh! I've gotten the login part and only the login part working. Here's my Context:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Globalization;
using System.Web.Security;

namespace Models
{
  public class UsersContext : DbContext
  {
    public UsersContext()
      : base("DefaultConnection")
    {
      this.Configuration.LazyLoadingEnabled = false; //me no likey.
      Database.SetInitializer<UsersContext>(null); //clear out all the strategies so that EF will leave the existing db ALONE.

    }

    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
      //throw new UnintentionalCodeFirstException(); in the event you don't want code-first
    }
  }

  [Table("User")]
  public class User
  {
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    [Column("User_Id")]
    public int UserId { get; set; }

    [Column("User_Name")]
    public string UserName { get; set; }

    [Column("Password_Hash")]
    public string PasswordHash { get; set; }
  }
}
No changes made in Global.asax added to configuration system.web :
    <membership defaultProvider="SimpleMembershipProvider">
      <providers>
        <clear/>
        <add name="SimpleMembershipProvider" type="PaySpan.Jms.Models.SimpleMembershipProvider,PaySpan.Jms"/>
      </providers>
    </membership>
Here is the derived SimpleMembershipProvider:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Web;
using System.Web.Helpers;
using System.Web.WebPages;

using Payformance.Core.Cryptography;

namespace PaySpan.Jms.Models
{
  public class SimpleMembershipProvider : WebMatrix.WebData.SimpleMembershipProvider
  {
    
    
    // Inherited from MembershipProvider ==> Forwarded to previous provider if this provider hasn't been initialized
    public override bool ValidateUser(string username, string password)
    {
      var userHash = Crypto.HashPassword(password); //if only we were using the default asp hash provider =(
      var ourHash = Hash.HashToString(password);
      Trace.WriteLine("userHash:" + userHash);
      Trace.WriteLine("ourHash:" + ourHash);
      try
      {
        Trace.WriteLine("trying custom validate user");
        using (var db = new UsersContext())
        {
          Trace.WriteLine("trying to get userId/Hash");
          var u=db.Users.Where(up => up.UserName == username).Select(up => new { up.UserId, up.PasswordHash}).FirstOrDefault();

          Trace.WriteLine("tracing user");
          Trace.WriteLine(u);


          //if (u!=null && Crypto.VerifyHashedPassword(u.PasswordHash,userHash)) return true; // this would be if you want to use the default hash provider
          return u != null && ourHash == u.PasswordHash;

        }
        return base.ValidateUser(username, password);
      }
      catch (Exception ex)
      {
        Trace.WriteLine(ex);
        throw;
      }
    }
  }
}
Then in the provided InitializeSimpleMembershipAttribute changed it to
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "User", "User_Id", "User_Name", autoCreateTables: false);

Add diagnostics.trace output to your asp.net trace.axd

For any of you that don't know, any Asp.net web application can be told to capture all kinds of diagnostic information on the fly. In your web.config add <system.web> <trace enabled="true"/> Then localhost//trace.axd will function. However it doesn't capture any calls you make in your code to System.Diagnostics.Trace. Here's the code as configuration method to hook the two together: In Global.asax
      var gbTraceListener = new WebPageTraceListener();
      System.Diagnostics.Trace.Listeners.Add(gbTraceListener);
More information at http://msdn.microsoft.com/en-us/library/b0ectfxd(v=vs.100).aspx

Copy data from one db to another in linqpad

I wanted to pull a single row of data from one db on one server to another db on another server. using C# and LinqPad. This looks like it would have worked, if I had the matching db on localhost.
void Main()
{
  this.DeferredLoadingEnabled=false; //critical to ignore navigation properties
  var oldcon= this.Connection;
  var user =Users.First (u => u.User_Name=="dummyuser").Dump();
  
  var settings=new Newtonsoft.Json.JsonSerializerSettings(){ NullValueHandling= NullValueHandling.Ignore, ReferenceLoopHandling= ReferenceLoopHandling.Ignore, MaxDepth=1  };
  var serUser= JsonConvert.SerializeObject(user, 
  settings).Dump();
  var myConString=oldcon.ConnectionString.Replace("devdb\\be","localhost").Dump();
  var otherCon= new System.Data.SqlClient.SqlConnection(myConString);
  var otherContext=new TypedDataContext(otherCon); 
  otherContext. Users.Attach((User)JsonConvert.DeserializeObject<User>(serUser.ToString()));
  otherContext.SubmitChanges();
}