Thursday, December 27, 2012

Windows 7 Activation Heck

A long time ago, I noticed that my hard drive was behaving suicidal. so I bought a new one, copied the old one with Ghost and installed the new one. Everything ran fine for awhile (I wasn’t getting updated from Microsoft, but I wasn’t paying attention), so everything was bliss as I continued to use my computer.

Then, behold, I was informed by Windows Activation Technologies that my Windows wasn’t “Genuine”. I figured that my windows license was destroyed with my HD, so I clicked “Resolve online now” and ended up buying a “Get Genuine Online Kit” online. Microsoft gave me a new Product Key on the spot. I entered it and I still got the message. A week later, the software came in the mail; I tried and failed to upgrade couple of times and it failed each time telling me that my computer isn’t compatible with Windows 7.

A couple of days ago I downloaded MGADiag.exe and when I run it, it tells me that my Windows is “Genuine”:

IsItGenuineOrNot

Update

Someone on answers.microsoft.com suggested that I reinstall my Intel Rapid Storage Tech driver and so far so good. Windows Update even works.

Wednesday, November 28, 2012

Testing and Medicine

Lately I have been thinking about testing in areas outside programming. This time I will tackle the area of Medicine.

Medicine

One problem is that you can’t do a unit test without killing the subject. The issue is that you can’t isolate your heart from the rest of the system. It is an area where you are doing maintenance, Doctors don’t build bodies; they have to keep the bodies designed by God or Nature in good working order. Sure they have a limited opportunity to do some refactoring using surgery and medication; there is no Green Field Medicine. It is all maintenance work.

Medical tests appear to be closer to code metrics that the kind of testing we do in software. For example, we know that too much cholesterol in the blood is a bad thing that people with too much cholesterol are more likely to have heart attacks. Does cholesterol cause heart attacks? I don’t know, but based on what we know right now, we need to keep it down below a certain level. Same for blood sugar, blood pressure, etc. There is a correlation between what we are measuring and what we care about. Just like too many GO TO statements and long procedures tend to appear in rotten code.

Modivation

I got a bad cough in September and it has continued through November. I have seen more doctors in the last 2 ½ months than I have in the last 10 years.

Wednesday, October 31, 2012

Testing and The Law

