Jquery Weblinks Module Setup


Credits

In my last post I covered the conceptual design of the weblinks module. From now on I will be creating posts at different stages of coding the module. Before I move on I need to give some credit for stuff I am using to help create this. For people who need help learning how to create modules in DotNetNuke I found the tutorial by Johan Seppäläinen at sipidcode.com very useful. I am going to use the template from the DotNetNuke starter kit and much of the code in this tutorial with names change to suit the weblinks module. Although I made some changes to the original code, the iweblite project allowed me to see how this could be possible. Now that I got that out of the way let’s do some coding.

Creating Project

It really does not matter what module template is  used but I believe the module template I used to create the project is from the DotNetNuke starter kit (I have several downloaded and a custom one I created so I lost track).  The project is in C# but I will be happy to provide the visual basic version if someone provides it. I setup DotNetNuke in Microsoft Webmatrix then hit the button in webmatrix to open the project in visual studio after DotNetNuke was installed. Once in visual studio I created a new module project inside of the DesktopModules folder in my DotNetNuke installation. I also deleted a bunch of files I won’t need for this demonstration. These were any files related to editing and settings pages. We could use the settings controls in this but I want to keep this as simple as possible.

Project Screen

As you can see in the above screenshot, webmatrix has the DotNetNuke which was transferred to visual studio. Aside from our jQuery and webservice stuff this is going to be setup like a typical module so I will not go into too much detail about that stuff.

After getting my project into visual studio and removing the files I didn’t need I added the table and stored procedure creation script in the 00.00.01.SqlDataProvider (please forgive me for any typos in this one. I had to go back to make changes a few times so hope I did not forget anything).

/** Create Table **/
if not exists (select * from dbo.sysobjects where id = object_id(N'{databaseOwner}[{objectQualifier}AjaxWebLinks_WebLinks]') and OBJECTPROPERTY(id, N'IsTable') = 1)
BEGIN
CREATE TABLE {databaseOwner}[{objectQualifier}AjaxWebLinks_WebLinks]
(
[ModuleID] [int] NOT NULL,
[LinkID] [int] NOT NULL IDENTITY(1, 1),
[LinkText] [nvarchar](100) NOT NULL,
[LinkURL] [nvarchar](100) NOT NULL
)

ALTER TABLE {databaseOwner}[{objectQualifier}AjaxWebLinks_WebLinks] ADD CONSTRAINT [PK_{objectQualifier}AjaxWebLinks_WebLinks] PRIMARY KEY NONCLUSTERED ([LinkID])
CREATE CLUSTERED INDEX [IX_{objectQualifier}AjaxWebLinks_WebLinks] ON {databaseOwner}[{objectQualifier}AjaxWebLinks_WebLinks] ([ModuleID])

ALTER TABLE {databaseOwner}[{objectQualifier}AjaxWebLinks_WebLinks] WITH NOCHECK ADD CONSTRAINT [FK_{objectQualifier}AjaxWebLinks_WebLinks_{objectQualifier}Modules] FOREIGN KEY ([ModuleID]) REFERENCES {databaseOwner}[{objectQualifier}Modules] ([ModuleID]) ON DELETE CASCADE NOT FOR REPLICATION
END
GO

/** Drop Existing Stored Procedures **/

