Tuesday, December 10, 2013

A little JQuery <-> Json <-> Mvc

It has been quite awhile since I've dealt with complex model binding across a set of inputs in mvc.

If one controller action's params (or a property on one of those params) is an IEnumerable<T> then Mvc will not write the element names in a way that will properly go back to the server.

Short and sweet (and probably hacky way) to do it:

I Json serialized the parent model into an html attribute on to some parent of the value(s) I want to submit. Some questions allow many answers, and I want to save each time a question answer is changed.

I'm working on making that serialization not contain the about to be consumed IEnumerable<T>property.
var save = function (element, value, event, previousValue,debug) {
    console.log('saving:' + value + ' to ' + saveUrl);

    
    var demoText = $(element).closest('[data-demographic]').attr('data-demographic');
    var demoJson = htmlDecode(demoText);
    var demoModel = JSON.parse(demoJson);
    var oldAnswers = demoModel.PossibleAnswers;
    demoModel.PossibleAnswers = [];
    //TODO: handle multi-select, single-select radio, etc...
    if (Object.prototype.toString.call(value) === '[object Array]') {
        //value and previousValue could be arrays for multi-select answers
        $.each(value, function (i, e) {
            demoModel.PossibleAnswers.push({ Id: e });
        });
    } else {
        demoModel.PossibleAnswers.push({ Id: value,Text:$(element).parent().text().trim()  });
    }
    var data = JSON.stringify(demoModel);

    data=data.replace('][', '].[');
    $.ajax({
        dataType: 'json',
        url: saveUrl,
        contentType: 'application/json; charset=utf-8',
        accept: debug ? {
            json: 'application/json',
        } : {},
        type: 'POST', data: data,
        success: function (data, status, jqXhr) {
            if (debug) {
                var answerMirror = data.PossibleAnswers;
                delete data.PossibleAnswers;
                console.log(data);
                console.log(answerMirror);
            } else { //update dom to new read-only model?
                //TODO: adjust with new html
                console.log(data);
            }
            
        }
    });
};
There's the heart of it. Notice I don't actually have to use the special name=foo.bar[0].Id on my inputs, but that is probably still a good idea. This thing was almost working without doing any JSON.stringify but the IEnumerable<T> data was ignored by Mvc's model binder. With that in mind, I had to specify the contentType of the ajax request.

Wednesday, December 4, 2013

Inline markup delegates and razor helper delegate wars

So I had some markup that was being duplicated all over the place in MVC.

This is mostly boilerplate bootstrap paneling, with masonry on top.

How would you provide a generic razor to meet bootstrap/masonry without creating a bunch of classes or partials to account for special case(s)?  How in razor would you write a method that can take inline markup (for example any @<text> call)?

 One way is @helper Take note that HelperResult's documentation says specifically it is not intended to be used directly in your code. So I headed in down the path of inline razor helper delegates:

Tuesday, July 16, 2013

How do you like your noodle baked? medium or well done?

The second reason to avoid this is simply because it bakes the noodle of anyone who reads the code. - Eric Lippert
So when I see the following... I want to scream, yell, and run away.
Csla.BusinessListBase:

public abstract class BusinessListBase<T, C> : ExtendedBindingList<C>, IEditableCollection, IBusinessObject, ISupportUndo, IUndoableObject, ICloneable, ISavable, IParent
        where T : Csla.BusinessListBase<T, C>
        where C : Csla.Core.IEditableBusinessObject
    {
     // ... other code
    }
CompanyName.Library.Base:
public abstract class CompanyBusinessBaseCollection<T, TCollection> : BusinessListBase<T, TCollection>
        where T : Csla.BusinessListBase<T, TCollection>
        where TCollection : Csla.Core.IEditableBusinessObject
    {
     // ... other code
    }
Take note... that that's 2 levels of abstract class so far.. climbing the chain we have: Csla.Core.ExtendedBindingList<T> (where T now means C), System.ComponentModel<T>. I only stopped once I hit the framework inheritance chain start.
I just had to get that out...
Now to find references to cite on my rant:
  • since inheritance is a very intimate (and encapsulation breaking) relationship, it's easy for subclasses to effectively break their superclasses by, for instance, omitting necessary behavior when they the methods are called - Martin Fowler - Designed Inheritance
  • In fact, the Object-Oriented Design Patterns book from "the gang of four" has this to say about inheritance: Prefer object composition to class inheritance
  • Inheritance is pretty enticing especially coming from procedural-land and it often looks deceptively elegant. I mean all I need to do is add this one bit of functionality to another other class, right? Well, one of the problems is that inheritance is probably the worst form of coupling you can have. Your base class breaks encapsulation by exposing implementation details to subclasses in the form of protected members. This makes your system rigid and fragile. The more tragic flaw however is the new subclass brings with it all the baggage and opinion of the inheritance chain. Why does a model that enforces validation attributes care how the model is constructed? The answer is it shouldn’t, and to add insult to injury, the better design is actually easier to implement. Listen closely and you may hear the wise whispers of our forefathers… - Inheritance is Evil: The Epic Fail of the DataAnnotationsModelBinder
  • Prefer object composition to class inheritance - JsPatterns.com - A case against inheritance
  • Joshua Bloch hits it on the nail in his Effective Java book item about “Favoring composition over inheritance.” - The Shyam - Is Inheritance Overrated? Needed even?