I work in software where test is paramount (some would say that we've gone overboard and spend more time testing than getting real work done...a discussion for later). Well, anyway, I've been thinking about testing in other fields.

Legal

Here testing appears to be expensive. There are many legal documents out there but few are ever tested. By testing I mean brought before a judge or jury for a decision, and the test isn't complete until the appeal process is completed.

The result of the test is based on human interpretation of the document and the law. There are various theories of law and you may get a different result based on who hears the case.

Much of it is settled without testing. The two sides asset their position and the law and come to an agreement. It is often based on the strength or weakness of each side of the case.

Since the law is based on president, or what was decided before, some people will deliberately test a law (bring it to trial) in hopes of changing the law based on the decision - a test case.

Motivation

I am trading my condo for another one of greater than or equal value. Well, anyway, the other party dropped off the documents to complete the deal. Reading them got me thinking.

Sunday, September 30, 2012

Healthcare: My Struggles with a Complex System

Earlier this month my decided to be less cooperate and developed a condition that I still don’t understand. So far I’ve been to “the doctor” 3 times and visited the pharmacists’ after each visit. I’ve missed more days this month that I’ve missed in the previous 3 years. I was even tested for Whooping Cough (I don’t have it).

I am dealing with a complex system that I don’t understand. Right now this system is important to me, so I am forced to wade through it the best I can. Perhaps this is the way non-nerds teal with technology and other things that I deal with every day.

First I didn’t know how to enter the system. I had the cough for over a week and things weren’t getting better; I hadn’t bothered to doctor up before the crisis (I should schedule these things better). Now supposed that I was a 75 year old woman who wanted to get a new tablet (my improv skills come in handy here). Do I get an iPad, Kindle Fire, Nook Color or some other thing I’ve never heard of? Would I even know of anything other than the iPad? What is it supposed to do anything? How much do I want to bother my son with question about the new thing? Etc.

So, I finally get myself to the doctor’s office. What do I say? What is relevant? What is too much information? Did I leave something out? Am I falling into the “ask your doctor about [sponsored drug name here]” trap? Now suppose that I need custom software to solve some problem. How much does the program need to match my current process? Do I care if it is written in Java, .NET or X86 Assembler? How do I know if the software vender is any good?

As a programmer, Search is my friend; I can Bing with Google and get quick answers to my programming query. I can even tell the good from the bad. When I searched for medical stuff over the last couple of weeks, I would find things to feed my paranoia. (Things like “Lung Cancer”, “Throat Cancer”, anything else with “Cancer” in the name; my perceptions of my symptoms would morph to match WebMD.) When a customer (or friend or family member) finds some article about I’m doing that turns out to be less than relevant or downright dangerous, I should think about my experience with WebMD and deal with them gently.

So, what, I don’t understand this whole medical stuff. What I am trying to do here is suggest that I can use this pain to emphasize with my customers. I mean I can’t forget all the things that I know about programming and technology and even if I did, I would still think different. So when they appear to struggle in my area, I need to remember what it was like to struggle in someone else’s area.

Tuesday, August 21, 2012

Weekend Challenge #1: CSV to a Web Page

If you know programming and want to see samples of my work, you can read this blog. If you are not a programmer and want to evaluate my skills, there is nothing out there that I can show you. I haven’t worked on a public web site for over 3 years. My current projects are internal Windows Forms applications. You could load Improv Suggester onto your Windows Phone, if you have one.

So last weekend I challenged myself to write a public sample. I wanted to challenge myself to work in technologies that I haven’t worked in for awhile if ever.

Problem

Suppose you have a system that uses Excel spreadsheets to store data. Now, suppose that you want to transition to a web based system but you want to be able to fill out an existing spreadsheet and “Import” the data into the new system.

The Tools

Web Matrix 2

Editor – Half way between Visual Studio and notepad. The editor felt bulky without the features I would expect in exchange for the bulk. There were a couple of times when the editor was a dozen or so keystrokes behind me. Publishing to the web is easy.

Link to Web Matrix 2

Razor Rendering Engine

Language & Rendering Engine – It is interesting how HTML, JavaScript and C# are mixed together. It looks cleaner than ASP.NET, PHP or T4 markup, though I wish the JavaScript looked more different than C#, but that may be an editor issue.

Link to Razor

Hanson Table

Grid Control – This was the first JQuery control that I found that behaved the way I needed it to. There were other grids that allowed you to edit the cells but forced you to click on the cell you wanted to edit.

Link to Hanson Table

Lumenworks (CsvReader)

Parse CSV – This is somewhat of a cheat. I have used this library on a couple of other projects. It has this cool feature that allows you to reference columns by name, assuming that these names are on the first line. Since I wanted to allow the user to put global data at the top of the sheet, I looked for the headers and that was the first line that I gave to CsvReader.

Link to Lumenworks on Code Project

The Code

According to the rules that I have imposed on myself, I give you the code as it existed as of the end of August 19. You can see the sample in action on my main site.

@using Microsoft.Web.Helpers;
@using System.Web;
@using System.IO;
@using LumenWorks.Framework.IO.Csv;
@using System.Text;
@{
    Layout = "~/_SiteLayout.cshtml";
Page.Title = "Upload Grid Demo";

var make = "Make";
var date = string.Empty;
var submittedData = "";
var fileName = "";
var content = "";
var dataArray = "";
if (IsPost) 
{
var _txtMake = Request.Form["_txtMake"];

if(_txtMake != null)
{
submittedData = "Make: " + Request.Form["_txtMake"] + Environment.NewLine +
"Date: " + Request.Form["_txtDate"] + Environment.NewLine +
"Grid Data: " + Environment.NewLine +
Request.Form["_hidGridJson"];
}
else
{        
var fileSavePath = "";
var uploadedFile = Request.Files[0];
fileName = Path.GetFileName(uploadedFile.FileName);

StreamReader sr1 = new StreamReader(uploadedFile.InputStream);
string st = sr1.ReadToEnd();

Dictionary<string,string> topParams;
string lineItems;

getParamsAndGridDetail(st, out topParams, out lineItems);

Stream st2 = GenerateStreamFromString(lineItems);
TextReader tr = new StreamReader(st2);

dataArray = getGridDataForTextReader(tr);

if (!topParams.TryGetValue("Make:", out make))
{
make = string.Empty;
}
if (!topParams.TryGetValue("Date:", out date))
{
date = string.Empty;
}
}
}
}
@functions{
    public void getParamsAndGridDetail(string allLines, out Dictionary<string,string>
topParams, out string lineItems)
{
topParams = new Dictionary<string,string>();
StringBuilder sb = new StringBuilder();
string[] linesArray=allLines.Replace("\r", string.Empty).Split(new char[]{'\n'});
int stepNumber = 1;
foreach(string line in linesArray)
{
if (stepNumber == 1)
{
if (isHeaderLine(line))
{
sb.AppendLine(line);
stepNumber = 2;
}
else
{
lookForKeys(line, ref topParams);
}
}
else if (stepNumber == 2)
{
if(line.Replace(",", string.Empty).Trim().Length == 0)
{
stepNumber = 3;
}
else
{
sb.AppendLine(line);
}
}
}
lineItems = sb.ToString();
}
public void lookForKeys(string line, ref Dictionary<string,string> topParams)
{
string[] sumItems = line.Split(new char[] {','});
//foreach(string cell in sumItems)
for (int i = 0; i < sumItems.Length - 1; ++i)
{
if(sumItems[i].EndsWith(":"))
{
topParams.Add(sumItems[i], sumItems[i + 1]);
}
}
}
public bool isHeaderLine(string line)
{
bool foundModel = false;
bool foundYear = false;
bool foundColor = false;
string[] sumItems = line.Split(new char[] {','});
foreach(string cell in sumItems)
{
string normalizedCell = cell.Trim().ToLower();
if(normalizedCell == "model")
{
foundModel = true;
}
if(normalizedCell == "year")
{
foundYear = true;
}
if(normalizedCell == "color")
{
foundColor = true;
}
}
return foundModel && foundYear && foundColor;
}
public Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
public string getGridDataForTextReader(TextReader tr)
{
var sb = new StringBuilder();
sb.AppendLine("[");
using (var csv = new CsvReader(tr, true))
{
bool isFirstLine = true;
int fieldCount = csv.FieldCount;
while (csv.ReadNextRecord())
{
if(!isFirstLine)
{
sb.AppendLine(",");
}
isFirstLine = false;
sb.Append("        [");
sb.AppendFormat("\"{0}\",{1},\"{2}\"", csv["Model"], csv["Year"], csv["Color"]);
sb.Append("]");
}
}
sb.AppendLine("");
sb.Append("    ];");
return sb.ToString();
}
}
@section Scripts
{
<script src="@Href("~/lib/jquery.js")"></script>
<script src="@Href("~/jquery.handsontable.js")"></script>
<script src="@Href("~/lib/bootstrap-typeahead.js")"></script>
<script src="@Href("~/lib/jquery.autoresize.js")"></script>
<script src="@Href("~/lib/jQuery-contextMenu/jquery.contextMenu.js")"></script>
<script src="@Href("~/lib/jQuery-contextMenu/jquery.ui.position.js")"></script>
<link rel="stylesheet" media="screen" 
href="/lib/jQuery-contextMenu/jquery.contextMenu.css">
<link rel="stylesheet" media="screen" href="/jquery.handsontable.css">
}
    @FileUpload.GetHtml(
initialNumberOfFiles:1,
allowMoreFilesToBeAdded:false,
includeFormTag:true,
uploadText:"Parse CSV File")
@if (IsPost) {
<br/>
<span>File uploaded!</span>
<h3>@fileName</h3>
}
@if (string.IsNullOrEmpty(submittedData)){
<form action="" method="post" name="_formWriteBack" onclick="doOnSubmit();"  >
<input type="hidden" name="_hidGridJson" id="_hidGridJson" />
Make: <input name="_txtMake" id="_txtMake" value="@make" /><br />
Date: <input name="_txtDate" id="_txtDate" value="@date" /><br />
<div id="example1grid" class="dataTable"></div>
<script>
var $container = $("#example1grid");
var $parent = $container.parent();
$container.handsontable({
rows: 2,
cols: 3,
minSpareCols: 0, //always keep at least 0 spare row at the right
minSpareRows: 1, //always keep at least 1 spare row at the bottom
contextMenu: true,
colHeaders: ["Model", "Year", "Color"],
autoComplete: [
{
match: function (row, col, data) {
if (col == 2) {
return true;
}
return false;
},
highlighter: function (item) {
var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
var label = item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
return '<strong>' + match + '</strong>';
});
return '<span style="margin-right: 10px; background-color: ' +
item + '">&nbsp;&nbsp;&nbsp;</span>' + label;
},
source: function () {
return ["Yellow", "Red", "Orange", "Green", "Blue", "Gray", "Black", "White"]
},
strict: false //allows other values that defined in array above
}
]

});

