Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Tuesday, October 20, 2009
Task:  create a WebService that returns a recording and all its entities when specifying the id of the recording. Return type of XML (ie not a .net dataset).

The DAL.Catalog returns a RecordingDataSet.Recording.

We need to write a DTO that takes an input and transforms(munges) it into something else

Using a Service Interface Pattern.

Build a stub, map it into a DTO, and verify each field.
First thing I did was to create a stub, to hide how the RecordingDataSet is retrieved..so am not relying on the DAL at this point.

Here is the test the Stub code:
[TestFixture]
  public class CatalogServiceStubFixture
     {
         RecordingDataSet.Recording recording;
         RecordingDataSet.Recording actual;
         CatalogServiceStub service;
 
         [SetUp]
         public void SetUp()
         {
             // create a test recording in memory
             recording = CreateRecording();
             service = new CatalogServiceStub(recording);
             actual = service.FindByRecordingId(recording.Id);
         }
 
         private RecordingDataSet.Recording CreateRecording() 
         {
             RecordingDataSet dataSet = new RecordingDataSet();
             RecordingDataSet.Recording recording = dataSet.Recordings.NewRecording();
             recording.Id = 1;
            // more code needed here to fill in the rest of the recording.
             return recording;
         }
 
         [Test]
         public void CheckId()
         {
             Assert.AreEqual(recording.Id, actual.Id);
         }

Next we want a dto to transform our dataset, into something else:



To specify in platform independant, we use XML.  This is still quite bulky, perhaps JSON would be lighter now.

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="http://nunit.org/webservices" elementFormDefault="qualified" targetNamespace="http://nunit.org/webservices" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Recording" type="tns:RecordingDto" />
  <xs:complexType name="RecordingDto">
    <xs:sequence>
      <xs:element minOccurs="1" maxOccurs="1" name="id" type="xs:long" />
      <xs:element minOccurs="1" maxOccurs="1" name="title" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="artistName" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="releaseDate" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="labelName" type="xs:string" />
      <xs:element minOccurs="0" maxOccurs="unbounded" name="tracks" type="tns:TrackDto" />
      <xs:element minOccurs="0" maxOccurs="unbounded" name="reviews" type="tns:ReviewDto" />
      <xs:element minOccurs="0" maxOccurs="1" name="totalRunTime" type="xs:int" />
      <xs:element minOccurs="0" maxOccurs="1" name="averageRating" type="xs:int" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="TrackDto">
    <xs:sequence>
      <xs:element minOccurs="1" maxOccurs="1" name="id" type="xs:long" />
      <xs:element minOccurs="1" maxOccurs="1" name="title" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="artistName" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="duration" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="genreName" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="ReviewDto">
    <xs:sequence>
      <xs:element minOccurs="1" maxOccurs="1" name="id" type="xs:long" />
      <xs:element minOccurs="1" maxOccurs="1" name="reviewerName" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="rating" type="xs:int" />
      <xs:element minOccurs="1" maxOccurs="1" name="reviewContent" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>


A benefit is that we can create C# from this:.. but really just getters and setters.  See below.. this led to an interesting bug.

http://www.codingday.com/xml-c-class-generator-for-c-using-xsd-for-deserialization/

xsd asdf.xml - create an xsd
xsd asdf.xsd /CLASSES  - creates a .cs

Then just creating an 'Assembler', which writes out the DTO...(from http://martinfowler.com/eaaCatalog/dataTransferObject.html)

The Assembler has business logic in it to flatten the structure (as in the similar example above)

The webservice is setup by adding it into IISAdmin.

As the default ASP.NET user does not have access to my local database
connection = new SqlConnection("Data Source=DAVEXPLAPTOP;Initial Catalog=catalog;Integrated Security=True");

The easiest way to get running on dev was to add the DAVEXPLAPTOP\ASPNET user into my SQL database.  This didn't show up under objects when adding, but I went ahead anyway and it worked.







So this is what we have so far:


Comments [0] | | # 
From the nbdn course, I had some interesting code I'd like to test.  Just the business logic really, no DAL nor UI.  As I wanted to make a full application, the first though was to make a DAL which talked to a text file, or just some dummy data.  How to do this well?  De-coupled.  Tried to use poor mans dependency injection, and got confused.  So I had a coffee, and bought this book.  Because it had an end to end example of a testable application.  It uses .net1.1 mostly (which is good as there are no language constructs to learn)



Some good introduction to refactorings, and unit testing.  The main meat of the book is an example called MediaLibrary (music recordings).  Chapter 5 started with testing the DAL.

Here are the first tests.  Am showing nunit test runner.. mostly I use testdriven.net, and have setup ctrl alt shft t to run tests.



for source control I'm using  git, and have coupled up with gvim as text editor.  And linked in beyond compare for a merge tool.

The book uses Strongly Typed Datasets, which were the 'star of the show' in the .net1.0 release.  By writing the sql, and having intellisense have autoproperties, this saves writing boiler plate code.

I learned about DataSets.. here is my edit (from wikipedia)..http://en.wikipedia.org/wiki/ADO.NET#DataSets

ADO.NET consists of two primary parts:

Data provider

These classes provide access to a data source, such as a Microsoft SQL Server.  Each data source has its own set of provider objects, but they each have a common set of utility classes:

  • Connection: Provides a connection used to communicate with the data source.
  • Command: Used to perform some action on the data source, such as reading, updating, or deleting relational data.
  • Parameter: Describes a single parameter to a command. A common example is a parameter to a stored procedure.
  • DataAdapter: A bridge used to transfer data between a Data source and a DataSet object (see below).
  • DataReader: Used to efficiently process a large list of results one record at a time. It allows records to be accessed in a read-only, forward-only mode, i.e., records have to be accessed in sequential order; they can neither be randomly accessed nor can a record which has been processed previously be accessed again.

DataSets

DataSet objects, a group of classes describing a simple in-memory relational database,

  • A DataSet object represents a schema (either an entire database or a subset of one). It can contain tables and relationships between those tables.
    • A DataTable object represents a single table in the database. It has a name, rows, and columns.
      • A DataView object overlays a DataTable and sorts the data (much like an SQL "order by" clause) and filters the records (much like an SQL "where" clause) if a filter is set. An in-memory index is used to facilitate these operations. All DataTables have a default filter, while any number of additional DataViews can be defined, reducing interaction with the underlying database and thus improving performance.
        • A DataColumn represents a column of the table, including its name and type.
        • A DataRow object represents a single row in the table; it allows reading and updating of values in that row, likewise retrieving any rows that are related to it through a primary-key foreign-key relationship.
VS has a nice editor:



Once I spiked up what datasets were (in simpleDatabaseTests.cs).. used this for reference: http://www.csharp-station.com/Tutorials/AdoDotNet/Lesson05.asp
 [Test]
        public void put_data_into_a_dataset()
        {
            DataSet dataset = new DataSet();
            SqlDataAdapter data_adapter = new SqlDataAdapter("select id, name from Artist", connection);
            SqlCommandBuilder sql_command_builder = new SqlCommandBuilder(data_adapter);
            data_adapter.Fill(dataset, "Artist");
            Assert.IsNotNull(dataset);

            DataTable data_table = dataset.Tables[0];
            for (int i = 0; i < data_table.Rows.Count; i++)
            {
                DataRow data_row = data_table.Rows[i];
                Console.Out.Write(data_row["id"] + " ");
                Console.Out.WriteLine(data_row["name"]);
            }
        }

The example I'm working through uses a Table Data Gateway Pattern for the DAL. 

http://martinfowler.com/eaaCatalog/tableDataGateway.html
"A Table Data Gateway holds all the SQL for accessing a single table or view: selects, inserts, updates, and deletes. Other code calls its methods for all interaction with the database."

Lets take an example of ArtistFixture.cs which tests ArtistGateway.cs

[TestFixture]
    public class ArtistFixture
    {
        static readonly string artistName = "Artist";
        SqlConnection connection;
        ArtistGateway gateway;
        RecordingDataSet recordingDataSet;
        long artistId;

        [SetUp]
        public void setup_and_open_connection_pass_to_gateway_setup_data_set()
        {
            connection = new SqlConnection(ConfigurationSettings.AppSettings.Get("Catalog.Connection"));
            connection.Open();

            recordingDataSet = new RecordingDataSet();
            gateway = new ArtistGateway(connection);
            // insert a new artist getting its ID from the database
            artistId = gateway.Insert(recordingDataSet, artistName);
        }

        [Test]
        public void RetrieveArtistFromDatabase()
        {
            // create new RDS, use same gateway.
            RecordingDataSet loadedFromDB = new RecordingDataSet();
            RecordingDataSet.Artist loadedArtist = gateway.FindById(artistId, loadedFromDB);

            Assert.AreEqual(artistId, loadedArtist.Id);
            Assert.AreEqual(artistName, loadedArtist.Name);
        }
Here is part of ArtistGateway.cs.. gateway is newed up with a connection passed in.. then only in Insert is it passed in a strongly typed RecordingDataSet, which has all the SQL in it which has been auto-genned.
public class ArtistGateway
{
SqlDataAdapter adapter;
SqlConnection connection;
SqlCommand command;
SqlCommandBuilder builder;

public ArtistGateway(SqlConnection connection)
{
this.connection = connection;

command = new SqlCommand("select id, name from artist where id = @id",connection);
command.Parameters.Add("@id", SqlDbType.BigInt);

adapter = new SqlDataAdapter(command);
builder = new SqlCommandBuilder(adapter);
}


public RecordingDataSet.Artist FindById(long artistId, RecordingDataSet recordingDataSet)
{
command.Parameters["@id"].Value = artistId;
adapter.Fill(recordingDataSet, recordingDataSet.Artists.TableName);
DataRow[] rows = recordingDataSet.Artists.Select(String.Format("id={0}", artistId));

if (rows.Length < 1) return null;
return (RecordingDataSet.Artist) rows[0];
}
Class Diagram done in VS2008 with the Class Designer Powertoy http://www.codeplex.com/modeling
To get the blue lines go to Class Diagram, Filter Lines, Show All Associations.

Sequence diagram done in Visio: (hmm - this is a bit complex... I prefer the class diagram above with notes)


Genre was next, then the rest.  Then relationships between objects eg ReviewReviewer.. just testing the test data we create comes back:  Have abstracted out some of the setup code into ConnectionFixture.
 [TestFixture]
 public class ReviewReviewerFixture : ConnectionFixture
 {
     [Test]
     public void ReviewerId()
     {
         RecordingDataSet recordingDataSet = new RecordingDataSet();

         ReviewGateway reviewGateway = new ReviewGateway(Connection);
         long reviewId = reviewGateway.Insert(recordingDataSet, 1, "Review Content");

         ReviewerGateway reviewerGateway = new ReviewerGateway(Connection);
         long reviewerId = reviewerGateway.Insert(recordingDataSet, "Reviewer Name");

         RecordingDataSet.Review review = reviewGateway.FindById(reviewId, recordingDataSet);

         review.ReviewerId = reviewerId;
         reviewGateway.Update(recordingDataSet);

         Assert.AreEqual(reviewerId, review.Reviewer.Id);

         reviewGateway.Delete(recordingDataSet, reviewId);
         reviewerGateway.Delete(recordingDataSet, reviewerId);
     }
 }
The hardest test is RecordingGateway, as it depends on all the other 'tables'.  To simplify, we abstract out the insert/del of test data to RecordingBuilder.cs.

The last class is Catalog, which is the only class that will be called from the Service layer.  In Catalog we have FindByRecordingId, which returns a RecordingDataSet.Recording (so all the data associated with this recordingId).




In summary we have done this of the overall structure of the APP:

Comments [0] | | # 
# Friday, October 09, 2009
JP Boodhoo's Nothing But Dot Net Bootcamp (Sydney)


A mindblowing (melting) experience.  The overall summary of what I learned, is that I know where I want to go now.  Can see how I'd like to develop.

A great series of articles on what we did:
http://www.davesquared.net/2009/08/nothin-but-net-sydney-2009-day-1.html

Xerxes video discussing the camp:
http://ozalt.net/blog/virtual-alt-net-aug-17-jp-boodhoo-s-bootcamp/

Over the last year I've started using:

gvim - text editor (still getting used to it!)
git - source control
gmail - learned the keyboard shortcuts which has been amazing
launchy - quick launcher
vs2008 - black colour of fonts, class diagram
resharper - auto formatting of doc, easily navigate large codebases, refactorings, moving code, create classes quickly
console2 with powershell - use it for git, navigating between projects
windows - keyboard shortcuts like windows file exploring tabbing around
firefox 3.5 with vimperator extensions
beyond compare - easily put stuff live
alt tab replacement
balsamiq - for mocking up UI's
sdedit  - for doing sequence diagrams


Goal over the next 2 months is to write an application in a well architected manner. 

Am starting with the MovieLibrary example (it could be used to catalog your home movies) we worked on at nbdn.  Basically putting a front end, and a DAL on the existing code..

Biggest lessons I've learned this year are:

- have fun!
- to become a great develop you need to code, code, code <grin>



Comments [0] | | # 
# Saturday, August 01, 2009
Interesting..added in C#2.0

using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        // enumerates through the IEnumerable
        // every time call GetInt() we receive a new incremented integer
        foreach (int i in GetInt())
            Console.WriteLine("Got " + i.ToString());
    }

    public static IEnumerable<int> GetInt()
    {
        // this method remembers its' state, so every time it is called, 
        // the next int is returned
        for (int i = 0; i < 5; i++)
            yield return i;
    }
}
thanks to: http://www.c-sharpcorner.com/UploadFile/rmcochran/yieldreturn04022006113850AM/yieldreturn.aspx?ArticleID=4617984b-2209-4211-9d08-8f06e0fe2da5

Comments [0] | | # 

From: http://msdn.microsoft.com/en-us/library/bb383977.aspx

Extension methods enable you to "add" methods to existing types without creating a new derived type,

Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type.

For client code, there is no apparent difference between calling an extension method and the methods that are actually defined in a type.

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string s = "hello extension methods are good";
            Console.WriteLine(s);
            int i = s.WordCount();
            Console.WriteLine("number of words is {0}", i.ToString());
        }
    }

    public static class MyExtensions
    {
        public static int WordCount(this String str)
        {
            return str.Split(new char[] { ' ', '.', '?' }, StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }
}

Comments [0] | | # 
# Monday, July 27, 2009
Thanks to:
http://davidhayden.com/blog/dave/archive/2006/05/28/2974.aspx

Anon methods, delegates, predicates.  Anon methods are simple shortcuts so don't have to declare a predicate method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestAnonymousMethods
{
    public class Program
    {
        // using an anon method
        static void Mainx(string[] args)
        {
            int[] _integers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            int[] evenIntegers = Array.FindAll(_integers,
                                        // this is the anonymous method below
                                       delegate(int integer)
                                       {
                                           return (integer % 2 == 0);
                                       }
                );

            foreach (int integer in _integers) 
                Console.WriteLine(integer);

            foreach (int integer in evenIntegers)
                Console.WriteLine(integer);
        }

        // not using anon method
        static void Mainy(string[] args)
        {
            int[] _integers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            // passing in IsEven..a delegate which represents the IsEven method
            int[] evenIntegers = Array.FindAll(_integers, IsEven);

            foreach (int integer in _integers)
                Console.WriteLine(integer);

            foreach (int integer in evenIntegers)
                Console.WriteLine(integer);
        }

        static bool IsEven(int integer)
        {
            return (integer % 2 == 0);
        }


       
        // not using anon method and looking at predicate / delegate of Array.FindAll
        static void Main(string[] args)
        {
            int[] _integers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            // a predicate is expected
            // passing in IsEven..a delegate which represents the IsEven method
            int[] whatIsInBoth = Array.FindAll(_integers, IsDaveSequence);

            foreach (int integer in whatIsInBoth)
                Console.WriteLine(integer);

        }

        static bool IsDaveSequence(int integer)
        {
            bool returnState = false;
            if ((integer == 1) || (integer == 3) || (integer ==4))
                returnState = true;
            return returnState;
        }



    }
}

Comments [0] | | # 
# Thursday, July 23, 2009
Delegates, delegate to another method.  In this example, depending on which person is wired up - Suzanne or Amy.. depends on which method is called when the Get the ingredient button is called.


source code here..delegateIngredients.zip (91.58 KB)






    // can be used to create a variable that can point to any method that takes an int parameter and returns a string
    public delegate string GetSecretIngredient(int amount);

On the form:
        // so variable ingredientMethod of type delegate GetSecretIngredient currently points to a null method
        GetSecretIngredient ingredientMethod = null;
        private void getSuzanne_Click(object sender, EventArgs e)
        {
            // suzanne.MySecretIngredientMethod property returns a new instance of the the GetSecretIngredient delegate thats
            // pointing to her secret ingredient method.
            ingredientMethod = new GetSecretIngredient(suzanne.MySecretIngredientMethod);
        }
When button is pressed it will go to either the suzanne.MySecretIngredientMethod or the amy.AmySecretIngredientMethod
        private void useIngredient_Click(object sender, EventArgs e)
        {
            if (ingredientMethod != null)
                Console.WriteLine("I'll add " + ingredientMethod((int)amount.Value));
            else
                Console.WriteLine("I dont have a secret ingredient");
        }
Good duck example here:
http://stackoverflow.com/questions/687626/the-purpose-of-delegates



Comments [0] | | # 
# Saturday, July 18, 2009
A simple MVC (Model View Controller) implementation..code by Jimmy Chandra
http://stackoverflow.com/questions/1107720/mvc-c-simplest-possible-implementation

Why use MVC?  Similar reasons to MVP - testability and seperation of concerns

Simple.MVC.zip (167.25 KB)



1. Program.cs runs, running Main.. as is standard in a Win Forms app.  Difference from MVP is that main here is instantiating and running a controller class first of all, instead of newing up the view, which calls the controller/presenter.
static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            
            TopEmployeeController controller = new TopEmployeeController();
            Application.Run(controller.View as Form);
        }
