Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Thursday, 20 February 2014

Figure out the different classes needed for Humour project

Entities – identified by unique ID eg a person.  If have the same name, they are still different people

Value Objects (going to leave for now and just explore DoaminEntities) – identified by the value eg address.  If the address is the same, then the same

namespace Humour.Infrastructure
{
    /// <summary>
    /// Serves as the base class for all entities in the system.
    /// </summary>
    /// <typeparam name="T">The type of the key for the entity.</typeparam>
    public abstract class DomainEntity<T>
    {
        /// <summary>
        /// Gets or sets the unique ID of the entity in the underlying data store.
        /// </summary>
        public T Id { get; set; }

        /// <summary>
        /// Checks if the current domain entity has an identity.
        /// </summary>
        /// <returns>True if the domain entity is transient (i.e. has no identity yet), false otherwise.</returns>
        public bool IsTransient()
        {
            return Id.Equals(default(T));
        }
    }
}

A base class for all DomainEntities.  Using generics to allow any type for Id.  IsTransient to see if data has an Id yet.

public class Story : DomainEntity<int>
{
    public int Id { get; set; }
}

The Story entity

[TestMethod]
public void NewStoryShouldHaveEmptyId()
{
    var story = new Story();
    //Assert.AreEqual(0, story.Id);
    //story.Id.Should().Be(0);
    story.IsTransient().Should().BeTrue();
}

Enums

Added if EF5.  So trying them here for StoryType.  Will be interesting to see how hard raw SQL will be when working with Code First generated Enums.

public enum StoryType
{
    Joke = 1,
    Video = 2,
    Quote = 3,
    Picture = 4,
    AnimatedGIF = 5
}

 

public class Story : DomainEntity<int>
{
    [Required]
    public string Title { get; set; }
    public StoryType StoryType { get; set; }
    public string Content { get; set; }
    public string VideoURL { get; set; }
    public string ImageURL { get; set; }
    public DateTime AddedDate { get; set; }
    public int Rating { get; set; }
}

 

public class Vote : DomainEntity<int>
{
    [Required]
    public string IPAddress { get; set; }
    public DateTime DateAdded { get; set; }
    public Story Owner { get; set; }
    public int OwnerId { get; set; }
}

One Story can have zero to many instances of Vote.  By having Owner property on Vote, you can assign a person to this class and link back to person from Vote.

By having OwnerId property (a foreign key property) EF lets you assign one entity to another by using the ID

var vote = new Vote { };
vote.Owner = _storyRepository.FindById(123);

vote.OwnerId = 123;

Much easier to simply assign the Story we’ve voted for by Id.  This may save a trip to the Db.

Dealing with Collections

public class Vote : DomainEntity<int>, IHasOwner
{
    [Required]
    public string IPAddress { get; set; }
    public DateTime DateAdded { get; set; }
    public Story Owner { get; set; }
    public int OwnerId { get; set; }
}

namespace Humour.Model
{
    /// <summary>
    /// This interface is used to mark the owner of an object.
    /// Useful for helping when there are orphaned Votes if a Story is deleted
    /// </summary>
    public interface IHasOwner
    {
        /// <summary>
        /// The Story instance this object belongs to.
        /// </summary>
        Story Owner { get; set; }
    }
}

Equality Comparison

We want to know when a Story object is the same eg if adding the same joke!  Or if we’ve got an import console app and we run it twice – don’t want duplicates

[TestMethod]
public void TwoStoriesWithSameIdShouldBeTheSame()
{
    var story1 = new Story { Id = 1, Title = "asdf" };
    var story2 = new Story { Id = 1, Title = "asdf" };
    (story1 == story2).Should().BeTrue();
}

This test fails as default implementation for comparison of classes in .NET is to use reference equality.  story1 and story2 are referring to difference instances of Story.

So need to override Equals and == and !=

/// <summary>
/// Determines whether the specified <see cref="T:System.Object" /> is equal to the current <see cref="T:System.Object" />.
/// </summary>
/// <returns>
/// true if the specified object is equal to the current object; otherwise, false.
/// </returns>
/// <param name="obj">
/// The object to compare with the current object.
/// </param>
public override bool Equals(object obj)
{
    if (obj == null || !(obj is DomainEntity<T>))
    {
        return false;
    }

    if (ReferenceEquals(this, obj))
    {
        return true;
    }

    var item = (DomainEntity<T>)obj;

    if (item.IsTransient() || IsTransient())
    {
        return false;
    }
    return item.Id.Equals(Id);
}

/// <summary>
/// Compares two instances for equality.
/// </summary>
/// <param name="left">The left instance to compare.</param>
/// <param name="right">The right instance to compare.</param>
/// <returns>True when the objects are the same, false otherwise.</returns>
public static bool operator ==(DomainEntity<T> left, DomainEntity<T> right)
{
    if (Equals(left, null))
    {
        return Equals(right, null);
    }
    return left.Equals(right);
}

/// <summary>
/// Compares two instances for inequality.
/// </summary>
/// <param name="left">The left instance to compare.</param>
/// <param name="right">The right instance to compare.</param>
/// <returns>False when the objects are the same, true otherwise.</returns>
public static bool operator !=(DomainEntity<T> left, DomainEntity<T> right)
{
    return !(left == right);
}

And here are the tests:

[TestMethod]
public void TwoStoriesWithSameIdShouldBeTheSame()
{
    var story1 = new Story { Id = 1, Title = "asdf" };
    var story2 = new Story { Id = 1, Title = "asdf" };
    (story1 == story2).Should().BeTrue();
}

Lots of tests in DomainEntity base class

Creating Collections

It’s quite common to do this:

public class Story : DomainEntity<int>
{
    [Required]
    public string Title { get; set; }
    public StoryType StoryType { get; set; }
    public string Content { get; set; }
    public string VideoURL { get; set; }
    public string ImageURL { get; set; }
    public DateTime AddedDate { get; set; }
    public int Rating { get; set; }

    public List<Vote> Votes { get; set; }
}

Or IQueryable

However not generally recommended to expose List<T> to the public API of a class as not mean for inheritence.  This means can’t override any of its members eg when Add/Find/Removing members.

Recommended to use Collection<T> however this doesn’t have Sort, add range.  Lets add a base class to do this.

/// <summary>
/// Represents a collection of Vote instances in the system.
/// </summary>
public class Votes : CollectionBase<Vote>
{
    /// <summary>
    /// Initializes a new instance of the <see cref="Votes"/> class.
    /// </summary>
    public Votes() { }

    /// <summary>
    /// Initializes a new instance of the <see cref="Votes"/> class.
    /// </summary>
    /// <param name="initialList">Accepts an IList of Votes as the initial list.</param>
    public Votes(IList<Vote> initialList) : base(initialList) { }

    /// <summary>
    /// Initializes a new instance of the <see cref="Votes"/> class.
    /// </summary>
    /// <param name="initialList">Accepts a CollectionBase of Vote as the initial list.</param>
    public Votes(CollectionBase<Vote> initialList) : base(initialList) { }

    /// <summary>
    /// Adds a new instance of Vote to the collection.
    /// </summary>
    /// <param name="ipAddress">The ip address</param>
    public void Add(string ipAddress)
    {
        Add(new Vote { IPAddress = ipAddress });
    }

then in Story:

public class Story : DomainEntity<int>
{
    public Story()
    {
        Votes = new Votes();
    }

    [Required]
    public string Title { get; set; }
    public StoryType StoryType { get; set; }
    public string Content { get; set; }
    public string VideoURL { get; set; }
    public string ImageURL { get; set; }
    public DateTime AddedDate { get; set; }
    public int Rating { get; set; }

    public Votes Votes { get; set; }
}

And with the add method on Votes, can do this:

var story = new Story();
story.Votes.Add("192.168.1.1");

Sorting

Using a custom comparer and wiring in a Sort method on a Collection.

[TestMethod]
public void SortPeopleWithSpecifiedComparerSortsCorrectly()
{
    var stories = new Stories();
    stories.Add(new Story { Title = "asdf", Content = "hello" });
    stories.Add(new Story { Title = "asdf3", Content = "hello" });
    stories.Add(new Story { Title = "asdf2", Content = "hello" });
    stories.Add(new Story { Title = "asdf1", Content = "hello" });
    stories.Add(new Story { Title = "asdf9", Content = "hello" });

    stories.Sort(new StoryComparer());

    stories[0].Title.Should().Be("asdf");
    stories[1].Title.Should().Be("asdf1");
    stories[2].Title.Should().Be("asdf2");
    stories[3].Title.Should().Be("asdf3");
}

[TestMethod]
public void SortIntsSorts()
{
    var ints = new IntCollection { 3, 2, 1 };
    ints.Sort();
    ints[0].Should().Be(1);
    ints[1].Should().Be(2);
    ints[2].Should().Be(3);
}

public class StoryComparer : IComparer<Story>
{
    public int Compare(Story x, Story y)
    {
        return x.Title.CompareTo(y.Title);
    }
}

 

/// <summary>
/// Sorts the collection based on the specified comparer.
/// </summary>
/// <param name="comparer">The comparer.</param>
public void Sort(IComparer<T> comparer)
{
    var list = Items as List<T>;
    if (list != null)
    {
        list.Sort(comparer);
    }
}

/// <summary>
/// Sorts the collection based on the specified comparer. Uses equals on the objects being compared.
/// </summary>
public void Sort()
{
    var list = Items as List<T>;
    if (list != null)
    {
        list.Sort();
    }
}

Auto Tracking of Create and Modified Dates

A common thing we want to do on entities.

public class Story : DomainEntity<int>, IDateTracking
    {

 

/// <summary>
/// Defines an interface for objects whose creation and modified dates are kept track of.
/// </summary>
public interface IDateTracking
{
    /// <summary>
    /// Gets or sets the date and time the object was created.
    /// </summary>
    DateTime DateCreated { get; set; }

