Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Tuesday, 20 September 2011
( Git | Glimpse | MVC | Ninject | NLog | VidPub )

Notes from TekPub ASP.NET MVC3 series of tutorials.

  • Startup – big idea.. charge people money for
  • Good idea, well executed
  • Get site out there and pay the bills!

Why MVC3 in this Fast Paced Startup?

  • Good stable version of MVC
  • I know C#

What are we doing (Elevator pitch) and when are we going to do it?

1 sentence!

Platform and Tools

MVC3

Unfuddle for project mgt

image

or agilezen (kanban)

Source is on http://github.com/tekpub/mvc3

Setup a new MVC3 solution called VidPub.Web

image

Lib is for external dlls.  Docs are for docs.  Everything is under git

git init in \dev\VidPub

git add .

git commit –am “Initial load”

DropBox

mkdir e:\dropbox\repositories\vpub

image

in e:\dropbox\repositories\vpub

git init –bare

from \dev folder  git push origin master

image

So other people can then pull from that repository… it is the whole repo up there, not just source.

Test Project

Have just created a container.

Authentication

Don’t want concurrent authentcation.. ie users sharing accounts.  Could use token based.

Now, 1 Year, 3 Years

ASP.NET Membership – complicated..

Consistency of FileNames

Public\javscripts

Public\stylesheets

no more content directory

Model\AccountModels.cs to AccountModel

change CSS path in _Layout.cshtml

CDN

http://code.google.com/apis/libraries/devguide.html#jquery

image

make faster for user as they may have this cached in their browser.  Also save us a bit of bandwidth.  Cache up to a year.

If using Azure to host http://www.microsoft.com/windowsazure/msdn-benefits/ MSDN have got some benefits.

Logging

NLog using NuGet

Code Snippet
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >

  <targets>
    <!--Useful for debugging-->
    <target name="console" xsi:type="ColoredConsole"
     layout="${date:format=HH\:mm\:ss}|${level}|${stacktrace}|${message}" />

    <target name="file" xsi:type="File" fileName="${basedir}/App_Data//logs/site.log"
     layout="${date}: ${message}" />

    <target name="eventlog" xsi:type="EventLog" source="My App" log="Application"
    layout="${date}: ${message} ${stacktrace}" />

  </targets>

  <rules>

    <logger name="*" minlevel="Info" writeTo="file" />
    <logger name="*" minlevel="Fatal" writeTo="eventlog" />

  </rules>

</nlog>

in dev we’re going to log everything to a file in App_Data/logs

In \Infrastructure we’ve got some code to help us log with an interface extracted.

Code Snippet
public class NLogger : VidPub.Web.Infrastructure.Logging.ILogger {
        Logger _logger;
        public NLogger() {
            _logger = LogManager.GetCurrentClassLogger();
        }
        public void LogInfo(string message) {
            _logger.Info(message);
        }

        public void LogWarning(string message) {
            _logger.Warn(message);
        }

        public void LogDebug(string message) {
            _logger.Debug(message);
        }

        public void LogError(string message) {
            _logger.Error(message);
        }
        public void LogError(Exception x) {
            LogError(BuildExceptionMessage(x));
        }
        public void LogFatal(string message) {
            _logger.Fatal(message);
        }
        public void LogFatal(Exception x) {
            LogFatal(BuildExceptionMessage(x));
        }
        string BuildExceptionMessage(Exception x) {

            Exception logException = x;
            if (x.InnerException != null)
                logException = x.InnerException;

            string strErrorMsg = Environment.NewLine + "Error in Path :" + System.Web.HttpContext.Current.Request.Path;

            // Get the QueryString along with the Virtual Path
            strErrorMsg += Environment.NewLine + "Raw Url :" + System.Web.HttpContext.Current.Request.RawUrl;


            // Get the error message
            strErrorMsg += Environment.NewLine + "Message :" + logException.Message;

            // Source of the message
            strErrorMsg += Environment.NewLine + "Source :" + logException.Source;

            // Stack Trace of the error

            strErrorMsg += Environment.NewLine + "Stack Trace :" + logException.StackTrace;

            // Method where the error occurred
            strErrorMsg += Environment.NewLine + "TargetSite :" + logException.TargetSite;
            return strErrorMsg;
        }
    }

IoC

So we don’t have anything coupled tightly right from the start (eg logging which we’re doing next).. lets use IoC

Ninject.MVC3