var data = @Html.Raw(dataArray)
$container.handsontable("loadData", data);

function doOnSubmit() {
var newdata;
newdata = $container.handsontable("getData", "");
_hidGridJson.value = newdata;
}
</script>
<input type="submit" value="Submit Form" />
</form>
}
@if (!string.IsNullOrEmpty(submittedData)){
<p>This is the data you just submitted to the web server. </p>
<pre>
@submittedData
</pre>
}

Friday, July 27, 2012

Dealing with DataSet’s Outdated Nullability Model

The DataSet is one of the most ancient relics of the .NET framework. DataSets were designed before the invention of Nullable<T> and came up with a different way to deal with database null values. So we are stuck with properties that throw StrongTypingException when the property is null and special IsXXXNull() methods to test whether a property is null. So you end up with ugly code like this:

if (!row.IsReportsToNull())
{
Console.WriteLine(row.ReportsTo);
}
else
{
Console.WriteLine("NULL");
}

or

try
{
Console.WriteLine(row.ReportsTo);
}
catch (StrongTypingException)
{
Console.WriteLine("NULL");
}

This code dance is necessary because you can’t even touch a null property without triggering an exception. So you can’t pass the property to a method that would check for nullability. But you can pass a Func<T> to a lamda:

private string GetStringForTFromDataRowField<T>(Func<bool> isNull, Func<T> getValue, 
string formatString = "{0}")
{
if (!isNull())
{
return string.Format(formatString, getValue());
}
else
{
return "NULL";
}
}

With this function I can reference the field in one (ugly) statement:

Console.WriteLine(GetStringForTFromDataRowField(row.IsReportsToNull, 
() => { return row.ReportsTo; }));

Here I am not referencing the actual property until I confirm that the property isn’t null. Since the property is referenced in an anonymous method it isn’t evaluated until after the IsNull() method confirms that the value isn’t null.

What do I get? Slightly cleaner code, I guess. You still need to match the property with the correct IsXXXNull() method. I find the code in the first couple of examples so ugly that this hack is worth the effort for me.

Thursday, June 14, 2012

Using LINQPad’s SQL Tab To Investigate EF’s Crud Commands

I like LINQPad. One thing I like to do with it is to use to figure out what queries the Entity Framework is generating when I do basic tasks. In this post, I will look at what is going on for basic CRUD operations (actually CUD, since the Read operations are self evident). For this example, I am going use the method outlined in Querying EF ObjectContext from LINQPad; I am using the PUBS database and the model from Building an EF 4 Model Assembly for Pubs DB.

Whenever you run a query in LINQPad you can click on the SQL to see what has been sent to the server. I find this method more useful than Getting TSQL Query With ToTraceString() in EF; I can run code that is not a LINQ query and see what happens.

sql_tab 

Add

Given this function:

void addTitle(PubsModel.pubsEntities context)
{
     var newTitle = new title();
     newTitle.title_id = "myTtl";
     newTitle.title = "Hamlet";
     newTitle.type = "Literature";
     newTitle.pubdate = DateTime.Today;
     newTitle.publisher = 
          context.publishers.Where(p => p.pub_id == "9901").Single();

     context.titles.AddObject(newTitle);

     context.SaveChanges();
}

I get this SQL from LINQPad:

SELECT TOP (2) 
[Extent1].[pub_id] AS [pub_id], 
[Extent1].[pub_name] AS [pub_name], 
[Extent1].[city] AS [city], 
[Extent1].[state] AS [state], 
[Extent1].[country] AS [country]
FROM [dbo].[publishers] AS [Extent1]
WHERE '9901' = [Extent1].[pub_id]
GO

-- Region Parameters
DECLARE @0 VarChar(6) = 'myTtl'
DECLARE @1 VarChar(80) = 'Hamlet'
DECLARE @2 Char(12) = 'Literature'
DECLARE @3 Char(4) = '9901'
DECLARE @4 DateTime2 = '2012-04-07 00:00:00.0000000'
-- EndRegion
insert [dbo].[titles]([title_id], [title], [type], [pub_id], [price], [advance], [royalty], [ytd_sales], [notes], [pubdate])
values (@0, @1, @2, @3, null, null, null, null, null, @4)


In the top part, EF is getting the linked record from the publishers table. For this specific add, the get is probably not necessary. I could avoid that call setting the pub_id directly as opposed to setting the publisher navigation property to the row.

The second part is a basic INSERT query with parameters. Other than the cryptic names and explicitly referencing null in the VALUES clause, this is pretty close to what I would have written.

Edit


Given this function:

void editTitle(PubsModel.pubsEntities context)
{
     var myTitle = context.titles.Where(t => t.title_id == "myTtl").Single();

     myTitle.price = 100m;
     myTitle.advance = 1000000m;
    
     context.SaveChanges();
}

I get this SQL from LINQPad:

SELECT TOP (2) 
[Extent1].[title_id] AS [title_id], 
[Extent1].[title] AS [title], 
[Extent1].[type] AS [type], 
[Extent1].[pub_id] AS [pub_id], 
[Extent1].[price] AS [price], 
[Extent1].[advance] AS [advance], 
[Extent1].[royalty] AS [royalty], 
[Extent1].[ytd_sales] AS [ytd_sales], 
[Extent1].[notes] AS [notes], 
[Extent1].[pubdate] AS [pubdate]
FROM [dbo].[titles] AS [Extent1]
WHERE 'myTtl' = [Extent1].[title_id]
GO