Tuesday, July 9, 2013

Using a local source repo to work on vs2008 projects in vs2012

If the project type can't be opened or worked in the newer Visual Studio then you are still out of luck, but otherwise here we go. Assuming you have Git installed, go to the top level of a directory that would include both your .sln and .proj files.
$ git init
inside that directory then if you don't have a default set of ignores. you will want to set that up. Before opening Visual Studio, do your initial commit.
$ git checkout -b Vs2012
to create the new branch. Open in Visual Studio 2012. Commit the changes. Now you can make all your edits and commit them. When you want to pull the changes to the old VS branch change to that branch and do a git-cherry-pick
$ git cherry-pick SHA
replace SHA with the SHA hash of the commit you want to pick. Or to do them in bulk...
$ git cherry-pick SHA1..SHA2
replace SHA1 with the SHA hash of the commit you want to skip, and SHA2 with the last one you want.

Tuesday, May 14, 2013

High speed data scraping example

Situation, I wanted to get the names of the different playable champions to print out and discuss.
So went to http://na.leagueoflegends.com/champions and ran jquery to get the names: $('td.description span a[href]').text()

This produced all the names run together. Perhaps there's a more straightforward way to aggregate them in a short single line, but I was in a hurry.

Open My LinqPad (which includes the Inflector NuGetPackage) Paste in the string and add .Titleize() on the end. Job Done.

Next up marvelheroes.com at https://marvelheroes.com/game-info/game-guide/heroes/grid

jQuery is loaded but not as $ here

jQuery('div.field-content a[href*=/heroes]').map(function(i,e){return jQuery(e).attr('href').split('/')[2];}) in this case did more jquery, so the inflector wasn't needed.
Steam games on sale: Click specials tab: jQuery('div.tabbar div[onclick]:contains(Specials)').click()

Enter the unspeakable as the first found working solution to help load all the items: eval(jQuery('#tab_Discounts_next a[href]').attr('href'))

make it get all the pages var getNext=jQuery('#tab_Discounts_next a[href]').attr('href'); var times=Math.ceil(getNext.split(':')[1].split(', ')[2]/10); eval(getNext);for(var i=1;i>times-1;i++){setTimeout(function(){console.log('getting more'); eval(getNext);},1500*i);} Get all the names jQuery('#tab_Discounts_items div.tab_desc.with_discount h4').map(function(i,e){return jQuery(e).text();}) Done.

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();
}

Thursday, January 31, 2013

Mvc4 unit(?) testing of views with BDD & SpecFlow

I wanted to unit test my mvc. I had no idea what that could mean. Not my pocos or models, my Mvc. After googling what are the primary targets taken by unit testers? Controllers, almost never Views. The level of complexity behind getting a test framework given v as our view to do v.ExecuteResult() seems over the top immense. The spec flow: Feature: Register a new User In order to register a new User As member of the site So that they can log in to the site and use its features Scenario: Browse Register page When the user goes to the register user screen Then the register user view should be displayed And the view should have a username input field The MsTest class:
using System;
using System.Web.Mvc;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using MvcContrib.TestHelper;

using MvcSpecFlow.Controllers;
using MvcSpecFlow.Views.Account;

using RazorGenerator.Testing;

using TechTalk.SpecFlow;

//http://www.codeproject.com/Articles/82891/BDD-using-SpecFlow-on-ASP-NET-MVC-Application
//http://blog.davidebbo.com/2011/06/precompile-your-mvc-views-using.html
//http://blog.davidebbo.com/2011/06/unit-test-your-mvc-views-using-razor.html

namespace MvcSpecFlow.Tests
{
  [Binding]
  public class RegisterUserSteps
  {
    ActionResult result;

    AccountController controller;

    [When(@"the user goes to the register user screen")]
    public void WhenTheUserGoesToTheRegisterUserScreen()
    {
      controller = new AccountController();
      result = controller.Register();

    }

