In the controller:
public ActionResult Index()
{
ViewData["page"] = 0;
return View(data);
}
public ActionResult More(long page = 0)
{
ViewData["page"] = page;
return View(data);
}
So, I have two views: Index.aspx and More.aspx. I created a partial view (PartialView.ascx) that is used in both of the views. Inside the partial view, it accessed both Model and ViewData. The strange thing (to me anyway) is that when I tried to cast ViewData["page"] to a long, I would get the following casting exception for one of the views:
System.InvalidCastException: Specified cast is not valid.
I tried to cast the ViewData["page"] like the following:
if ((long) ViewData["page"] > 1) { ... }
and
long page = (long) ViewData["page"];
if (page > 1) { ... }
Each of them would throw a casting exception in one view of the other (but not both).
One difference between Index.aspx and More.aspx is that Index.aspx uses a master page, and More.aspx does not.
Would anyone have any suggestion what may be wrong? Please let me konw if I need to provide more details. BTW, I'm farily new to C# and ASP.NET MVC.
This line:
ViewData["page"] = 0;
is setting the value to be a boxed int. You're trying to unbox it to a long. The simplest way to avoid this is to box to a long to start with:
ViewData["page"] = 0L;
... or use int for your page number to start with. (Are you really going to get more than int.MaxValue pages?)
Related
This is probably a very simple problem, but I am extremely new to C# / MVC and I have been handed a broken project to fix. So it's time to sink or swim!
I have an array of strings that is being passed from a function to the front end.
The array looks something like
reports = Directory.GetFiles(#"~\Reports\");
On the front end, I would like it to display each report, but I am not sure how to do that.
This project is using a MVC, and I believe the view is called "Razor View"? I know that it's using an HTML helper.
In essence, I need something like
#HTML.DisplayTextFor(Model.report [And then print every report in the array]);
I hope that makes sense.
If you want to display the file name array you can simply use a foreach:
#foreach(var report in Model.Reports){ #report }
Note that you should add the Reports property to your view model:
public class SampleViewModel
{
public string [] Reports { get; set; }
}
You could use ViewData or TempData but I find that using the view model is the better way.
You can then populate it:
[HttpGet]
public ActionResult Index()
{
var model = new SampleViewModel(){ Reports = Directory.GetFiles(#"~\Reports\")};
return View(model);
}
And use it in the view as you see fit.
Here is a simple online example: https://dotnetfiddle.net/5WmX5M
If you'd like to add a null check at the view level you can:
#if(Model.Reports != null)
{
foreach(var report in Model.Reports){ #report <br> }
}
else
{
<span> No files found </span>
}
https://dotnetfiddle.net/melMLW
This is never a bad idea, although in this case GetFiles will return an empty list if no files can be found, and I assume a possible IOException is being handled.
I'm working on an ASP.Net MVC project, and I've hit a (seemingly) very strange error. I have a model named Lens, here is the class structure for it
public class Lens
{
public int LensID { get; set; }
public string LensName { get; set; }
}
In one of my views, I have a list of lenses (acquired in controller). I'm getting an ArgumentOutOfRangeException in the following code snippet
#for (int i = 0; i < Lenses.Count; i++)
{
<input type="text" data-LID="#Lenses[i].LensID" value="#Lenses[0].LensName" readonly id="lens #i" />
}
Lenses is the list I get from the controller. I really can't understand why this code is throwing an exception. I looked at the Locals view in my debugger and found that, at the time that the exception is thrown, the value of the argument i is 0, and there is a Lens object at index 0 of Lenses. Even stranger, when I use a foreach loop to pull from the exact same list, it has no issue retrieving the object. I've also tried
#Lenses[0].LensID
Instead, and I got the same error. Also, in case it's relevant. According to the Locals view, the Lenses list has a Count of 1. Here's the creation of Lenses
List<Lens> Lenses = (List<Lens>)ViewBag.Lenses;
And here's how it's being sent to the View from Controller
LensQueries lQuery = new LensQueries();
ViewBag.Lenses = lQuery.GetAll();
And here's the reference for LensQueries.GetAll()
public List<Lens> GetAll()
{
List<Lens> retList;
using (var context = new SqlDbContext())
{
retList = context.Lenses.SqlQuery("select *from dbo.Lens").ToList<Lens>();
}
return retList;
}
Found the solution (kinda?). Still have no idea why it was breaking but when I went into my references and deleted certain assemblies, the issue went away.
For anyone curious, the assemblies I removed were the Owin.Security.Providers assembly, as well as all of it's sub-assemblies.
is there a way to add logic in the _ViewStart.cshtml file to drive which _Layout file to use?
Conceptually, I want to do the code below (ViewBag.Context is determined in the Home controller). But I get a red squiggly under ViewBag (does not exist in current context). I guess this is a problem because this view page doesn't know which controller/method is calling it.
#{if (ViewBag.Context == "AA")
{
Layout = "~/Views/Shared/_Layout_AA.cshtml";
}
else
{
Layout = "~/Views/Shared/_Layout.cshtml";
}
}
FWIW, you can also do this in the controller:
if (someCondition == "AA")
{
return View("MyView", "~/Views/Shared/_Layout_AA.cshtml");
}
else
{
return View ("MyView", "~/Views/Shared/_Layout.cshtml");
}
Use the PageData property (it's something more applicable to ASP.NET WebPages and seldom used in MVC)
Set:
#{
PageData["message"] = "Hello";
}
Retrieve
<h2>#PageData["message"]</h2>
Source: How do I set ViewBag properties on _ViewStart.cshtml?
Use a ternary operator:
#{
Layout = ViewBag.Context == "AA" ? "~/Views/Shared/_Layout_AA.cshtml" : "~/Views/Shared/_Layout.cshtml" ;
}
Some of you are not seeing "But I get a red squiggly under ViewBag (does not exist in current context). I guess this is a problem because this view page doesn't know which controller/method is calling it."
My solution was to embed the value in a cookie while in the controller at the start. Then in the _ViewStart.cshtml file, I retrieve the cookie value and can now use it to dictate my layout logic.
I have a razor view showing details of a Hotel.
model for the view:
#model MySite.MyViewModels.Hotel
Have to show many details segments of the hotel. So, I have to check null for the Model on each segment. Is it possible if I can check once for all and stop the compilation of c# code if it is null.
You can say on top of the view If I can write something like:
#If(Model==null || Model.RoomsAvailable.Count<1)
{
//Don't read c# code on rest of the view now
}
Hope it make sense.
In your controller:
pubilc ActionResult YourAction()
{
if (null == YourModel)
{
return View(SomeEmptyView); // or return null
}
return View(Some legitimate view);
}
By that, you don't need to add logic to your view and you get what you wanted.
I'm working on a piece of code that shows a random sponsor image on each webpage. I figured that the best place to call my function is in the Views/Shared/_Layout.cshtml page, because that's the one that loads at every page.
I wrote the function in a service class in my domain model, and wrote a ChildActionOnly function in my homecontroller, returns the value in a simple view in Views/Home/Randomsponsor.cshtml and called the function in the shared layout with a Html.action.
Everything builds fine, but while running i get the next error:
{"The controller for path '/' was not found or does not implement IController."}
Does anyone know how to fix this one?
Method in the domain project:
public String advertsForCountry()
{
String studentSchool = finder.getLoggedStudent().SchoolId;
int studentCountry = db.Schools.Find(studentSchool).CountryId;
List<Sponsor> sponsorsForStudent = new List<Sponsor>();
List<Advert> adverts = db.Adverts.ToList();
foreach(Advert adv in adverts)
{
foreach(Country cntry in adv.Countries)
{
if(cntry.CountryId == studentCountry)
{
sponsorsForStudent.Add(adv.Sponsor);
}
}
}
Random random = new Random();
int randomSP = random.Next(0, sponsorsForStudent.Count()-1);
string sponsorAdvert = sponsorsForStudent.ElementAt(randomSP).SponsorCompany;
return sponsorAdvert;
}
In HomeController:
[HttpGet]
[ChildActionOnly]
public ActionResult RandomSponsor()
{
var model = service.advertsForCountry();
return PartialView("RandomSponsor", model);
}
Simple view in Views/Home/ :
#{
ViewBag.Title = "RandomSponsor";
}
#Html.Action("RandomSponsor")
And my function call in the View/Shared/_Layout.cshtml whitch contains the navigation bar, etc:
#Html.Action("RandomSponsor", "HomeController")
Regards.
(Converted from comment)
You don't need to specify the full class name of the Controller in Html.Action. Try using #Html.Action("RandomSponsor", "Home") instead of #Html.Action("RandomSponsor", "HomeController").
You are missing the name of the controller. Please note, when you create a controller and called it Alexie, by default MVC will name it AlexieController. Therefore, when you are calling a function within a controller, it should be like this:
#Html.Action("Function Name", "Alexie").
And not like this:
#Html.Action("Function Name", "AlexieController").
So, I agreed with wgraham's answer.