-- Region Parameters
DECLARE @0 Decimal(7,4) = 100
DECLARE @1 Decimal(11,4) = 1000000
DECLARE @2 VarChar(6) = 'myTtl'
-- EndRegion
update [dbo].[titles]
set [price] = @0, [advance] = @1
where ([title_id] = @2)


Not much to see here. It is getting the data with a SELECT command and then editing it with the data with an UPDATE command. Again this is pretty close to what I would do.


Delete


Given this function:

void delTitle(PubsModel.pubsEntities context)
{
     var myTitle = context.titles.Where (t => t.title_id == "myTtl").Single ();
     context.DeleteObject(myTitle);
     context.SaveChanges();
}

I get this SQL from LINQPad:

SELECT TOP (2) 
[Extent1].[title_id] AS [title_id], 
[Extent1].[title] AS [title], 
[Extent1].[type] AS [type], 
[Extent1].[pub_id] AS [pub_id], 
[Extent1].[price] AS [price], 
[Extent1].[advance] AS [advance], 
[Extent1].[royalty] AS [royalty], 
[Extent1].[ytd_sales] AS [ytd_sales], 
[Extent1].[notes] AS [notes], 
[Extent1].[pubdate] AS [pubdate]
FROM [dbo].[titles] AS [Extent1]
WHERE 'myTtl' = [Extent1].[title_id]
GO

-- Region Parameters
DECLARE @0 VarChar(6) = 'myTtl'
-- EndRegion
delete [dbo].[titles]
where ([title_id] = @0)

This one is a little bit more controversial. Do I really need to get the doomed record before I delete it? Does it really make that much difference? I probably wouldn’t get the record before I deleted it. I have seen examples where you send an update command through EF that deletes the record without ever reading it.


LINQPad Code

const string EF_CONNECTION_STRING = 
@"metadata=res://*/PubsModel.csdl|res://*/PubsModel.ssdl|res://*/PubsModel.msl;" +
@"provider=System.Data.SqlClient;" +
@"provider connection string=" +
@"'data source=WIN-SEVEN-02\SQLEXPRESS;initial catalog=pubs;" +
@"integrated security=True;" + 
@"MultipleActiveResultSets=True;App=EntityFramework'";
void Main()
{
PubsModel.pubsEntities context = new PubsModel.pubsEntities(EF_CONNECTION_STRING);
addTitle(context);
showMyTitle(context, "After Add");
editTitle(context);
showMyTitle(context, "After Edit");
delTitle(context);
showMyTitle(context, "After Delete");

}
void addTitle(PubsModel.pubsEntities context)
{
var newTitle = new title
{
title_id = "myTtl",
title1 = "Hamlet",
type = "Literature",
pubdate = DateTime.Today,
publisher = context.publishers.Where(p => p.pub_id == "9901").Single()
// If I set the ID, I can avoid a SELECT command
//pub_id = "9901"
};
context.titles.AddObject(newTitle);
context.SaveChanges();
}
void editTitle(PubsModel.pubsEntities context)
{
var myTitle = context.titles.Where(t => t.title_id == "myTtl").Single();

//    myTitle.EntityState.Dump("EntityState Before Edit");
isDirty(myTitle).Dump("isDirty Before Edit");
myTitle.price = 100m;
myTitle.advance = 1000000m;
//    myTitle.EntityState.Dump("EntityState After Edit");
isDirty(myTitle).Dump("isDirty After Edit");

context.SaveChanges();
}
void delTitle(PubsModel.pubsEntities context)
{
var myTitle = context.titles.Where (t => t.title_id == "myTtl").Single ();
context.DeleteObject(myTitle);
context.SaveChanges();
}
void showMyTitle(PubsModel.pubsEntities context, string message)
{
context.titles.Include("publisher").Where(t => t.title_id == "myTtl").Dump(message);
}
bool isDirty(EntityObject entity)
{
return entity.EntityState == EntityState.Added || 
entity.EntityState == EntityState.Modified || 
entity.EntityState == EntityState.Deleted;
}

Thursday, June 07, 2012

Improv @ Seattle Code Camp

Ted Neward is doing a session on Improv at the 2012 Seattle Code Camp. So I am excited to go to a code camp to take a tiny Improv workshop. As I said here, I have been doing improve for the past couple of years. My worlds come together.

I have been doing a lot of thinking about how Improv would benefit many of us nerds and geeks (Geekprov anyone?) You know the classic stereotype of a computer programmer: a socially awkward recluse who spends whole nights in a dark room coding with a 2 liter of Mountain Dew and cold pizza. I am the poster child.