Wire up in global.asax

 public class MvcApplication : NinjectHttpApplication  {

**NO this is not correct as in MVC3 it is bootstrapped, so just leave as:

public class MvcApplication : System.Web.HttpApplication {

Setting up logging in App_Start bootstrapper file.

“Every time you see a request for ILogger interface in a controller, return a new NLogger class”

 

kernel.Bind<ILogger>().To<NLogger>();

added in Logs/Site.log into our project.

Glimpse

Added in bookmarks into bar to turn on and off.

image

git add .

git commit –am “Added logging, IoC and rearranged stuff”

git push origin master (to save to dropbox)

 

current state of play of our filesystem.

image

| | # 
# Monday, 15 August 2011

an Entity could be a Person object.

Code Snippet
// app is comprised of various services
    // which have entities (components)

    public class BusinessService {
        private readonly string _databaseConnectionString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
        private readonly string _webServiceAddress = ConfigurationManager.AppSettings["MyWebServiceAddress"];
        private readonly LoggingDataSink _loggingDataSink;
    
        private DataAccessComponent _dataAccessComponenet;
        private WebServiceProxy _webServiceProxy;
        private LoggingComponent _loggingComponent;

        public BusinessService() {
            _loggingDataSink = new LoggingDataSink();
            _loggingComponent = new LoggingComponent(_loggingDataSink);
            _webServiceProxy = new WebServiceProxy(_webServiceAddress);
            _dataAccessComponenet = new DataAccessComponent(_databaseConnectionString);
        }
    }

refactoring for constructor based DI:

Code Snippet
    public class BusinessServiceWithDI {
        private IDataAccessComponent _dataAccessComponent;
        private IWebServiceProxy _webServiceProxy;
        private ILoggingComponent _loggingComponent;

        public BusinessServiceWithDI(IDataAccessComponent dataAccessComponent, IWebServiceProxy webServiceProxy, ILoggingComponent loggingComponent) {
            _dataAccessComponent = dataAccessComponent;
            _webServiceProxy = webServiceProxy;
            _loggingComponent = loggingComponent;
        }
    }

Can now inject whatever I like as long as it implements the required interface eg a ‘test’ database.  So mock instances of these services can be injected for testing.

DI frameworks give us an alternative to Factory Patterns which can get unwieldy.

Allow us to easily define dependencies and rules for creating the concrete objects.

Ninject

Code Snippet
public class BusinessService {
        private IDataAccessComponent _dataAccessComponent;
        private IWebServiceProxy _webServiceProxy;
        private ILoggingComponent _loggingComponent;

        public BusinessService(IDataAccessComponent dataAccessComponent, IWebServiceProxy webServiceProxy, ILoggingComponent loggingComponent) {
            _dataAccessComponent = dataAccessComponent;
            _webServiceProxy = webServiceProxy;
            _loggingComponent = loggingComponent;
        }
    }

then:

Code Snippet
[Test]
        public void ShouldBeAbleToGetBusinessServiceFromNinject() {
            BusinessService actual;
            var kernel = new StandardKernel(new CoreModule());
            actual = kernel.Get<BusinessService>();
            Assert.IsNotNull(actual);
        }

so can get a BusinessService and all of its dependencies injected for us.

Code Snippet
public class CoreModule : NinjectModule{
        public override void Load() {
            // any requests to ninject for a class that implements ILoggingDataSink should return
            // a concrete instance of LoggingDataSink
            Bind<ILoggingDataSink>().To<LoggingDataSink>();
            Bind<ILoggingComponent>().To<LoggingComponent>();
            Bind<IDataAccessComponent>().ToProvider(new DataAccessComponentProvider());
            Bind<IWebServiceProxy>().ToProvider(new WebServiceProxyComponentProvider());
        }
    }

    public class DataAccessComponentProvider : Provider<IDataAccessComponent> {
        protected override IDataAccessComponent CreateInstance(IContext context) {
            var databaseConnectionString = ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;
            return new DataAccessComponent(databaseConnectionString);
        }
    }

    public class WebServiceProxyComponentProvider : Provider<IWebServiceProxy> {
        protected override IWebServiceProxy CreateInstance(IContext context) {
            var webServiceAddress = ConfigurationManager.AppSettings["MyWebServiceAddress"];
            return new WebServiceProxy(webServiceAddress);
        }
    }

Service and Repository

Code Snippet
public interface IPersonService {
        Person GetPerson(int personId);
    }

    public class PersonService : IPersonService {
        private readonly IPersonRepository _personRepository;

        public PersonService(IPersonRepository personRepository) {
            _personRepository = personRepository;
        }
        public Person GetPerson(int personId) {
            return _personRepository.GetPerson(personId);
        }
    }

    public class Person {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public interface IPersonRepository {
        Person GetPerson(int personId);
    }

    public class PersonRepository : IPersonRepository {
        private readonly IList<Person> _personList;

        public PersonRepository() {
            _personList = new List<Person> {
                                            new Person{Id = 1, FirstName = "John", LastName="Doe"},
                                            new Person{Id = 2, FirstName = "Richard", LastName="Roe"},
                                            new Person{Id = 3, FirstName = "Amy", LastName="Adams"}
                                            };
        }

        public Person GetPerson(int personId) {
            var person = _personList.Where(p => p.Id == personId).FirstOrDefault();
            return person;
        }
    }

tests:

Code Snippet
[TestFixture]
    public class PersonServiceTests {
        [Test]
        // not truly a unit test as it breaks boundaries between PersonService and PersonRepository
        // we should pass a mock repository into the service.
        public void ShouldBeAbleToCallPersonServiceAndGetPerson() {
            var expected = new Person { Id = 1, FirstName = "John", LastName = "Doe" };
            var kernel = new StandardKernel(new CoreModule());
            var personService = kernel.Get<PersonService>();
            var actual = personService.GetPerson(expected.Id);

            Assert.AreEqual(expected.Id, actual.Id);
            Assert.AreEqual(expected.FirstName, actual.FirstName);
            Assert.AreEqual(expected.LastName, actual.LastName);
        }

        [Test]
        // not using ninject
        // using moq
        public void ShouldBeAbleToCallPersonServiceAndGetPersonWithMock() {
            var expected = new Person { Id = 1, FirstName = "Bob", LastName = "Smith" };
            var personRepositoryMock = new Mock<IPersonRepository>();
            personRepositoryMock
                    .Setup(pr => pr.GetPerson(1))
                    .Returns(new Person { Id = 1, FirstName = "Bob", LastName = "Smith" });
            var personService = new PersonService(personRepositoryMock.Object);

            var actual = personService.GetPerson(expected.Id);

            Assert.AreEqual(expected.Id, actual.Id);
            Assert.AreEqual(expected.FirstName, actual.FirstName);
            Assert.AreEqual(expected.LastName, actual.LastName);
        }
    }
| | #