if exists (select * from dbo.sysobjects where id = object_id(N'{databaseOwner}[{objectQualifier}AjaxWebLinks_GetLinks]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure {databaseOwner}{objectQualifier}AjaxWebLinks_GetLinks
GO

if exists (select * from dbo.sysobjects where id = object_id(N'{databaseOwner}[{objectQualifier}AjaxWebLinks_GetLink]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure {databaseOwner}{objectQualifier}AjaxWebLinks_GetLink
GO

if exists (select * from dbo.sysobjects where id = object_id(N'{databaseOwner}[{objectQualifier}AjaxWebLinks_AddLink]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure {databaseOwner}{objectQualifier}AjaxWebLinks_AddLink
GO

if exists (select * from dbo.sysobjects where id = object_id(N'{databaseOwner}[{objectQualifier}AjaxWebLinks_UpdateLink]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure {databaseOwner}{objectQualifier}AjaxWebLinks_UpdateLink
GO

if exists (select * from dbo.sysobjects where id = object_id(N'{databaseOwner}[{objectQualifier}AjaxWebLinks_DeleteLink]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure {databaseOwner}{objectQualifier}AjaxWebLinks_DeleteLink
GO

/** Create Stored Procedures **/

create procedure {databaseOwner}{objectQualifier}AjaxWebLinks_GetLinks
@ModuleId int
as

select ModuleId,
LinkID,
LinkURL,
LinkText
from {objectQualifier}AjaxWebLinks_WebLinks
where ModuleId = @ModuleId
GO

create procedure {databaseOwner}{objectQualifier}AjaxWebLinks_GetLink
@ModuleId int,
@LinkID int
as

select ModuleId,
LinkID,
LinkURL,
LinkText
from {objectQualifier}AjaxWebLinks_WebLinks
where ModuleId = @ModuleId
and LinkID = @LinkID
GO

create procedure {databaseOwner}{objectQualifier}AjaxWebLinks_AddLink
@ModuleId int,
@LinkURL nvarchar(100),
@LinkText nvarchar(100)
as

insert into {objectQualifier}AjaxWebLinks_WebLinks (
ModuleId,
LinkURL,
LinkText
)
values (
@ModuleId,
@LinkURL,
@LinkText
)

SELECT @@identity
GO

create procedure {databaseOwner}{objectQualifier}AjaxWebLinks_UpdateLink
@ModuleId int,
@LinkID int,
@LinkURL nvarchar(100),
@LinkText nvarchar(100)
as

update {objectQualifier}AjaxWebLinks_WebLinks
set LinkUrl = @LinkURL,
LinkText = @LinkText
where ModuleId = @ModuleId
and LinkID = @LinkID
GO

create procedure {databaseOwner}{objectQualifier}AjaxWebLinks_DeleteLink
@ModuleId int,
@LinkID int
as

delete
from {objectQualifier}AjaxWebLinks_WebLinks
where ModuleId = @ModuleId
and LinkID = @LinkID
GO
[/sourcecode ]

The DataProvider.cs is the abstract class containing the methods we will override in out SqlDataProvider.cs.

public abstract IDataReader GetLinks(int ModuleId);
public abstract IDataReader GetLink(int ModuleId, int LinkID);
public abstract int AddLink(int ModuleId, string LinkURL, string LinkText);
public abstract void UpdateLink(int ModuleId, int LinkID, string LinkURL, string LinkText);
public abstract void DeleteLink(int ModuleId, int LinkID);

The above methods will be used in our business layer to manage links. As you can see, each method requires  a module id to access records in the database. Each of the stored procedures contain a where clause which enforces this requirement.

The next file is the AjaxWebLinkInfo class which represents a single row in the AJaxWebLinks_WebLinks table.

    public class AjaxWebLinkInfo
    {
       public int ModuleId { get; set; }
       public int LinkID { get; set; }
       public string LinkURL { get; set; }
       public string LinkText { get; set; }
    }

The business layer class AjaxWebLinksController.cs will be responsible for executing the business layer methods in our webservice.

namespace DotNetNuke.Modules.AjaxWebLinks.Components
{

    /// -----------------------------------------------------------------------------
    /// <summary>
    /// The Controller class for AjaxWebLinks
    /// </summary>
    /// -----------------------------------------------------------------------------
    public class AjaxWebLinksController 
    {

        
        #region Public Methods
        public List GetLinks(int ModuleId)
        {
            return CBO.FillCollection(DataProvider.Instance().GetLinks(ModuleId));
        }

        public AjaxWebLinkInfo GetLink(int ModuleId, int LinkID)
        {
            return (AjaxWebLinkInfo)CBO.FillObject(DataProvider.Instance().GetLink(ModuleId, LinkID), typeof(AjaxWebLinkInfo));
        }

        public int AddLink(AjaxWebLinkInfo link)
        {
            
            if ( link.LinkText.Trim()!= string.Empty &amp;&amp; link.LinkURL.Trim() != string.Empty )
            {
               return DataProvider.Instance().AddLink(link.ModuleId,link.LinkURL, link.LinkText);
            }
            return 0;

        }

        public void UpdateLink(AjaxWebLinkInfo link)
        {
            if (link.LinkText.Trim() != string.Empty &amp;&amp; link.LinkURL.Trim() != string.Empty)
            {
                DataProvider.Instance().UpdateLink(link.ModuleId, link.LinkID, link.LinkURL, link.LinkText);
            }
        }

        public void DeleteLink(int ModuleId, int linkID)
        {
            DataProvider.Instance().DeleteLink(ModuleId, linkID);
        }


        #endregion


    }

}

The Webservice

After getting the typical data and business layer stuff out of the way it is time to look into the cool stuff. I created a traditional asp.net webservice called Handler.asmx and a wcf webservice called Handler.svc. Although these files have different names, the script generator created two classes with the same name so I renamed the wcf class wfHandler. Everything that I will be doing in this module is essentially a very simplified version of a solution I used in a real project so in my project I used the asmx webservice without any problems. However, I decided to try to get this module working with a wcf webservice. So far, I have not been able to get it working but will keep looking into it. I also do not know how to setup this up without having to create a serviceModel configuration inside of the DotNetNuke web.config (I am not sure that is acceptable for a distributable module). I will eventually want to do this in WCF so if anyone has any ideas please let me know.

This is what the Handler.asmx.cs file looks like:

namespace DotNetNuke.Modules.AjaxWebLinks
{
    /// <summary>
    /// Summary description for Handler
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
     [ScriptService]
    public class Handler : WebService
    {
        private AjaxWebLinksController controller;
        private AjaxSecurityContext securityContext;

        public Handler()
        {
            //Hook up security context
            securityContext = new AjaxSecurityContext(this.Context);
            //Get reference to business logic layer
            controller = new AjaxWebLinksController();
            //Then Have fun!!
           
        }


        [WebMethod]
        public List GetLinks()
        {
            return controller.GetLinks(securityContext.moduleInfo.ModuleID);
        }

        [WebMethod]
        public AjaxWebLinkInfo GetLink(int LinkID)
        {
            return controller.GetLink(securityContext.moduleInfo.ModuleID, LinkID);
        }

        [WebMethod]
        public int AddLink(AjaxWebLinkInfo link)
        {
            //Check if user has access to add stuff to the module if not throw an exception
            //This can be rewritten to send something back that javascript understands but I am not sure that is necessary
            //Would be nice to create an attribute to assert permissions [access(level= accesslevel.edit)]
            if (securityContext.canEdit)
            {
                throw new Exception("You do not have sufficient rights to perform this action");
            }
                //returns the id of the new link or 0 if failed
               return controller.AddLink(link);

        }

        [WebMethod]
        public void DeleteLink(int LinkID)
        {
            //Check if user has access to add stuff to the module if not throw an exception
            //This can be rewritten to send something back that javascript understands but I am not sure that is necessary
            //Would be nice to create an attribute to assert permissions [access(level= accesslevel.edit)]
            if (securityContext.canEdit)
            {
                throw new Exception("You do not have sufficient rights to perform this action");
            }
   
            controller.DeleteLink(securityContext.moduleInfo.ModuleID, LinkID);

        }


    }
}

The real magic happens in the webservice constructor which passes on the current http context to a new instance of the AjaxSecurityContext class (IWebLite). In the AddLink and DeleteLink methods we use the security context to figure out if the client has the right permissions before we all them to do something. For those who are wondering, the view permissions are checked inside of the AjaxSecurityContext file. This means that execution will never even get to a WebMethod if the client does not have at least view permissions.

My next post will go into detail about the AjaxSecurityContext.cs file and subsequent posts will talk about the client side of things.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s