Since I have started to improvise, I have been braver; I have spoken in public several times. I feel that I listen better and feel better equipped to deal with change. I can better deal with fear and failure. When I find myself in a Dilbertian situation, I think about how I would use it in a scene. I believe other geeks could benefit from Improv.

I have toyed with the idea of bring Improv to the unwashed developer masses. I’m not sure how I would do it in an hour session. Would it be lecture or practice? What would I do for the hour? I am looking forward to seeing what Ted has in mind. Ted Neward is Cool!

Thursday, May 31, 2012

On Not Writting

For the past month I have struggled to finish what I've started. I think too much about what I'm trying to say and nothing comes out. Or my inner critic edits it before I can finish the bloody sentence. It can always be better.

It once was better: I start thinking about something, say on the way home from work, walking through Riverfront Park (doing laundry, driving to nowhere, etc). Regardless of what I was doing, it was brilliant. The kind of thing that changes the world. Everyone would recognize ME as the guru of whatever. So on and you know the rest… Then I get home, open up Word and… The phrases that sounded good in my head look terrible on the screen (if I can even remember them).

As the Improv Gods would say, I am in my head. I am thinking too much about things that are not important, at least not in the present moment. If I can get the words down, I can fix the style later. If I can't get the words down in the first place I have nothing. Ok, Mr. Critic it ain't perfect but it's on virtual paper.

Ok, I let Mr. Critic silence me. The only way I can grow is to put myself out there and risk being the fool. I can’t succeed if I don’t risk failure. This post, like the others, is a disappointment. It had so much promise when I was thinking it over in my mind. .. It may not meet my impossible, I'll post it anyway.

Saturday, May 12, 2012

Log4Net: Minimalist demo using config settings

The other day, it was decided at work that we will be using Log4Net, Apache’s logging tool for the .NET Framwork. It was left to me to investigate this tool. This post is the beginning of this investigation. For my first post, I present a minimal demo of Log4Net using Config settings. So here are the steps I’ve come up with using Microsoft C# Express 2010:

  1. Create a Console Application Project
  2. Make sure that Target Framework is .NET Framework 4, (select the project in Solution Explorer and press Alt+Enter, Look at Target Framework), the default is .NET Framework 4 Client Profile.
  3. Add a reference to log4net.dll
  4. Add the following attribute outside of any class or namespace (in my project I put it in Program.cs between the using and namespace statements, in a real project I would probably put it in AssemblyInfo.cs):
    [assembly: log4net.Config.XmlConfigurator]
    
    In this case XmlConfigurator tells the Framework to look in my application's .config file for configuration information.
  5. In app.config:

    <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> </configSections>

    This tells the framework about Log4Net’s custom configuration section below.

    <log4net> <appender name="MyAppender" type="log4net.Appender.FileAppender"> <file value="TestLog.txt"/> <layout type="log4net.Layout.SimpleLayout" /> </appender>


    log4net is the configuration section we described configSections above.


    This creates an appender; an appender is an object that is writes the logged data to somewhere. A FileAppender will write it to a text file. The name is used below to tell log4net to actually use this appender;


    The file element declares the name of the file. Here we will be logging to TestLog.txt in the same directory as the program.


    The layout tells log4net how to write the data. SimpleLayout is as simple as they get, In the real world, I’d use a more flexible layout. the PatternLayout is popular.

    <root>
    <appender-ref ref="MyAppender"/>
    </root>
    </log4net>

    Declaring an appender is good, but log4net won’t use it unless you tell it to.  The appender-ref element tells log4net to use my appender. You can specify as many appenders as you want.


  6. Create an instance of Log
    log4net.ILog log = log4net.LogManager.GetLogger("Some String");
    

  7. And Log away.
    log.Info("For Your Information");
    log.Warn("Danger Will Robinson");
    log.Debug("Debug Message");
    try
    {
    throw new Exception("Deliberate Exception");
    }
    catch (Exception ex)
    {
    log.Error(ex.Message, ex);
    }
    log.Fatal("Die. Die. Die!", new ApplicationException("Fatal Exception"));

    Running the code above, my log looks like this (note that there are not time stamps):

    INFO - For Your Information
    WARN - Danger Will Robinson
    DEBUG - Debug Message
    ERROR - Deliberate Exception
    System.Exception: Deliberate Exception
    at Log4NetConsole001.Program.Main(String[] args) in C:\Users\jack\documents\visual studio 2010\Projects\Log4NetConsole001\Log4NetConsole001\Program.cs:line 20
    FATAL - Die. Die. Die!
    System.ApplicationException: Fatal Exception
    
    


 

