EstimatorX - Project Estimation Application

EstimatorX

A simple project estimation application.
http://estimatorx.com

Project Tasks

Features

Projects

A project contains all the details that make up an estimate. An estimate is broken down into Assumptions, Factors and Tasks. The estimate is padded with a contingency rate.

Assumptions

When making an estimate, there are assumptions the estimator makes to come up with the estimate. Document those assumptions to help raise the red flag in the future when an assumptions proves not to be true.

Factors

Factors are a type of task with hours associated with the complexity of that task. Factors allow the estimator to state hours based on a specific type of task, regardless of the project.

Tasks

Tasks are a specific item or feature of the project being estimated. A task is assigned a Factor. The estimator enters the number of tasks per complexity level.

Tasks are part of a Section. Sections are a way to group a set of common features. Tasks totals are also rolled up to the section level.

Reports

Project estimates can be displayed as a simple report. The estimator can create a public shared link to allow anonymous view access to the report. The report can also be downloaded as a PDF.

Contingency

Contingency percentage rate is the confidence level in the information used to create the estimate. The contingency percentage rate is used to padded the estimate with a percentage rate.

Complexity

Tasks and Factors use following complexity scale.

  • Very Simple - Task is trivial, owner knows how to solve the problem and can be done quickly.
  • Simple - Owner knows how to solve the problem.
  • Medium - Owner needs to do a little bit of research to solve the problem, but the resulting solution is not complex.
  • Complex - Task needs research and some clarification on details. Resulting solution is not trivial.
  • Very Complex - Task needs research and clarification. Resulting solution requires significant new work or change.

Organizations

Projects and Templates are placed in an organization. All members of the organization can edit the Project or Template.

Select 'Private' to make the Project or Template accessible by only you.

Templates

A template is a group of factors you can quickly add to a project. Templates allow reuse of common factors across projects.


FluentCommand - Fluent Wrapper for DbCommand

Fluent Wrapper for DbCommand

Download

The FluentCommand library is available on nuget.org via package name FluentCommand.

To install FluentCommand, run the following command in the Package Manager Console

PM> Install-Package FluentCommand

Features

  • Fluent wrapper over DbConnection and DbCommand
  • Callback for parameter return values
  • Automatic handling of connection state
  • Caching of results
  • Automatic creating of entity from DataReader
  • Create Dynamic objects from DataReader
  • Handles multiple result sets

Example

Query all users with email domain. Entity is automaticly created from DataReader.

string email = "%@battlestar.com";
string sql = "select * from [User] where EmailAddress like @EmailAddress";

List<User> users;
using (var session = new DataSession("Tracker").Log(Console.WriteLine))
{
    users = session            
        .Sql(sql)
        .Parameter("@EmailAddress", email)
        .Query<User>();
}

Execute a stored procedure with out parameters

Guid userId = Guid.Empty;
int errorCode = -1;

var username = "test." + DateTime.Now.Ticks;
var email = username + "@email.com";

int result;
using (var session = new DataSession("AspNet").Log(Console.WriteLine))
{
    result = session.StoredProcedure("[dbo].[aspnet_Membership_CreateUser]")
        .Parameter("@ApplicationName", "/")
        .Parameter("@UserName", username)
        .Parameter("@Password", "T@est" + DateTime.Now.Ticks)
        .Parameter("@Email", email)
        .Parameter("@PasswordSalt", "test salt")
        .Parameter<string>("@PasswordQuestion", null)
        .Parameter<string>("@PasswordAnswer", null)
        .Parameter("@IsApproved", true)
        .Parameter("@CurrentTimeUtc", DateTime.UtcNow)
        .Parameter("@UniqueEmail", 1)
        .Parameter("@PasswordFormat", 1)
        .ParameterOut<Guid>("@UserId", p => userId = p)
        .Return<int>(p => errorCode = p)
        .Execute();
}

Query for user by email address. Also return Role and Status entities.

