Search code examples
c#jqueryjsonsubsonicnullreferenceexception

NullReferenceException in SubSonic's 2.2 RecordBase.cs after Json request. Why?


I have an MVC project that consumes a WCF service. The service returns a collection of locations that is used to filter for autocomplete in a text box.

I initially tried this with with my own "Person" object to ensure I had the entire thing working.

jQuery call:

    $(function () {

        $("#txtGeoLocation").autocomplete({
            source: function (request, response) {
                $.ajax({
                    url: "/home/FindLocations", type: "POST", dataType: "json",
                    data: { searchText: request.term, maxResults: 10 },
                    success: function (data) {
                        response($.map(data, function (item) {
                            return { label: item.FullName, value: item.FullName, id: item.PersonId }
                            // return { label: item.GeoDisplay, value: item.GeoDisplay, id: item.GeoID }
                        }))
                    }
                })
            },
            select: function (event, ui) {
                alert(ui.item ? ("You picked '" + ui.item.label + "' with an ID of " + ui.item.id)
                    : "Nothing selected, input was " + this.value);
            }
        });

    });

Controller Action:

    [HttpPost]
    public JsonResult FindNames(string searchText, int maxResults)
    {
        PersonRepository repository = new PersonRepository();
        var result = repository.FindPeople(searchText, maxResults);
        return Json(result);

    }

Person repository:

public class PersonRepository
{


    internal List<Person> FindPeople(string searchText, int maxResults)
    {

        List<Person> names = new List<Person>();

        BuildNameList(names);


        var result = from n in names
                     where n.FullName.Contains(searchText)
                     orderby n.FullName
                     select n;

        return result.Take(maxResults).ToList(); 
    }

    private static void BuildNameList(List<Person> names)
    {
        names.Add(new Person { PersonId = 1, FullName = "Kristina H. Chung" });
        names.Add(new Person { PersonId = 2, FullName = "Paige H. Chen" });
        names.Add(new Person { PersonId = 3, FullName = "Sherri E. Melton" });

Worked great... so I replaced my Json call from /home/FindNames to /home/FindLocations and uncommented the following line (commenting out the item.FullName line in my jQuery call):

return { label: item.GeoDisplay, value: item.GeoDisplay, id: item.GeoID }

Here is my controller action:

    [HttpPost]
    public JsonResult FindLocations(string searchText, int maxResults)
    {
        GeoLocationRepository repository = new GeoLocationRepository();
        var result = repository.FindGeo(searchText, maxResults);

        return Json(result);    // returned a list collection of geo locations
    }

My repository method:

    internal List<FeederService.GeoLocation> FindGeo(string searchText, int maxResults)
    {
        // get geolocations from the cache

        var result = from l in HttpRuntime.Cache["WebsiteGeoLocations"] as FeederService.GeoLocationCollection
                     where l.GeoDisplay.Contains(searchText)
                     orderby l.GeoDisplay
                     select l;

        return result.Take(maxResults).ToList();
    }

Everything seems to work just fine until the end of the action method:

return Json(result);    // returned a list collection of geo locations

There is in fact the right collection with the right number of items in it, but nothing returned to my client. VS pops up with the SubSonic file RecordBase.cs and a null reference exception at the get call of public string TableName:

    /// <summary>
    /// Name of the table in the database that contains persisted data for this type
    /// </summary>
    /// <value>The name of the table.</value>
    [XmlIgnore]
    [HiddenForDataBinding(true)]
    public string TableName
    {
        get { return BaseSchema.TableName; }  // <--- error occurs here
    }

Is this happening due to some entity reference issue, as I am the referencing FeederService.GeoLocation object and how can I get this to work?

The entities are all in a DAL project, referenced from and exposed through my FeederService: GeoLocationCollection [CollectionDataContract]

[Serializable]
[CollectionDataContract]
public partial class GeoLocationCollection : ActiveList<GeoLocation, GeoLocationCollection>
{      
    public GeoLocationCollection() {}

And I've added [DataContract] to GeoLocation.

I have also placed "debugger;" in my jquery code (moved it into the function), but I am unable to debug the data returned. How can I accomplish this?

Lastly, the issue only occurs when there is a match in the collection.


Solution

  • I've managed to solve the problem, although not as elegant as I wanted it to be, and I would still like to know why I was having issues referencing a class exposed through my service.

    For the solution, I created a WebsiteGeoLocation model class that has some of the properties of the FeederService.GeoLocation class.

    I then iterated through the collection, and copied the values into my new local object. Works just fine. I will be moving the copy functionality into the caching method, so the object returned is always of the local type.

        List<WebsiteGeoLocation> geoList = null;
    
        internal List<WebsiteGeoLocation> FindGeo(string searchText, int maxResults)
        {
            // get geolocations from the cache
    
            var result = from l in HttpRuntime.Cache["WebsiteGeoLocations"] as FeederService.GeoLocationCollection
                         where l.GeoDisplay.Contains(searchText)
                         orderby l.GeoDisplay
                         select l;
    
            geoList = new List<WebsiteGeoLocation>();
    
            foreach (FeederService.GeoLocation location in result)
            {
                geoList.Add(new WebsiteGeoLocation
                {
                    GeoID = location.GeoID,
                    GeoDisplay = location.GeoDisplay,
                    GeoCity = location.GeoCity,
                    GeoState = location.GeoState,
                    WebsiteID = location.WebsiteID,
                    WorldCitiesID = location.WorldCitiesID
                });
            }
    
            return geoList.Take(maxResults).ToList();
        }