That is my minimalist implementation of Log4Net; it is probably too simple to be useful, but is is a start. If my ambition holds, I hope to expand on this.

Complete Sample

program.cs

using System;

[assembly: log4net.Config.XmlConfigurator]

namespace Log4NetConsole001
{
class Program
{
static void Main(string[] args)
{
log4net.ILog log = log4net.LogManager.GetLogger("Some String");
log.Info("For Your Information");
log.Warn("Danger Will Robinson");
log.Debug("Debug Message");
try
{
throw new Exception("Deliberate Exception");
}
catch (Exception ex)
{
log.Error(ex.Message, ex);
}
log.Fatal("Die. Die. Die!", new ApplicationException("Fatal Exception"));
Console.WriteLine("======================= End ========================");
Console.ReadKey();
}
}
}

app.config

<?xml version="1.0"?>
<configuration>
<configSections>
<section name="log4net" 
     type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>

<log4net>
  <appender name="MyAppender" type="log4net.Appender.FileAppender">
<file value="TestLog.txt"/>
<layout type="log4net.Layout.SimpleLayout" />
  </appender>

<root>
<appender-ref ref="MyAppender"/>
</root>
</log4net>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>

Thursday, April 26, 2012

My Nokia 900

Recently I traded my iPhone 3G for a Nokia 900. The Nokia is nicer than the Apple, but I don't think that is a fair comparison; lots have happened in the last 3 years. There are some things that the Nokia does better than the iPhone ( I love the hardware button for the camera), and things I miss about the old phone (hardware mute button, combined email).

I've had this thing for a week and I'm already making apps. There are three of my creations on there right now! They are all really lame; they will make me laugh in a couple of months -- that's a start.

I like the iPhone, I like the apps, but it locked me into the apps that already exist (yes, I could a Mac and write apps in Objective-C; I have a job and other commitments). As a developer in the Microsoft space, the Windows Phone puts me into the "What can I get this thing to do" space. With the iPhone, it's "Where can I find an app to".

I am interested in building apps it get a feel of how they work than make my first million selling Winphone apps. I want to get a better feel for the mobile metaphors. If Winphone crashes and burns, I can transfer these skills to Droid, iOS or whatever comes next. Developing for Winphone allows me to concentrate on the smaller device and not deal with Java or Objective-C until after I get the new platform.

I think it is important to learn the new stuff. Whether its iPad, Windows 8, some Android based Tablet or something I don't yet know about, the tech world is changing and I need to understand it.

Saturday, March 24, 2012

Doing Notes for my Boise Code Camp Presentation

I presented this afternoon at the Boise Code Camp. All in all, it went OK. However, I had a really rough start. I am proud that I was able to brush it off and go on (I even got a couple of complements). It is important to continue on when I am bombing and debug my performance after the ordeal is over. After an Improv show (at least at the Blue Door Theatre), the performers do “Notes”.

I have observed that many code camp presentations start out scripted and eventually move into improv. It isn’t like a short games or a Harold where it can go in any direction; more like a Larry David script that has a story arc but no written dialog. This pivot usually occurs when the first question is asked. The presentation becomes a dialog that follows the outline of the presentation. I usually am good at engaging the audience in that dialog; I guess I am good at crowd work.

Rough Start

I had a lot of trouble getting started. I umed, I spoke too fast, spoke in a single note, I left stuff off (I didn’t even properly introduce myself), it took too long to get into a groove. My first 5 minutes were really weak. I didn’t rehearse that part of the presentation enough. I didn’t speak the words out loud enough. The first 5 minutes sets the pace for the rest of the show.

Improvements in Other Areas

I felt good about the rest of the talk. Last time out I had trouble talking and coding at the same time; this time I felt comfortable coding on stage. The steps of my demos were well defined and rehearsed; I even had completed demos that I could use if I had a demo failure. I also felt comfortable changing the demos based on questions or comments of my audience. I need to keep the improvements I made and fix what didn’t work

Perspective

It is not my goal to oust Scott Hanselman as the Jon Skeet of technical speaking. I am using technical speaking (and Improv for that matter) to help me get outside of myself and the traditional dweeb mindset. I am getting out of my shell and doing thing I wouldn’t have done and going places I wouldn’t have gone 3 years ago.

Thursday, March 08, 2012

EF Eager Loading Using Include()

Setup for this post

(if you want to run the code as displayed)

Lazy Loading is cool; you don’t have to load things you don’t need. However, each item you load is more expensive for each item you load; it can be a net saving if you can avoid loading enough unneeded data.

If you, the smart human, knew that you need to load that data, wouldn’t it be nice to tell the Entity Framework to go ahead and get the data NOW. I can tell EF to Eager Load specific related tables with the Include method. All I have to do is pass in the name of the navigator property of the related object you would like to load.

