6

I'm getting a 500 internal server error when I click on an Ajax.ActionLink. I have a profile page that's made up of a number of partials. Each partial makes Ajax calls to the server to allow for editing of user information related to that specific partial.

I've implemented 3 partials with said functionality that work fine. The one I'm working on now should initially show a list of uploaded images - if the user hasn't uploaded any images the Ajax.ActionLink mentioned previously will be shown, which when clicked will bring the user to a partial that facilitates image uploading.

Here's what I'm seeing in Chrome when I hit the link:

enter image description here

Here's the GET and POST ActionResults:

    //
    // GET: /Tenants/TenantUploadReference

    [HttpGet]
    public ActionResult TenantUploadReference()
    {
        try
        {
            var currentTenant = tenantRepository.GetLoggedInTenant();
            if (currentTenant.ReferencePhotos == null)
            {
                currentTenant.ReferencePhotos = currentTenant.ReferencePhotos ?? new List<ReferencePhoto>();
            }
            return PartialView("_TenantUploadReferencePartial", currentTenant.ReferencePhotos.ToList());
        }
        catch (Exception e)
        {
            ModelState.AddModelError("", e);
            return View();
        }
    }

    //
    // POST: /Tenants/TenantUploadReference

    [HttpPost]
    public ActionResult TenantUploadReference(HttpPostedFileBase file, Tenant tenant)
    {
        try
        {
            if (file != null)
            {
                if (file.ContentLength > 10240)
                {
                    ModelState.AddModelError("file", "The size of the file should not exceed 10 KB");
                    return View();
                }

                var supportedTypes = new[] { "jpg", "jpeg", "png", "JPG", "JPEG", "PNG" };
                var fileExt = System.IO.Path.GetExtension(file.FileName).Substring(1);

                if (!supportedTypes.Contains(fileExt))
                {
                    ModelState.AddModelError("photo", "Invalid type. Only the following types (jpg, jpeg, png) are supported.");
                    return View();
                }

                using (var db = new LetLordContext())
                {
                    var reference = db.Image.Create<ReferencePhoto>();

                    // Convert HttpPostedFileBase to byte array
                    MemoryStream target = new MemoryStream();
                    file.InputStream.CopyTo(target);
                    byte[] photo = target.ToArray();

                    reference.File = photo;
                    reference.Format = fileExt;
                    reference.DateUploaded = DateTime.Now.Date;
                    reference.Description = "";
                    reference.Name = "";

                    db.Image.Add(reference);
                    db.SaveChanges();

                    return PartialView("_TenantReferencePhotosPartial", file);
                }

            }
            else
            {
                return View();
            }
        }
        catch (Exception e)
        {
            ModelState.AddModelError("", e);
            return View();
        }
    }

When I step through the debugger with a break point on the GET ActionResult it hits return PartialView and no exceptions are thrown.

In _TenantUploadReferencePartial I use

@using (Ajax.BeginForm("TenantUploadReference", "Tenants", FormMethod.Post, new AjaxOptions { InsertionMode = InsertionMode.Replace, HttpMethod = "POST", UpdateTargetId = "tenant-reference-photos" }))

and in _TenantReferencePhotosPartial (where the ActionLink throws 500 error) I use this

@if (Model.ReferencePhotos == null)
{
    <h3>You haven't uploaded any references! 
        @Ajax.ActionLink("Upload now?",
            "TenantUploadReference",
            new AjaxOptions
            {
                UpdateTargetId = "tenant-reference-photos",
                InsertionMode = InsertionMode.Replace,
                HttpMethod = "GET",
                LoadingElementId = "ajax-loader"
            })</h3>

It may also be useful to know that other partials on the page work as expected, so I don't think it's an issue with missing scripts. I'm at a loss as to why this is happening - a solution would be much appreciated.

pnuts
  • 58,317
  • 11
  • 87
  • 139
MattSull
  • 5,514
  • 5
  • 46
  • 68
  • I find it interesting that your GET action will never return null for Model.ReferencePhotos, but you still test for null on the view. What happens in the else in the view? And are you sure the get method don't simply try/catch and return View() with Model = null? – Jani Hyytiäinen Mar 23 '13 at 15:05
  • I was getting a NullReferenceException in the GET, and upon investigating I read that using null coalescing operators can remedy that in this type of situation. Do I even need to test for null before using the operator? The else will display references photos if the user has any, if they don't (the if) app displays ActionLink to user. To reconfirm, I've just stepped through the GET with the debugger, Model isn't null and return PartialView is being hit. – MattSull Mar 23 '13 at 15:18
  • Sorry I've just realised what you meant, it makes sense - about never returning null and still testing for it in the view. The reason I was using the operator in the GET was to deal with the NullReferenceException. – MattSull Mar 23 '13 at 15:27
  • Exception type is actually ArgumentNullException. – MattSull Mar 23 '13 at 15:34

1 Answers1

4

I've solved the problem. I was returning currentTenant.ReferencePhotos.ToList() which threw a ArgumentNullException. Now I'm returning just currentTenant, and the GET is working as expected.

MattSull
  • 5,514
  • 5
  • 46
  • 68
  • 1
    glad it is fixed, however two things. you shouldnt have checks for `currentTenant.ReferencePhotos == null` - the standard is to `new` this list (or any list) in the objects constructor. Secondly, you should have elmah enabled for your web app; this will log any 500 errors and most likely would have made this bug very obvious (you shouldnt be debugging these bugs from the browser side) – wal Mar 23 '13 at 16:13
  • Thanks for the advice. ReferencePhotos is an ICollecetion (I'm using code first), can that be instantiated in the object constructor in the same way a list can? I actually read about elmah before, thanks for reminding me, I'll make sure to enable it. – MattSull Mar 23 '13 at 16:20
  • yes, if its an `ICollection`, in your ctor you can simply go `ReferencePhotos = new List( );` because List implements `ICollection` – wal Mar 23 '13 at 16:34
  • 1
    you need to turn this on too, always :) http://stackoverflow.com/questions/9976099/is-there-a-setting-to-show-me-when-an-exception-is-caught?lq=1 – wal Mar 23 '13 at 16:38