string email = "kara.thrace@battlestar.com";
string sql = "select * from [User] where EmailAddress = @EmailAddress; " +
             "select * from [Status]; " +
             "select * from [Priority]; ";

User user = null;
List<Status> status = null;
List<Priority> priorities = null;

using (var session = new DataSession("Tracker").Log(Console.WriteLine))
{
    session.Sql(sql)
        .Parameter("@EmailAddress", email)
        .QueryMultiple(q =>
        {
            user = q.QuerySingle<User>();
            status = q.Query<Status>().ToList();
            priorities = q.Query<Priority>().ToList();
        });
}

KickStart - Application Initialization Framework

Application start-up helper to initialize things like an IoC container, register mapping information or run a task.

Features

  • Run tasks on application start-up
  • Extension model to add library specific start up tasks
  • Common IoC container adaptor
  • Sigleton instance of an application level IoC container

Download

The KickStart library is available on nuget.org via package name KickStart.

To install KickStart, run the following command in the Package Manager Console

PM> Install-Package KickStart

Example

This example will scan the assembly containing UserModule. Then it will find all Autofac modules and register them with Autofac. Then, all AutoMapper profiles will be registered with Automapper. Finally, it will find all classes that implement IStartupTask and run it.

Kick.Start(config => config
    .IncludeAssemblyFor<UserModule>()
    .UseAutofac()
    .UseAutoMapper()
    .UseStartupTask()
);

Extensions

  • StartupTask - Run any class that implements IStartupTask
  • Autofac - Registers all Autofac Module classes and creates the container
  • AutoMapper - Registers all AutoMapper Profile classes
  • log4net - Use log4net as a logger
  • MongoDB - Registers all BsonClassMap classes with MongoDB serialization
  • Ninject - Registers all NinjectModule classes and creates an IKernal
  • NLog - Use NLog as a logger
  • SimpleInjector - Run all ISimpleInjectorRegistration instances allowing container registration
  • Unity - Run all IUnityRegistration instances allowing container registration

StartupTask

The StartupTask extension allows running code on application start-up. To use this extension, implement the IStartupTask interface. Use the Priority property to control the order of execution.

Basic usage

Kick.Start(config => config
    .IncludeAssemblyFor<UserModule>() // where to look for tasks
    .UseStartupTask() // include startup tasks in the Kick Start        
);

Use the Common Container to resolve startup tasks

Kick.Start(config => config
    .IncludeAssemblyFor<UserModule>()
    .UseAutofac() // init Autofac or any other IoC as container
    .UseStartupTask(c => c.UseContainer()) // config to use the shared container
);

Autofac

The Autofac extension allows registration of types to be resolved. The extension also creates a default container and sets it to the Kick.Container singleton for access later.

Basic usage

Kick.Start(config => config
    .IncludeAssemblyFor<UserRepository>() // where to look for tasks
    .UseAutofac() // initialize Autofac        
);

Use with ASP.NET MVC

Kick.Start(c => c
    .IncludeAssemblyFor<UserModule>()
    .UseAutofac(a => a
        .Builder(b => b.RegisterControllers(typeof(MvcApplication).Assembly)) // register all controllers 
        .Container(r => DependencyResolver.SetResolver(new AutofacDependencyResolver(r))) // set asp.net resolver
    )
    .UseAutoMapper()
    .UseMongoDB()
    .UseStartupTask()
);

To install Autofac extension, run the following command in the Package Manager Console

PM> Install-Package KickStart.Autofac

SimpleInjector

The SimpleInjector extension allows registration of types to be resolved by running all instances of ISimpleInjectorRegistration. The extension also creates a default container and sets it to the Kick.Container singleton for access later.

Basic usage

Kick.Start(config => config
    .IncludeAssemblyFor<UserRepository>() // where to look
    .UseSimpleInjector () // initialize SimpleInjector         
);

To install SimpleInjector extension, run the following command in the Package Manager Console

