简体   繁体   中英

Unable to display LINQ query output values from controller to view

Controller

public ActionResult Track(string awb)
    {
        ViewBag.Title = "Track Your Shipment";
        ViewBag.ErrorMessage = string.Empty;
        ViewBag.ShipmentNo = awb;
        FLCourierDetail trackOutput = new FLCourierDetail();

        if (awb != null)
        {
            trackOutput = db.FL_CourierDetail.SingleOrDefault(fLCourierDetail => fLCourierDetail.AWBNumber == awb);
            if (trackOutput != null)
            {
                var courierId = db.FL_CourierDetail.Where(s => s.AWBNumber == awb).Select(s => s.Courier);
                var currentStatus = (from c in db.FL_CourierDetail
                                     join s in db.FL_CourierStatus
                                     on c.Courier equals s.CourierId
                                     where c.AWBNumber == awb
                                     select new { awb = c.AWBNumber, staus = s.StatusId, updated = s.StatusId, remark = s.Remark }).ToList();
                ViewBag.CurrentStatus = currentStatus;
            }
            else
            {
                ViewBag.ErrorMessage = "Shipment number not found.";
            }
        }
        else
        {
            ViewBag.ErrorMessage = "Please provide valid Shipment number.";
        }

        return View(trackOutput);
    }

View

       <div class="col-md-6">
            @{ 
                var status = ViewBag.CurrentStatus;

                foreach (var item in status)
                {
                    <p>@item</p>
                }
            }
        </div>

If I iterate using foreach or if loop I am able to see the data in debug, but I am not able to write in html.

Debug

在此处输入图片说明

Web Page

在此处输入图片说明

Error

I am not able to read each value like awb, status, date etc.

在此处输入图片说明

Did I miss anything here?

The query result is an anonymous class, within the loop, each item is an object and thus the exception, object has now awb property.

One way to solve this is by defining a class:

public class Status {
    public string awb { get; set; }
    public int staus { get; set; }
    public int updated { get; set; }
    public string remark { get; set; }
}

Then your select would look like:

... select new Status { awb = c.AWBNumber, staus = s.StatusId, updated = s.StatusId, remark = s.Remark }).ToList();

Then, within the View:

var status = (List<Status>) ViewBag.CurrentStatus;

Another possible solution is to use strongly typed view model

Firstly, you could create a Model class for returned data;

var currentStatus = (from c in db.FL_CourierDetail
    join s in db.FL_CourierStatus
        on c.Courier equals s.CourierId
    where c.AWBNumber == awb
    select new CurrentStatus  { awb = c.AWBNumber, staus = s.StatusId, updated = s.StatusId, remark = s.Remark }).ToList();

public class CurrentStatus
{
    public string awb { get; set; }

    public int staus { get; set; }

    public int updated { get; set; }

    public string remark { get; set; }
}

Secondly, you can't get output an entire object, you should specify properties which you want to display;

<div class="col-md-6">
            @{ 
                var status = (List<CurrentStatus>) ViewBag.CurrentStatus;

                foreach (var item in status)
                {
                    <p>@item.awb</p>
                    <p>@item.staus</p>
                    <p>@item.updated</p>
                    <p>@item.remark</p>

                }
            }
</div>

This is really strange, but in console application the following code actually works :

dynamic even = new List<int> { 1, 2, 3, 4 }
              .Where(x => x % 2 == 0)
              .Select((x, index) => new { Position = index, Num = x });

// Output:
// Position: 0, Number: 2
// Position: 1, Number: 4
foreach (dynamic item in even)
{
    Console.WriteLine($"Position: {item.Position}, Number: {item.Num}");
}

However, in ASP.NET ths doesn't work, and I don't really understand because ViewBag is dynamic, too.

UPDATE

Same question was asked here . A quote from there:

You're returning an instance of an anonymous type. If you weren't using dynamic , your only choice here would be to return an object - the anonymous type is unknown outside of your own function. If you had a variable of type object , you'd get a compile time error that it doesn't have a LogoName property. All you've done with dynamic is defer exactly the same lookup rules until runtime. At runtime, the best type that can be determined is object .

As this answer states, the following must not work, but it works :

static void DoWork()
{
    dynamic evens = GetEvens();
    foreach (dynamic item in evens)
        Console.WriteLine($"Position: {item.Position}, Number: {item.Num}");

}

static dynamic GetEvens() =>
    new List<int> { 1, 2, 3, 4 }
    .Where(x => x % 2 == 0)
    .Select((x, index) => new { Position = index, Num = x });

In this case I return dynamic. However, the code work correctly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM