MVC 4 Routing , Get/Post requests handling - asp.net-mvc

I'm faced with the following problem :
I have a controller with lets say the following actions:
[HttpGet]
public ActionResult Index()
{
var viewModel = new IndexViewModel();
return View("Index", viewModel);
}
[HttpPost]
public void ExportToExcell(LeadsViewModel model)
{
// Export to excell code goes here
}
The problem is the following:
The User enters on Index page with this URL : /Controller/Index
Then the user submits the form to Action ExportToExcel
Data is exported to Excel( file downloaded ) and it's okay.
The URL becomes /Controller/ExportToExcell
Then when I am clicking "Enter" I am going To /Controller/ExportToExcell but with GET
and of course falling with Page Not Found, the question is how properly to Deal with this in MVC

Don't use void as returned type of your post action, use an ActionResult
[HttpPost]
public ActionResult ExportToExcell(LeadsViewModel model)
{
// Export to excell code goes here
return RedirectToAction("Index");
}

I believe that your problem is that you aren't returning a FileResult, and the browser will redirect you to your post path. Can't test it right now, but I believe the following should work.
[HttpPost]
public ActionResult ExportToExcell(LeadsViewModel model)
{
// Generate the Excel file into a MemoryStream for example
// Return a FileResult with the Excel mime type
return File(fileStream, "application/vnd.ms-excel", "MyExcelFile.xls");
}
Check FileResult and Controller.File for more details.
As a note, I'm not completely sure if that's the mime type for an Excel file, but if you say you are already downloading the file, your probably already have it :)

You must return ActionResult instead of void.
public ActionResult ExportToExcel(PagingParams args)
{
var data = new StudentDataContext().Student.Take(200).ToList();
return data.GridExportToExcel<Student>("GridExcel.xlsx", ExcelVersion.Excel2007, args.ExportOption);
}
Please check the link: Export Action

Related

ASP .NET MVC - getting null querystring values in controller

I'm trying to reach a controller method by providing some url parameters :
http://localhost/GoTo/Index?topic=test
Here's the method I want to reach :
public ActionResult Index(string topic)
{
//do some stuff
}
Problem is, the topic parameter in the method is always null. I also tried to check what I got in Request.QueryString collection, but it's empty.
Any lead/explanation would be appreciated.
EDIT : Screenshot requested :
Please try this it's working for me check below screenshot
Just call you're URL like this
http://localhost/GoTo?topic=test
public class TestingController : Controller
{
// GET: Testing
public ActionResult Index(string topic)
{
return View();
}
}

How to direct to POST action in ActionAsPDF?

I am creating an MVC 5 application. I am using Rotativa to generate PDFs
they have a method called
public ActionAsPdf(string action, object routeValues);
I am having trouble to direct to POST method of an action
this is that GET and POST actions
[HttpGet]
[ValidateInput(false)]
public ActionResult Create_Brochure(IEnumerable<ProductsPropertiesVM> model)
{
.............
return View(selectedIDs);
}
[HttpPost]
[ValidateInput(false)]
public ActionResult Create_Brochure(string m)
{
return View();
}
Once I run this program its directing to GET method but I want to direct to POST action
using following method
public ActionResult PrintIndex()
{
return new ActionAsPdf("Create_Brochure") { FileName = "Test.pdf" };
}
You need to match the parameters of the POST version of Create_Brochure:
return new ActionAsPdf("Create_Brochure", new List<ProductsPropertiesVM>())
{
FileName = "Test.pdf"
};
Of course, you'll have to pass the correct model data instead of the List<ProductsPropertiesVM>.

Basic wizard, and passing model from one view to another?

I'm new to MVC and trying to create a wizard-style series of views, passing the same model instance from one view to the next, where the user completes a little more information on each form. The controller looks something like this:-
[HttpGet]
public ActionResult Step1()
{
return View();
}
[HttpPost]
public ActionResult Step1(MyModel model)
{
if (!ModelState.IsValid)
return View(model);
return View("Step2", model);
}
[HttpPost]
public ActionResult Step2(MyModel model)
{
if (!ModelState.IsValid)
return View(model);
return View("Step3", model);
}
// etc..
Questions:-
When I submit the form from the Step1 view, it calls the Step1 POST method and results in the Step2 view being displayed in the browser. When I submit the form on this view, it calls the Step1 POST method again! I got it to work by specifying the action and controller name in Html.BeginForm(), so I'm guessing that the parameterless overload just POSTs back to the action that rendered the view?
I've noticed that the browser's address bar is out of sync with the current view - when I'm on the Step2 view it still shows the Step1 URL, and when on Step3 it shows the Step2 URL. What's going on?
Another approach I've seen for passing a model between views is to put the model in TempData then use RedirectToAction(). What are the pros and cons of this method versus what I'm currently doing?
I won't be providing any "back" buttons of my own in the wizard. Are there any pitfalls to be aware of regarding the browser's back button, and do either of the above two approaches help (or hinder)?
Edit
Prompted by #StephenMuecke's comment I've now rewritten this to use a single view. I tried this once before but had difficulties round-tripping a "step number" to keep track of where I was in the wizard. I was originally using a hidden field created with #Html.HiddenFor', but this wasn't updating as the underlying model property changed. This appears to be "by design", and the workaround is to create the hidden field using vanilla HTML (
Anyway the one-view wizard is now working. The only problem is the old chestnut of the user being able to click the back button after they have completed the wizard, make a change, and resubmit a second time (resulting in a second DB record).
I've tried adding [OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")] to my POST method, but all this does is display (in my case) a Chrome error page suggesting that the user clicks refresh to resubmit the form. This isn't user friendly and doesn't prevent a second submit.
you can use RedirectToAction() in this case without worrying about TempData. Just add your model as a parameter to each action and use RedirectToAction("Step2", model);
[HttpGet]
public ActionResult Step1()
{
return View();
}
[HttpPost]
public ActionResult Step1(MyModel model)
{
if (!ModelState.IsValid)
return View(model);
return RedirectToAction("Step2", model);
}
[HttpGet]
public ActionResult Step2(MyModel model)
{
return View(model);
}
[HttpPost]
public ActionResult Step2(MyModel model)
{
if (!ModelState.IsValid)
return View(model);
return RedirectToAction("Step3", model);
}
// etc..
The answer to #1 is found in #2.. if you dont specify the Action in you Html.BeginForm() it posts to the current url.
Using TempData to avoid model displaying in url.
[HttpGet]
public ActionResult Step1()
{
return View();
}
[HttpPost]
public ActionResult Step1(MyModel model)
{
if (!ModelState.IsValid)
return View(model);
TempData["myModel"] = model;
return RedirectToAction("Step2");
}
[HttpGet]
public ActionResult Step2()
{
var model = TempData["myModel"] as MyModel;
return View(model);
}
[HttpPost]
public ActionResult Step2(MyModel model)
{
if (!ModelState.IsValid)
return View(model);
TempData["myModel"] = model;
return RedirectToAction("Step3");
}
// etc..
Another option would be to add the name of the next action to ViewBag and set your actionName in each BeginForm()
[HttpGet]
public ActionResult Step1()
{
ViewBag.NextStep = "Step1";
return View();
}
[HttpPost]
public ActionResult Step1(MyModel model)
{
if (!ModelState.IsValid)
{
ViewBag.NextStep = "Step1";
return View(model);
}
ViewBag.NextStep = "Step2";
return View("Step2", model);
}
[HttpPost]
public ActionResult Step2(MyModel model)
{
if (!ModelState.IsValid)
{
ViewBag.NextStep = "Step2";
return View(model);
}
ViewBag.NextStep = "Step3";
return View("Step3", model);
}
//View
#using (Html.BeginForm((string)ViewBag.NextStep, "ControllerName"))
{
}
I'd prefer to add NextStep as a property to MyModel and using that instead of using ViewBag though.
I understand the thought behind your approach and don't have any issues with it. Unfortunately, I don't believe that ASP.NET MVC is geared very well for passing the the same view model (with data!) between different actions.
Typically, the scaffolded actions in the controller will either create a model item or find it by identifier in the database.
I don't know if this would help, but you could try to save it to the database on every step, and then retrieve it by identifier, or you could also save it to a session and grab it that way.
One issue I do see with your approach is you have Step2 set as a get, yet you probably want to post data to it from Step1 instead of using a query string. You may need to reconcile that issue.

By default not redirecting to Index action method of controller

Recently I've created on controller call DashboardVideos and an action method called Index.
And after Add Or Update, I'm redirecting it to Index page using
RedirectToAction("Index", "DashboardVideos").
but this code redirecting it to /DashboardVideos/ and it says
HTTP Error 403.14 - Forbidden
The Web server is configured to not list the contents of this directory.
so the issue is by default it's supposed to load Index page when I say /Dashboard
But its not, same url pattern working with all other controller (So I don't think there's anything wrong with routing pattern).
Any help would be appreciated.
Code:
public class DashboardVideosController : BaseController
{
private readonly IDashboardVideosComponent socialTagComponent;
public DashboardVideosController()
{
socialTagComponent = ComponentFactory.Get<IDashboardVideosComponent>();
}
// GET: DashboardVideos
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult AddUpdate(DashboardVideosModel socialTagChannel)
{
//Save data to database
return RedirectToAction("Index", "DashboardVideos");
}
}
Simply write this if both actions are in same controller.
public ActionResult AddUpdate(DashboardVideosModel socialTagChannel)
{
//Save data to database
return RedirectToAction("Index");
}
Try to take a look at your "RouteConfig" class and you can specify custom routes there. Also It is possible if the call comes from AJAX it can go directly to action without redirecting. Did you tried to Debug the code?

MVC: trying to understand where ActionResult sends it's data

I have been trying to understand an online tutorial and I am stumped.
Can someone please tell me where the text "Hello" is sent to? Is the message sent directly to the browser without being placed on a page?
public class GoHomeController : Controller
{
public string Index()
{
return "Hello";
}
}
How's this? Your controller action needs to have a return type of ActionResult, there are many subclasses of this class that allow for various types of responses however you can always influence with brute force if you like. For example"
public ActionResult Index()
{
Response.Write("hello world");
return null;
}
The above code writes to the Response stream directly, in my example I return a null. This indicates no ActionResult is needed to be performed by the MVC system, typically this is where the View is specified, the View will be read, parsed and written to the Response stream as well.
But typical controller actions do have return values, for example here is how I could return JSON, remember the View is just an abstraction to allow you to control what is written to the Response stream.
public ActionResult Index()
{
return Json( new { Message="Hello world"});
}
And then there is the typical ActionResult that directs the output to a .cshtml file:
public ActionResult Index()
{
return View();
}
This will write to the Response stream using the Index.cshtml file tied to this controller namespace or I could specify the name of the .cshtml:
public ActionResult Index()
{
return View("HelloWorld"); //<-- looks for HelloWorld.cshtml
}

Resources