Finding Content/Items

Topics: Developer Forum
Apr 15, 2009 at 11:33 AM
Hi all,

I am having a problem with finding items using an Addon I am trying to develop.

I used this reference to help me find the items I will need: http://n2cms.com/Documentation/Manipulating%20content/Finding%20content.aspx

In my EnquiryManager addon, I have created an EnquiryManager.cs and an Enquiry.cs, in the plugins folder a EnquiryList.aspx with code behind which will create an enquirymanager object and getEnquiries() to return the items in the database.

I get the following error when I attempt to get Enquiries..

Object reference not set to an instance of an object.

Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Line 13: 		{
Line 14: 			// find and return all the enquiries
Line 15: 			IList<ContentItem> result = N2.Find.Items.Where.Type.Eq(typeof(Enquiry)).Select();
Line 16: 			
Line 17:
Stack trace:
[NullReferenceException: Object reference not set to an instance of an object.]
   N2.Persistence.NH.Finder.QueryBuilder.GetDiscriminator(Type value) +16
   N2.Persistence.NH.Finder.PropertyClassCriteria.Eq(Type value) +51
   N2.Addons.EnquiryManager.Items.EnquiryManager.getEnquiries() in C:\inetpub\wwwroot\life\Addons\EnquiryManager\Items\EnquiryManager.cs:15
   N2.Addons.EnquiryManager.Plugins.EnquiryManager.Page_Load(Object sender, EventArgs e) in C:\inetpub\wwwroot\life\Addons\EnquiryManager\Plugins\EnquiryList.aspx.cs:26
   System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
   System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
   System.Web.UI.Control.OnLoad(EventArgs e) +99
   System.Web.UI.Control.LoadRecursive() +50
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +627
My code (that causes the error) uses the N2.Find api methods, is it that I am unable to use these within my Addon? Is it some kind of bug as the Enquiry item will not currently exist in the database. If it can't find the object, surely it should return null rather than continue calling methods (this might not be happening obviously).

Any help appreciated (quicker the better).
Cheers
Pete
Apr 15, 2009 at 12:04 PM
Does your class have a definition attribute?

Did you change the name in the definition attribute or the class name to something different after you allready saved it in the DB?
Apr 15, 2009 at 1:16 PM
Edited Apr 15, 2009 at 1:33 PM
Previously it didn't have any [Definition] attributes, I have since added them but this has not solved the problem:

[Definition("Enquiry Manager", "EnquiryManager", "Represents a Management Addon for handling Enquiries.", "Enquiry Manager Addon.", 1)]

I have also tried changing the statement as I was getting warnings about accessing static types via derived types:

IList<ContentItem> result = GenericFind<ContentItem, StartPage>.Items.Where.Type.Eq(typeof (Enquiry)).Select();
then..
return GenericFind<ContentItem, StartPage>.Items.Where.Type.Eq(typeof (Enquiry)).Select();

Rather than testing the result, just return it (if it might be an empty list that's fine). Still getting the error !! eeek!

The items don't exist in the database at the moment, ideally I would want an empty list or null to be returned from the find.
Coordinator
Apr 16, 2009 at 8:09 PM
I changed the null reference exception into something friendlier.

However I didn't manage to reproduce your other errors. Are you sure you're getting the same error? Can you spot anything different in the last two unit tests here:

http://code.google.com/p/n2cms/source/browse/trunk/src/N2.Tests/Persistence/NH/ItemFinderTests.cs


Apr 17, 2009 at 9:43 AM
The only difference I can see is the way the finder is created.. I didn't create a finder variable simpy tried to return this:

return GenericFind<ContentItem, StartPage>.Items.Where.Type.Eq(typeof(Enquiry)).Select();

From the example in the unit test I don't understand how I can implement a finder the same way as your code uses 'engine' which I don't know how to get access to.

If there are no items of the type I am searching for (once I get this working) will I just get an empty list returned rather than null? What did you mean you changed it (is this in a pre-release version you are working on)?

Please help! :)
Thanks
Pete
Apr 17, 2009 at 10:39 AM
I also tried this, but to no avail:

    var engine = N2.Context.Current;
    var sessionProvider = engine.Resolve<ISessionProvider>();
    var finder = new ItemFinder(sessionProvider, N2.Context.Current.Definitions);
    return finder.Where.Type.Eq(typeof(Enquiry)).Select();

Coordinator
Apr 18, 2009 at 8:56 PM
The only thing I can think of is that Enquiry for some reason isn't picked up as a content item by the system. Does it appear in the list on /edit/install/diagnose.aspx? Can you post the code for that class?
Apr 20, 2009 at 8:23 AM
Hi! It doesn't seem to be showing up on that page :(

Code for the enquiry:

namespace N2.Addons.EnquiryManager.Items
{
    [Definition("Enquiry", "Enquiry", "Represents an Enquiry item in the system.", "User submitted enquiry.", 1)]
    public class Enquiry
    {
        public string name { get; set; }
        public string email { get; set; }
        public string message { get; set; }

        // TODO: add validation for email, strip bad HTML etc from fields? or is this done on the form that represents this.
    }
}


Enquiry Manager:

[Definition("Enquiry Manager", "EnquiryManager", "Represents a Management Addon for handling Enquiries.", "Enquiry Manager Addon.", 1)]
    public class EnquiryManager
    {
        public IList<ContentItem> Enquiries
        {
            get { return GenericFind<ContentItem, StartPage>.Items.Where.Type.Eq(typeof(Enquiry)).Select(); }
        }
    }

EnquiryList.aspx.cs:

namespace N2.Addons.EnquiryManager.Plugins
{
    /// <summary>
    /// This class describes the object that manages user enquiries from the website
    /// </summary>
    [ToolbarPlugin( // The toolbar plugin attribute tells N2 to put an icon in the toolbar
        "", // we don't want any text (only icon)
        "EnquiryManager", // this is a string that uniquely identifies the plugin
        "~/Addons/EnquiryManager/Plugins/EnquiryList.aspx?selected={selected}", // this is the url to the page that represents our plugin, {selected} is replaced by the path of the selected item
        ToolbarArea.Preview, // we want to put the icon the right hand toolbar area
        "preview", // this is the preview frame
        "~/Addons/EnquiryManager/UI/Img/enquiry.png", // the icon to show in the toolbar
        1000)] // the order in the toolbar
    public partial class EnquiryManager : EditPage
    {   
        protected void Page_Load(object sender, EventArgs e)
        {
            // get enquiries
            var myEnquiryManager = new Items.EnquiryManager();
            var myEnquiryList = myEnquiryManager.Enquiries;
            // bind enquiries
            rptEnquiries.DataSource = myEnquiryList;
            rptEnquiries.DataBind();
        }
    }
}
Coordinator
Apr 21, 2009 at 5:06 PM
The problem is that N2 doesn't recognize your classes as content items since they must derive from N2.ContentItem.

Try changing:
public class Enquiry : N2.ContentItem
Apr 22, 2009 at 8:24 AM
Oh what an absolute clanger! :)

Thanks mate.