Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Wednesday, 17 February 2016
( MVC5 )

http://stackoverflow.com/questions/18570158/handling-singular-and-plural-controllers-routes/21227932#21227932

From this answer I’m considering the Authors and Books example I am building:

/Authors                               - list of Authors (multiple)
/Authors/1                           - individual Author  (this is the only non default route in MVC)
/Authors/Create                 - create an Author
/Authors/Edit/1                   - edit an Author
/Authors/Delete/1              - delete an Author


/Authors/Search?lastName=mateer  - search for an Author lastName=mateer
/Authors/Search?tab=newest&lastName=mateer

/Authors/1/Dave-Mateer   - individual Author  (first name / last name)

Database

image
Pluralising the table name.  Discussion here: http://stackoverflow.com/questions/338156/table-naming-dilemma-singular-vs-plural-names?rq=1
A descriptive auto-inc ID.

Stored Proc Parameters

CREATE PROCEDURE [dbo].SearchAuthorByLastName
    @LastName varchar(255)
AS
    SELECT * FROM [Authors] WHERE LastName like '%' + @LastName + '%'

Use capital letters for SP parameters

| | # 
# Sunday, 05 April 2015
( Dapper | Miniprofiler | MVC5 )

Got working

using (profiler.Step("Doing complex stuff")) { using (profiler.Step("Step A")) { Thread.Sleep(5); } using (profiler.Step("Step B")) { Thread.Sleep(25); } }

Simple example of timing

using (mp.CustomTiming("http", url)) { var json = CallAPI(stopWatchResult, url); return json; }

This is good

image

Interesting – Azure DNS broken again, or just slow network?

image
A good use case for Async!

image
Well – actually I could increase the limit size from 20 to 50 to make it faster.

image
Yes as expected it makes it faster to do all gets in parallel.

image

image
Showing the difference

| | # 
# Monday, 06 October 2014
( EF6 | MVC5 )

Problem: 10s on laptop to bring up a project in debug

Cache Symbols (did nothing for me) - http://stackoverflow.com/questions/12567984/visual-studio-debugging-loading-very-slow

image
4s from F5 to load (on fast desktop) on IE and Chrome
Instant on no debug

| | # 
# Friday, 24 January 2014
( EF6 | MVC5 | Unity | UoW )

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

  • Entity Framework Power Tools
  • UoW & Repo Framework
  • Generating EF Mappings and POCO’s
  • Upgrading the stack to EF 6.2
  • Basic Customer CRUD Use Case with MVC Scafolding Template w/ Async
  • Refactoring the CustomerController to use UoW & Repo Framework w/ Async
  • Why the ICustomerService Approach?
  • Why Commit Unit of Work Outside the Service vs. versa
  • Quick Examples with Eager Loading, Filter, and Sorting

image

| | # 
# Friday, 10 January 2014
( MVC5 | Project )

Going through sample projects to build up Winter.

image
Custom logic on the model to not allow any Title called Dave.

[Required]
[Range(0, 9999, ErrorMessage = "Rating should be in the range of 0 to 9999")]
public int Rating { get; set; }

public System.Collections.Generic.IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    if (Title == "Dave")
    {
        yield return new ValidationResult("Sorry you can't do this Dave");
    }
}

In class Story which implements IValidateableObject

EF CodeFirst without automatic? migrations.  When I was trying to easily reset the db

 http://www.itorian.com/2012/10/entity-frameworks-database-seed-method.html

image

public Configuration()
{
    AutomaticMigrationsEnabled = true;
    AutomaticMigrationDataLossAllowed = true;
}

Then added this, so live kicks in again.

Unit Testing the Controller

http://geekswithblogs.net/Frez/archive/2013/04/26/unit-testing-an-asp.net-mvc-4-controller-using-ms-test.aspx

He is being very fastidious testing the controller.   But it i is almost testing MVC.

 

Put your controllers on a Diet!

http://www.viddler.com/v/b568679c

 

ContosoUniversity

http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application

image
Interesting UI.  Done very simply with a table and overloaded index method.

image
Filtering, Paging and Sorting.

No testing.  Interesting logger.  InstructorIndexViewModels are lists of Instructors/Courses.Enrollments

Uses migrations (not auto)

EF Power Tools

http://visualstudiogallery.msdn.microsoft.com/72a60b14-1581-4b9b-89f2-846072eff19d

For creating db diagram

Holistic Testing – Jimmy Bogard: Holistic Testing

From London NDC 2013:

http://vimeo.com/68390508

redux of putting controllers on a diet:

1. http://lostechies.com/jimmybogard/2013/10/10/put-your-controllers-on-a-diet-redux/

2. http://lostechies.com/jimmybogard/2013/10/22/put-your-controllers-on-a-diet-defactoring/

3. http://lostechies.com/jimmybogard/2013/10/23/put-your-controllers-on-a-diet-a-survey/

4. http://lostechies.com/jimmybogard/2013/10/29/put-your-controllers-on-a-diet-gets-and-queries/

5. http://lostechies.com/jimmybogard/2013/12/19/put-your-controllers-on-a-diet-posts-and-commands/

| | # 
# Thursday, 09 January 2014
( EF6 | MVC5 | Project )

Looking at admin interface and how to handle foreign keys / drop downs.

@*@Html.DropDownList("StoryTypeID", String.Empty)*@
@Html.DropDownList("StoryTypeID")

Getting rid of the blank type in the dropdown list.

image

image

image

image
The standard first deployment screen!

  <system.web>
    <authentication mode="None" />
    <compilation debug="true" targetFramework="4.5.1" />
    <httpRuntime targetFramework="4.5.1" />
    <customErrors mode="Off"/>
    
  </system.web>

Added customErrors into web.config.. and suddenly it broke into life.  Hmm – initially a timeout.  Took customErrors out and it still works.

image
A working app.  Important.

Deploying and Cleaning up

Because I’d like to really encourage collaboration in teams I’m going to be as open as possible and put this code on GitHub.

I’ve got lots of commits and legacy code in current local git repo, but only want to push up current.  Basically tidy up.

image
Don’t want this publish profile in github.

image
Thats all we need – in fact don’t need packages, as NuGet would get these anyway.

http://robertcorvus.com/visual-studio-command-to-delete-all-bin-and-obj-folders-in-solution/

##########################################################
# PLEASE READ:
#
# This script will be loaded by Visual Studio only when
# the solution is loaded therefore any changes you make
# to it will not be effective until after you exit Visual
# Studio and reload the solution.
##########################################################
function global:DeleteBinObj()
{
    Get-ChildItem .\ -include bin,obj -recu -Force | remove-item -force -recurse
}
image

image

image
This was with no packages from NuGet.

image
This seems excessive – EF is 30MB

image
Found that I was referencing EF6.0.0 in web and 6.0.2 in test.  So upgraded web (which seems to have speeded startup time of project up)

Driving Out From Tests

So have got:

  • Rudimentary framework (I suspect will need to refactor out into separate projects Web and Core.. but not yet)
  • Source controlled on GitHub
  • Working live on: http://britishhumour.azurewebsites.net/
  • 6 passing tests – a few integration

Want to make sure current site is ‘working’, and want to drive out functionality from tests now.

tried to test WinterDb directly from tests class for Integration testing:

Error    1    The type 'Microsoft.AspNet.Identity.EntityFramework.IdentityDbContext`1<T0>' is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.AspNet.Identity.EntityFramework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.    E:\Dev\Winter Project\Winter\Winter.Web.Tests\Repository\StoryRepositoryTests.cs    20    17    Winter.Web.Tests

Its because I’m using IdentityDbContext and shortcutting.. Hmm.  Used NuGet to get around this.

Currently all logic is in Model (good) and Controller (just for UI rendering, so that is fine).

Made context Sets virtual to help with lazy loading and change tracking.

Making admin screen – changing size of input boxes

All done with Bootstap3

http://www.mytecbits.com/microsoft/dot-net/bootstrap-3-with-asp-net-mvc-5

Adding content and using the site

image

Layout work will have to be done soon.

image

image

Admin interface coming together.

| | # 
# Wednesday, 08 January 2014
( EF6 | MVC5 | Project )

Am using the database in Winter.Web\App_Data\Winter.mdf and using

<connectionStrings>
    <add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\Winter.mdf;Initial Catalog=Winter;Integrated Security=True" providerName="System.Data.SqlClient" />
  </connectionStrings>

However in the test project the |DataDirectory| is in Winter.Web.Tests so need to point to Winter.Web directory

<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=e:\\dev\\winter project\\winter\\winter.web\\app_data\\Winter.mdf;Initial Catalog=Winter;Integrated Security=True" providerName="System.Data.SqlClient" />

