I am using Razor WebGrid and my controller action is getting repeatedly called when click on sort by header or click on page links. First time it is getting called only once but next time onwards it is getting called repeatedly. Please can anyone help.
[HttpGet]
public ActionResult Index(int page = 1, string sort = "GridName", string sortDir = "ASC")
{
const int pageSize = 5;
string successMessage = string.Empty;
var message = string.Empty;
int pageIndex1 = page - 1;
if (RenderFirstTime == 1)
{
GridCRUDCollection.UpdateGridModelCollection(null, pageSize, pageIndex1, sort, sortDir);
RenderFirstTime = 0;
return View(GridCRUDCollection);
}
else
{
GridCRUDCollection.UpdateGridModelCollection(null, pageSize, pageIndex1, sort, sortDir);
return PartialView("GridDetailsView", GridCRUDCollection);
}
}
Code with an <img src="#" ... > is what did it for me. Once I removed the #'s the controller got called just once. The grid may be generating those and populating them later via Javascript. One way to diagnose it is to use LabJS to prevent immediate execution.
Related
I have a page with many items on it. Each one has a button, that is supposed to take user to another jsp with another layout for detailed information about the current item. Can I even do this with ResponseEntity, as it doesn't redirect anywhere? Or may be there's some better way to do it and send my Object to the page? I tried "ResponseEntity.created(location).body(object)" but it doesn't do the job, I stay on the same page. May be I'm just using it wrong?
My method:
#RequestMapping(value = {"/details+{id}"}, method = RequestMethod.GET)
public ResponseEntity<Item> details(#PathVariable("id") int id) {
Item item = itemService.findById(id);
if(item == null){
return new ResponseEntity<Item>(HttpStatus.NO_CONTENT);
}
return new ResponseEntity<Item>(item, HttpStatus.OK);
}
Have a look at ModelAndView. It's purpose is to return a view with attached model to it. So for each value of the id, you can decide a pair of view and model to return.
#RequestMapping(value = {"/details+{id}"}, method = RequestMethod.GET)
public ModelAndView details(#PathVariable("id") int id) {
String viewToUse;
Map<String, Item> modelToUse;
if(id == ...) {
viewToUse = ...
modelToUse = ...
} else if (id == ...) {
viewToUse = ...
modelToUse = ...
} else if (id == ...) {
viewToUse = ...
modelToUse = ...
}
return new ModelAndView(viewToUse, modelToUse);
}
my view have two dropdown and one submit buttom if no value is selected and if form get sumbited with GET method then my URL will be http://localhost:53372/question/index?Index=List&type=&stage=&mid=1&mod=5.
but i m applying an ActionFilter with OnActionExcuting() overriden method. so after submitting form URL is like http://localhost:53372/question/index?index=List&mid=1&mod=5.
where other two QueryString is gone?
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.QueryString["mid"] == null || filterContext.RequestContext.HttpContext.Request.QueryString["mod"] == null)
{
mid = Convert.ToString(HttpUtility.ParseQueryString(filterContext.RequestContext.HttpContext.Request.UrlReferrer.Query)["mid"]);
mod = Convert.ToString(HttpUtility.ParseQueryString(filterContext.RequestContext.HttpContext.Request.UrlReferrer.Query)["mod"]);
if (!string.IsNullOrEmpty(mid) || !string.IsNullOrEmpty(mod))
{
RouteValueDictionary redirecttargetDictionary = new RouteValueDictionary();
NameValueCollection Qstr = null;
if (filterContext.HttpContext.Request.RequestType == "GET")
{
Qstr = HttpUtility.ParseQueryString(filterContext.HttpContext.Request.Url.Query);
foreach (string item in Qstr)
{
redirecttargetDictionary.Add(item, Qstr[item]);
}
if (Qstr["mid"] == null)
{
redirecttargetDictionary.Add("mid", mid);
}
if (Qstr["mod"] == null)
{
redirecttargetDictionary.Add("mod", mod);
}
filterContext.Result = new RedirectToRouteResult(redirecttargetDictionary);
}
}
}
}
but if i select Dropdown value then all queryString is in URL.
QueryString with no values stage=&type= are not allowed?
By default MVC passes data as a query string unless you are submitting a form in which case the query string is bundled as part of the HttpRequest object. You can access the query string directly using the FormCollection object or as part of the HttpRequest object. The most direct way to access the query string is through the FormCollection object as follows
[HttpPost]
public ActionResult SubmitData(FormCollection form)
{
foreach(var key in form.AllKeys)
{
switch(key)
{
case "stage":
// do some work
break;
case "type":
// do some more work
break;
}
}
return RedirectToAction("SomeAction");
}
I have seen empty query string values cause issues with some browsers (I think IE) under certain circumstances. I suggest populating your DropDownList with a token instead of no value such as "Select..." and -1 for the value.
var dropDownList = new List<SelectListItem>();
dropDownList.Add(new SelectListItem{ Text = "Select", Value = "-1"} );
and then
#Html.DropDownList("stage", Model.Stages)
or something like that.
I hope this helps :)
If I have the following code (EDIT: Sorry if I wasn't clear, I want to encapsulate the following (forget about the view its calling), so that I could do other stuff within the ActionResult):
public ActionResult ModelBased(string[] items, PostedItems postedItems) {
var model = new ItemsViewModel();
var selectedItems = new List<Item>();
var postedItemIDs = new string[0];
if (postedItems == null) postedItems = new PostedItems();
if (items!= null && items.Any()) {
postedCityIDs = items;
postedItems.ItemIDs = items;
}
if (postedItems.ItemIDs != null && postedItems.ItemIDs.Any()) {
postedItemIDs = postedIems.ItemIDs;
model.WasPosted = true;
}
if (postedItemIDs.Any())
selectedItems = ItemRepository.GetAll()
.Where(x => postedItemIDs.Any(s => x.Id.ToString().Equals(s))).ToList();
model.AvailableItems = ItemRepository.GetAll();
model.SelectedItems = selectedItems;
model.PostedItems = postedItems;
return View(model);
}
How might I reuse it in different Actions in my controller without having to copy/paste. I tried doing a private method with the code. But I am stuck on:
Either calling it wrong within an action method : private void Item (Item item) {//copied code from above} then calling Item(item); in the action; or
It has something to do with the (string[] items, PostedItems postedItems) that I am doing wrong; or
Something entirely different that I am not doing right.
Any examples would be much appreciated.
EDIT: The code above works with a CheckBoxList. It's one particular CheckBoxList. But I want to be able to use it in other views without having to copy/paste the code to other ActionResults. Just calling the ActionResult won't work, because I plan on doing other things. In particular, I have code for wizards in each ActionResult, such as:
if ((nextButton != null) && ModelState.IsValid)
return RedirectToAction("EMailConfirm");
return View("EMail/BasicDetails", myData);
which are returning specific views, so call to just the ActionResult won't work, unless I am missing something.
return View(model); tries to find a view for the original action.
Specify return View("ModelBased", model); to always render the view named "ModelBased"
public void SomeAction(string[] items, PostedItems postedItems)
{
// Modify the data as your like
return ModelBased(string[] items, PostedItems postedItems);
}
public void SomeOtherAction(string[] items, PostedItems postedItems)
{
// Modify the data as your like
return ModelBased(string[] items, PostedItems postedItems);
}
private ActionResult ModelBased(string[] items, PostedItems postedItems) {
var model = new ItemsViewModel();
var selectedItems = new List<Item>();
var postedItemIDs = new string[0];
if (postedItems == null) postedItems = new PostedItems();
if (items!= null && items.Any()) {
postedCityIDs = items;
postedItems.ItemIDs = items;
}
if (postedItems.ItemIDs != null && postedItems.ItemIDs.Any()) {
postedItemIDs = postedIems.ItemIDs;
model.WasPosted = true;
}
if (postedItemIDs.Any())
selectedItems = ItemRepository.GetAll()
.Where(x => postedItemIDs.Any(s => x.Id.ToString().Equals(s))).ToList();
model.AvailableItems = ItemRepository.GetAll();
model.SelectedItems = selectedItems;
model.PostedItems = postedItems;
return View(model);
}
Your example is unclear, however, I would normally move common functionality into a seperate method and mark it with [NonAction] attribute. E.g.
[NonAction]
protected UserInfo GetUserInfo(string username)
{
// Return relevant data
}
I would then call GetUserInfo in your action method.
Edit:
You need to look into partial views. You can think of a partial view as a control that you can re-use on multiple pages. For example, I can put a login control in a partial view and renged it on multiple pages. This will promote code re-usability.
I can't give you the example as I haven't done this for a while, but you'd have to do the following:
Instead of return View(); you'll have to return PartialView("_NameOfYourPartialView", viewModel);
Modify your view, so it's no longer a view, but a partial view.
You'll need to do a bit of reading and try it out for yourself.
Good luck
You can call this action from another action that returns ActionResult.
public ActionResult OtherAction()
{
return ModelBased(items, postedItems);
}
Also, why private void? Which part do you actually want to reuse? If it takes an Item and returns ItemsViewModel, it should be private ItemsViewModel - depends on the part you want to reuse. void doesn't return anything.
Please help me ... I don't know how to write event for button. I placed button in the mvc 2 aspx file that i created. i want to write function to do some thing when the button is clicked.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EvaluvateStudent(FormCollection collection)
{
Model.StudentModels studentDetail = new Model.StudentModels();
studentDetail.Name = collection["Name"];
studentDetail.RegNo = Convert.ToInt32(collection["RegNo"]);
studentDetail.Tamil = Convert.ToSingle(collection["Tamil"]);
studentDetail.English = Convert.ToSingle(collection["English"]);
studentDetail.Total = CalculateTotal(studentDetail.Tamil, studentDetail.English);
ViewData["Total"] = studentDetail.Total;
return View("Student");
}
public float CalculateTotal(float tamil,float english)
{
float total = tamil + english;
return total;
}
I am working on Steven Sanderson's book (Pro ASP.NET MVC 3). I am on p. 294. I've copied word per word what's in the book but it is not working.
This is the action method
public ActionResult Edit(Product product, HttpPostedFileBase image)
{
if(ModelState.IsValid)
{
if(image != null)
{
product.ImageMimeType = image.ContentType;
product.ImageData = new byte[image.ContentLength];
image.InputStream.Read(product.ImageData, 0, image.ContentLength);
}
//...Save product in the database using Entity Framework
}
}
This is how to display the image on the razor page
<img width="150" height="150"
src = "#Url.Action("GetImage", "Home", new { Model.ProductID })" />
And finally, the GetImage
public FileContentResult GetImage(int productID)
{
Product prod = repository.Products.FirstOrDefault(p => p.ProductID == productID);
if (prod != null)
{
return File(prod.ImageData, prod.ImageMimeType);
}
else
{
return null;
}
}
EDIT
I have followed the whole process (while debugging) from the beginning to the end and this is what I can say:
After I have press the "Save" button on the view, the HttpPostedFileBase object is not null.
After I call the db.SaveChanges() method, one row is added in database's table.
When I call the GetImage, it doesn't return null.
But on the view, there's not image displayed
Thanks for helping
File should be FileContentResult since it is bytes and not an actual file on the disk. And img should be prod, correct?
public FileContentResult GetImage(int productID)
{
Product prod = repository.Products.FirstOrDefault(p => p.ProductID == productID);
if (prod != null)
{
return new FileContentResult(prod.ImageData, prod.ImageMimeType);
}
else
{
return null;
}
}
Modify your action method like so:
<img width="150" height="150" src = "#Url.Action("GetImage", "Home", new { #id = Model.ProductID })" />
Other than that small difference (adding the id parameter), your code is very similar to mine, and my images load just fine. BTW, if you look at the HTML source for your page, do you see:
/GetImage/<some number here>
or
/GetImage/
as the value of your src attribute? If the latter, this should definitely fix the problem. If the former, you may need to enable GET requests.
Here's the answer to get that Steven Sanderson example working, change your saving procedure as such:
if (image != null)
{
var product = new Product();
product.FileName = image.FileName; //<- optional filename
product.ImageMimeType = image.ContentType;
int length = image.ContentLength;
byte[] buffer = new byte[length];
image.InputStream.Read(buffer, 0, length);
product.ImageData = buffer;
//Save product to database
}
I had the same problem, too.
Just change the part of Edit method in controller to sth like this:
if (image != null)
{
mvcImages img = db.mvcImages.Where(p => p.p_id == prod.p_id).FirstOrDefault();
prod.p_imageMimeType = image.ContentType;
byte[] buffer = new byte[image.ContentLength];
image.InputStream.Read(buffer, 0, image.ContentLength);
prod.p_imageData = buffer;
img.p_imageMimeType = prod.p_imageMimeType;
img.p_imageData = prod.p_imageData;
db.SaveChanges();
}
That works fine.
Also remember to save changes within the same brackets as your "if" command.
Even simpler resolution is to just change the following line in your product class:
change from:
public byte ImageData {get;set;}
To:
public byte[] ImageData{get;set;}
I run into the same problem.. try this:
public ActionResult Edit(Product product, HttpPostedFileBase image)
{
if(ModelState.IsValid)
{
if(image != null)
{
product.ImageMimeType = image.ContentType;
product.ImageData = new byte[image.ContentLength];
iname.InputStream.Position = 0; // This is what makes the difference
image.InputStream.Read(product.ImageData, 0, image.ContentLength);
}
//...Save product in the database using Entity Framework
}
the problem is in Action method..
it should be
you has to change de name of the Controller... "GetImage" function is in "Admin" Controller.. The rest of the code is fine...
Simple Open the Products.cs file in your entities folder and change
public byte ImageData {get;set;}
To:
public byte[] ImageData{get;set;}