    [Then(@"the register user view should be displayed")]
    public void ThenTheRegisterUserViewShouldBeDisplayed()
    {
      Assert.IsInstanceOfType(result, typeof(ViewResult));

      var vResult = (ViewResult)result;
      Assert.AreEqual(string.Empty, vResult.ViewName);

      vResult.AssertViewRendered().ForView(string.Empty); //should follow convention not pass a special view name
      
    }

    [Then(@"the view should have a username input field")]
    public void ThenTheViewShouldHaveAUsernameInputField()
    {
      var view = new Register();
      var doc = view.RenderAsHtml();
      var username = doc.GetElementbyId("UserName");
      Assert.IsNotNull(username);
    
    }
  }
}
The requirements:
  1. Use RazorGenerator to precompile your views
  2. The view you are testing has the RazorGenerator set as the Custom Tool
  3. The view you are testing does not have the following razor: @Html.AntiForgeryToken()
  4. Your testing project has RazorGenerator.Testing installed.

Wednesday, January 30, 2013

CORS without preflight

I had some trouble getting a CORS request to fire without preflight I finally got it and here it is In raw javascript:
  var xmlhttp = new XMLHttpRequest();
  xmlhttp.open("GET", "http://jira/rest/api/latest/issue/DEV-793", false);
  xmlhttp.send();
  //exception (as expected) for 401 response from that site
  document.getElementById("myDiv").innerHTML = xmlhttp.responseText;
since the server is not responding with the proper response header the browser won't let me read the response for security reasons, but at least the send side is working currently. This also works for send (still has the issue with the browser blocking the response from the javascript:
  var xmlhttp = new XMLHttpRequest();
  xmlhttp.open("GET", "http://jira/rest/api/latest/issue/DEV-793", false);
  xmlhttp.setRequestHeader("accept", "application/json");
  xmlhttp.send();
  document.getElementById("myDiv").innerHTML = xmlhttp.responseText;
I can't get jQuery to do it in Chrome whatsoever. Posted a SO question. Perhaps this is the problem, a bug in chrome Also I've found that I don't need to muck with the server if I set the command line option for chrome `http://stackoverflow.com/a/13154327/57883`

Monday, January 14, 2013

Clean your EDMX programmatically

So you have pesky underscores in your edmx, that appear every time you add a new property, table, view, relationship, or whatever. Here's the cleaning code based on Inflector and some help from a co-worker. `.Dump` is just a generic print out command available in linqpad, the code would work without those method calls.
void Main()
{
  var edmx= @"C:\Projects\psh\hpx\src\Entities\JobSystem\JobSystem.edmx";
  var xdoc=System.Xml.Linq.XDocument.Load(edmx);
  xdoc.Dump();
  var ns=xdoc.Root.Name.Namespace;
  
  //sort entity types?
  
  var storageModels=xdoc.Root.Element(ns+"Runtime").Element(ns+"StorageModels");
  var storeNs=storageModels.GetNamespaceOfPrefix("store");
  
  new {Root=ns,Default=xdoc.Root.GetDefaultNamespace(),DefaultLocal=storageModels.GetDefaultNamespace(), Store=storeNs}.Dump("namespaces");
  
  var schemas=storageModels.Elements();
  
  Debug.Assert(schemas.All (s => s.Name.LocalName=="Schema"));
  //ProcessSchemas(schemas); //not helpful or necessary
  var mappings = xdoc.Root.Element(ns+"Runtime").Element(ns+"Mappings").Elements();
  Debug.Assert(mappings.All (m => m.Name.LocalName=="Mapping"));
  ProcessMappings(mappings);
  var concept= xdoc.Root.Element(ns+"Runtime").Element(ns+"ConceptualModels");
  
  ProcessConceptual(concept);
  xdoc.Save(edmx);    
    
  
}

