I have this test page. This is the action method.
public ActionResult TestView()
{
ViewData["Test"] = "1";
return View("TestView");
}
In TestView.cshtml, I have this line of code
#ViewData["Test"]
It is coming up as null, it is not printing the "1".
Any idea what I am doing wrong?
Thanks.
MV3 have ViewBag as a new object that can hold the dynamic properties as Key/Value pair.
So you can directly assign a property using ViewBag. For e.g. -
In your action in controller you can write something like
ViewBag.Message = "1";
Now to retrieve the value you can write in your .cshtml
<h2>#ViewBag.Message</h2>
Related
My view looks like this
My url link http://localhost:63897/UploadImages?id=1361. 1361 is my pr_id. I need to pass the id which is 1361 from url to database, but it is going null.
Here is my controller code:
public ActionResult UploadImages(int id) {
ViewBag.prid = id;
return View();
}
[HttpPost]
public ActionResult UploadImages([Bind(Include = "id,photo_url,photo_caption,photo_credit,pr_id")] Photo photos, HttpPostedFileBase photo_file)
{
if (ModelState.IsValid)
{
if (photo_file != null && photo_file.FileName != null && photo_file.FileName != "")
{
try
{
string path = Path.Combine(Server.MapPath("~/Images/Releases"), Path.GetFileName(photo_file.FileName));
photo_file.SaveAs(path);
string f1 = path.Substring(path.LastIndexOf("\\"));
string[] split = f1.Split('\\');
string newpath = split[1];
string imagepath = "~/Images/Releases/" + newpath;
photos.photo_url = imagepath;
_db.Photos.Add(photos);
_db.SaveChanges();
}
catch (Exception ex)
{
ViewBag.Message = "ERROR:" + ex.Message.ToString();
}
return RedirectToAction("List");
}
}
return View();
}
View :
#Html.HiddenFor(model => model.pr_id, new { #Value = ViewBag.id })
Your view bag dictionary item's key is prid. But in your view code you are using a different key.
Use ViewBag.prid. Also use the Hidden helper method.
#Html.Hidden("pr_id", new { #value = ViewBag.prid })
Or just write plain HTML and set the value attribute value.
<input type="hidden" name="pr_id" value="#ViewBag.prid" />
Check the view source of the page to confirm the correct value attribute is set to the hidden input element with name pr_id
Assuming you fixed the wrong ViewBag key name, your existing approach will basically generate the below markup
<input Value="23" name="pr_id" type="hidden" value="0" />
Remember, Value != value
This is one major reason i do not use dynamic stuff like ViewBag. You make a silly mistake like this and there are no warnings/errorrs from the IDE/compiler. It just silently fails :( If you use a strongly typed view model, the compiler will complain when you make a silly typo.
Also do not use the *For method and try to manually overwrite the value/id/name etc. The helpers are designed to set the value/name/id attribute values properly. Consider using a view model and use these For methods with them. That will be less code.
If your view model has a property called pr_id, set that property value in your GET action, send that view model to the view and in the view(which is strongly typed to this view model), simply call HiddenFor method on that property
#Html.HiddenFor(a=>a.pr_id);
I am storing a value in dynamic property called login in my Login action method in my controller and I am accessing the value of the viewbag in Index view. I am gettng the value as null. Why is this so.?
Following is my code which is in controllers Login action method.
ViewBag.Login = "false";
return RedirectToAction("Index");
here is my code which I am using in the Index view(cshtml).
#if (#ViewBag.Login != "")
Here in view I am getting #ViewBag.Login's value as null. Even if i remove the # symbol like this
ViewBag.Login Still I get value as null.
Please help. ViewBag should persist value within view's and action methods which are bind to same controller.
ViewBag does not persist across http requests.
You could do
public ActionResult Login()
{
/* Pass `Login` by QueryString */
return RedirectToAction("Index", new { Login = false });
}
public ActionResult Index(bool Login)
{
/* Read from QueryString, and pass the value to `ViewBag` */
ViewBag.Login = Login;
return View();
}
The ViewBag won't survive across a RedirectToAction. You can use TempData, which can be accessed exactly once:
TempData["Login"] = "false";
return RedirectToAction("Index");
ViewData and ViewBag allows you to access any data in view that was passed from controller.
The main difference between those two is the way you are accessing the data.
In ViewBag you are accessing data using string as keys - ViewBag[“numbers”]
In ViewData you are accessing data using properties - ViewData.numbers.
ViewData example
CONTROLLER
var Numbers = new List<int> { 1, 2, 3 };
ViewData["numbers"] = Numbers;
VIEW
<ul>
#foreach (var number in (List<int>)ViewData["numbers"])
{
<li>#number</li>
}
</ul>
ViewBag example
CONTROLLER
var Numbers = new List<int> { 1, 2, 3 };
ViewBag.numbers = Numbers;
VIEW
<ul>
#foreach (var number in ViewBag.numbers)
{
<li>#number</li>
}
</ul>
Session is another very useful object that will hold any information.
For instance when user logged in to the system you want to hold his authorization level.
// GetUserAuthorizationLevel - some method that returns int value for user authorization level.
Session["AuthorizationLevel"] = GetUserAuthorizationLevel(userID);
This information will be stored in Session as long as user session is active.
This can be changed in Web.config file:
<system.web>
<sessionState mode="InProc" timeout="30"/>
So then in controller inside the action :
public ActionResult LevelAccess()
{
if (Session["AuthorizationLevel"].Equals(1))
{
return View("Level1");
}
if (Session["AuthorizationLevel"].Equals(2))
{
return View("Level2");
}
return View("AccessDenied");
}
TempData is very similar to ViewData and ViewBag however it will contain data only for one request.
CONTROLLER
// You created a method to add new client.
TempData["ClientAdded"] = "Client has been added";
VIEW
#if (TempData["ClientAdded"] != null)
{
<h3>#TempData["ClientAdded"] </h3>
}
TempData is useful when you want to pass some information from View to Controller. For instance you want to hold time when view was requested.
VIEW
#{
TempData["DateOfViewWasAccessed"] = DateTime.Now;
}
CONTROLLER
if (TempData["DateOfViewWasAccessed"] != null)
{
DateTime time = DateTime.Parse(TempData["DateOfViewWasAccessed"].ToString());
}
ViewBag, ViewData, TempData, Session - how and when to use them?
ViewBag
Avoid it. Use a view model when you can.
The reason is that when you use dynamic properties you will not get compilation errors. It's really easy to change a property name by accident or by purpose and then forget to update all usages.
If you use a ViewModel you won't have that problem. A view model also moves the responsibility of adapting the "M" (i.e. business entities) in MVC from the controller and the view to the ViewModel, thus you get cleaner code with clear responsibilities.
Action
public ActionResult Index()
{
ViewBag.SomeProperty = "Hello";
return View();
}
View (razor syntax)
#ViewBag.SomeProperty
ViewData
Avoit it. Use a view model when you can. Same reason as for ViewBag.
Action
public ActionResult Index()
{
ViewData["SomeProperty"] = "Hello";
return View();
}
View (razor syntax):
#ViewData["SomeProperty"]
Temp data
Everything that you store in TempData will stay in tempdata until you read it, no matter if there are one or several HTTP requests in between.
Actions
public ActionResult Index()
{
TempData["SomeName"] = "Hello";
return RedirectToAction("Details");
}
public ActionResult Details()
{
var someName = TempData["SomeName"];
}
TempData
is meant to be a very short-lived instance, and you should only use it during the current and the subsequent requests only! Since TempData works this way, you need to know for sure what the next request will be, and redirecting to another view is the only time you can guarantee this. Therefore, the only scenario where using TempData will reliably work is when you are redirecting. This is because a redirect kills the current request (and sends HTTP status code 302 Object Moved to the client), then creates a new request on the server to serve the redirected view. Looking back at the previous HomeController code sample means that the TempData object could yield results differently than expected because the next request origin can't be guaranteed. For example, the next request can originate from a completely different machine and browser instance.
ViewData
ViewData is a dictionary object that you put data into, which then becomes available to the view. ViewData is a derivative of the ViewDataDictionary class, so you can access by the familiar "key/value" syntax.
ViewBag
The ViewBag object is a wrapper around the ViewData object that allows you to create dynamic properties for the ViewBag.
public class HomeController : Controller
{
// ViewBag & ViewData sample
public ActionResult Index()
{
var featuredProduct = new Product
{
Name = "Special Cupcake Assortment!",
Description = "Delectable vanilla and chocolate cupcakes",
CreationDate = DateTime.Today,
ExpirationDate = DateTime.Today.AddDays(7),
ImageName = "cupcakes.jpg",
Price = 5.99M,
QtyOnHand = 12
};
ViewData["FeaturedProduct"] = featuredProduct;
ViewBag.Product = featuredProduct;
TempData["FeaturedProduct"] = featuredProduct;
return View();
}
}
namespace TempData.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
TempData["hello"] = "test"; // still alive
return RedirectToAction("About");
}
public ActionResult About()
{
//ViewBag.Message = "Your application description page.";
var sonename = TempData["hello"]; // still alive (second time)
return RedirectToAction("Contact");
}
public ActionResult Contact()
{
var scondtime = TempData["hello"]; // still alive(third time)
return View();
}
public ActionResult afterpagerender()
{
var scondtime = TempData["hello"];//now temp data value becomes null
return View();
}
}
}
In above conversation, there is little confuse for everyone. if you look at my above code, tempdata is like viewdata concept but then it is able to redirect other view also. this is first point.
second point:
few of them are saying it maintains value till read and few of them are asking that so will it read only time? not so.
Actually, you can read any number of time inside your code in one postpack before page render. once page render happened, if you do again postpack (request) means, the tempdata value becomes NULL.
even you are requesting so many time , but the tempdata value is still alive -->this case your number of request should not read temp data value.
In simple terms:
ViewBag is a dynamic (dynamic: ability to assign more than one value by different programs on the same object) object which is used to send data from controller to view. It can be used when we jump from controller's action to some view. However the value which we get in the view(in the viewbag object) can not be further replicated in other view/controller/js page etc. Meaning: Controller->View (possible). Now this value can not be send to next view/controller. Meaning Controller->View->View/controller/some js file (not possible), to carry this value you need to define some other variable and store viewbag value into it and then send it as a parameter.
Tempdata is very much different than viewbag. It has nothing to do with view at all. It is used when we send data from one action(method) to other action in the same controller. That's the reason we use RedirectToAction whenever sending tempdata value from one action to another. Value of tempdata are not retained when send from controller to veiw (because it is not meant to do so).
ViewData is simillar to viewbag but is a dictionary object. ViewData may require type casting while viewbag may not. It depends on the user which one he may want to use.
I have the following in partial view
<%= Ajax.ActionLink("Plunder Again", "Resources", new { controller = "Resource", parent = Model.ToJson() }, new AjaxOptions { UpdateTargetId = Model.ResourceType })%>
going to the controller method:
public ViewResult Resources(/*ModelResource parent*/)
{
Debug.Assert(Request.Params["parent"]!=null);
var jss=new System.Web.Script.Serialization.JavaScriptSerializer();
var parent=jss.Deserialize<ModelResource>(Request.Params["parent"]);
return View(parent.PlunderAmount);
}
but it throws an exception because the json doesn't properly pass via url, it can't find the 'Type' parameter.
I tried simply having the ModelResource as a parameter to the Action but it came in as null
This action will also be returning a partial view if that matters in any way.
ActionLink is used to create an anchor to a URL -- the URL must be valid! In general, you don't pass a whole object to an Action because the route values have to be bound back into the model and passed to the action. You might pass an ID of object though so the Action can get the object using that key.
If you want to send Model to controller instead of Ajax.ActionLink use Ajax.BeginForm
Okay so, i am totally new to MVC and I'm trying to wrap my head around a few of the concepts. I've created a small application...
This application has a view for creating a new Individual record. The view is bound to a model ViewPage... And I have a associated IndividualController which has a New method...
The New method of the IndividualController looks like this...
public ActionResult New()
{
var i = new Individual();
this.Title = "Create new individual...";
i.Id = Guid.NewGuid();
this.ViewData.Model = new Individual();
return View();
}
Now, the above all seems to be working. When the view loads I am able to retrieve the data from the Individual object. The issue comes into play when I try and save the data back through the controller...
In my IndividualController I also have a Save method which accepts an incoming parameter of type Individual. The method looks like...
public ActionResult Save(IndividualService.Individual Individual)
{
return RedirectToAction("New");
}
Now, on my view I wanted to use a standard html link/href to be used as the "Save" button so I defined an ActionLink like so...
<%=Html.ActionLink("Save", "Save") %>
Also, defined in my view I have created a single textbox to hold the first name as a test like so...
<% using (Html.BeginForm()) { %>
<%=Html.TextBox("FirstName", ViewData.Model.FirstName)%>
<% } %>
So, if I put a break point in the Save method and click the "Save" link in my view the break point is hit within my controller. The issue is that the input parameter of the Save method is null; even if I type a value into the first name textbox...
Obviously I am doing something completely wrong. Can someone set me straight...
Thanks in advance...
Your New controller method doesn't need to create an individual, you probably just want it to set the title and return the view, although you may need to do some authorization processing. Here's an example from one of my projects:
[AcceptVerbs( HttpVerbs.Get )]
[Authorization( Roles = "SuperUser, EditEvent, EditMasterEvent")]
public ActionResult New()
{
ViewData["Title"] = "New Event";
if (this.IsMasterEditAllowed())
{
ViewData["ShowNewMaster"] = "true";
}
return View();
}
Your Save action should take the inputs from the form and create a new model instance and persist it. My example is a little more complex than what I'd like to post here so I'll try and simplify it. Note that I'm using a FormCollection rather than using model binding, but you should be able to get that to work, too.
[AcceptVerbs( HttpVerbs.Post )]
[Authorization( Roles = "SuperUser, EditEvent, EditMasterEvent")]
public ActionResult Save( FormCollection form )
{
using (DataContext context = ...)
{
Event evt = new Event();
if (!TryUpdateModel( evt, new [] { "EventName", "CategoryID", ... }))
{
this.ModelState.AddModelError( "Could not update model..." );
return View("New"); // back to display errors...
}
context.InsertOnSubmit( evt );
context.SubmitChanges();
return RedirectToAction( "Show", "Event", new { id = evt.EventID } );
}
}
If I don't create a new Indvidual object in the New method then when my view tries to bind the textbox to the associated model I get a NullReferenceException on the below line in my view...
`<%=Html.TextBox("FirstName", ViewData.Model.FirstName)%>`
With regards to the Save method. From what I understand since my view is strongly typed shouldn't I be able to have a method signature like...
`public ActionResult New(IndividualService.Individual ind)
{
return View();
}`
I thought that was the purpose behind model binding..?
I would strongly recommend that you take a step back from what you are doing and run through some of the Tutorials/Videos here http://www.asp.net/learn/
If you have a strongly typed View it means that when the Controller picks that view to generate the output the view has better access to the Model.
However the View is not responsible for what comes back from the client subsequently such as when a form is posted or a URL is otherwise navigated to.
ASP.NET-MVC uses information in the URL to determine which Controller to hand the request off to. After that it's the controller's responsibility to resolve the various other elements in the request into instance(s) of Model classes.
The relationship between the incoming request and the controller is clouded by the significant assistance the ASP.NET-MVC routing gives the controller. For example a route can be defined to supply parameters to the controller method and thats all the controller needs and hence you don't see any code in the method relating to the http request. However it should be understood that the contoller method is simply processing a http request.
I hope you can see from the above that it would be too early in a requests life-cycle for an instance of a class from the model to passed to a public method on a controller. Its up to the controller to determine which model classes if any need instancing.