    /// <summary>
    /// Gets or sets the date and time the object was last modified.
    /// </summary>
    DateTime DateModified { get; set; }
}

wire up later

Infrastructure - Repository Interfaces

For generic repository.

/// <summary>
/// Defines various methods for working with data in the system.
/// </summary>
public interface IRepository<T, K> where T : class
{
    /// <summary>
    /// Finds an item by its unique ID.
    /// </summary>
    /// <param name="id">The unique ID of the item in the database.</param>
    /// <param name="includeProperties">An expression of additional properties to eager load. For example: x => x.SomeCollection, x => x.SomeOtherCollection.</param>
    /// <returns>The requested item when found, or null otherwise.</returns>
    T FindById(K id, params Expression<Func<T, object>>[] includeProperties);

    /// <summary>
    /// Returns an IQueryable of all items of type T.
    /// </summary>
    /// <param name="includeProperties">An expression of additional properties to eager load. For example: x => x.SomeCollection, x => x.SomeOtherCollection.</param>
    /// <returns>An IQueryable of the requested type T.</returns>
    IQueryable<T> FindAll(params Expression<Func<T, object>>[] includeProperties);

    /// <summary>
    /// Returns an IQueryable of items of type T.
    /// </summary>
    /// <param name="predicate">A predicate to limit the items being returned.</param>
    /// <param name="includeProperties">An expression of additional properties to eager load. For example: x => x.SomeCollection, x => x.SomeOtherCollection.</param>
    /// <returns>An IEnumerable of the requested type T.</returns>
    IEnumerable<T> FindAll(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties);

    /// <summary>
    /// Adds an entity to the underlying collection.
    /// </summary>
    /// <param name="entity">The entity that should be added.</param>
    void Add(T entity);

    /// <summary>
    /// Removes an entity from the underlying collection.
    /// </summary>
    /// <param name="entity">The entity that should be removed.</param>
    void Remove(T entity);

    /// <summary>
    /// Removes an entity from the underlying collection.
    /// </summary>
    /// <param name="id">The ID of the entity that should be removed.</param>
    void Remove(K id);
}

May want to refactor as potentially too complex – p59 of the pdf

var stories = repository.FindAll(st => st.StoryType == StoryType.Joke);
/// <summary>
/// Defines the various methods available to work with people in the system.
/// </summary>
public interface IStoryRepository : IRepository<Story, int>
{
    /// <summary>
    /// Gets a list of all the stories title exactly matches.
    /// </summary>
    /// <param name="lastName">The last name that the system should search for.</param>
    /// <returns>An IEnumerable of Story with the matching people.</returns>
    IEnumerable<Story> FindByTitle(string title);
}
[HttpDelete]
        public ActionResult Delete(intid)
        {
            using(_unitOfWorkFactory.Create())
                {
                    _peopleRepository.Remove(id);
                }
            return RedirectToAction("Index");
        }

In fact – fairly simple to use

Summary

  • Base class for collections
  • Custom collections inherit from base and don’t use List<T> as can’t override
  • Extensive tests for model classes

 

.

| | # 
# Tuesday, 18 February 2014

Making Controllers Testable

fakepersonrepository – using a fake its much easier to test the controller now

StructureMap

using constructor based DI is prone to errors, and labour intensive… so use a DI framework

public static IContainer Initialize()
{
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
// x.For<IExample>().Use<Example>();
});
returnObjectFactory.Container;

Uses a similar concept to Unity, so ISomething is requested it returns Something.

PeopleController and Views