This works but relative would be much better.  Stick with this for now as it works.

photo

Initial sketch of front page (and only real page)

image
As all in 1 project can use trick to pull the ApplicationDbContext used for authentication into WinterDb

@if (User.IsInRole("admin"))
{
    <li>@Html.ActionLink("Admin", "Index", "Story")</li>
}

Menu now reacts if the users is in admin role or not.

image

image
Mocking out the front end.

image
Beginnings of an admin interface.

Working on foreign keys and drop downs working.

image
A useful trick is to get the model sorted out, then do an Add Controller (and associated views) which gives a good starting point.

| | # 
# Tuesday, 07 January 2014
( EF6 | MVC5 | Project )

Enabling migrations – have currently got a POCO:

namespace Winter.Core.Model
{
    public class Story
    {
        public int StoryID { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }
    }
}

Install EF into Infrastructure

ALT V E O to get package manager console up

Enable-migrations

Change

Update-database to kick it into life

Ended up looking at Azure again, and it has stopped working (free trial ended).. but didn’t roll over into a paid one.  And credit card wouldn’t work.

image

Set startup project to Infrastructure! To get update-database –verbose to use that (instead of web project) or

Enable-Migrations -ContextTypeName Web.Infrastructure.ContextName

Bring together Core and Infrastructure projects?

http://stackoverflow.com/questions/14891640/implementing-bounded-context-to-entity-framework-based-infrastructure

“Assuming you have a complex business domain and significant business logic, it can be worth making the effort as you have to isolate your domain layer from infrastructure concerns. However, this is often not the case. If you are mostly just moving data from the database to the UI and back again, then this is overengineering and you should seek something with fewer moving parts.”

Don’t need to isolate and test infrastructure currently as it is just EF.

What are we testing?

The main goal of this project is to drive it out via testing.  So goal is to have many unit tests which are totally independent.

Want a fat model and skinny controller.

Use interfaces

Telerik JustMock

namespace Winter.UnitTests.Web
{
    [TestClass]
    public class WinterUnitTests
    {
        // Unit test as injecting in a fake repository
        [TestMethod]
        public void Index_GivenAFakeRepository_ShouldReturnAListOfAllStories()
        {
            var storyRepository = Mock.Create<IStoryRepository>();
            Mock.Arrange(() => storyRepository.GetAllStories())
                .Returns(new List<Story>()
                {
                    new Story { StoryID=1, Title="title1", Content="content1"},
                    new Story { StoryID=2, Title="title2", Content="content2"}
                })
                .MustBeCalled();

            // Act
            HomeController controller = new HomeController(storyRepository);
            ViewResult result = controller.Index() as ViewResult;
            IEnumerable<Story> model = result.Model as IEnumerable<Story>;

            Assert.AreEqual(2, model.Count());
        }
    }
}

however much more elegant? is to have our own fake

Do we really need a repository pattern over it all, as have EF?

CTRL R + CTRL T – run current test

[TestMethod]
public void StoriesDb_GivenANewStory_ShouldSaveToDb_AndThenRevertBackDB()
{
    using (var db = new StoryRepository())
    {
        var story = new Story { Title = "test", Content = "testcontent" };

        db.Stories.Add(story);
        db.SaveChanges();

        var result = db.Stories;

        Assert.AreEqual(4, result.Count());

        db.Stories.Remove(story);
        db.SaveChanges();
        Assert.AreEqual(3, result.Count());
    }
}

Integration testing the repository.  Also implemented the transactional stuff so don’t need to remove.

Starting to build up domain model:

public class Story
{
    public int StoryID { get; set; }

    [Required]
    public string Title { get; set; }
        
    public string Content { get; set; }
}

Simplify

From Scott Allen’s code http://pluralsight.com/training/Courses/TableOfContents/mvc4-building I’ve simplified the project even further to see if it’s robust enough to do the job.

So now I’ve got a Web project and a Tests project.

image

| | # 
# Monday, 06 January 2014
( BitBucket | MVC5 )

There comes a time to just take a deep breath and get on with it:

What am I building

  • Website to display
    • jokes
    • quotes
    • funny videos
    • funny pictures
  • A rating system so any anonymous user can upvote or downvote an item

Why

  • Explore technologies:  TDD, DDD, Refactoring, Patterns eg Repository
  • Work with other people
  • Have something to talk about/demo at user group and conferences
  • Make own professional work better
    • so this is a medium sized architected app that will change it’s requirements over time
  • Have fun
  • Be able to remember jokes