// Define other methods and classes here
void ProcessConceptual(XElement concept)
{
  var processed= new List<string>();
      var localNs=concept.Elements().First ().Name.Namespace;
    foreach(var s in concept.Elements())
    {
  
      localNs.Dump("Entity Type?");
      
      foreach(var et in s.Elements(localNs+"EntityType"))
      {
        foreach(var p in et.Elements(localNs+"Property"))
        {
          var pName=p.Attribute(XNamespace.None+"Name");  
          var existing=pName.Value;
          var proposed=existing.Pascalize();
          if(existing != proposed){
            processed.Add(et.Attribute(XNamespace.None+"Name").Value+":"+existing);
            pName.Value=proposed;
          }
        }
        
      }
      
    }
    var propRefs=concept.XPathSelectElements(".//*[local-name()='PropertyRef']");
    
    foreach(var propRef in propRefs)
    {
      var pName=propRef.Attribute(XNamespace.None+"Name");  
          var existing=pName.Value;
          var proposed=existing.Pascalize();
          if(existing != proposed){
            processed.Add(propRef.Parent.Name+":"+existing);
            pName.Value=proposed;
          }
    }
  
  processed.Dump("Conceptuals");
}
void ProcessMappings(IEnumerable<XElement> mappings)
{
  var processed=new List<string>();
  foreach(var m in mappings)
  {
    var localNs=m.Name.Namespace;
    foreach(var ecm in m.Elements(localNs+"EntityContainerMapping"))
    foreach(var esm in ecm.Elements(localNs+"EntitySetMapping"))
    foreach(var etm in esm.Elements(localNs+"EntityTypeMapping"))
    {
      var typeName=etm.Attribute(XNamespace.None+"TypeName");
      foreach(var mf in etm.Elements(localNs+"MappingFragment"))
      foreach(var sp in mf.Elements(localNs+"ScalarProperty"))
      {
        var spName=sp.Attribute(XNamespace.None+"Name");  
        var existing=spName.Value;
        var proposed=existing.Pascalize();
        if(existing != proposed){
          processed.Add(typeName+":"+existing);
          spName.Value=proposed;
        }
      }
    }
  }
  processed.Dump();
}


Inflector is just awesome available as a nuget package if you don't need it to be strongly signed.
/// <summary>
  /// Inflector NuGet package is not strong signed =(
  /// </summary>
  public static class Inflector
{
    readonly static List<Rule> _plurals;

    readonly static List<Rule> _singulars;

    readonly static List<string> _uncountables;

    static Inflector()
    {
        _plurals = new List<Rule>();
        _singulars = new List<Rule>();
        _uncountables = new List<string>();
        AddPlural("$", "s");
        AddPlural("s$", "s");
        AddPlural("(ax|test)is$", "$1es");
        AddPlural("(octop|vir|alumn|fung)us$", "$1i");
        AddPlural("(alias|status)$", "$1es");
        AddPlural("(bu)s$", "$1ses");
        AddPlural("(buffal|tomat|volcan)o$", "$1oes");
        AddPlural("([ti])um$", "$1a");
        AddPlural("sis$", "ses");
        AddPlural("(?:([^f])fe|([lr])f)$", "$1$2ves");
        AddPlural("(hive)$", "$1s");
        AddPlural("([^aeiouy]|qu)y$", "$1ies");
        AddPlural("(x|ch|ss|sh)$", "$1es");
        AddPlural("(matr|vert|ind)ix|ex$", "$1ices");
        AddPlural("([m|l])ouse$", "$1ice");
        AddPlural("^(ox)$", "$1en");
        AddPlural("(quiz)$", "$1zes");
        AddSingular("s$", string.Empty);
        AddSingular("(n)ews$", "$1ews");
        AddSingular("([ti])a$", "$1um");
        AddSingular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis");
        AddSingular("(^analy)ses$", "$1sis");
        AddSingular("([^f])ves$", "$1fe");
        AddSingular("(hive)s$", "$1");
        AddSingular("(tive)s$", "$1");
        AddSingular("([lr])ves$", "$1f");
        AddSingular("([^aeiouy]|qu)ies$", "$1y");
        AddSingular("(s)eries$", "$1eries");
        AddSingular("(m)ovies$", "$1ovie");
        AddSingular("(x|ch|ss|sh)es$", "$1");
        AddSingular("([m|l])ice$", "$1ouse");
        AddSingular("(bus)es$", "$1");
        AddSingular("(o)es$", "$1");
        AddSingular("(shoe)s$", "$1");
        AddSingular("(cris|ax|test)es$", "$1is");
        AddSingular("(octop|vir|alumn|fung)i$", "$1us");
        AddSingular("(alias|status)es$", "$1");
        AddSingular("^(ox)en", "$1");
        AddSingular("(vert|ind)ices$", "$1ex");
        AddSingular("(matr)ices$", "$1ix");
        AddSingular("(quiz)zes$", "$1");
        AddIrregular("person", "people");
        AddIrregular("man", "men");
        AddIrregular("child", "children");
        AddIrregular("sex", "sexes");
        AddIrregular("move", "moves");
        AddIrregular("goose", "geese");
        AddIrregular("alumna", "alumnae");
        AddUncountable("equipment");
        AddUncountable("information");
        AddUncountable("rice");
        AddUncountable("money");
        AddUncountable("species");
        AddUncountable("series");
        AddUncountable("fish");
        AddUncountable("sheep");
        AddUncountable("deer");
        AddUncountable("aircraft");
    }