  • use ViewModels – could be exposing too much data with Model, and could be changing Model
  • Paging required
  • Sorting required

Multiple ViewModels – eg displaying a person (fewer fields) would have different data to editing a person..

He uses AutoMapper

Car car = _carRepository.FindById(id);
CarViewModel carViewModel = newCarViewModel();
carViewModel.Id = car.Id;
carViewModel.Name = car.Name;
return View(carViewModel);

Car car = _carRepository.FindById(id);
CarViewModel carViewModel = newCarViewModel();
Mapper.Map(car, carViewModel)

AutoMapper

public static class AutoMapperConfig
{
public static voidStart()
{
Mapper.CreateMap<Person, DisplayPerson>();
// Other mappings go here
Mapper.AssertConfigurationIsValid();
}
}

Can even do it automatically if have the same name and types of members

Sorting

public ActionResult Index(string sort = "Id", string sortDir = "ASC")
{
    var sortedPeopleList = _peopleRepository
    .FindAll().OrderBy(string.Format("{0} {1}", sort, sortDir));
    // Other code here
    return View();
}

eg using a grid and want to sort based on column header

Linq doesn’t allow this.. no overload of OrderBy that accepts a string.

Can use DynamicQuery library

Paging

public ActionResult Index(int page = 1, string sort = "Id", string sortDir = "ASC")
{
    var allPeople = _peopleRepository.FindAll()
    .OrderBy(string.Format("{0} {1}", sort, sortDir)).Skip((page * PageSize) - PageSize)
    .Take(PageSize);
    var model = new List<DisplayPerson>();
    Mapper.Map(allPeople, model);
    return View(model);
}

Combining paging and sorting

public ActionResult Index(int page = 1, string sort = "Id", string sortDir = "ASC")
{
    int totalRecords = _peopleRepository.FindAll().Count();
    var data = new List<DisplayPerson>();
    IQueryable<Person> allPeople = _peopleRepository.FindAll()
    .OrderBy(BuildOrderBy(sort, sortDir)).Skip((page * PageSize) - PageSize)
    .Take(PageSize);
    Mapper.Map(allPeople, data);
    var model = new PagerModel<DisplayPerson> { Data = data, PageNumber = page, PageSize = PageSize, TotalRows = totalRecords };
    return View(model);
}

Using Count() to get proper paging links.  PagerModel<T> – made it generic which means other ViewModel types that need to support paging can use it.

public class PagerModel<T> where T : class
{
    public IEnumerable<T> Data { get; set; }
    public int PageSize { get; set; }
    public int PageNumber { get; set; }
    public int TotalRows { get; set; }
}

He is using MVC WebGrid to render:

@if (Model.Data.Any())
{
    var grid = new WebGrid(null, defaultSort: "FirstName", columnNames: new[] { "Id", "FullName", "DateOfBirth", "Type" }, rowsPerPage: Model.PageSize);
    grid.Bind(Model.Data, rowCount: Model.TotalRows, autoSortAndPage: false);

    @grid.GetHtml(columns: grid.Columns(
   grid.Column("Id"),
   grid.Column(header: "Full name", columnName: "FullName", format: (item) => Html.ActionLink(((string)item.FullName), "Details", new { item.id })),
   grid.Column("DateOfBirth", header: "Date of Birth", format: (item) => item.DateOfBirth.ToString("d")),
   grid.Column("Type", canSort: false),
   grid.Column(header: "Addresses", format: item => new HtmlString(
                Html.ActionLink("Home", "Edit", "Addresses", new { personId = item.Id, contactType = (int)ContactType.Personal }, null).ToString() + " | " +
                Html.ActionLink("Work", "Edit", "Addresses", new { personId = item.Id, contactType = (int)ContactType.Business }, null).ToString())
   ),
   grid.Column(format: (item) => Html.ActionLink("E-mail addresses", "List", "EmailAddresses", new { personId = item.id }, null)),
   grid.Column(format: (item) => Html.ActionLink("Phone numbers", "List", "PhoneNumbers", new { personId = item.id }, null)),
   grid.Column(format: (item) => Html.ActionLink("Edit", "Edit", new { item.id })),
   grid.Column(format: (item) => Html.ActionLink("Delete", "Delete", new { item.id }))
  )
)
}

CreateAndEditPerson has dataannotations on it.

If anything fails then am passing good EF error messages back to the user.

Validation

public class CreateAndEditPerson : IValidatableObject
{
    public int Id { get; set; }

    [Required, DisplayName("First name")]
    public string FirstName { get; set; }

    [Required, DisplayName("Last name")]
    public string LastName { get; set; }

    [DisplayName("Date of birth")]
    public DateTime DateOfBirth { get; set; }

    public PersonType Type { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Type == PersonType.None)
        {
            yield return new ValidationResult("PersonType can't be None.", new[] { "Type" });
        }
    }
}

Duplication here with annotations and Validate method.. reckons is okay as potentially different validations.  eg for legacy code on model.. and tighter on ViewModel.

DropDownList

He uses a helper… better way in EF6 and MVC5

Suggests using JQueyryUI or KendoUI to make good looking UI’s.

| | # 
# Sunday, 16 February 2014

Install via NuGet into the Repositories project, and IntegrationTests project

Only the Person is the AggregateRoot.. so only need a DbSet<T> properties and later on repository for that.

Then he is creating a Factory pattern for repositories

Configuring your Model’s Business Rules

Property level validation using attributes

Using fluent API

IValidateableObject – Object Level Validation

 

Database Initialization and Migrations

sdf

Base Repository Class

asd

Search

asdf

Unit Of Work

asfd

IDateTracking

asdf

Improving Error Messages

asdf

| | # 

Entities

The canonical example is the Personclass. If two Personinstances have the same name, do you consider them to represent the same person?
Most likely not, as the name would not uniquely identify the person, and there’s a high probability that even though
these instances contain the same name they refer to two different people in the real world

Value Objects

A Value Object on the other hand is identified by its properties and the values they contain. The canonical example
here is Address: two instances of Addressthat contain the data “327 Washington Blvd Venice, California 90291” are
most likely considered the same; they don’t have (or need) an identity on their own.

image
And People class inherits off CollectionBase.  Notice Address is missing as app doesn’t need it.

 

namespace DLayer.Infrastructure
{
    public abstract class DomainEntity<T>
    {
        /// <summary>
        /// Gets or sets the unique ID of the entity in the underlying data store.
        /// </summary>
        public T Id { get; set; }
        /// <summary>
        /// Checks if the current domain entity has an identity.
        /// </summary>
        /// <returns>True if the domain entity is transient (i.e. has no identity yet),
        /// false otherwise.
        /// </returns>
        public bool IsTransient()
        {
            return Id.Equals(default(T));
        }
    }
}
public class Person : DomainEntity<int>
{
}