2. Controller is instantiated and constructor called:
        private ITopEmployeeView _view;
        private Employee _employee;

        private bool _monitoring;

        public TopEmployeeController()
        {
            _employee = new Employee();
            _view = new TopEmployeeForm(this, _employee);
        }
3. Controller news up an employee (dumb).. then a view of type TopEmployeeForm, passing its self (the controller) and employee to it.

4. View (the observer) subscribes to the model (the subject) so that when model.OnPropertyChange is called, view.UpdateView is called.  This is the observer pattern, made easier in C# using events.. which is using a delegate.
// view
public TopEmployeeForm(ITopEmployeeController controller, Employee model)
        {
            _controller = controller;
            _model = model;

            //Let the model know that this view is interested if the model change
            _model.OnPropertyChange += new Action(UpdateView);

            InitializeComponent();
}
6. When Button is pressed on the view.  The controller.GetTopEmplyee method is called.  This calls model.MontorChanges:
// controller
public void GetTopEmployee()
{
if (!_monitoring)
{
_monitoring = true;
_employee.MonitorChanges();
}
}



7. MonitorChanges does some waiting code, then every second calls FirePropertyChange(). Which calls model.OnPropertyChange.
Which is really a delegate to View.UpdateView
// model
public event Action OnPropertyChange;

