Products

Solutions

Resources

Partners

Community

Blog

About

QA

Ideas Test

New Community Website

Ordinarily, you'd be at the right spot, but we've recently launched a brand new community website... For the community, by the community.

Yay... Take Me to the Community!

Welcome to the DNN Community Forums, your preferred source of online community support for all things related to DNN.
In order to participate you must be a registered DNNizen

HomeHomeArchived Discus...Archived Discus...Developing Under Previous Versions of .NETDeveloping Under Previous Versions of .NETASP.Net 2.0ASP.Net 2.0jQuery + ajax + DNN ModulesjQuery + ajax + DNN Modules
Previous
 
Next
New Post
11/25/2009 2:28 PM
 

I am developing a DNN module that utilizes jQuery and ajax calls via JSON.  Because merely using ASP.NET ajax controls is really slow for what I'm doing, I thought using a combination of jQuery and ajax calls would speed things up.  However, I have a problem because my user control (module.ascx) is already inheriting from DNN's PortalModuleBase class, it cannot also inherit from System.Web.Services.WebService, which it needs to enable web methods for a page. Consequently, I created a separate web service (module.asmx) and implemented all my web methods there.

Because DNN adds an extra layer of complexity, I need access to things like the PortalSettings object, and other DNN objects that are just not available in my web service code (code in asmx.cs).  I tried using the Session object to pass objects from my user control to the web service control, but obviously that didn't work since my web service code doesn't have access to the Session object  (at least that's what I observed, I don't know if I was just doing it wrong).

Is there any way to put the web methods in my actual user control instead of having to create a separate web service page so I can access DNN objects like PortalSettings?  If not, is there a robust, proper way to access DNN objects in my web service code?

 
New Post
11/25/2009 3:46 PM
 

 Do you need to do a webservice or can you just use normal ajax?

Since the draw of jQuery seems to be that ASP AJAX is REALLY slow [and it is terrible] I'd think that you don't actually need webservice, just a faster form of AJAX. jQuery does do this really well. I've used it extensively in a module. Any time I need AJAX in a module, I now use jQuery to do it.

My jQuery looks something like this

jQuery.ajax({
type: "POST",
async: "false",
url: location.href,
dataType: "json",
data: ({'FUNCTION': 'FunctionName', 'param0': '1' }),
success: function(data) {
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
},
beforeSend: function(xhr) {
xhr.setRequestHeader("X-OFFICIAL-REQUEST", "TRUE");//Used to ID as a AJAX Request
},
complete: function(XMLHttpRequest, textStatus) {
}
}); 

My server side code to deal with the postback looks something like

protected void Page_Load(object sender, EventArgs e)
{
if(Request.Headers["X-OFFICIAL-REQUEST"] == "TRUE") AjaxWrapper();
...

protected void AjaxWrapper()
{
Response.Clear();
string strData = ""; 
try
{
MethodInfo mi = GetType().GetMethod(Request.Params["FUNCTION"],
BindingFlags.Instance | BindingFlags.NonPublic); 
object[] objs = new object[mi.GetParameters().Length];
for (int i = 0; i < objs.Length; i++)
{
objs[i] = (new PortalSecurity()).InputFilter(Request.Params["param" + i], PortalSecurity.FilterFlag.NoMarkup);
}
strData = mi.Invoke(this, objs).ToString();
}
catch (Exception ex)
{
strData = "{Error : Caught}";
Exceptions.ProcessModuleLoadException(this, ex);
}
Response.Write(strData);
Response.Flush();
try {  Response.Close(); }catch { }//It likes to break sometimes - and other times it's needed
Response.End();
return;

Hopefully I can explain how this works intelligently... 

If you have a function, we'll call it 'MyFunc', with 3 parameters - the jQuery data line would like like

data: ({'FUNCTION': 'MyFunc', 'param0': 'Data', 'param1': 'Goes', 'param2': 'Here' }),

Except with actual data as the parameters. 

In my use of this, I have discovered a couple important things:

Your function, MyFunc, can only have strings as parameters. There are probably ways around this, but I found the simplest way was to have the parameters as strings and convert them to new variables in the function.

The other is that you have to pass in, as data, any input from the user that you need. This method basically calls a new page, so there is no user input.

 

Your function then returns a JSON of data, that you can then use on the client side to update whatever you need to.

A very very simple example of a function is

protected string FunctionName(string param)
{
    Response.ContentType = "text/json";\\<-- Important
    return "{'string' : 'Not yet implemented. \\'" + param + "\\''}";
}

 

 This is the stripped down version. I have a couple other things [constants and such] that I use when I do this, but it has worked well for me.
Hopefully this makes sense - I'll try to keep an eye on this thread so I can answer any questions that come up.

 
New Post
11/30/2009 3:40 PM
 

Thanks for the detailed reply.  Let me show you what I'm doing.  I don't really need a web service, but I didn't know how else to run ajax calls.  In my module project, I created a web service page, (DocMgrWebService.asmx) and declared all my methods in the code behind.  here's an example from my asmx.cs file:

[WebMethod]
[ScriptMethod(Responseformat = Responseformat.Json)]
public List<RoleInfo> GetRoles(int portalID)
{
            ArrayList arrRoles = new ArrayList();
            RoleController objRoles = new RoleController();
            arrRoles = objRoles.GetPortalRoles(portalID);
            List<RoleInfo> gRoles = new List<RoleInfo>();
            foreach (RoleInfo role in arrRoles)
            {
                gRoles.Add(role);
            }
            return gRoles;
}

The method returns a generic list of objects that I can access via the ajax call.  I also have a javascript file that will use jQuery to call the method:

function populateRoles(moduleID)
{
    var portalID = jQuery('#dnn_ctr' + moduleID + '_DocumentManager_hdnPortalID').val();
    var roleDiv = '#Roles' + moduleID;
    var rolesListName = '#dnn_ctr' + moduleID + '_DocumentManager_lstRoles';
    jQuery.ajax({
                            type: "POST",
                            async: "false",
                            contentType: "application/json; charset=utf-8",
                            url: getCallbackUrl('GetRolesList'),
                            data: "{portalID : " + portalID + ",moduleID : " + moduleID + "}",
                            dataType: "json",
                            success: function(result) {
                                    var rolesList = (typeof result.d) == 'string' ? eval('(' + result.d + ')') : result.d;
                                    jQuery(rolesListName).find('option').remove();
                                    for( var i = 0; i < rolesList.length; i++ )
                                    {
                                        var listValues = rolesList[i].split(":::");
                                        jQuery(rolesListName).append(jQuery('<option></option').val(listValues[0]).html(listValues[1]));
                                    }
       
                            },
                            error: function(request, status, errorThrown) { error in populateRoles"); }
    });
    return false;
}

Because I have to gain access to things like module IDs and portal IDs, I use hidden fields and populate them on the server side so I can access them when the client side code runs.  I know you were saying that your method only allows for string parameters, but for me, doing it this way allows me to use other types as well, such as integers without having to explicitly convert anything.

Like I mentioned in my first post, because I am using an .asmx file, I can't inherit from PortalModulesBase, so I don't have access to DNN objects, nor do I have access to the Session object, so I can't really pass complex objects back and forth without some hardcore ajax work.  For example, I need to access the PortalSettings object, so instead of just accessing it, I have to run this:

DotNetNuke.Entities.Portals.PortalController objPortals = new PortalController();
PortalInfo objPortal = objPortals.GetPortal(portalID);

which I guess works, but if there is a "best practice" way of doing it, I'd like to know.

I feel like if I had to resort to some hardcore ajax work to pass complex objects between into the web service file, I will be overengineering things, so I just wanted to get some feedback on a more elegant and more simple solution, if one exists.

Thanks for your help.

 

 
New Post
12/3/2009 3:39 PM
 

I tried implementing AJAX like you recommended, but it doesn't seem to be working for me.  The ajax call is sent, but I get an error, and I can tell it doesn't even get to my server code because my breakpoints don't hit when I debug.  This is my

function testBooyah()
{
    jQuery.ajax({
        type: "POST",
        async: "false",
        url: '/dotnetnuke5/DesktopModules/Precept.DocumentManager/DocumentManager.ascx',
        dataType: "json",
       data: "({'FUNCTION': 'TestBooyah', 'param0': '1' })",
        success: function(data) {
            data);
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            error");
        },
        beforeSend: function(xhr) {
            sending ajax");
            xhr.setRequestHeader("X-OFFICIAL-REQUEST", "TRUE");//Used to ID as a AJAX Request
        },
        complete: function(XMLHttpRequest, textStatus) {
            complete");
        }
    });
}

I'm wondering if it's my url parameter.  I tried using location.href, but that didn't work either.

 
New Post
12/3/2009 4:27 PM
 

 When I have problems like that I use FireFox and FireBug and check the data being sent.

What's the error you get?

 
Previous
 
Next
HomeHomeArchived Discus...Archived Discus...Developing Under Previous Versions of .NETDeveloping Under Previous Versions of .NETASP.Net 2.0ASP.Net 2.0jQuery + ajax + DNN ModulesjQuery + ajax + DNN Modules


These Forums are dedicated to discussion of DNN Platform and Evoq Solutions.

For the benefit of the community and to protect the integrity of the ecosystem, please observe the following posting guidelines:

  1. No Advertising. This includes promotion of commercial and non-commercial products or services which are not directly related to DNN.
  2. No vendor trolling / poaching. If someone posts about a vendor issue, allow the vendor or other customers to respond. Any post that looks like trolling / poaching will be removed.
  3. Discussion or promotion of DNN Platform product releases under a different brand name are strictly prohibited.
  4. No Flaming or Trolling.
  5. No Profanity, Racism, or Prejudice.
  6. Site Moderators have the final word on approving / removing a thread or post or comment.
  7. English language posting only, please.
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out