    private static void AddIrregular(string singular, string plural)
    {
        var objArray = new object[5];
        objArray[0] = "(";
        objArray[1] = singular[0];
        objArray[2] = ")";
        objArray[3] = singular.Substring(1);
        objArray[4] = "$";
        AddPlural(string.Concat(objArray), string.Concat("$1", plural.Substring(1)));
        var objArray1 = new object[5];
        objArray1[0] = "(";
        objArray1[1] = plural[0];
        objArray1[2] = ")";
        objArray1[3] = plural.Substring(1);
        objArray1[4] = "$";
        AddSingular(string.Concat(objArray1), string.Concat("$1", singular.Substring(1)));
    }

    private static void AddPlural(string rule, string replacement)
    {
        _plurals.Add(new Rule(rule, replacement));
    }

    private static void AddSingular(string rule, string replacement)
    {
        _singulars.Add(new Rule(rule, replacement));
    }

    private static void AddUncountable(string word)
    {
        _uncountables.Add(word.ToLower());
    }

    private static string ApplyRules(List<Inflector.Rule> rules, string word)
    {
        string str = word;
        if (!_uncountables.Contains(word.ToLower()))
        {
            for (int i = rules.Count - 1; i >= 0; i--)
            {
                string str1 = rules[i].Apply(word);
                str = str1;
                if (str1 != null)
                {
                    break;
                }
            }
        }
        return str;
    }

    public static string Camelize(this string lowercaseAndUnderscoredWord)
    {
        return lowercaseAndUnderscoredWord.Pascalize().Uncapitalize();
    }

    public static string Capitalize(this string word)
    {
        return string.Concat(word.Substring(0, 1).ToUpper(), word.Substring(1).ToLower());
    }

    public static string Dasherize(this string underscoredWord)
    {
        return underscoredWord.Replace('\u005F', '-');
    }

    public static string Humanize(this string lowercaseAndUnderscoredWord)
    {
        return Regex.Replace(lowercaseAndUnderscoredWord, "_", " ").Capitalize();
    }

    private static string Ordanize(int number, string numberString)
    {
        int num = number % 100;
        if (num < 11 || num > 13)
        {
            int num1 = number % 10;
            switch (num1)
            {
                case 1:
                {
                    return string.Concat(numberString, "st");
                }
                case 2:
                {
                    return string.Concat(numberString, "nd");
                }
                case 3:
                {
                    return string.Concat(numberString, "rd");
                }
            }
            return string.Concat(numberString, "th");
        }
        else
        {
            return string.Concat(numberString, "th");
        }
    }

    public static string Ordinalize(this string numberString)
    {
        return Inflector.Ordanize(int.Parse(numberString), numberString);
    }

    public static string Ordinalize(this int number)
    {
        return Inflector.Ordanize(number, number.ToString());
    }

    public static string Pascalize(this string lowercaseAndUnderscoredWord)
    {
        string str = lowercaseAndUnderscoredWord;
        string str1 = "(?:^|_)(.)";
        return Regex.Replace(str, str1, (Match match) => match.Groups[1].Value.ToUpper());
    }

    public static string Pluralize(this string word)
    {
        return Inflector.ApplyRules(Inflector._plurals, word);
    }

    public static string Singularize(this string word)
    {
        return Inflector.ApplyRules(Inflector._singulars, word);
    }

    public static string Titleize(this string word)
    {
        string str = word.Underscore().Humanize();
        string str1 = "\\b([a-z])";
        return Regex.Replace(str, str1, (Match match) => match.Captures[0].Value.ToUpper());
    }

    public static string Uncapitalize(this string word)
    {
        return string.Concat(word.Substring(0, 1).ToLower(), word.Substring(1));
    }

    public static string Underscore(this string pascalCasedWord)
    {
        return Regex.Replace(Regex.Replace(Regex.Replace(pascalCasedWord, "([A-Z]+)([A-Z][a-z])", "$1_$2"), "([a-z\\d])([A-Z])", "$1_$2"), "[-\\s]", "_").ToLower();
    }

    private class Rule
    {
        private readonly Regex _regex;

        private readonly string _replacement;

        public Rule(string pattern, string replacement)
        {
            this._regex = new Regex(pattern, RegexOptions.IgnoreCase);
            this._replacement = replacement;
        }

        public string Apply(string word)
        {
            if (this._regex.IsMatch(word))
            {
                return this._regex.Replace(word, this._replacement);
            }
            else
            {
                return null;
            }
        }
    }
}