default returns the type’s default value. 

So using Id, whereas usually I prefer to use PersonId

He does low level annotations at the Entity level eg Required:

[TestMethod]
public void FirstAndLastNameResultsInFullName()
{
    var person = new Person() { FirstName = "Imar", LastName = "Spaanjaars" };
    person.FullName.Should().Be("Imar Spaanjaars");
}

[TestMethod]
public void EmptyFirstNameReturnsLastName()
{
    var person = new Person() { LastName = "Spaanjaars" };
    person.FullName.Should().Be("Spaanjaars");
}

[TestMethod]
public void EmptyLastNameReturnsFirstName()
{
    var person = new Person() { FirstName = "Imar" };
    person.FullName.Should().Be("Imar");
}

[TestMethod]
public void AllEmptyReturnsEmpty()
{
    var person = new Person();
    person.FullName.Should().Be(string.Empty);
}

and implementation:

public class Person : DomainEntity<int>
{
    [Required]
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public PersonType Type { get; set; }

    public string FullName
    {
        get
        {
            string temp = FirstName ?? string.Empty;
            if (!string.IsNullOrEmpty(LastName))
            {
                if (temp.Length > 0)
                {
                    temp += " ";
                }
                temp += LastName;
            }
            return temp;
        }
    }
}

Notice how the tests will pass as we’re not worried about IValidateable yet.

Also as this is a readonly property EF will ignore it.

namespace DLayer.Model
{
  /// <summary>
  /// Represents an e-mail address in the system.
  /// </summary>
    public class EmailAddress : DomainEntity<int>
    {
        /// <summary>
        /// Gets or sets the text of the e-mail address.
        /// </summary>
        [Required]
        [EmailAddressAttribute]
        public string EmailAddressText { get; set; }

        /// <summary>
        /// Gets or sets the type of the e-mail address.
        /// </summary>
        public ContactType ContactType { get; set; }

        /// <summary>
        /// Gets or sets the owner (a Person) of the e-mail address.
        /// </summary>
        public Person Owner { get; set; }

        /// <summary>
        /// Gets or sets the ID of the owner (a Person) of the e-mail address.
        /// </summary>
        public int OwnerId { get; set; }
    }
}

Hmm – XML comments cluttering up I’d say.  Also ambiguous Owner and OwnerId… why not Person and PersonId.?

Foreign Key Properties

This is Owner and OwnerId above
So we can shortcut..ie don’t need this:

var emailAddress = new EmailAddress { ... };
emailAddress.Owner = _personRepository.FindById(123)

can have this:

var emailAddress = new EmailAddress { ... };
emailAddress.OwnerId = 123

which could save a trip to the db eg when creating a new email address and all we have is the personId passed in the query string.

ValueObject

public class Address : ValueObject<Address>
{
    #region Constructors

    /// <summary>
    /// Initializes a new instance of the Address class.
    /// The constructor is marked private because we want other consuming code to use the overloaded constructor.
    /// However, EF still needs a parameterless constructor.
    /// </summary>
    private Address() { }

    /// <summary>
    /// Initializes a new instance of the Address class.
    /// </summary>
    /// <param name="street">The street of this address.</param>
    /// <param name="city">The city of this address.</param>
    /// <param name="zipCode">The zip code of this address.</param>
    /// <param name="country">The country of this address.</param>
    /// <param name="contactType">The type of this address.</param>
    public Address(string street, string city, string zipCode, string country, ContactType contactType)
    {
        Street = street;
        City = city;
        ZipCode = zipCode;
        Country = country;
        ContactType = contactType;
    }

    /// <summary>
    /// Gets the street of this address.
    /// </summary>
    public string Street { get; private set; }

    /// <summary>
    /// Gets the zip code  of this address.
    /// </summary>
    public string ZipCode { get; private set; }

    /// <summary>
    /// Gets the city of this address.
    /// </summary>
    public string City { get; private set; }

    /// <summary>
    /// Gets the country of this address.
    /// </summary>
    public string Country { get; private set; }

    /// <summary>
    /// Gets the contact type of this address.
    /// </summary>
    public ContactType ContactType { get; private set; }

    /// <summary>
    /// Determines if this address can be considered to represent a "null" value.
    /// </summary>
    // <returns>True when all four properties of the address contain null; false otherwise.
    public bool IsNull
    {
        get
        {
            return (string.IsNullOrEmpty(Street) && string.IsNullOrEmpty(ZipCode) && string.IsNullOrEmpty(City) && string.IsNullOrEmpty(Country));
        }
    }
}

Make it immutable

EF not Deleting Collections

var person = myContext.People.First(x => x.Id = id);
person.EmailAddresses.Clear();
myContext.SaveChanges()

This doesn’t delete the associated EmailAddresses.  EF just clears the FK that points to the Person (from each EmailAddress).  Trick is to use IHasOwner our own custom interface to detect.