Goal for week1: 

Get project on BitBucket/Github
                 Get an end to end core working
                    use git from command line for source control
                   
                
                    do TDD from outset
                        EF6 CodeFirst, MVC5
                        AutoMapper to map objects to domain objects (dtos) ot not as code first?
                        StructureMap for DI
                       
                    make unit test
                        integration tests
                   
                    make build batch files / automation
                       
                    modular/loosley coupled
                    use mocking
                    use transactions
                    use a generic repository?

 

Start – MVC5 Project

VS2013, New blank solution called Winter.  Then MVC5 project called Winter.Web

image

Right click Add Solution to Source Control.

image
So now there is a .git folder in my windows directory.  Went to bitbucket.org and added a repository called Winter.

image

TDD

image
Getting VS to display the tests when running them.  Sleep trick here to have enough time to get to Test Explorer and pin it while the tests are running.
Ctrl R A – Run all tests using VS MSTest runner.

What describes this list of things

  • jokes
  • quotes
  • funny videos
  • funny pictures

Story – lets go for it and refactor later.

image
Added a reference from Web to Core.

Looking like most unit testing will be against core.

image
Banana joke being displayed via the ViewBag

image
A list of stories on the home page.

// Integration test as going from Web to Core repository.
[TestMethod]
public void Index_GivenNothing_ShouldReturnAListOf3Stories()
{
    HomeController controller = new HomeController();

    ViewResult result = controller.Index() as ViewResult;

    IEnumerable<Story> model = result.Model as IEnumerable<Story>;

    Assert.AreEqual(3, model.Count());
}

First real test of the app.

End to End

Next aim is to get CRUD to the database.  Going to use Repository pattern so can mock out and have fast unit tests on the core. 

PluralsightBook project is a good example – mock unit tests, and integration test, and spikes

| | # 
# Thursday, 19 December 2013
( MVC4 | MVC5 )

 

    <add key="MailServer" value="mail.server.com" />
  </appSettings>
ViewBag.MailServer = ConfigurationManager.AppSettings["MailServer"];
@ViewBag.MailServer

Connectionstring, FileShareNames, MailServer names

Deploying

image
setting up IIS on the deb box instead of IIS Express.

then IIS Management Console and SQL Express.  Using LocalDB from full IIS can be a pain.

sa password – System Administrator

AutomaticMigrationsEnabled=false;

Delete the _InitialCreate file in migrations.

Add-Migration InitialCreate

image

Right click on Web Project and select publish

image

image

image
As we’re doing migrations in code – Global.asax.cs don’t need to force via config.

image

/T – checks

/Y – does it.

image
On first load..

So it has actually created the database…

image
ahh – it was Anonymous Authentication was set to false..

image

image
Controllers / all C# code compiled into the OdeToFood.dll

Publish up to Azure and don’t need to check the code migrations box as am doing it in Global.asax

| | # 
# Wednesday, 18 December 2013
( EF6 | MVC4 | MVC5 )

Taken and modified from Scott Allen’s http://pluralsight.com/training/Courses/TableOfContents/mvc4-building

This is using MVC5 (with the new Identity provider), and AutomaticMigrationsEnabled.  I’m kept with 1 DbContext for now for the ease of auto migrations being able to do Update-Database without any parameters.

public interface IOdeToFoodDb : IDisposable
{
    IQueryable<T> Query<T>() where T : class;
    void Add<T>(T entity) where T : class;
    void Update<T>(T entity) where T : class;
    void Remove<T>(T entity) where T : class;
    void SaveChanges();
}

// Was ApplicationDbContext (which contains User and Role in MVC5)
public class OdeToFoodDb : IdentityDbContext<ApplicationUser>, IOdeToFoodDb
{
    public OdeToFoodDb()
        : base("DefaultConnection")
    { }

    public DbSet<Restaurant> Restaurants { get; set; }
    public DbSet<RestaurantReview> Reviews { get; set; }

    IQueryable<T> IOdeToFoodDb.Query<T>()
    {
        return Set<T>();
    }

    void IOdeToFoodDb.Add<T>(T entity)
    {
        Set<T>().Add(entity);
    }

    void IOdeToFoodDb.Update<T>(T entity)
    {
        Entry(entity).State = System.Data.Entity.EntityState.Modified;
    }

