Project management web application that features the management of projects, tasks, issues, conferences, teams, developers, messages, notes, documents, and clients.
3. 1. SUMMARY
The project is a part of coursework for .NET Architectures (6 ECTS) course hosted by North Karelia University of
Applies Sciences in Finland. For the sake of the course this project will use Microsoft’s .NET architecture and its latest
framework to date which is 4.0. The course is a bit aligned towards web side of programming therefore my project will
also be web application. The subject of my project is project management application with web interface and I have
named it as Trevo which is a Portuguese word for clover in English.
2. LEARNING OBJECTIVES
The goal is to learn a bit more advanced web programming with ASP.NET MVC 3, Razor view engine, ADO.NET Entity
Framework, LINQ, MSSQL and some more common techniques such as jQuery (with AJAX), HTML5 and CSS3. This is a
good packet overall to create almost any kind of web application.
3. BRAINSTORMED IDEAS
I usually start my projects by brainstorming ideas and this was not an exception. It is a great way to get to know the
project subject first hand. I just started to get some ideas and quickly wrote them down. There are no right and wrong
ideas at this state, because the ideas are not evaluated until the end of brainstorming. My main focus here was to
think about the feature set, but my mind also focused in UI.
Task view (percentage completed, expected time, time worked on, who has worked on, approve on closing)
Projects view
Developers assigned to project and tasks
Time planner (scheduler, tasks, charts)
Agile methods (Visualizing Agile Projects with Kanban Boards)
Save documents
Cost management (charts showing expected and current costs)
Milestones
Overview (total time spend on project etc.)
Message forum
Conferences (with Google maps location and calendar)
Chat (+real-time video messaging)
Dynamic document / whiteboard (e.g. Google docs)
Reporting and analyzing
Issue tracker
Customer contact details
Notes
Developer effectiveness monitoring and analysis (w/ charts)
UI templates
Simple to use
Fascinating UI
1
4. 4. SUBJECT EXCLUSION
How great it would have been to have had time to implement all of the features that were brainstormed but in the
real world I needed to limit the upcoming features drastically if I ever planned to finish this project on time. Given the
limited amount of time I first decided to drop the most advanced and at the same time most time consuming features
from the list. As much as I would have been delighted to have seen Agile features, video communication, cost
management, time planning, dynamic document editing to become reality, it was just not going to happen. However
there are still plenty of features left even when compared to the market leaders in this sector.
5. FEATURES DECIDED TO BE IMPLEMENTED
Dashboard includes overview of the application context for example calculated values, reminders of events, charts
etc.
To represent people there are clients, developers and teams. One client and multiple developers can be assigned to a
project. Developers can belong to teams.
There are tasks so that project work amount can be divided into multiple segments. Then there are also categories for
tasks and projects to organize similar concepts.
Issues can be assigned to projects and they can also be categorized. Additionally files can be attached to issues.
Milestones can be set projects and issues.
Notes can be added to projects.
Developers can leave messaged categorized under topics.
Developers can save documents for others to view.
Developers can issue conferences and confirm their attendance.
2
5. Figure 1. Use case diagram
6. DEVELOPMENT PHASES
I will shed light on how I proceeded with the project in chronological manner. This is to give you a brief overview what
steps needed to be taken to achieve the goals set in the project specification. I intentionally excluded the
brainstorming phase from the list below.
1. Designing of use case diagram
2. Designing Entity-Relationship model with MS Visio
3. Creating multiple projects (as in component-based programming). One for data and one for web UI.
4. Adding data project as a reference for web UI project.
5. Creating ADO.NET Entity Data Model (Model-First approach). No need to create separate model classes (i.e.
DbContext).
6. Generating database from the ADO.NET Entity Data Model
7. Executing generated SQL code to create database tables with columns. Connection string is automatically
added to web.config.
8. Adding foreign key relationships manually to database so that SQL Server will maintain referential integrity. It
prevents adding invalid rows or deleting rows that are still referenced. It also allows cascade delete on items
that are not referenced anymore.
9. Adding unique indexes to couple of tables to make some string type variables/columns unique thus
disallowing duplicates.
10. Generating ObjectContext class and persistence awareness classes with ADO.NET EntityObjectGenerator
11. Creating/generating Controllers (with data access logic to interact with the database)
12. Creating/generating Views (create, edit, delete)
13. Using LINQ queries to access database in controller methods
3
6. 14. Using JQuery for UI on Views
15. Writing CSS stylesheets
7. ARCHITECTURE
7.1 REQUIREMENTS
Server side
.NET Framework 4
ASP.NET MVC 3
Razor view engine
IIS
MS SQL Server
Browser side
HTML5
CSS3
JavaScript
jQuery 1.3+
7.2 DESIGN CONSIDERATIONS
It is well worth taking time to evaluate the different design aspects of software.
7.2.1 MODULARITY
The MVC application itself is already quite modular, because models, views and controllers are separated. Additionally
I separated entity model and ObjectContext class to separate component.
7.2.2 COMPATIBILITY
The application runs on most web browsers but is not designed for mobile devices. JavaScript also needs to be
enabled. Used JQuery libraries are also widely supported by web browsers. The software uses the latest .NET
Framework 4.0, ASP.NET MVC 3 and Razor view engine. Therefore it is not backward compatible what comes to
software.
7.2.3 EXTENSIBILITY
Extensions can be done fairly easily. Database for example can be extended by adding a new entity in entity model
and generating a new database or manually modifying the database. ObjectContext class is updated automatically
when generating the database in entity model designer therefore object-relational mapping does not need to be
taken care of by the developer. However sometimes Entity Framework can leave old fields which are only visible in
entity model’s XML code and modifying fields might need manual changes to that code.
7.2.4 MAINTAINABILITY
4
7. ASP.NET MVC provides nice concept to debug and unit test applications. This is due to separation of models, views
and controllers. Testing is one of the main aspects of maintainability.
New pages can also be created with minimal effort.
7.2.5 USABILITY
Usability is always one of the main concerns when designing a website. It can also easily lead to compromises,
because usually the simplest kind of websites will work on most web browsers and platforms. This application is not
designed for mobile devices for example. For that, a new user interface would have to be build. I tried to invent a
more intuitive UI but there is still work on that field.
7.2.6 SECURITY
It is always advised to go with the standard and preferred way which in this case is ASP.NET Membership for user
authentication. It saves a lot of work from the developer. It is much better to use well tested and known to be secure
interface rather than designing your own. Register view and Register action in Account controller were slightly
modified to include more fields in order to create developer object at the same time.
7.3 DESIGNING DATABASE
I used Microsoft Visio to make ER-model with Crow’s foot notation. This model is a bit more clear compared to what
can be done with Visual Studio’s designer. Primary and foreign keys are shown clearly.
5
9. Figure 3. ADO.NET Entity Data Model aka LINQ to SQL class model
7.4 CREATING A DATABASE
At first I used ADO.NET generated SQL code to create the initial database from entity model. After that if I made a
change to the entity model, I had to generate database again in order to get table mappings done.
Some modifications I had to include in database were primary keys, foreign keys and indexes.
There are also various cascading options. For example, if a project is deleted, all tasks belonging to that project are
also deleted.
7
10. 7.4.1 QUERIES TO DATABASE
In this project I decided to go with a model first approach which generates ObjectContext class and SQL code to create
database. Therefore I decided to retrieve data from the data model by using user defined functions (LINQ queries)
which I coded within controllers. I could have also written stored procedures within the database and then map those
into the data model (i.e. integrating with ObjectContext class). After that SPs could have been executed quite similarly
as user defined functions by LINQ query, because mapped SPs are methods in ObjectContext class. The main reason
why I did not use SPs was simple because I wanted to learn LINQ during this project. There are no plans to create
other user interfaces so I thought LINQ queries would be good enough. The additional fact is that writing LINQ to SQL
queries is pretty effortless and fast comparing to writing SPs with SQL. On the other hand, If I knew that the project
contained let’s say desktop, web and mobile UIs, I would not think twice to go with SPs.
7.5 IMPLEMENTATION
Being an MVC project, most of the files are models, views and controllers. Fewer models in fact, because
they were mostly generated by ADO.NET. I still needed to create couple special case models that contain the
specific data I need especially the union of two models. The most work intensive part was the views.
Controllers do not contain that much code especially when the object-relational mapping and LINQ-to-SQL
work so coherently. However most controllers control index, create, edit, details and remove views if not
even more. Some special cases might need their own views e.g. showing details in jQuery dialog.
Figure 4. MVC architecture.
Figure 5. Solution/workspace listing.
8
11. Figure 6. Class diagram: controller etc. classes coded in C#.
9
12. 7.6 USER INPUT VALIDATION
User input validation is done by the ADO.NET Entity Framework. The EF knows which fields cannot be null by looking
at the entity model I created. The code for input validation is created alongside with ObjectContext class which is
created from the entity model to map entities, fields and relations etc. with the database.
7.7 USER INTERFACE
JQuery provides great functions to create an interactive UI. JQuery was used to open dialogs, post back data from the
server via AJAX, drag and drop HTML elements, add and remove CSS styles, fading animations etc. CSS3 was helpful
for creating stretched background, transparent menu buttons and rounded elements.
Figure 7. Tasks view.
Figure 8. Issues view.
10
19. Figure 21. Message details view.
Figure 22. Notes view.
7.8 CODE EXAMPLES
The following code is from the team view. It is the most JavaScript intensive view in this project. The purpose of this
view is to allocate developers into teams. Developers not yet associated with a team can be dragged into team
elements. Teams can be unallocated by clicking green recycle icon or dragging back to developer area. Developers can
also be transferred from team to team with simple drag-and-drop. Teams can be created but not developers, because
user account is associated with only one developer. There are multiple buttons associated with developers and team.
Additionally there are jQuery dialogs to create team and confirm deletion of team.
@model IEnumerable<PrjctMngmt.Models.TeamDeveloperModel>
@{
ViewBag.Title = "Teams";
}
<script type="text/javascript">
$(function () {
// there's the developers and the team
var $developers = $(".developers"),
$teams = $(".teams");
17
20. // let the developers without team be draggable
$("li", $developers).draggable({
cancel: "a.ui-icon", // clicking an icon won't initiate dragging
revert: "invalid", // when not dropped, the item will revert back to its initial position
helper: "clone",
cursor: "move"
});
// let the developers within teams be draggable
$("li", $teams).draggable({
cancel: "a.ui-icon", // clicking an icon won't initiate dragging
revert: "invalid", // when not dropped, the item will revert back to its initial position
helper: "clone",
cursor: "move"
});
// let the team be droppable, accepting developers
$teams.droppable({
accept: '.developers > *, .teams > *', //allow also team to team drops
hoverClass: "ui-state-highlight",
drop: function (event, ui) {
moveToTeam(ui.draggable, $(this));
}
});
// let developers be droppable, accepting developers from teams
$developers.droppable({
accept: ".teams > li",
hoverClass: "ui-state-highlight",
drop: function (event, ui) {
unbindDeveloper(ui.draggable);
}
});
// add developer to team function
var removeMember = "<a href='link/to/unbind/script/when/js/is/off' title='Unbind developer' class='devRecycle
ButtonLink recycleIcon'></a>";
function moveToTeam($item, $dropped) {
$item.fadeOut(function () {
if (!$item.hasOwnProperty(removeMember)) {
$item.find("a.recycleIcon").remove();
$item.append(removeMember);
}
$item.appendTo($dropped).fadeIn(function () { });
$.post("/Developer/ChangeTeam?devId=" + $item.attr("id") + "&teamName=" + $dropped.attr("id"), function () {
});
});
}
// remove developer from the team
function unbindDeveloper($item) {
$item.fadeOut(function () {
$item
.find("a.recycleIcon").remove()
.end()
.appendTo($developers)
.fadeIn();
$.post("/Developer/ChangeTeam?devId=" + $item.attr("id") + "&teamName=", function () { });
});
}
// resolve the icons behavior with event delegation
$("ul.developers > li").click(function (event) {
var $item = $(this),
$target = $(event.target);
if ($target.is("a.recycleIcon")) {
unbindDeveloper($item);
}
return false;
});
// resolve the icons behavior with event delegation
$(".teams > li").click(function (event) {
var $item = $(this),
$target = $(event.target);
if ($target.is("a.recycleIcon")) {
unbindDeveloper($item);
}
return false;
});
});
</script>
18
22. @foreach (var item in Model)
{
foreach (var dev in item.developers)
{
if (dev.TeamName == null || dev.TeamName=="")
{
<li id="@dev.DeveloperID" class="ui-widget-content ui-corner-tr devLi">
@dev.FirstName @dev.LastName
<img alt="Details" title="Details" class="devDetails ButtonLink detailIcon"
src="../../Content/themes/base/images/mag_glass.png" />
</li>
}
}
}
<!-- placement hack --><img alt="." src="../../Content/themes/base/images/transparent_dot.png"
height="30px"/>
</ul>
<br />
<b>Teams</b>
<br />
@foreach (var item in Model)
{
foreach (var team in item.teams)
{
<div id="@team.TeamName" class="teams">
<div class="teamTitle ui-widget-header">
@team.TeamName
<img alt="Remove" title="Remove" class="removeTeam ButtonLink removeIcon"
src="../../Content/themes/base/images/remove-icon.png" />
<a href='@Url.Action("Details", "Team", new { TeamName = team.TeamName })'>
<img alt="Details" title="Details" class="teamDetails ButtonLink detailIcon"
src="../../Content/themes/base/images/mag_glass.png" />
</a>
</div>
@foreach (var dev in item.developers)
{
if (dev.TeamName == team.TeamName)
{
<li id="@dev.DeveloperID" class="ui-widget-content ui-corner-tr devLi">
@dev.FirstName @dev.LastName
<a href='@Url.Action("Details", "Developer", new { id = dev.DeveloperID })'>
<img alt="Details" title="Details" class="devDetails ButtonLink detailIcon"
src="../../Content/themes/base/images/mag_glass.png" />
</a>
<a href='link/to/unbind/script/when/js/is/off' title='Unbind developer'
class='devRecycle ButtonLink recycleIcon'></a>
</li>
}
}
</div>
}
}
<img alt="Create team" id="addTeam" class="ButtonLink" style="float:right;"
src="../../Content/themes/base/images/plus-sign_small.png" />
</div>
<div id="confirmTeamDelete" title="Confirmation">
<p>
<span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span>
Are you sure you want to delete this team?
</p>
</div>
8. TESTING
I should have given a far greater bearing for testing. It is one of the most crucial aspects of developing maintainable
code with high reliability. My only excuse is that I did not have time to write unit tests, although unit tests might save
time in the future. The lack of unit test will surely mean higher costs of bug fixing. I did however debugging and also
tested the application as normal user would. At this point it becomes quite clear that it takes significant amount of
time to test UI and features over and over again and in the end unit tests will save you from a lot of trouble.
9. WHAT COULD HAVE BEEN DONE DIFFERENTLY?
20
23. It became evident pretty soon that there were too many planned features. The entities are also very detailed and
some of the information is not significant really. Most of the information had to be hid behind a detail button. It
becomes quite messy if all available information is visible in basic view. When designing a database it is difficult to
determine which attributes are really needed (or could be needed) and what would be the level of detail.
10. WHAT NEXT?
There is still plenty of work to be done. Especially the UI could benefit from contributions. The UI side might not be
fully functional, as easy to use as it could be, or aesthetically eye-popping. Cascading drop-down lists are on the way
to filter tasks and milestones that belong to a certain project. Major testing (unit tests) would also be one of the
highest priorities. The application is not ready yet for the users until proper testing is done and verified as stable.
11. ACQUIRED KNOWLEDGE
I learned new aspects of ASP.NET MVC and many automated features that will save developer’s time. I am very
pleased with ADO.NET Entity Framework as a whole. It provides such useful tools. I also refreshed my memory in the
field of relational databases. The ORM (Object-Relational Mapping) concept was really advantageous to learn and
using LINQ to handle queries. JavaScript was also an unfamiliar language and during this project I wrote quite a bit of
it. All in all ASP.NET MVC taught me a lot.
12. PROJECT HOSTING
Project is hosted in Google code (http://code.google.com/p/trevo-project-management) in open-source manner. It is
licensed under MIT license. It allows also commercial use. The further development can be tracked by visiting the site.
13. OUTCOME
It is fair to say that the project was ambitious. There was plenty to do and I did not even dream to implement all the
features I brainstormed. The main goal was to learn about new technologies and work as much as I possibly could. I
have to admit that once again I was surprised at the end how much time it took after all. However I am also as
surprised to realize how much I did and how well I reached my goals.
21