NOTE: LINQPad 4 is good at displaying the results of these queries in a way that may help you visualize what is happening. I spent a good amount of time trying to include that display: it was ugly.

For example, if I ran this query (LINQPad: C# Expression):

from s in stores.Include("sales")
    select s

This query would fetch all the stores and related sales.

If I wanted to load more than related object I could chain includes like this:

from s in stores.Include("sales").Include("discounts")
    select s

I get all the stores, related sales and discounts.

If I wanted to load related objects to related objects I would put a dot (".") between each level of related objects like this:

from d in discounts.Include("store.sales")
    select d

Here I get the discounts and the stores and the sales per store; the sales will appear below the stores.

Sunday, March 04, 2012

Getting TSQL Query With ToTraceString() in EF

Setup for this post

(if you want to run the code as displayed)

I use ObjectQuery.ToTraceString() to figure out what is going on behind the scenes. ToTraceString() returns the TSQL (assuming you are using the SQL Server provider) for that ObjectQuery.

Since I can see the TSQL code that EF generates I can poke around and figure what is going around behind the curtain.

For example if you ran this in LINQPad:

void Main()
{
    PubsModel.pubsEntities context = new PubsModel.pubsEntities(EF_CONNECTION_STRING);

    // Entity SQL:
    // Returns ObjectQuery<T> directly
    ObjectQuery<author> esqlq = context.CreateQuery<author>(
        "SELECT VALUE a FROM authors AS a");
    esqlq.ToTraceString().Dump("--CreateQuery");
    
    // Linq to Entities
    // ObjectQuery<T> implements IQueryable<T>
    // This statement returns an ObjectQuery<T>
    // casted as IQueryable<T>
    IQueryable<author> linqq = from a in context.authors select a;    
    // So it must be cast back to execute ToTraceString()
    ((ObjectQuery)linqq).ToTraceString().Dump("--Linq Query");
}

You would get:

--CreateQuery

SELECT 
[Extent1].[au_id] AS [au_id], 
[Extent1].[au_lname] AS [au_lname], 
[Extent1].[au_fname] AS [au_fname], 
[Extent1].[phone] AS [phone], 
[Extent1].[address] AS [address], 
[Extent1].[city] AS [city], 
[Extent1].[state] AS [state], 
[Extent1].[zip] AS [zip], 
[Extent1].[contract] AS [contract]
FROM [dbo].[authors] AS [Extent1]  

--Linq Query

SELECT 
[Extent1].[au_id] AS [au_id], 
[Extent1].[au_lname] AS [au_lname], 
[Extent1].[au_fname] AS [au_fname], 
[Extent1].[phone] AS [phone], 
[Extent1].[address] AS [address], 
[Extent1].[city] AS [city], 
[Extent1].[state] AS [state], 
[Extent1].[zip] AS [zip], 
[Extent1].[contract] AS [contract]
FROM [dbo].[authors] AS [Extent1]  

Querying EF ObjectContext from LINQPad

I have noticed that if I create an ObjectContext or a decendant of ObjectContext (like pubsEntities from Building an EF 4 Model Assembly for Pubs DB), LINQPad can’t get the connection string correctly.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings>
    <add name="pubsEntities" 
         connectionString="metadata=res://*/PubsModel.csdl|
         res://*/PubsModel.ssdl|res://*/PubsModel.msl;
         provider=System.Data.SqlClient;
         provider connection string='data source=.\SQLEXPRESS;
         attachdbfilename=&quot;C:\MDF\pubs.mdf&quot;;
         integrated security=True;connect timeout=30;
         user instance=True;multipleactiveresultsets=True;App=EntityFramework'" 
         providerName="System.Data.EntityClient" />
  </connectionStrings>
</configuration>

So I take the connection string from the app.config:

And copy it to a LINQPad C# Program .linq file as a constant on the top of the file (I am calling the constant EF_CONNECTION_STRING):

const string EF_CONNECTION_STRING = 
    @"metadata=res://*/PubsModel.csdl|res://*/PubsModel.ssdl|res://*/PubsModel.msl;" +
    @"provider=System.Data.SqlClient;" +
    @"provider connection string='data source=.\SQLEXPRESS;attachdbfilename=" + "\"" + 
    @"C:\MDF\pubs.mdf" + "\"" + 
    @";;integrated security=True;connect timeout=30;user instance=True;" +
    @"multipleactiveresultsets=True;App=EntityFramework'";

void Main()
{
    PubsModel.pubsEntities context = new PubsModel.pubsEntities(EF_CONNECTION_STRING);
    // Use Context Here
}