So EmailAddress and PhoneNumber implement IHasOwner (which is why we use Owner in those classes)

Implementing Equality Comparison

eg we’re going to need to see if 2 addresses are the same eg business and personal of a person.

eg see if a person is being entered twice

quite complex here…

Creating Collections

he’s got a CollectionBase

going towards:

Person person = new Person();
person.EmailAddresses.Add("imar@spaanjaars.com", ContactType.Business)

Automatic Tracking of Creation and Modification Dates

Instead of:

myPerson.DateModified = DateTime.Now

hmm can get EF to automatically manage these properties

public class Person : DomainEntity<int>, IDateTracking
namespace DLayer.Model
{
    /// <summary>
    /// Defines an interface for objects whose creation and modified dates are kept track of.
    /// </summary>
    public interface IDateTracking
    {
        /// <summary>
        /// Gets or sets the date and time the object was created.
        /// </summary>
        DateTime DateCreated { get; set; }

        /// <summary>
        /// Gets or sets the date and time the object was last modified.
        /// </summary>
        DateTime DateModified { get; set; }
    }
}

Putting It All Together

eg a Person should be given collection classes for EmailAddress and PhoneNumber classes.  All these properties should be instantiated in the constructor so can access them immediately.

public class Person : DomainEntity<int>, IDateTracking
  {
    #region Constructors

    /// <summary>
    /// Initializes a new instance of the Person class.
    /// </summary>
    public Person()
    {
      EmailAddresses = new EmailAddresses();
      PhoneNumbers = new PhoneNumbers();
      HomeAddress = new Address(null, null, null, null, ContactType.Personal);
      WorkAddress = new Address(null, null, null, null, ContactType.Business);
    }

    #endregion

    #region Properties

    /// <summary>
    /// Gets or sets the date and time the object was created.
    /// </summary>
    public DateTime DateCreated { get; set; }

    /// <summary>
    /// Gets or sets the date and time the object was last modified.
    /// </summary>
    public DateTime DateModified { get; set; }

    /// <summary>
    /// Gets or sets the first name of this person.
    /// </summary>
    [Required]
    public string FirstName { get; set; }

    /// <summary>
    /// Gets or sets the last name of this person.
    /// </summary>
    [Required]
    public string LastName { get; set; }

    /// <summary>
    /// Gets or sets the date of birth of this person.
    /// </summary>
    public DateTime DateOfBirth { get; set; }

    /// <summary>
    /// Gets or sets the type of person.
    /// </summary>
    public PersonType Type { get; set; }

    /// <summary>
    /// Gets or sets the home address of this person.
    /// </summary>
    public Address HomeAddress { get; set; }

    /// <summary>
    /// Gets or sets the work address of this person.
    /// </summary>
    public Address WorkAddress { get; set; }

    /// <summary>
    /// Gets or sets the e-mail addresses of this person.
    /// </summary>
    public EmailAddresses EmailAddresses { get; private set; }

    /// <summary>
    /// Gets or sets the phone numbers of this person.
    /// </summary>
    public PhoneNumbers PhoneNumbers { get; set; }

    /// <summary>
    /// Gets the full name of this person.
    /// </summary>
    public string FullName
    {
      get
      {
        string temp = FirstName ?? string.Empty;
        if (!string.IsNullOrEmpty(LastName))
        {
          if (temp.Length > 0)
          {
            temp += " ";
          }
          temp += LastName;
        }
        return temp;
      }
    }

XML comments hide in VS with http://visualstudiogallery.msdn.microsoft.com/03141ea7-c35e-4533-b05b-9e60545e93eb

Defining Repository Interface

namespace Spaanjaars.Infrastructure
{
  /// <summary>
  /// Defines various methods for working with data in the system.
  /// </summary>
  public interface IRepository<T, K> where T : class
  {
    /// <summary>
    /// Finds an item by its unique ID.
    /// </summary>
    /// <param name="id">The unique ID of the item in the database.</param>
    /// <param name="includeProperties">An expression of additional properties to eager load. For example: x => x.SomeCollection, x => x.SomeOtherCollection.</param>
    /// <returns>The requested item when found, or null otherwise.</returns>
    T FindById(K id, params Expression<Func<T, object>>[] includeProperties);

    /// <summary>
    /// Returns an IQueryable of all items of type T.
    /// </summary>
    /// <param name="includeProperties">An expression of additional properties to eager load. For example: x => x.SomeCollection, x => x.SomeOtherCollection.</param>
    /// <returns>An IQueryable of the requested type T.</returns>
    IQueryable<T> FindAll(params Expression<Func<T, object>>[] includeProperties);

    /// <summary>
    /// Returns an IQueryable of items of type T.
    /// </summary>
    /// <param name="predicate">A predicate to limit the items being returned.</param>
    /// <param name="includeProperties">An expression of additional properties to eager load. For example: x => x.SomeCollection, x => x.SomeOtherCollection.</param>
    /// <returns>An IEnumerable of the requested type T.</returns>
    IEnumerable<T> FindAll(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties);

    /// <summary>
    /// Adds an entity to the underlying collection.
    /// </summary>
    /// <param name="entity">The entity that should be added.</param>
    void Add(T entity);

    /// <summary>
    /// Removes an entity from the underlying collection.
    /// </summary>
    /// <param name="entity">The entity that should be removed.</param>
    void Remove(T entity);

    /// <summary>
    /// Removes an entity from the underlying collection.
    /// </summary>
    /// <param name="id">The ID of the entity that should be removed.</param>
    void Remove(K id);
  }
}

Summary of this section

- very interesting way the model is being built up and tested.

| | # 

Reset Keyboard bindings in VS2012 to vs2005 to get F6 working for compiling

MVC5 – now available on nuget, so added MVC to the tests project

FluentAssertions

[TestClass]
public class PersonTests
{
    [TestMethod]
    public void NewPersonHasEmptyId()
    {
        var person = new Person();
        //Assert.AreEqual(0, person.Id);
        person.Id.Should().Be(0);
    }
}

Library has 180k downloads.

| | # 
# Sunday, 02 February 2014

http://imar.spaanjaars.com/573/aspnet-n-layered-applications-introduction-part-1

First project (Structuremap) doesn’t compile
Ninject one did work

image

MVC4 app

image
Has 116 tests including Unit and Integration.

  • MVC
  • WebForms
  • WCFService
  • CommandLine

image

image
Looking promising.. no service layer?

| | # 

image

what references what

image
A more logical flow of what is happening

| | # 
# Saturday, 01 February 2014

http://blog.longle.net/2014/01/06/unit-of-work-unity-3-quick-start-video/

EF Power Tools Beta4 – 10/12/2013
Use to generate EF mappings and POCO objects from existing db into code first
http://visualstudiogallery.msdn.microsoft.com/72a60b14-1581-4b9b-89f2-846072eff19d

UoW and Generic Repo
Also handle elegant ways to work with objects while detached from datacontext
https://genericunitofworkandrepositories.codeplex.com/

Why UoW and Repo Pattern?

UoW pattern – allows build up a unit of work with granular control of when and where you want to commit the UoW

Repo pattern – compartmentalise where SQL queries are happening and minimise surface area of ORM.  So if wanted to use different orm then would only have to refactor in repo layer

http://sqlserversamples.codeplex.com/ AdventureWorks here

http://northwinddatabase.codeplex.com/ Northwind here

Am using his version of Northwind which came in the download from codeplex

image
New MVC5 project with different projects.  Imported Repository project from codeplex download.  Reverse engineered Northwind into the Data project.

image
Context and Mappings in data project

Models in Entites project

User R# to make a field.

Put in simple CRUD methods.  However Customer isn’t happy -

Extract interface using R# – ICustomerService in Service project

Unity

image

public static void RegisterTypes(IUnityContainer container)
{
    container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
}

PerRequest – binds lifecycle of instances to lifecycle of httprequest

Framework

namespace Northwind.Data.Models
{
    public partial class NorthwindContext : DbContextBase
    {
        static NorthwindContext()
        {
            Database.SetInitializer<NorthwindContext>(null);
        }

must inherit from DataContext / DbContextBase (the version of the framework I’m using).  Video is out of sync with code.

public static void RegisterTypes(IUnityContainer container)
{
    container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
    container.RegisterType<IDbContext, NorthwindContext>(new PerRequestLifetimeManager());
    container.RegisterType<ICustomerService, CustomerService>(new PerRequestLifetimeManager());
    container.RegisterType<IRepository<Customer>, Repository<Customer>>(new PerRequestLifetimeManager());
}

All entities must inherit EntityBase


namespace Northwind.Data.Models
{
    public partial class Customer : EntityBase
    {
        public Customer()
        {

Controller

image

image

Generates nice CRUD and a view.  However wired to EF directly and not through service.

image
Read working, but not write.

image
Wired up the service and now edit works.

Why ICustomerService approach?

  • Is it necessary? No
  • Organisation, maintainability, separation of concerns
  • Testability

Ctrl-F12 – go to implementation

public Customer Update(Customer customer)
{
    // validate customers address against UPS here?
    _customerRepository.Update(customer);
    return customer;
}
  • That way we keep the controllers code clean – their job is just to hydrate data
  • Testable service layer
  • Easier to plug in a WPF app say.

Unit of Work

Committing the unit of work outside the service

public async Task<ActionResult> Edit([Bind(Include="CustomerID,CompanyName,ContactName,ContactTitle,Address,City,Region,PostalCode,Country,Phone,Fax")] Customer customer)
{
    if (ModelState.IsValid)
    {
        customer.ObjectState = ObjectState.Modified;
        _customerService.Update(customer);

        await _unitOfWork.SaveAsync();
        return RedirectToAction("Index");
    }
    return View(customer);
}

Nothing stopping us injecting the UoW inside the service, and committing once the update was complete.

image
Controller being injected with n number of services.  Between method calls there is some kind of db activity.

If each service was in charge of doing db commits – would have 8 commits.

image
If have UoW outside the service, then we’ll have only 1 commit.

Deep (eager) Loading / Filtering / Sorting

public class CustomerService : ICustomerService
{
    private readonly IRepository<Customer> _customerRepository;

    public CustomerService(IRepository<Customer> customerRepository)
    {
        _customerRepository = customerRepository;
    }

    public Customer DeepLoadCustomer(string id)
    {
        var customer = _customerRepository
            .Query()
            .Filter(t => t.CustomerID == id)
            // Deep load Order, and then Order_Details
            .Include(t => t.Orders.Select(u => u.Order_Details))
            .Get()
            .FirstOrDefault();

        return customer;
    }

    public IList<Customer> GetCustomerWithOrders()
    {
        var customers = _customerRepository
            .Query()
            .Filter(t => t.City == "Dallas")
            .Include(t => t.Orders)
            .Get()
            .OrderBy(t => t.ContactName)
            .ThenBy(t => t.CompanyName)
            .ToList();

        return customers;
    }

Notes from Website

http://blog.longle.net/2014/01/06/unit-of-work-unity-3-quick-start-video/

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "CustomerID,CompanyName,ContactName,ContactTitle,Address,City,Region,PostalCode,Country,Phone,Fax")] Customer customer)
{
    if (ModelState.IsValid)
    {
        customer.ObjectState = ObjectState.Modified;
        _unitOfWork.Repository<Customer>().Update(customer);
        await _unitOfWork.SaveAsync();
        return RedirectToAction("Index");
    }
    return View(customer);
}   

Missing out the service and going to repo directly.

IEnumerable vs IQueryable

“HAVING THE REPOSITORY RETURN ALL THINGS IEnumerable or IList is a best practice and preferred approach. Down the line, if you were to ever switch out your back-end, you won’t be bound to the requirements that the back-end implements IQueryable e.g. moving from EF to pure REST services.”

However the repo layer does return IQueryable.

Can make the repo return IEnumarble.

High Level

http://lelong37.files.wordpress.com/2013/06/modern-web-application-logical-and-physical-architecture-high-level-design-with-spa3.pdf

Testing

Only a small example… not quite working yet.

| | # 

Continuation of project review

http://pluralsight.com/training/Courses/TableOfContents/ioc-aspdotnet-mvc4

As he is looking mainly at IoC and I’m not immediately interested, as can hopefully get away with Constructor based DI for a while:

Using Getters and Setters on Properties.

http://stackoverflow.com/questions/1568091/why-use-getters-and-setters

image

Implemented ProteinDave solution.

  • Simple project
  • Not abstracted into projects yet.  Makes referencing easy!
  • Getters and Setters
  • Web layer (with a few tests passing in a StubService)
  • Service layer which depends on a repository
  • Protein data which is really an Entity model
  • A static singleton (ProteinData) which allows total to be added to
| | # 

Am doing a code review of a few promising projects to see which sections I want to take mine.

http://weblogs.asp.net/shijuvarghese/archive/2014/01/24/releasing-socialgoal-reference-web-app-for-asp-net-mvc-5-ef-6-code-first-automapper-autofac-tdd-and-ddd.aspx

https://github.com/MarlabsInc/SocialGoal

based upon http://efmvc.codeplex.com/ (same author)

“SocialGoal is a social networking web app for socializing your goals and strategies with people. People can create goals and can be shared across the network of SocialGoal users. Goals can have start date, end date, metrics and target. People can update their goals and others can see those updates and can comment on each updates. People can support any public goal.

Groups can be created within SocialGoal so that it is very easy to build goals for a team. Group goals can be assigned to any of the group members. Groups can have focus and group goal can be created with a particular focus also.”

image

Interesting project.  Thoughts:

  • Good front end
  • Finished / Shippable!
  • Tests don’t cover anything but controller
  • Could be simpler
  • Methods too busy
  • Lots of boilerplate eg most of Data.xxxRepositories are pass through code
| | # 
# Friday, 24 January 2014

There are going to be in depth notes here from this article.  Please consider buying the whole pdf  from him (as I have) as it
http://imar.spaanjaars.com/573/aspnet-n-layered-applications-introduction-part-1

These are purely my notes Imar’s article.

My goals are:

  • Understand this architecture as it “can be used to build real-world, large scale web applications.”
  • Build up from scratch his sample
  • Build out my own Winter Project app with the concepts I like from here
  • Pragmatic
  • Simple

Why Use N-Layers

  • Testability
  • Separation – make it easier to find where things are in large projects eg dataaccess, business logic, UI
  • Reuse – eg a console app can use all the goodness of the main MVC app

image

Previous Versions

  • BLL/DAL – lots of pass through code
  • DAL tight coupling making hard to test
  • SP’s hard to maintain and test
  • Validation was custom – now have better ways

Sidenote: PDF reader being horrible.. trying: http://www.foxitsoftware.com/downloads/

Starting from Scratch

image
Updating all packages

Also have enabled NuGet Package Restore.

image
My DLayer version.

Put into source control – am using github.

| | #