    void IOdeToFoodDb.Remove<T>(T entity)
    {
        Set<T>().Remove(entity);
    }

    void IOdeToFoodDb.SaveChanges()
    {
        SaveChanges();
    }
}

and calling

public class HomeController : Controller
{
    IOdeToFoodDb _db;

    public HomeController()
    {
        _db = new OdeToFoodDb();
    }

    public HomeController(IOdeToFoodDb db)
    {
        _db = db;
    }

    public ActionResult Index(string searchTerm = null, int page = 1)
    {
        var model = _db.Query<Restaurant>()
                        //.Restaurants
                        .OrderByDescending(r => r.Reviews.Average(review => review.Rating))
                        .Where(r => searchTerm == null || r.Name.StartsWith(searchTerm))
                        .Select(r => new RestaurantListViewModel
                                {
                                    Id = r.Id,
                                    Name = r.Name,
                                    City = r.City,
                                    Country = r.Country,
                                    NumberOfReviews = r.Reviews.Count()
                                })
                            .ToPagedList(page, 10);
        return View(model);
    }

primarily good for testing:

[TestMethod]
public void Index()
{
    // Arrange
    var db = new FakeOdeToFoodDb();
    db.AddSet(TestData.Restaurants);
    HomeController controller = new HomeController(db);
    // Was needed for a call in HomeController for isAjaxRequest.
    //controller.ControllerContext = new FakeControllerContext();

    // Act
    ViewResult result = controller.Index() as ViewResult;
    IEnumerable<RestaurantListViewModel> model = result.Model as IEnumerable<RestaurantListViewModel>;

    // Assert
    Assert.AreEqual(10, model.Count());
}

Injecting in a FakeDb

public class FakeOdeToFoodDb : IOdeToFoodDb
{
    public IQueryable<T> Query<T>() where T : class
    {
        return Sets[typeof(T)] as IQueryable<T>;
    }

    void IDisposable.Dispose() { }

    public void AddSet<T>(IQueryable<T> objects)
    {
        Sets.Add(typeof(T), objects);
    }

    public void Add<T>(T entity) where T : class
    {
        Added.Add(entity);
    }

    public void Update<T>(T entity) where T : class
    {
        Updated.Add(entity);
    }

    public void Remove<T>(T entity) where T : class
    {
        Removed.Add(entity);
    }

    public void SaveChanges()
    {
        Saved = true;
    }

    public Dictionary<Type, object> Sets = new Dictionary<Type, object>();
    public List<object> Added = new List<object>();
    public List<object> Updated = new List<object>();
    public List<object> Removed = new List<object>();
    public bool Saved = false;
}

The FakeDb which operates as an in-memory collection.

| | # 
# Wednesday, 11 December 2013
( EF6 | MVC4 | MVC5 )

public class Employee
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}

EF can do change tracking if make virtual. Using alt to add virtual everywhere.

Migrations


namespace eManager.Web.Infrastructure
{
    public class DepartmentDb : DbContext, IDepartmentDataSource
    {
        public DbSet<Employee> Employees { get; set; }
        public DbSet<Department> Departments { get; set; }

        IQueryable<Employee> IDepartmentDataSource.Employees
        {
            get { return Employees; }
        }

        IQueryable<Department> IDepartmentDataSource.Departments
        {
            get { return Departments; }
        }
    }
}

Super simple database abstraction.

image
Hmm –authentication is wired into MVC5 in Models\IdentityModels… but inherits from IdentityDbContext

Stripped out the authentication stuff for now to get compiling.  Commented out AccountController and ApplicationDbContext classes.

image

image
Enabling automatic migrations

Seed allows us to initally populate eg

  • Lookup tables

Update-Database

image

Hmmmm am not getting migration file created nor database created in App_Data

Version2

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IDepartmentDataSource
    {
        public ApplicationDbContext()
            : base("DefaultConnection")
        {
        }

        public DbSet<Employee> Employees { get; set; }
        public DbSet<Department> Departments { get; set; }

        IQueryable<Employee> IDepartmentDataSource.Employees
        {
            get { return Employees; }
        }

        IQueryable<Department> IDepartmentDataSource.Departments
        {
            get { return Departments; }
        }
    }

To make a simple happy path for easy single migrations, I’ve added our entities to the existing context.