private void FirePropertyChange()
        {
            var propChange = OnPropertyChange;
            if (propChange != null)
            {
                OnPropertyChange();
            }
        }

8. The view method which runs every second and displays the name on the form.
// view
        public void UpdateView()
        {
            // to do with threading
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(UpdateView));
            }
            else
            {
                TopEmployeeName = _model.FullName;
            }
        }




Comments [1] | | # 
# Thursday, July 16, 2009
( MVP | Patterns | Testing )
Easy to understand, working example WinForms app using MVP (Model View Presenter) pattern.

Why use this pattern?  Testability and maintainability (ie loosely coupled so less likely to break!)

Download noddy.zip (106.62 KB) (VS2008)

Notes:
View is dumb and does render logic
View never talks to the model (or any business entity eg customer) directly
Presenter retries data and manipulates
Model is the data and business rules

usually MVP sits on top of an ORM or Database Abstraction / Business Logic layer:


How it works:

1) Application comes to Program.cs which calls Form1.cs.. no MVP code here.
static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// Standard code.. nothing MVP
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }

2) Form1 (which is the view in MVP) which implements IView interface (**why**).. instantiates a new MainPresenter calling it presenter.
public partial class Form1 : Form, IView
    {
        private MainPresenter presenter;

        public Form1()
        {
            InitializeComponent();
             presenter = new MainPresenter(this);
        }

        private void btnPostCustomer_Click(object sender, EventArgs e)
        {
            presenter.PostCustomer();
        }

        // IView members
        public string FirstName
        {
            get { return txtFirstName.Text; }
            set { txtFirstName.Text = value; }
        }

        public string LastName
        {
            get { return txtLastName.Text; }
            set { txtLastName.Text = value; }
        }

        public void DisplayResult(string result)
        {
            MessageBox.Show(result);
        }
    }