PM> Install-Package KickStart.SimpleInjector

Unity

The Unity extension allows registration of types to be resolved by running all instances of IUnityRegistration. The extension also creates a default container and sets it to the Kick.Container singleton for access later.

Basic usage

Kick.Start(config => config
    .IncludeAssemblyFor<UserRepository>() // where to look
    .UseUnity () // initialize Unity         
);

To install Unity extension, run the following command in the Package Manager Console

PM> Install-Package KickStart.Unity

NLog

Use NLog as a logger for KickStart

Basic usage

Kick.Start(c => c
    .IncludeAssemblyFor<Project>()
    .UseNLog()
    .UseStartupTask()
);

Configure NLog to use ConsoleTarget

Kick.Start(c => c
    .IncludeAssemblyFor<Project>()
    .UseNLog(config =>
    {
        var consoleTarget = new ConsoleTarget();
        consoleTarget.Layout = "${time} ${level:padding=1:fixedLength=true} ${logger:shortName=true} ${message} ${exception:format=tostring}";        
        config.AddTarget("console", consoleTarget);

        var consoleRule = new LoggingRule("*", NLog.LogLevel.Trace, consoleTarget);
        config.LoggingRules.Add(consoleRule);
    })
    .UseStartupTask()
);

To install NLog extension, run the following command in the Package Manager Console

PM> Install-Package KickStart.NLog

NLog Fluent Library

Fluent API for NLog

Download

The NLog.Fluent library is available on nuget.org via package name NLog.Fluent.

To install NLog.Fluent, run the following command in the Package Manager Console

PM> Install-Package NLog.Fluent

Examples

Writing info message via fluent API.

_logger.Info()
    .Message("This is a test fluent message '{0}'.", DateTime.Now.Ticks)
    .Property("Test", "InfoWrite")
    .Write();

Writing error message.

try
{
    string text = File.ReadAllText(path);
}
catch (Exception ex)
{
    _logger.Error()
        .Message("Error reading file '{0}'.", path)
        .Exception(ex)
        .Property("Test", "ErrorWrite")
        .Write();
}

Caller Info

Use the static Log class so you don't have to include loggers in all of classes. The static Log class using .net 4.5 caller info to get the logger from the file name.

Writing info message via static Log class with fluent API.

Log.Info()
    .Message("This is a test fluent message.")
    .Property("Test", "InfoWrite")
    .Write();

Writing error message.

try
{
    string text = File.ReadAllText(path);
}
catch (Exception ex)
{
    Log.Error()
        .Message("Error reading file '{0}'.", path)
        .Exception(ex)
        .Property("Test", "ErrorWrite")
        .Write();
}

NLog MongoDB Library

Writes NLog messages to MongoDB.

Download

The NLog.Mongo library is available on nuget.org via package name NLog.Mongo.

To install NLog.Mongo, run the following command in the Package Manager Console

PM> Install-Package NLog.Mongo

Configuration Syntax

<extensions>
  <add assembly="NLog.Mongo"/>
</extensions>

<targets>
  <target xsi:type="Mongo"
          name="String"
          connectionName="String"
          connectionString="String"
          collectionName="String"
          cappedCollectionSize="Long"
          cappedCollectionMaxItems="Long"
          includeDefaults="Boolean">

    <!-- repeated --> 
    <field name="String" Layout="Layout" />

    <!-- repeated --> 
    <property name="String" Layout="Layout" />
  </target>
</targets>

Parameters

General Options

name - Name of the target.

Connection Options

connectionName - The name of the connection string to get from the config file.

connectionString - Connection string. When provided, it overrides the values specified in connectionName.

Collection Options

collectionName - The name of the MongoDB collection to write logs to.

cappedCollectionSize - If the collection doesn't exist, it will be create as a capped collection with this max size.

cappedCollectionMaxItems - If the collection doesn't exist, it will be create as a capped collection with this max number of items. cappedCollectionSize must also be set when using this setting.