internal sealed class Configuration : DbMigrationsConfiguration<ApplicationDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
    }

    protected override void Seed(ApplicationDbContext context)
    {
        context.Departments.AddOrUpdate(d => d.Name,
                new Department { Name="Engineering"},
                new Department { Name="Sales"},
                new Department { Name="Shipping"},
                new Department { Name="Human Resources"}
                );

        // Could you use this way
        if (!context.Users.Any(u => u.UserName == "dave"))
        {
            var roleStore = new RoleStore<IdentityRole>(context);
            var roleManager = new RoleManager<IdentityRole>(roleStore);

            var userStore = new UserStore<ApplicationUser>(context);
            var userManager = new UserManager<ApplicationUser>(userStore);
            var user = new ApplicationUser { UserName = "dave" };

            userManager.Create(user, "letmein");
            roleManager.Create(new IdentityRole { Name = "admin" });
            userManager.AddToRole(user.Id, "admin");
        }
    }
}

Alt V E O – Package Manager console

update-database –verbose

| | # 
# Tuesday, 10 December 2013
( MVC5 )

image
New database, and password is hashed.  Can enable MS, Facebook, Google, Twitter

image

User.IsInRole("admin")
false

public class SecretController : Controller
{
    // Just return a string
    public ContentResult Secret()
    {
        return Content("This is a secret...");
    }

    public ContentResult Overt()
    {
        return Content("This is a not a secret...");
    }
        
}

image

[Authorize]
public ContentResult Secret()
{
    return Content("This is a secret...");
}

redirects to login

[Authorize]
public class SecretController : Controller
{
    // Just return a string
    public ContentResult Secret()
    {
        return Content("This is a secret...");
    }

    [AllowAnonymous]
    public ContentResult Overt()
    {
        return Content("This is a not a secret...");
    }
}
    [Authorize(Users="dave, bob")]
    //[Authorize(Roles="admin, sales")]
    public class SecretController : Controller
    {
        // Just return a string
        public ContentResult Secret()
        {
            return Content("This is a secret...");
        }

        [AllowAnonymous]
        public ContentResult Overt()
        {
            return Content("This is a not a secret...");
        }
    }

The Database

image
Double click on the mdf to open in Server Explorer.

Data in AspNetUsers.

UserManager is what we’ll use within our app.

Changing the System

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        var user = await UserManager.FindAsync(model.UserName, model.Password);
        if (user != null)
        {
            await SignInAsync(user, model.RememberMe);
            return RedirectToLocal(returnUrl);
        }
        else
        {
            ModelState.AddModelError("", "Invalid username or password.");
        }
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

3:38 in d

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }

    public DbSet<Movie> Movies { get; set; }
}

public class Movie
{
    public int Id { get; set; }
    public string Title { get; set; }
}

So this is how we can have 1 migration

image

image

internal sealed class Configuration : DbMigrationsConfiguration<Identity.Models.ApplicationDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = true;
    }

    protected override void Seed(Identity.Models.ApplicationDbContext context)
    {
        //  This method will be called after migrating to the latest version.

        //  You can use the DbSet<T>.AddOrUpdate() helper extension method
        //  to avoid creating duplicate seed data. E.g.
        //
        //    context.People.AddOrUpdate(
        //      p => p.FullName,
        //      new Person { FullName = "Andrew Peters" },
        //      new Person { FullName = "Brice Lambson" },
        //      new Person { FullName = "Rowan Miller" }
        //    );
        //

        if (!context.Users.Any(u => u.UserName == "dave"))
        {
            var roleStore = new RoleStore<IdentityRole>(context);
            var roleManager = new RoleManager<IdentityRole>(roleStore);

            var userStore = new UserStore<ApplicationUser>(context);
            var userManager = new UserManager<ApplicationUser>(userStore);
            var user = new ApplicationUser { UserName = "dave" };

            userManager.Create(user, "letmein");
            roleManager.Create(new IdentityRole { Name = "admin" });
            userManager.AddToRole(user.Id, "admin");
        }
    }
}

Changed auto migrations to be true.  And implemented a seed method.

image

image

enable-miragtions –force to regen the above file.  Delete migrations files too.

| | # 
# Thursday, 05 December 2013
( Azure | EF6 | MVC5 )

New Web Site – Custom Create

image

image

winterjAT9VB56yf

z…

image
Bottom right, download publish profile.

Actually in VS publish web project, import from azure,

image

image
Had to remember to select the correct db.  Actually I didn’t push out Executre code first.

