Downloads:
1. Introduction and Background
Do you want to add the simple messaging,
friends and group interaction to your website, but don't want to go for
a complete CMS based solution? Are you using microsoft’s
Asp.Net role based security and want to provide interaction between your website users? Or do you want to know the basics of social networking so that you can easily add them to your website if needed? Parichay
is an attempt to help you address your intention.
Although
Asp.Net Social Networking book is an amazing read, but still it carries
a lot of information and the code contains quite a big (and of course
efficient) framework for social network. In Parichay, we would try to
Keep It Short and Simple(KISS)
Therefore, Parichay is a Short and Simple Asp.Net Social Networking and messaging
website starter app. The application has been designed with KISS(Keep
it Short and Simple) principle in mind. We will use Asp.Net MVC 3 (with
razor) as web application framework. NHibernate will be used for data
persistence framework - which will give our project the portability to
several databases.
Of
course, if you are looking for a well attested, well beaten track, you would prefer to go with a complete cms based solution, and add social
networking to it as a plugin module. Still, this article will give
you an Idea about what you mayconsider if you are develping your own
social networking module. Further, this app can easily be converted
into a CMS module as it has been designed as an independent module with
least of dependencies to the security layer.
**(Please
Note:- This application doesn’t have one-click installer. Remember to go to the INSTALLATION section for information about installation. Basically - you'll need to:-
- create a database(e.g. create database parichaytest)
- create tables using SQLs provided (MySql => 1_ParichaySecurity.sql & 2_ParichayData.sql, SQLServer=> SQLServer_DbScript.sql)
- Update the NHibernate connection string in Web.Config )**
2. Overview
As mentioned earlier, we will be using the default
Asp.Net role based security. We will be adding a simple layer of
permission based security to it as an httpmodule. (more info. about this module can be found in this article.
Here is the basic overview of this article and components we'll be talking about:-
Introduction and Background (Discussed Above)
- Overview
- Modules (Tables=>Db Objects and their respective Controller-Actions)
- Member Details: (User Details, Password & Password Q&A mgmt., Recovery etc.)
- Member Alerts: (Simple track of your website activity and responses.)
- Member Messages: (Status Updates sharing and receiving replies/responses to your thoughts.)
- Member Friends: (Connecting with other Existing/External users to the system)
- Member Requests: (finding and sending Friend/Group/Other request to existing users.)
- Member Invitations: (Inviting friends from outside)
- Member Groups: (Discussion groups, Making publicly visible/private groups, Managing groups{currently all groups are public only managed by admin})
- Member Uploads: (Uploading images to the site)
- System Administration: (Blocking/Unblocking/Managing/Deleting users, Roles and Permissions)
- System Logs: (The track of website hiccups)
- Points of Interest (Some Interesting and re-usable pieces of code for developers)
- Using the Code
- Installation
- History
For a quick overview of the table structure and controllers, here is the link to :-
- Parichay.Data Table Diagram (for messaging system only)
- Parchay.MVC Controllers Class Diagram
- This is how our Home Screen will look like.
- User Edit Info
- An Alert for Activity (Sender's View), (Recipient's View)
- My Messages
- Find A Friend, Send a Friend Request
- Acknowledge Request (Sender view), (Recipient View)
- Group Home, Create A Group
Lets proceed now to discuss these modules one by one.
3. Modules
3.1) Member Details (AccountController):
(User Details, Password & Password Q&A Management, Recovery etc.)
The first thing which is done as a user signs up to our website is - user’s profile is created into the **member_details
** table (PS the code below). Our entire messaging system has dependencies tied to this table only. Security module can continue to work independently.
Within our Parichay.Data module, only member_details
table has the dependency over aspnet_membershipuser
table’s
primary key. This is to ensure that Security module can continue to work independently as Data Module grows. The entire Parichay.Data module can be
ported and wrapped around to some other security module also. (e.g. - If
you might want to port it to a CMS plugin.)
As soon as the user signs up, an empty member_de
tails
entry is created for the user. The primary key for member_d
etails
comes from the aspnet_membershipusers
's primary key (Id)
FormsService.SignIn(model.UserName, false ); try
{
MembershipUser thisUsr = Membership.GetUser(model.UserName,true);
MemberDetails toCreate = new MemberDetails();
toCreate.Id = Int32.Parse(thisUsr.ProviderUserKey.ToString()); toCreate.PEmail = thisUsr.Email;
toCreate.Givennm = model.Givennm;
toCreate.bShowPrvInfo = false;
Data.Helper.NHibernateHelper.Save<MemberDetails>(toCreate);
}
catch (Exception ex1)
{
Data.Helper.NHibernateHelper.Log(new Exception("Problem creating default user profile==>", ex1));
}
3.2) Member Alerts (AlertController)
(Simple track of your website activity and responses.)
The
first experience of interaction you want to provide an incoming user
are the updates and responses about his activity in the system. This keeps the user updated about what’s going on in here. The table which
stores this information is member_alert
.
So from now on, any activity/response to user can be stored to
this table and it should display in his Alerts. (On the home page and in
the NOTICES section. Here is the table:-
The P_UserId
is a foreign key, pointing to member_details
table.
So once you have a profile, you are eligible for alerts!!! Message field stores the message, and Version is timestamp of the alert. (There is
Alert_Type_Id
fields which is not currently tied to any lookup table
yet, as we wanted to keep our system light. This field can be used for templating the alerts for specific type of activity. So that we can Just
pass in the parameters and activity code, the template should generate
the necessary message ).
Here is the method Alert which is used to send alerts to a user (its located in the BaseController
class):-
protected void Alert(int to, string message)
{
try
{
Data.Entity.MemberAlert obj = new Data.Entity.MemberAlert();
obj.Ishidden = 0;
obj.Message = message;
obj.PUser = Data.Helper.NHibernateHelper.UniqueResult<Data.Entity.MemberDetails>(null, "Id", to);
Data.Helper.NHibernateHelper.Save<Data.Entity.MemberAlert>(obj);
TempData["message"] = "Requested User Notified.";
}
catch (Exception ex1)
{
Data.Helper.NHibernateHelper.Log(new Exception("Error Notifying UserKey:" + to.ToString(), ex1));
TempData["message"] = "Unable to Notify. Error: " + ex1.Message;
}
}
I think the code is quite self explainatory. We tie an alert to the primary key (from the member_details
table. The message is whatever message we want to sent. By default it is not hidden (obj.Ishidden=0). And then we call our pretty NHibernateHelper
class to Save the object.
3.3) Member Messages (MessageController)
(Status Updates - sharing and receiving replies/responses.)
Now,
as a user is already signed-up to our website and he'll be alerted of his
activities here - the first activity we’re gonna give to him is Messaging and replies. Obviously, if the sender is himself
the recipient of a message - that becomes a status update. A user can
reply to his status as well - in that case the second message will have a ParentId pointing to first message. Therefore, member_messages table is tied to the
member_details
table through two keys - the SenderId, and the
RecipientId.
And there is another nullable key here “ParentId” which
points back to the member_messages
table's primary key. Which means in addition to
simple status updates (where sender=recipient and parentId =null) there
is going to be replies. The replies will have the Primary Key of the
orginal message as their parentId. We can grow this tree to many
levels, but right now we are only going to give a two level tree. All
the subsequent replies to a status update (or parent message) will be
ordered by the date. So the latest reply comes to bottom.
Below
is the code for adding a message. As obvious, Replying a message is
also simply adding a message. But this time = the Parent Id points to
another message, and the recipient Id points to the SenderId of the
parent message.
public ActionResult AddMessage(MemberMessage model)
{
var result = new JsonResponse();
if (string.IsNullOrEmpty(model.Text))
{
result.isSuccessful = false;
TempData["message"] = result.errorMessage = "Message cannot be blank.";
}
else
{
if (IsUserAuthenticated)
{
try
{
MemberDetails thisUsr = NHibernateHelper.UniqueResult<MemberDetails>(null, "Id", LoggedInUserKey);
var msg = new MemberMessage
{
Text = model.Text.Replace("\r\n", " "),
Modifiedon = DateTime.Now.ToUniversalTime(),
Createdon = DateTime.Now.ToUniversalTime(),
Sender = thisUsr,
Type = ((int)model.Type),
Isprivate = 0,
Source = "parichay",
Recipient = thisUsr
};
if (model.ParentId != null)
{
msg.ParentId = NHibernateHelper.UniqueResult<MemberMessage>(null, "Id", model.ParentId.Id);
}
if (model.Recipient != null)
{
MemberDetails recUsr = NHibernateHelper.UniqueResult<MemberDetails>(null, "Id", model.Recipient.Id);
if (recUsr == null)
{
throw new Exception("This user do not have profile information. Message cannot be sent.");
}
else
{
msg.Recipient = recUsr;
}
}
NHibernateHelper.Save<MemberMessage>(msg);
try
{
if (msg.Sender.Id != msg.Recipient.Id)
{
string msgUrl = "<a href='" + Url.Action("MsgDtl", "Message", new { id = msg.Id }) + "' >reply</a>";
Alert(msg.Recipient.Id, string.Format("You have received a ({0}) to from: {1}", msgUrl, msg.Sender.Givennm));
}
}
catch (Exception ex1)
{
Data.Helper.NHibernateHelper.Log(new Exception("Error Sending Message Alert=>", ex1));
}
result.Id = msg.Id.ToString();
result.isSuccessful = true;
TempData["message"] = result.responseText = "Message Sent Successfully";
}
catch (Exception excp1)
{
Data.Helper.NHibernateHelper.Log(new Exception("Error Sending Message=>", excp1));
result.isSuccessful = false;
TempData["message"] = result.errorMessage = "Failed to save message. Error: " + excp1.Message;
}
}
else
{
result.isSuccessful = false;
TempData["message"] = result.errorMessage = "You must be logged in to post a message";
}
}
if (IsJsonRequest())
{ return Json(result); }
else
{
return RedirectToAction("Index",((Parichay.AppConstants.ReturnContollerHomes)model.rUrl).ToString());
}
}
3.4) Member Friends (FriendController)
(Inviting a friend to the system, Sending a friend Request to existing user in the system)
Let’ say our signed-up user wants to connect to more users - there are two scenarios- 1. Either the user has already joined the system - In this case you can send him a “Request”. 2. The user is not yet joined - In this case you send him an “Invitation”.
Hense, an invitation will complete in two steps - firstly and invitation will be sent to the external user to “Join” the system .And
once he joins(or signs-up) and acknowledges your Join "Invitation"- a “Request” is
automatically created for him to become your friend (or join your group -depending upon where your invitation originated in the first place). The new user can still
accept/decline your Friend "Request" after signing-up. “Requests” and “Invitations” are discussed in next section. Lets take a look at the member_friends
table.
The
member_friends
table defines a relationship between two users.
member_friends
table points to member_details
table through two keys
UserId
and FriendId
. ( It doesn’t matter which side you are, once your
ID’s are here, you are friends.)
And
ID’s of two users in member_details table are added here only if the
recipient user “Confirms” the freind request of requesting user. That
happens when the recipient acknowledges the request. In the next section (Member Requests) you'll find what happens when the recipient presses “Confirm” button on “AckRequest” page of the Connect Controller.
In the FriendController, one of the interesting section is the find user page, which actually gives you the link to send a friend request to a found user. Here is the code for the Find action and the binding as used in UsrSrch.cshtm view page:-
[HttpPost]
public ActionResult Find(string givenEmail)
{
IList<MemberDetails> rtrn = Data.Helper.NHibernateHelper.FetchProjection<MemberDetails>(new string[] { "Givennm", "Id", "PicId", "Institute", "Addr" }, "Givennm", "%" + givenEmail + "%", 0, 10, true, null, false);
ViewBag.LoggedInUserKey = LoggedInUserKey;
ViewBag.searchResults = rtrn;
return View();
}
@foreach (Parichay.Data.Entity.MemberDetails item in Model)
{
if (item != null)
{
<tr>
<td>.........
@Html.ActionLink("Request Friend", "VRequest","Connect",new { id = (item.Id),tId=(int)ViewBag.LoggedInUserKey, type=(int)Parichay.AppConstants.RequestTypes.Friend},null)}
.....
...</tr>
}
3.5) Member Requests (ConnectController)
(finding and sending Friend/Group/Other request to existing users.)
As shown below, the table member_r
equests
has two foreign keys - the
senderId
and the RecipientId
mapped to member_details
table. This means
that this interaction is between an “existing” sender and an
“existing” recipient in our website. Once a sender initiates a "Request", the
sender and recipient can see the Request in Invitations & Requests panel.
The recipient can accept/decline the request. The respective alerts are
shown.
Now
in the same controller, we have AckRequest Action. This Action performs
the actual task of connecting people :) Once the recipient presses
confirm - the type of request is Identified(whether it is a friend or a
group request) and a respective relationship is created accordingly as
shown below:
switch (model.submitButton)
{
case ("Accept"):
{
if (source.Type == (int)AppConstants.RequestTypes.Friend)
{
return AddFriend(source);
}
else if (source.Type == (int)AppConstants.RequestTypes.Group)
{
return JoinGroup(source);
}
break;
}
3.6) Member Invitations (ConnectController)
(Inviting friends from outside)
For
a friend, who has not yet joined our website, an existing user in the
system can place an invitation. The target e-mail ID is recorded into
the member_invitations
table. Next time the recipient of the Invitation joins in (or signs up) - he can
acknowledge the sender's invitation and the sender gets notified.(The "Type
" field of member_invitation
is set up depending on where you started your request - wheather you invited him as a friend or to join your group. The TargetPageId
contains the ID of the user or the Id of the target group) . Below is the code of AckInvite method which creates the appropriate request on the basis of "Type
" of the original invitation :-
switch (model.submitButton)
{
case ("Confirm"):
{
Alert(source.Senderid.Id, string.Format("Hello {0} your freind {1} (e-mail: {2}) has accepted your invitation to join Parichay.", source.Senderid.Givennm, LoggedInUserName, source.Email));
source.BecameUserId = LoggedInUserKey;
source.Status = 0;
try
{
CreateRequest(source);
Data.Helper.NHibernateHelper.Delete<MemberInvitations>(source);
...
....
private void CreateRequest(MemberInvitations model)
{
MemberRequests itm = new MemberRequests();
Guid val;
do
{
val = System.Guid.NewGuid();
} while (Data.Helper.NHibernateHelper.UniqueResult<MemberRequests>("Guid", "Guid", val.ToString()) != null);
itm.Guid = val.ToString();
itm.Senderid = model.Senderid;
itm.Recipientid = Data.Helper.NHibernateHelper.UniqueResult<MemberDetails>(null, "Id", LoggedInUserKey);
itm.TargetPageid = model.TargetPageid;
itm.Type = model.Type;
itm.Createdate = DateTime.Now;
itm.Status = 1;
Data.Helper.NHibernateHelper.Save<MemberRequests>(itm);
}
3.7) Member Groups (GroupController)
(Discussion groups, Making publicly visible/private groups, Managing groups{by admin})
As
we see in the image below - each member_groups
has member_groupmembers
and member_groupmessages
. The member_groupmessages
are related to
member_
details
table through two foreign keys - SenderId
, RecipientId
. And it is related to member_groups
table through the third foreign key GroupId
. In
the same way, we have member_groupmembers
table which is the many to many mapper table between member_groups
and member_details
.Also , there is
another foreign key- OwnerId which relates member_groups directly to the
member_details.
(I’m
sorry, Currently, all the groups are public. The feature to join the
group has not been enabled yet. And therefor the group invitations and
requests. I will try to enable them ASAP. So, just as we invite or
request a friend, we can invite/request our friends to our groups.)
The PostMessage
method of GroupController is pretty much like that of the MessageController above, as obviously the function is same. However, upon accepting the group request (in ConnectController>>AckRequest), here is how the group member is created:-
private ActionResult JoinGroup(MemberRequests thisReq)
{
try
{
if (thisReq.Senderid.Id == LoggedInUserKey)
{
throw new Exception("You are already a member of your group.");
}
MemberGroupmembers itm = new MemberGroupmembers();
itm.MemberDetails = Data.Helper.NHibernateHelper.UniqueResult<MemberDetails>(null, "Id", thisReq.Recipientid.Id);
itm.Group = Data.Helper.NHibernateHelper.UniqueResult<MemberGroups>(null, "Id", thisReq.TargetPageid);
itm.bRole = false;
itm.bStatus = true;
.....
Data.Helper.NHibernateHelper.Save<MemberGroupmembers>(itm);
......
}
3.8) Member Uploads (MediaController)
(Your uploads to the site)
This
table requires quite a little introduction. All our file uploads are
placed here. Every upload is tied to member_details
table through
P_UserId
key. What might be interesting to read is the resizing of image
to thumbnail. Below is the code used for it.
One of very interesting methods in MediaController is SaveAvImage which is used to upload an image to the member_uploads database. Here is the code:-
public ActionResult AddAvatar()
{
try
{
SaveAvImage();
}
foreach (string inputTagName in Request.Files)
{
HttpPostedFileBase file = HttpContext.Request.Files[inputTagName];
if (isImage(file.FileName, true))
{
MemberDetails usr = NHibernateHelper.UniqueResult<MemberDetails>(null, "Id", LoggedInUserKey);
if (file.ContentLength > 0)
{
TempData["message"] = "Resizing the file '" + file.FileName + "' to avatar Image now.";
MemberUploads attch = new MemberUploads();
attch.Owner = usr;
attch.Attachmt = file.FileName;
attch.FileContentT = file.ContentType;
attch.CreateD = DateTime.Now;
attch.FileDetail = Utilities.CreateAvatar(100, file.InputStream);
attch.FileSize = attch.FileDetail.Length;
NHibernateHelper.Save<MemberUploads>(attch);
.....
}}}}
The Utilities>>CreateAvatar method is taken from Gunnard Peipman's blog here.
3.9) System Administration (AdminController)
(Blocking/Unlocking/Managing/Deleting users, Roles and Permissions)
As mentioned, we are using the Default Asp.Net role based security. Here we are using custom asp.net membership
providers and custom role providers. The providers have been taken
from this tutorial and customized. And Additional layer of security has been added as
an HttpModule as described in this project. The UI screens for the User
Management, Roles, Permissions can be understood in the aadhaar
tutorial. Here we just reproduce the screens.
3.10) System Logs (The track of your application’s hiccups)
The
Logger for our system uses the similar table (system_log
) as Log4Net,
however it records the system exceptions using NHibernateHelper class.
The same table can be used to combine the logging for both log4net as
well as inner System Logger
4. Points of Interest (Some Interesting pieces of code)
Here are some of interesting tricks you will notice
in the code(and perhaps would like to re-use). The inspiration has come
from various sources and from my intuitions. The credit goes to the
amazing helpful Asp.Net community and independent bloggers for sharing
all the valuable information.
4.1) The selective Data Access (from NHibernateHelper class)
There
are two of the selective Data Access methods from NhibernateHelper
class which I would like to tell you about - the UniqueResult<T>
method, and the FetchProjection<T> method which are used quite
often in the system. These methods are used to create a custom ICriteria based
query for us.
model.myInfo
=
Parichay.Data.Helper.NHibernateHelper.FetchProjection<MemberDetails>(new
string[] { "Id", "Nicknm", "Surnm", "Givennm", "TitleC", "GenderC",
"Institute", "CtryC", "ShowPrvInfo" }, "Id", uId, 0, 1, false, null,
false)[0];
Here is the signature for FetchProjection<T> method:
public
static IList<T> FetchProjection<T>(string[] fieldNames,
string[] propertyNames, object[] propertyValues, int? pageIndex, int?
pageSize, bool isSoftSearch, string sortField, bool isAscSort)
{
…
if ((null != propertyValues) && (null != propertyNames))
{......}
…..
…{ProjectionList proj = Projections.ProjectionList();
for (int i = 0; i < fieldNames.Length; i++)
{
proj.Add(Projections.Property(fieldNames[i]), fieldNames[i]);
}
criteria = criteria.SetProjection(proj);
}
…
if (null != sortField)
if (isAscSort)
criteria.AddOrder(Order.Asc(sortField));
else
criteria.AddOrder(Order.Desc(sortField));
…
if(pageIndex.HasValue&&pageSize.HasValue)
criteria = criteria.SetFirstResult(pageSize.Value * pageIndex.Value).SetMaxResults(pageSize.Value);
…...
}
As we see above, FetchProjection methods sets up options for Projection => the projected fieldNames, properties to Compare and their values, Sorting, Paging options for our custom ICriteria query accordingly.
All we need to do in order to turn off any feature is provide a null for
not needed parameter.
The
second method UniqueResult creates a ICriterea based query for us to
fetch either a UniqueResult object or if we wish to fetch out only a particular
field, we can use it like this:-
Data.Helper.NHibernateHelper.UniqueResult<MemberInvitations>(null, "Guid", id);
Data.Helper.NHibernateHelper.UniqueResult<MemberInvitations>(“Id”, "Guid", id);
Here is the signature of the method:-
public static T UniqueResult<T>(string fieldName, string[] propertyNames, object[] propertyValues)
{
if ((null != propertyValues) && (null != propertyNames))
{
for (int i = 0; i < propertyValues.Length; i++)
{
criteria = criteria.Add(Expression.Eq(propertyNames[i], propertyValues[i]));
}}.....
......
if (!string.IsNullOrEmpty(fieldName))
{
ProjectionList proj = Projections.ProjectionList();
proj.Add(Projections.Property(fieldName), fieldName);
criteria = criteria.SetProjection(proj);
object rtrn = criteria.UniqueResult();
if (rtrn != null)
{
object obj = (T)System.Activator.CreateInstance(typeof(T));
Helper.PropertyInspector.SetPropertyValue(ref obj, fieldName, rtrn);
return ((T)obj); }
else
{ return default(T); }
}
else
{
return (T)criteria.UniqueResult();
}
}
4.2) Use of Reflections (from PropertyInspector class)
This
class uses Reflections to set the selective properties in case of our
query fetches partial data for the object. For example the UniqueResult
method above returns the object of type T, setted with only one property
which is referred through “fieldName”.
More info. with thanks to Philippe Leybaert here.
4.3) The Email class
This
is one of the interesting class which is used to create E-mails.
Setting the to property adds to addresses to the e-mail. The Send method
performs the send.
More info. with thanks to Jake Howlette here.
4.4) The ImageResult and JsonResponse classes.
The
Images stored in member_upload class are returned as ImageResult so
that they can be used with <Img src=”...” /> attribute.
More info. with thanks to Sean here.
4.5) Asp.Net MVC3 and CheckBoxFor boolean properties.
We tried to keep the flags as Int values here. In expectation that later point of time we might tie them to foreign key or may be selectable values. But to keep them as boolean (to bind them with checkboxes), we add boolean properties to the Int32 properties of our NHibernate Objects like this:-
private Int32 _ShowPrvInfo;
public virtual Int32 ShowPrvInfo
{
get { return _ShowPrvInfo; }
set { _ShowPrvInfo = value; }
}
public bool bShowPrvInfo { get { return (_ShowPrvInfo != 0); } set { _ShowPrvInfo = (value) ? 1 : 0; } }
4.6) Enum as replacement for Lookup Tables
In order to cut down the on Lookup Tables, we are using Dictionary<int,string>
and enums
int the AppConstrants
class for lookup. Here is an example of an enum which stores the Controller names for redirection.
Here is how, we parse int (to replace as primary key), and string(to retrieve the value) from enum.
int rUrl = model.rUrl;
(Parichay.AppConstants.ReturnContollerHomes)rUrl;
int requestType = (int)Parichay.AppConstants.RequestTypes.Friend
Parichay.AppConstants.ReturnContollerHomes rUrl = Parichay.AppConstants.ReturnContollerHomes.Message;
bool flat = Enum.TryParse<Parichay.AppConstants.ReturnContollerHomes>(Url.RequestContext.RouteData.Values["controller"].ToString(),out rUrl);
4.7) Indefinite Record count Paging
For
performing indefinite paging, without the need to fire the count query,
we use the basic indefinite pages enabling/disabling the Previous/Next
buttons on the basis of page count. The cshtml is located in
Shared/pg.cshtml
@model System.Int32
@{
int pg = 0;
bool nxtFlag= Int32.TryParse(Request.QueryString["p"],out pg);
}
<b>Page:</b> @if(pg>
4.8) System Logger
The
Logger for our system uses the similar table (system_log) as Log4Net,
however it records the system exceptions using NHibernateHelper class.
The same table can be used to combine the logging for both log4net as
well as inner System Logger.
4.9) The Message,Friends,Groups tables
And of-course many thanks to Emad Ibrahim, the table structure for member_messages, member_freinds and groups are inspired from his open source microblog project Yonkly written in Asp.Net MVC2, Linq to SQL and is Ajax capable.
4.10) The Utilities.CreateAvatar method
One of the interesting utility method Utilities.CreateAvatar has been taken from Gunnard Peipman's blog here. It is used to resize the uploaded image to a square thumbnail.
5. Using the code
The
current application has been tested over MySql database. The first
thing you will do is to create the database and run the table scripts.
The MySql database script has been provided with the solution.
For
databases, other than MySql you might prefer to enable the createschema
functionality to NHibernate helper class which should create the
database schema from the Mapping Files. Or you can create the table
scripts yourself and change the Nhibernate parameters in the web.config
file of the application.
For
initial seeding of the database, you can either run the initial seeding
script which will create the user with name sysadmin and default
password "password", and then add this user as Admin of the website.
*Currently
you can simply sign-up with username "sysadmin" and the application
will add you to the "Admin" role. The following loop has been added to
the "Account>>Register" controller to ensure this:
6. Installation:-
- Please
note that auto installer has not been created for this app. Kindly
create the MySql Database first. e.g.- with name "parichaytest" and install
the two SQL scripts provided.
- The 1ParichaySecurity.sql contains the schema for Security.
- 2ParichayMessaging.sql contains the schema for Messaging tables.
- Change the name of NHibernate "connection string" in the web.config of the application to point to your database
- e.g., Enable & Update following settings for MySql Database in Web.Config file. (Update the DB name, Username, Password etc):-
<property name="show_sql">true</property>
<property name="use_outer_join">true</property>
<property name="use_proxy_validator">false</property>
<property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
<property name="connection.isolation">ReadCommitted</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.MySQLDialect</property>
<property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
<property name="connection.connection_string">Server=localhost;Database=parichaytest;User ID=**Your DB UserId**;Password=**yourdbpasswrd**;Convert Zero Datetime=true</property>
Enable & Update following settings for SQL Server in Web.Config file:-
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">Data Source=.\sqlexpress;Initial Catalog=parichaytest;User ID=**Your DB UserId**;Password=**yourdbpasswrd**</property>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="show_sql">true</property>
- Build and run the application.
- Remember
to sign up with "sysadmin" username. The system will assign you the
"Admin" role. Once the sysadmin is already created for you. You can
comment out the following code block in the "Account>>Register"
Controller action:-
if
((string.Equals(model.UserName,"sysadmin",StringComparison.InvariantCultureIgnoreCase))&&(Roles.GetAllRoles().Length
== 0))
{
Roles.CreateRole("Admin");
Roles.AddUserToRole(model.UserName, "Admin");
}
The
current system has been tested with MySql database. For other databases
you can either generate the schema from mapping files. To do this, you
will need following code in NHibernateHelper classes of
"Parichay.Security" and "Parichay.Data" projects:-
cfg.Configure();
cfg.AddAssembly(typeof (aClassFromYourProject).Assembly);
new SchemaExport(cfg).Execute(false, true, false, false);
Information can be found here and here
- After setting up the database, remember to update the NHibernate connection string in Web.Config file of the application.
Once I am able to test the application with different database, I will be updating the SqlScripts.
7. History
-
21-Feb-2011 For security, the basic Asp.Net role based security has been used along with additional layer of security as described in the Aadhaar project at codeproject.
- 21-Feb-2011 Parichay added to codeplex. If you find it interesting to contribute, please contact.
- 23-Feb-2011 All UInt values in NHibernate mapping replaced with Int32. The system is now tested with MS-SQLServer. The scripts will be provided soon as the table relationships are created.