Document Options

includeDefaults - Specifies if the default document is created when writing to the collection. Defaults to true.

field - Specifies a root level document field. There can be multiple fields specified.

property - Specifies a dictionary property on the Properties field. There can be multiple properties specified.

Examples

Default Configuration with Extra Properties

NLog.config target

<target xsi:type="Mongo"
        name="mongoDefault"
        connectionString="mongodb://localhost/Logging"
        collectionName="DefaultLog"
        cappedCollectionSize="26214400">
  <property name="ThreadID" layout="${threadid}" />
  <property name="ThreadName" layout="${threadname}" />
  <property name="ProcessID" layout="${processid}" />
  <property name="ProcessName" layout="${processname:fullName=true}" />
  <property name="UserName" layout="${windows-identity}" />
</target>

Default Output JSON

{
    "_id" : ObjectId("5184219b545eb455aca34390"),
    "Date" : ISODate("2013-05-03T20:44:11Z"),
    "Level" : "Error",
    "Logger" : "NLog.Mongo.ConsoleTest.Program",
    "Message" : "Error reading file 'blah.txt'.",
    "Exception" : {
        "Message" : "Could not find file 'C:\\Projects\\github\\NLog.Mongo\\Source\\NLog.Mongo.ConsoleTest\\bin\\Debug\\blah.txt'.",
        "Text" : "System.IO.FileNotFoundException: Could not find file 'C:\\Projects\\github\\NLog.Mongo\\Source\\NLog.Mongo.ConsoleTest\\bin\\Debug\\blah.txt' ...",
        "Type" : "System.IO.FileNotFoundException",
        "Source" : "mscorlib",
        "MethodName" : "WinIOError",
        "ModuleName" : "mscorlib",
        "ModuleVersion" : "4.0.0.0"
    },
    "Properties" : {
        "ThreadID" : "10",
        "ProcessID" : "21932",
        "ProcessName" : "C:\\Projects\\github\\NLog.Mongo\\Source\\NLog.Mongo.ConsoleTest\\bin\\Debug\\NLog.Mongo.ConsoleTest.exe",
        "UserName" : "pwelter",
        "Test" : "ErrorWrite",
        "CallerMemberName" : "Main",
        "CallerFilePath" : "c:\\Projects\\github\\NLog.Mongo\\Source\\NLog.Mongo.ConsoleTest\\Program.cs",
        "CallerLineNumber" : "43"
    }
}

Complete Custom Document

NLog.config target

<target xsi:type="Mongo"
        name="mongoCustom"
        includeDefaults="false"
        connectionString="mongodb://localhost/Logging"
        collectionName="CustomLog"
        cappedCollectionSize="26214400">
  <field name="Date" layout="${longdate}" />
  <field name="Level" layout="${level}"/>
  <field name="Message" layout="${message}" />
  <field name="Logger" layout="${logger}"/>
  <field name="Exception" layout="${exception:format=tostring}" />
  <field name="ThreadID" layout="${threadid}" />
  <field name="ThreadName" layout="${threadname}" />
  <field name="ProcessID" layout="${processid}" />
  <field name="ProcessName" layout="${processname:fullName=true}" />
  <field name="UserName" layout="${windows-identity}" />
</target>

Custom Output JSON

{
    "_id" : ObjectId("5187abc2545eb467ecce9184"),
    "Date" : "2013-05-06 08:10:26.5019",
    "Level" : "Debug",
    "Message" : "Sample debug message",
    "Logger" : "NLog.Mongo.ConsoleTest.Program",
    "ThreadID" : "9",
    "ProcessID" : "26604",
    "ProcessName" : "C:\\Projects\\github\\NLog.Mongo\\Source\\NLog.Mongo.ConsoleTest\\bin\\Debug\\v4.5\\NLog.Mongo.ConsoleTest.exe",
    "UserName" : "pwelter"
}