3) MainPresenter constructor runs, and is passed in the view object of type IView. (**could we have just passed it in as a Form object?**)

public class MainPresenter
    {
        private IView view;
        private MainModel model = new MainModel();

        public MainPresenter(IView view)
        {
            this.view = view;    
        }

        public void PostCustomer()
        {
            Debug.Assert(view != null);

            try
            {
                Customer customer = new Customer(view.FirstName, view.LastName);
                model.PostCustomer(customer);
                view.DisplayResult(customer.ToString() + " posted");
            }
            catch(Exception ex)
            {
                view.DisplayResult(ex.Message);
            }
        }
    }
4) App is run, names are filled in, and Post button is submitted.



5) View code (form1.cs) runs presenter.PostCustomer
private void btnPostCustomer_Click(object sender, EventArgs e)
        {
            presenter.PostCustomer();
        }
6) presenter creates a new customer (which could be seen as being outside of MVP, and more in an entity later, as the model layer is usually light, and only relating the modelviews) and passes in the names.  Nothing special on the constructor of customer. 

public void PostCustomer()
        {
            Debug.Assert(view != null);

            try
            {
                Customer customer = new Customer(view.FirstName, view.LastName);
                model.PostCustomer(customer);
                view.DisplayResult(customer.FullName() + " posted");
            }
            catch(Exception ex)
            {
                view.DisplayResult(ex.Message);
            }
        }