image
Hmm database doesn’t look like it is there.

Did execute code first, and got authentication working

<system.web>
    <customErrors mode="Off"/>
    <authentication mode="None"/>
    <compilation debug="true" targetFramework="4.5.1"/>
    <httpRuntime targetFramework="4.5.1"/>

Actually had to just make sure customErrors were off

image

Ahh, it turned out it did do the first identity migration, but not the second library.

Ended up doing a generate scripts and http://social.msdn.microsoft.com/Forums/windowsazure/en-us/259af3d5-4016-43e2-9a84-7a17d4f52673/im-unable-to-create-a-new-table-on-sql-azure?forum=ssdsgetstarted

Needed to get rid of the ON PRIMARY stuff in the dump out to 2008R2

image

Then it worked:

image
We have a live site, connecting to a database!

Alt B O – toggle beteen debug / release

Alt B H – publish

| | # 
# Tuesday, 03 December 2013
( EF6 | Glimpse | MVC5 )

public class BooksDb : DbContext
    {
        public BooksDb()
            : base("DefaultConnection")
        {
            Database.Log = sql => Debug.Write(sql);
        }

        public DbSet<Book> Books { get; set; }
    }

When app is in debug, will be able to see in Output window in VS.

image
First time EF is being used, checks to see if DB is in sync with migrations.

Could parse and only log queries > 2000ms

Glimpse

image

image

 

image
Push the on button

Only enabled for local server by default.

image

image
Seeing what SQL has ran, and how long.

| | # 
( EF6 | MVC5 )

Goal is to CRUD up Books now that we have Books entities, and a Books table.

image

image

image
Created books controller and put on [Authorize]

<ul class="nav navbar-nav">
                    <li>@Html.ActionLink("Home", "Index", "Home")</li>
                    <li>@Html.ActionLink("Books", "Index", "Books")</li>
                    <li>@Html.ActionLink("About", "About", "Home")</li>
                    <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
                </ul>

In Views\Shared\_Layout.cshtml

image
Responsive UI and authorization, and CRUD.

image
Validation too, but notice the Enum category is freeform text – not good.

Editor Templates

image
Adding a global template for Genre.

Reflect over the Enum type to get values, so can render on the view.  As the database is only storing the int values.

namespace Books.Web.Helpers
{
    public static class EnumHelpers
    {
        public static IEnumerable<SelectListItem> GetItems(this Type enumType)
        {
            if (!typeof(Enum).IsAssignableFrom(enumType))
            {
                throw new Exception("Type must be an Enum");
            }

            var names = Enum.GetNames(enumType);
            var values = Enum.GetValues(enumType).Cast<int>();

            // Stitch together 2 sequences
            var items = names.Zip(values, (name, value) =>
                new SelectListItem
                {
                    Text = name,
                    Value = value.ToString()
                }
                );

            return items;
        }
    }
}
@using Books.Entities
@using Books.Web.Helpers
@{
    var items = typeof(Genre).GetItems();
}

@Html.DropDownList("", items)

image
However spaces are not elegant

public enum Genre
    {
        [Display(Name="Non Fiction")]
        NonFiction,
        Romance,
        Action,
        [Display(Name = "Science Fiction")]
        ScienceFiction
    }

And wire up:

public static IEnumerable<SelectListItem> GetItems(this Type enumType)
        {
            if (!typeof(Enum).IsAssignableFrom(enumType))
            {
                throw new Exception("Type must be an Enum");
            }

            var names = Enum.GetNames(enumType);
            var values = Enum.GetValues(enumType).Cast<int>();

            // Stitch together 2 sequences
            var items = names.Zip(values, (name, value) =>
                new SelectListItem
                {
                    Text = GetName(enumType,name),
                    Value = value.ToString()
                }
                );

            return items;
        }

        static string GetName(Type enumType, string name)
        {
            var result = name;

            var attribute = enumType
                            .GetField(name)
                            .GetCustomAttributes(inherit: false)
                            .OfType<DisplayAttribute>()
                            .FirstOrDefault();

            if (attribute != null)
            {
                result = attribute.GetName();
            }

            return result;
        }

image

image
However on edit, selected category not working so:

