add logic to _ViewStart.cshtml - c#

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.

Related

Display Each Element From Array Using HTML Helper in C#

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.

MVC razor view - Stop c# code compilation

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.

what is a good way of creating a back button to different 'coming from' pages

I have two different pages, from which a user can click on a 'details' link and go to the details page.
On the details page, I have a 'back' button, which leads the user to the originating page, being one of the two original pages of course.
There is also one extra issue: in one of the return links, I must specify an extra anonymous object.
my view code right now is:
#{
MvcHtmlString backLink = null;
if (Model.ReturnPage == MatchResultReturnPage.Search)
{
backLink = Html.ActionLink("GoBack", "Search", new {search = true});
}
else
{
backLink = Html.ActionLink("GoBack", "Dashboard");
}
}
In the controller I now look in the url.referrer if it contains 'dashboard', then I set the Model.ReturnPage to 'Dashboard'.
Is there a cleaner way of doing this?
Put the ReturnLink as a property on your model and set it inside the controller, which will alleviate the need for you to put that logic in the view.
There are certainly cleaner ways, but as your code is currently, it is very easy to understand what you are trying to do.
I would say keep it as is and simply put a #region wrapper around it and hide it when you don't need to work with it:
#region get referrer page
MvcHtmlString backLink = null;
if (Model.ReturnPage == MatchResultReturnPage.Search)
{
backLink = Html.ActionLink("GoBack", "Search", new {search = true});
}
else
{
backLink = Html.ActionLink("GoBack", "Dashboard");
}
#region
The only thing I would suggest is to have this check in the Controller, rather than the view and simply putting the result of your check either in model property, or in the ViewBag.
To gain access to Helpers in your controller, do the following:
var URL = new UrlHelper(this.Request.RequestContext).Action("MyAction", "MyController", new { id = 123 });
you should probably implement the Back button entirely in JavaScript.
using the history object
<a href=”javascript:history.back()”> [Back]</a>

System.InvalidCastException: in ASP.NET MVC partial views

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?)

Implementing Forms in ASP.net MVC

I have a simple form on a view page, implemented as a user control, that looks something like this:
<%=Html.BeginForm("List", "Building", FormMethod.Post) %>
//several fields go here
<%Html.EndForm(); %>
There are two problems I would like resolved, the first is that I would like the controller method that receives this to take a type parameter of the user control. The goal is to avoid putting all of the fields of the form into the parameter list for the method. The controller method currently looks like this:
[AcceptVerbs("Post")]
public ActionResult List(string capacityAmount)
{
ProfilerDataDataContext context = new ProfilerDataDataContext();
IEnumerable<Building> result = context.Buildings.OrderBy(p => p.SchoolName);
ViewData["Boroughs"] = new SelectList(Boroughs.BoroughsDropDown());
return View(result);
}
The rest of the fields in the form will be used to conduct a search against the buildings type.
The form posts fine, I can search on the capacity the way you would expect, but I can smell ugliness ahead as I add parameters to the search.
Second, smaller problem is that when the page renders the BeginForm tag renders the string "System.Web.Mvc.Form" to the page. How do I make that go away?
1) Use FormCollection as the argument:
public ActionResult List(FormCollection searchQuery)
Now you can iterate the FormCollection and get key/value search terms from your search form.
2) Remove the "=" from BeginForm:
<% Html.BeginForm("List", "Building", FormMethod.Post) %>
That said, you should really be using, um... using:
<% using (Html.BeginForm("List", "Building", FormMethod.Post)) { %>
<% } %>
If I'm understanding your question properly, you use the html helper and create inputs named:
<%=Html.TextBox("building.FieldNumber1")%>
<%=Html.TextBox("building.FieldNumber2")%>
You should be able to access the data using:
public ActionResult List(Building building)
{
...
var1 = building.FieldNumber1;
var2 = building.FieldNumber2;
...
}
and if your action is to do two different things depending on if form is submitted:
public ActionResult List()
{
//some code here
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult List(Building building)
{
...
var1 = building.FieldNumber1;
var2 = building.FieldNumber2;
...
}
if anybody is skeptical about the whole 'using' pattern with Html.BeginForm - realize that the IDE is smart enough to match the opening '{' with the ending '}' which makes it very easy to see where your form begins and ends.
Also <% Html.EndForm(); %> requires a semicolon which I'm not sure i like :)

Categories

Resources