![]() |
Web Development »
ASP.NET »
General
Intermediate
License: The Code Project Open License (CPOL)
Developing Simple Issue Tracker ModuleBy Ali OzgurHow to develop your own issue tracker module for Cuyahoga framework |
C# (C# 2.0), Windows (Win2K, WinXP, Win2003), ASP.NET, CEO, Dev, Design
|
||||||||||||
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
See Pragma Issue Tracker Online
Download Source Code (Needs registration)
Download Install Only Package (Bin)
PragmaSQL started as part time development effort and by time PragmaSQL evolved to a commercial product.
Today PragmaSQL has a dedicated web site (PragmaSQL Online) build on Cuyahoga Framework.
PragmaSQL Online was primarly designed to meet very simple requirements like
As the number of people using PragmaSQL increased PragmaSQL Forum was added to enable users to communicate
with each other and with PragmaSQL developers. PragmaSQL forum was the only place where people submitted bugs,
support and new feature requests. But as the number of posts increased managing all this content became a real pain for
me. It was hard to group and keep track of the posts, for example i could not know exactly how many bugs were posted
and how many of these bugs are waiting, in progress or already resolved.
Forum approach to maintainance was also inefficient for the users , they had no clue about the status of their posts
because Forum Module did not provided custom post attributes and the communication model was very loose. Forum module
did not have any mechanism to notify users about the status changes of their posts.
In order to overcome maintainance related problems listed above the solution was to add Issue Tracker (Help Desk)
module to PragmaSQL Online, but Cuyahoga Framework did not have Issue Tracker module.
After spending some time searching for open source Issue Tracking software i found two projects.
But these open source software had some limitations, one of them did not integrated well with Cuyahoga Framework
because it was not designed as Cuyahoga Module. Second one had very extensive issue tracking capabilities but their approach
did not supported role/user based authentication. The ideal solution was something like JIRA, but JIRA was a commercial
product and it was certain that I would have to implement Cuyahoga integration myself.
So I decided to write my own simple Issue Tracker module for Cuyahoga meeting the following simple requirements.
Most of the requirements listed above were implemented with four domain classes (in fact entity classes) named Project, IssueType, Issue and IssueComment.
<<>> >
From the class diagram above we can infere these rules
All domain classes listed in the diagram has some commons
Cuyahoga framework allows you to develop custom modules very easily. In order to develop a basic module
you have to implement three classes.
Pragma Issue Tracker implements these three classes plus some other ASP.NET pages and user controls as specified in the
following diagram.
1) We have to perform some Cuyahoga specific configuration in order to our module function correctly. Browse to <Cuyahoga Installation Root >\Config directory Add <assembly>Pragma.IssueTracker</assembly> under <assemblies></assemblies> element to facilities.config file. facilities.config should look like
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<facilities>
<facility type="Castle.Facilities.NHibernateIntegration.NHibernateFacility, Castle.Facilities.NHibernateIntegration"
id="nhibernate" isWeb="true" useReflectionOptimizer="false">
<factory id="nhibernate.factory">
<settings>
<item key="hibernate.connection.provider">NHibernate.Connection.DriverConnectionProvider</item>
<item key="hibernate.connection.driver_class">#{nhibernateDriver}</item>
<item key="hibernate.dialect">#{nhibernateDialect}</item>
<item key="hibernate.connection.connection_string">#{connectionString}</item>
<item key="hibernate.cache.provider_class">NHibernate.Caches.SysCache.SysCacheProvider, NHibernate.Caches.SysCache</item>
<item key="hibernate.cache.use_query_cache">true</item>
<item key="relativeExpiration">30</item>
</settings>
<assemblies>
<assembly>Cuyahoga.Core</assembly>
<!--We added the following element -->
<assembly>Pragma.IssueTracker</assembly>
</assemblies>
</factory>
</facility>
<facility type="Castle.Facilities.AutomaticTransactionManagement.TransactionFacility, Castle.Facilities.AutomaticTransactionManagement"
id="autotransaction" />
</facilities>
</configuration>2) Cuyahoga makes use of Castle IoC container and provides module developers with some simple methods to retreive service object instances. For example
_issueTrackerDao = ContainerAccessorUtil.GetContainer().Resolve<IIssueTrackerDao>()
/*
* We call this method inside a web form (aspx) which is inherited from Cuyahoga.Web.UI.GeneralPage
* which in turn is inherited from a CuyahogaPage indirectly.
* Container is IWindowsContainer instance provided by the base CuyahogaPage automatically
* and we use Container instance to resolve and retreive service object instances.
*/
IIssueTrackerDao dao = this.Container.Resolve<IIssueTrackerDao>() as IIssueTrackerDao;
As a result of utilizing this concept you have to modify services.config file which is located under <Cuyahoga Installation Root >\Config directory. Add following lines under components.
<component
id="pragma.issuetracker"
service="Pragma.IssueTracker.DataAccess.IIssueTrackerDao, Pragma.IssueTracker"
type="Pragma.IssueTracker.DataAccess.IssueTrackerDao, Pragma.IssueTracker">
</componen>
3) Because Pragma Issue Tracker uses Ajax toolkit for creating/editing issue comments and prompting e-mail notification errors we have to modify our Web.config file to enable Ajax support. If we do not add the following configuration information it is likely that
we will get "Sys not defined" error when our module tries to execute Ajax related code.
<system.web>
<httpHandlers>
<remove verb="*" path="*.asmx"/>
<add verb="*" path="Error.aspx" type="System.Web.UI.PageHandlerFactory" />
<add verb="*" path="*.aspx" type="Cuyahoga.Web.HttpHandlers.PageHandler, Cuyahoga.Web" />
<add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false"/>
</httpHandlers>
<httpModules>
<add type="Cuyahoga.Web.HttpModules.AuthenticationModule, Cuyahoga.Web" name="AuthenticationModule" />
<add type="Cuyahoga.Web.HttpModules.CoreRepositoryModule, Cuyahoga.Web" name="CoreRepositoryModule" />
<add name="NHibernateSessionWebModule" type="Castle.Facilities.NHibernateIntegration.Components.SessionWebModule, Castle.Facilities.NHibernateIntegration" />
<!--Ajax toolkit support-->
<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</httpModules>
</system.web> 1) We may design a base class with Id and Version property and inherit all domain classes from
this class.
public class BaseIssuTrackerClass
{
private long _version = 0;
private int _id;
public int Id
{
get { return _id; }
internal set { _id = value; }
}
}2) We may design seperate classes for Project and Component.
Current design uses Project class to model both Project and Component instances.
public class Project: BaseIssuTrackerClass
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private string _description;
public string Description
{
get { return _description; }
set { _description = value; }
}
private DateTime _createdon;
public DateTime CreatedOn
{
get { return _createdon; }
set { _createdon = value; }
}
private bool _active = true;
public bool Active
{
get { return _active; }
set { _active = value; }
}
private IList _components;
public IList Components
{
get { return _components; }
set { _components = value; }
}
public Project(){}
}
public class Component:BaseIssuTrackerClass
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private string _description;
public string Description
{
get { return _description; }
set { _description = value; }
}
private string _key;
public string Key
{
get { return _key; }
set { _key = value; }
}
private bool _active = true;
public bool Active
{
get { return _active; }
set { _active = value; }
}
private DateTime _createdon;
public DateTime CreatedOn
{
get { return _createdon; }
set { _createdon = value; }
}
private User _leaduser;
public User LeadUser
{
get { return _leaduser; }
set { _leaduser = value; }
}
private Role _role;
public Role Role
{
get { return _role; }
set { _role = value; }
}
private Project _parentProject;
public Project ParentProject
{
get { return _parentProject; }
internal set { _parentProject = value; }
}
internal Component()
: this(null)
{
}
public Component(Project parentProject)
{
_id = -1;
_parentProject = parentProject;
}
}
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 29 Mar 2009 Editor: |
Copyright 2008 by Ali Ozgur Everything else Copyright © CodeProject, 1999-2009 Web21 | Advertise on the Code Project |