public static IEnumerable<SelectListItem> GetItems(this Type enumType, int? selectedValue)
        {
            if (!typeof(Enum).IsAssignableFrom(enumType))
            {
                throw new Exception("Type must be an Enum");
            }

            var names = Enum.GetNames(enumType);
            var values = Enum.GetValues(enumType).Cast<int>();

            // Stitch together 2 sequences
            var items = names.Zip(values, (name, value) =>
                new SelectListItem
                {
                    Text = GetName(enumType,name),
                    Value = value.ToString(),
                    Selected = value == selectedValue
                }
                );

            return items;
        }

Pass in the selectedValue to the helper, and do true or false for selected.

@{
    var items = typeof(Genre).GetItems((int?)Model);
}

Problem on Index view that it still displays ScienceFiction.. but solvable in a similar way, using a global DisplayTemplate

| | # 
( MVC5 )

e:\dev\Winter Project\Books

  • Blank solution called Books
  • MVC5 project – Books.Web
    • which references Books.Entities
  • Domain Logic – Books.Entities
namespace Books.Entities
{
    public class Book
    {
        public int Id { get; set; }

        [Required]
        [StringLength(255)]
        public string Title { get; set; }

        public Genre Category { get; set; }
    }
}

Creating an simple entity using CodeFirst
namespace Books.Entities
{
    public enum Genre
    {
        NonFiction,
        Romance,
        Action,
        ScienceFiction
    }
}

So can demo EF6 Enum support

DbContext

namespace Books.Web.DataContexts
{
    public class BooksDb : DbContext
    {
        public BooksDb()
            : base("DefaultConnection")
        {
        }
        public DbSet<Book> Books { get; set; }
    }
}

DbContext to talk to the db

DbSet for the most part will map to a table

namespace Books.Web.DataContexts
{
    public class IdentityDb : IdentityDbContext<ApplicationUser>
    {
        public IdentityDb()
            : base("DefaultConnection")
        {
        }
    }
}

Moved from Models into DataContexts, using the same connection string.

Migrations

  • Create, seed and apply schema changes
  • Now supports multiple DbContexts
    • ContextTypeName
    • MigrationsDirectory

image

Stores in a table which migrations have been applied.

Want more control.. Quick launch Ctrl Q:  pack

image

Code First Migrations enabled for project Books.Web.
PM> enable-migrations -ContextTypeName IdentityDb -MigrationsDirectory DataContexts\IdentityMigrations
Checking if the context targets an existing database...
Code First Migrations enabled for project Books.Web.
PM>

image

PM> enable-migrations -ContextTypeName BooksDb -MigrationsDirectory DataContexts\BookMigrations

Same again for Books.  Notice AutomaticMigrations are false.

image
Then press Tab to get autocompletion hints in powershell

PM> Add-Migration -ConfigurationTypeName Books.Web.DataContexts.IdentityMigrations.Configuration "InitialCreate"
Scaffolding migration 'InitialCreate'.

Which created InitialCreate

Add-Migration -ConfigurationTypeName Books.Web.DataContexts.BookMigrations.Configuration "InitialCreate"

Which created:

public partial class InitialCreate : DbMigration
{
    public override void Up()
    {
        CreateTable(
            "dbo.Books",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    Title = c.String(nullable: false, maxLength: 255),
                    Category = c.Int(nullable: false),
                })
            .PrimaryKey(t => t.Id);
            
    }
        
    public override void Down()
    {
        DropTable("dbo.Books");
    }
}
PM> Update-Database -ConfigurationTypeName Books.Web.DataContexts.IdentityMigrations.Configuration
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Applying explicit migrations: [201312031038087_InitialCreate].
Applying explicit migration: 201312031038087_InitialCreate.
Running Seed method.

Created the Identity table

image
Database is in App_Data folder

PM> Update-Database -ConfigurationTypeName Books.Web.DataContexts.BookMigrations.Configuration -Verbose
Using StartUp project 'Books.Web'.
Using NuGet project 'Books.Web'.
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Target database is: 'aspnet-Books.Web-20131202052105' (DataSource: (LocalDb)\v11.0, Provider: System.Data.SqlClient, Origin: Configuration).
Applying explicit migrations: [201312031041428_InitialCreate].
Applying explicit migration: 201312031041428_InitialCreate.
CREATE TABLE [dbo].[Books] (
    [Id] [int] NOT NULL IDENTITY,
    [Title] [nvarchar](255) NOT NULL,
    [Category] [int] NOT NULL,
    CONSTRAINT [PK_dbo.Books] PRIMARY KEY ([Id])
)

image

ASP.NET Identity tables and our own Books table.

| | #