views:

419

answers:

2

I'm using the Telerik PanelBar to do some asynchronous loading using a partial view. I'm creating a model for the partial view in a parent view, but for some reason my data isn't coming through in tact.

// Parent view
<% Html.Telerik().PanelBar().Name("PanelBar").HtmlAttributes(new { style = "padding-left: 0em;" }).Items(items =>
{
    foreach (var item in Model.Visits)
    {
        SiteVisitDetailModel model = new SiteVisitDetailModel();
        model.URL = item.Key; // this is properly set
        model.Dates = new List<DateTime>(); // this is null in the controller
        model.Dates.Add(DateTime.Now);

        items.Add()
            .Text(item.Key.ToString() + " " + item.Count().ToString() + " visits")
            .LoadContentFrom("SiteViewDetail", "Report", model);

    }
}).Render();



  // Report controller method
    public ActionResult SiteViewDetail(SiteVisitDetailModel model)
    {
        return PartialView(model); // model.URL is correct, model.Dates is null
    }

    // Model
    public class SiteVisitDetailModel
    {
        public String URL
        {
            get;
            set;
        }

        public List<DateTime> Dates
        {
            get;
            set;
        }
    }

As suggested by my comments, when the controller's SiteVisitDetail method is called, Model.URL has the correct data, and Model.Dates is null (it's not a list containing null, it itself is null). It, as would be expected, is also null in the partial view (SiteViewDetail).

What would cause this behavior?

+1  A: 

I've not used Telerik MVC controls yet myself but looking at the API for LoadContentFrom it seems this method (and all its overload) will do a GET request at a certain URL. The overload that takes an object to pass parameters more then likely doesn't know how to serialize Lists (inspecting HTTP traffic will give more details).

Your only option is to use the LoadContentFrom(String) method and pass it a formatted list of dates as string:

var dateArray = model.Dates.Select(d => d.ToString()).ToArray();
var serializedDateString = String.Join("#", dateArray);
items.Add()
        .Text(item.Key.ToString() + " " + item.Count().ToString() + " visits")
        .LoadContentFrom(Url.Action("SiteViewDetail","Report" new { dates = serializedDateString, url = model.URL}))

Then your controller should look something like this:

public ActionResult SiteViewDetail(string dates, string url)
    {
        SiteVisitDetailModel model = new SiteVisitDetailModel();
        //split dates back into a List<DateTime>
        model.Dates = dates.Split('#').Select(s => DateTime.Parse(s)).ToList<DateTime>();
        model.URL = url;
        return PartialView(model); 
    }

It's a hack (or at least not very pretty) but it'll work.

Martijn Laarman
You know what's really weird? I'd actually tried that earlier, and had the same problem. the date string ended up null as well. I tried it just now again (only I just set the string to "biscuits", my favorite test word), and again, it's null, while URL is properly set. And I did remember to change the property type in the model. So the fact that this happens with a simple string type, and that others have suggested that you can pass a list this way, makes me think something else is going wrong here.
Mike Pateras
`Url.Action` can't serialize `List<T>`'s to GET strings either so I'm not surprised Telerik doesn't support it either. You can POST `List<T>` just fine however. Can you update your question with the updated code using this work around ? Maybe another set of eyes might spot where it goes wrong :)
Martijn Laarman
URL is a string, and that seems to be working.Seriously, all I did was change the model from public List<String> Dates to public String Dates, and the view from model.Dates = new List<DateTime>() (and remove the line below that) to model.Dates = "biscuits". In the controller method, model.URL (a string) is the proper value, and model.Dates (now also a string) is null.
Mike Pateras
Sounds like it should work indeed. Fire up a HTTP traffic analyzer (such as fiddler) and see what HTTP request is actually fired. This might help determing where the modelbinder is screwing up. Did you try out the `LoadContentFrom(String)` overload in combination with `Url.Action` instead also?
Martijn Laarman
Yeah, I've tried Url.Action. No difference. Fiddler doesn't seem to pick up any requests, except for the one that the partial view makes to Google (unrelated to this problem). I've never used it before, though, so perhaps I need to set differently for it to view local requests?
Mike Pateras
Yeah you need to open the page using `localhost.:<port>` or `127.0.0.1.:<port>` note the added `.`. Also check `Hide Image Requests` under `Rules` in the menu bar.
Martijn Laarman
A: 

It turns out the query string being built isn't correct. It's generating something like:

?value1=somevalue&amp;value2=whatever

So while the value is there and correct, it's not getting parsed properly because of that amp;.

I'm guessing this is a problem with the Telerik control. I'll report the bug and see what they say.

Since that appears to be the problem, I'm just going to concatenate everything into one big string and parse it in the controller, until a more formal solution can be found.

Thanks for your help, Martijn.

Mike Pateras
Telerik has responded, confirmed that there is a bug, and said that it will be fixed in the next version.
Mike Pateras