7) Presenter calls the main model to PostCustomer which writes out to disk the Customer which has just been entered.
public void PostCustomer(Customer customer)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(Customer));

            if (File.Exists("Customer.xml"))
            {
                using (FileStream stream = new FileStream("Customer.xml", FileMode.Append, FileAccess.Write))
                {
                    serializer.Serialize(stream, customer);
                }
            }
            else
            {
                using (FileStream stream = new FileStream("Customer.xml", FileMode.Create, FileAccess.Write))
                {
                    serializer.Serialize(stream, customer);
                }
            }
        }



8) Presenter calls the view to DisplayResult, passing in the customer data as a string.
public void DisplayResult(string result)
        {
            MessageBox.Show(result);
        }


Included in the download are simple tests on the ViewModel and Domain model.  Also Form2 which has a Form2Presenter.  Uses same ViewModel (hmm probably should have a seperate one), and the same domain model (customer.cs).  Next step for me is to get tests working on the Presenters.




Comments [0] | | # 
# Friday, July 03, 2009
In preparation for JPBoodhoo's course in Sydney in a months time, I'm looking at the tooling he recommends and going through this videos on dnrtv.com

this is going to be an ongoing list of ideas for me refer to.. excuse the mess!

Setting up Subversion
http://www.west-wind.com/presentations/subversion/

Console2 - console with an alpha transparency
AltTab - alt tab replacement
Resharper4.5 - makes VS2008 faster
Testdriven.net - unit testing easier
mbunit - unit testing framework


Keyboard shortcuts

Testdriven.net - bound to  in VS2008, Tools, Options, Keyboard.  testdriven.net.runtests.. Ctrl-Shift-Alt-T
rerun tests is to testdriven.net.reruntest.. Ctrl-Shift-Alt-R

Resharper
Ctrl-Alt-v  - introduce variable (highlight and it gens the variable)
Alt-Int - generate constructor and..... from an interface
F2 - rename

Comments [0] | | #