I'm using ASP.NET MVC 4. I am trying to pass data from one controller to another controller. I'm not getting this right. I'm not sure if this is possible?
Here is my source action method where I want to pass the data from:
public class ServerController : Controller
{
[HttpPost]
public ActionResult ApplicationPoolsUpdate(ServiceViewModel viewModel)
{
XDocument updatedResultsDocument = myService.UpdateApplicationPools();
// Redirect to ApplicationPool controller and pass
// updatedResultsDocument to be used in UpdateConfirmation action method
}
}
I need to pass it to this action method in this controller:
public class ApplicationPoolController : Controller
{
public ActionResult UpdateConfirmation(XDocument xDocument)
{
// Will add implementation code
return View();
}
}
I have tried the following in the ApplicationPoolsUpdate action method but it doesn't work:
return RedirectToAction("UpdateConfirmation", "ApplicationPool", new { xDocument = updatedResultsDocument });
return RedirectToAction("UpdateConfirmation", new { controller = "ApplicationPool", xDocument = updatedResultsDocument });
How would I achieve this?
HTTP and redirects
Let's first recap how ASP.NET MVC works:
When an HTTP request comes in, it is matched against a set of routes. If a route matches the request, the controller action corresponding to the route will be invoked.
Before invoking the action method, ASP.NET MVC performs model binding. Model binding is the process of mapping the content of the HTTP request, which is basically just text, to the strongly typed arguments of your action method
Let's also remind ourselves what a redirect is:
An HTTP redirect is a response that the webserver can send to the client, telling the client to look for the requested content under a different URL. The new URL is contained in a Location header that the webserver returns to the client. In ASP.NET MVC, you do an HTTP redirect by returning a RedirectResult from an action.
Passing data
If you were just passing simple values like strings and/or integers, you could pass them as query parameters in the URL in the Location header. This is what would happen if you used something like
return RedirectToAction("ActionName", "Controller", new { arg = updatedResultsDocument });
as others have suggested
The reason that this will not work is that the XDocument is a potentially very complex object. There is no straightforward way for the ASP.NET MVC framework to serialize the document into something that will fit in a URL and then model bind from the URL value back to your XDocument action parameter.
In general, passing the document to the client in order for the client to pass it back to the server on the next request, is a very brittle procedure: it would require all sorts of serialisation and deserialisation and all sorts of things could go wrong. If the document is large, it might also be a substantial waste of bandwidth and might severely impact the performance of your application.
Instead, what you want to do is keep the document around on the server and pass an identifier back to the client. The client then passes the identifier along with the next request and the server retrieves the document using this identifier.
Storing data for retrieval on the next request
So, the question now becomes, where does the server store the document in the meantime? Well, that is for you to decide and the best choice will depend upon your particular scenario. If this document needs to be available in the long run, you may want to store it on disk or in a database. If it contains only transient information, keeping it in the webserver's memory, in the ASP.NET cache or the Session (or TempData, which is more or less the same as the Session in the end) may be the right solution. Either way, you store the document under a key that will allow you to retrieve the document later:
int documentId = _myDocumentRepository.Save(updatedResultsDocument);
and then you return that key to the client:
return RedirectToAction("UpdateConfirmation", "ApplicationPoolController ", new { id = documentId });
When you want to retrieve the document, you simply fetch it based on the key:
public ActionResult UpdateConfirmation(int id)
{
XDocument doc = _myDocumentRepository.GetById(id);
ConfirmationModel model = new ConfirmationModel(doc);
return View(model);
}
Have you tried using ASP.NET MVC TempData ?
ASP.NET MVC TempData dictionary is used to share data between controller actions. The value of TempData persists until it is read or until the current user’s session times out. Persisting data in TempData is useful in scenarios such as redirection, when values are needed beyond a single request.
The code would be something like this:
[HttpPost]
public ActionResult ApplicationPoolsUpdate(ServiceViewModel viewModel)
{
XDocument updatedResultsDocument = myService.UpdateApplicationPools();
TempData["doc"] = updatedResultsDocument;
return RedirectToAction("UpdateConfirmation");
}
And in the ApplicationPoolController:
public ActionResult UpdateConfirmation()
{
if (TempData["doc"] != null)
{
XDocument updatedResultsDocument = (XDocument) TempData["doc"];
...
return View();
}
}
Personally I don't like to use TempData, but I prefer to pass a strongly typed object as explained in Passing Information Between Controllers in ASP.Net-MVC.
You should always find a way to make it explicit and expected.
I prefer to use this instead of TempData
public class Home1Controller : Controller
{
[HttpPost]
public ActionResult CheckBox(string date)
{
return RedirectToAction("ActionName", "Home2", new { Date =date });
}
}
and another controller Action is
public class Home2Controller : Controller
{
[HttpPost]
Public ActionResult ActionName(string Date)
{
// do whatever with Date
return View();
}
}
it is too late but i hope to be helpful for any one in the future
If you need to pass data from one controller to another you must pass data by route values.Because both are different request.if you send data from one page to another then you have to user query string(same as route values).
But you can do one trick :
In your calling action call the called action as a simple method :
public class ServerController : Controller
{
[HttpPost]
public ActionResult ApplicationPoolsUpdate(ServiceViewModel viewModel)
{
XDocument updatedResultsDocument = myService.UpdateApplicationPools();
ApplicationPoolController pool=new ApplicationPoolController(); //make an object of ApplicationPoolController class.
return pool.UpdateConfirmation(updatedResultsDocument); // call the ActionMethod you want as a simple method and pass the model as an argument.
// Redirect to ApplicationPool controller and pass
// updatedResultsDocument to be used in UpdateConfirmation action method
}
}
Related
I have an ASP.NET Core MVC To Do app. When I start the app, the app has a default URL of https://localhost but how do I get the filename from a URL like this one https://localhost/14-11-2020. I need to get the 14-11-2020 as parameter and display it in a .cshtml file between <time></time> tags as 14 / 11 / 2020. Each time the user changes the date, it needs to show the tasks from that date (since this is a "TODO" app). I have already setup the model with a database with DateTime attribute.
My question is that: how do I extract the filename of a URL and show it to the user in the View?
how do I extract the filename of a URL and show it to the user in the
View?
The AbsolutePath property contains the path information that the server uses to resolve requests for information in C#. (More Details)
passing data to view from controller (more details)
I am using ViewData here,
ViewData is a ViewDataDictionary object accessed through string keys.
String data can be stored and used directly without the need for a
cast, but you must cast other ViewData object values to specific types
when you extract them. You can use ViewData to pass data from
controllers to views and within views, including partial views and
layouts.
[HttpGet]
public IActionResult Index()
{
Uri baseUri = new Uri("http://www.contoso.com/");
Uri myUri = new Uri(baseUri, "catalog/shownew.htm?date=today");
string name = Path.GetFileName(myUri.AbsolutePath);
ViewData["FileName"] = name;
return View();
}
For the Path class use namespace using System.IO;
and inside view use,
<title>#ViewData["FileName"] - WebApplication</title>
You can parse the url params from the method on the controller
public class ToDoController : Controller
{
[HttpGet]
[Route("{date:DateTime}")]
public IActionResult Index(DateTime date)
{
//// filter by date
return View();
}
}
In the above example a url of http://localhost:1234/todo/01-01-2020 would pass a date time of '01/01/2020 00:00:00' into the todo controller method
Get the date from RouteData and store it in ViewBag or ViewDate in controller, then access it the view:
Controller:
public IActionResult Index()
{
string date = RouteData.Values.Values.LastOrDefault().ToString();
var mydate = date.Replace("-", "/");
ViewBag.CurrentDate = mydate;
return View();
}
View:
<time>#ViewBag.CurrentDate</time>
I am a beginner and I am going through some tutorials in my MVC. So, I came across two scenarios.
Scenario 1.
I had to pass some data to my view on post and then send that data as hidden field. Here is the code.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ForgotPassword(ForgotPasswordMV viewModel)
{
if (ModelState.IsValid)
{
return RedirectToAction("VerifyToken", new { emailId = viewModel.EmailId });
}
^^ USING ANONYMOUS OBJECTS
return View();
}
public ActionResult VerifyToken(string emailId = null)
{
VerifyTokenMV viewModel = new VerifyTokenMV
{
EmailId = emailId
};
return View(viewModel);
}
VerifyToken View
#using (#Html.BeginForm("VerifyToken", "Security"))
{
#Html.HiddenFor(m => m.EmailId)
<button class="btn btn-primary">Continue</button>
}
Works Perfectly fine. I am able to receive values of EmailId. So far so good.
Scenario 2.
Needed to open a partial view from Main view, here is the snippet.
Main cshtml file
<div class="abc">
#Html.Partial("../Widget/Customize", Model.Unit, new ViewDataDictionary() { { "ElementName", "UnitWidget" } })
</div>
partial cshtml file
#{
string custWidgetElementName = ViewBag.ElementName;
}
// some html code below
Observation:
In scenario 2 why have I used ViewDataDictionary. Although both example works perfectly fine. But is there any reason that I had to use ViewDataDictionary. In scenraio 1 can we use ViewDataDictionary? If Yes, then which one is optimum solution.
Question: When I need to pass values shall I use new {key : value} or use ViewDataDictionary or there is no corelation? Instead of ViewDataDictionary can I use anonymous object in Senario 2
Your two scenarios are totally different. They are not doing the same thing.
In scenario 1 when using this line:
return RedirectToAction("VerifyToken", new { emailId = viewModel.EmailId });
A new URL is genrated and sent back to the client (the browser) with HTTP Code 301 or 302. When received the browser will re-contact your application wiht the received URL. With that URL, your application will execute the associated action. In your case, the client's browser will call VerifyToken action with the emailId parameter setted when you call RedirectionToAction into ForgotPassword action. So using RedirectionToAction method is just telling that method to generate a new URL with parameter defined in the anonymous type.
In scenario 2 is completely different to scenario 1. With this line:
#Html.Partial("../Widget/Customize", Model.Unit, new ViewDataDictionary() { { "ElementName", "UnitWidget" } })
You're telling your view to inject the partial view which path is ../Widget/Customize. Because that partial view the strongly typed, you passed Model.Unit as an second parameter. You use also a third parameter new ViewDataDictionary() { { "ElementName", "UnitWidget" } } because your partial seems to internally need to access to the dynamic property ViewBag or dictionary property ViewData of your view.
Conclusion:
In scenario 1 you are just telling the client's browser to go to the new URL you have generated after requesting ForgetPassword URL. We just call that a rediretion.
In scenario 2, you're just rendering a partial view into a view. The client's broswer doesn't know anything what's going on with partial views they don't know if they exist.
I've got the following controller method defined that creates two different asp.net core routes (named route1 and route2). I'm expecting that when I use the cshtml below that when I call:
localhost/route1
localhost/route2
that my cache will be replaced but it is not.
(Having the parameter {param} passed in does not change my expected results)
Controller Page
[Route("/route1/{param}", Name = "route1")]
public IActionResult Route1(string param)
{
ViewData["Message"] = "route1.";
return View("CacheTagHelper/vary-by-route");
}
[Route("/route2/{param}", Name = "route2")]
public IActionResult Route2(string param)
{
ViewData["Message"] = "route2.";
return View("CacheTagHelper/vary-by-route");
}
View Page
<Cache vary-by-route="route1,route2">Time Inside Cache Tag Helper : #DateTime.Now</Cache>
There is no route value keyed route1/route2. Aka your cache TagHelper should be:
<cache vary-by-route="param">Time Inside Cache Tag Helper : #DateTime.Now</cache>
I found a good definition for this from on old issue posted to the github repo.
A comma-separated list of route data parameter names that the result
should be varied by. The route data parameter values are used as part
of the cache entry key.
https://github.com/aspnet/Mvc/issues/1552
I have two controllers Project and Tag, both of which have a create view and get post methods.
From the Project create view I have the option to add a tag which opens a dialog with the tag create view.
When i add the tag it goes to the tag controller create post method at which point i want to be able to get the controller action that sent it there (in this case Project). I have seen the UrlReferer class, is there a better way to get the controller than that?
the reason i need this is i want to be able to do something like
if (Request.IsAjaxRequest())
{
if (REFERER CONTROLLER != Tag Controller)
{
return Json(new { Item = item, Success = true });
}
else
{
return RedirectToAction("Index");
}
}
so basically if the dialog is in another controller then return a json of the new value otherwise return the index action
Edit ended up using this idea again. went for
if (Url.IsLocalUrl(Request.UrlReferrer.AbsoluteUri) && !String.Equals(Request.UrlReferrer.LocalPath.TrimEnd('/'), Url.Action("Index"), StringComparison.OrdinalIgnoreCase))
{
return Json(new { Item = item, Success = true, Field = String.Format("#Selected{0}s", ControllerName) });
}
return Json(new { Success = true, Field = "#mainContent", Url = Url.Action("Index") });
You have a few options:
You can look at the referring URL (there's no point in taking the referring URL string, parsing out the controller name and then creating an instance of your controller class unless you need access to some sort of method or property in the class; I would just look at the string).
You can include a hidden input which includes the controller name.
You could store a value in session (this seems like overkill; remember, a cookie will be created for this) to remember what page the user came from.
Options 1 and 2 could be tampered with before your server receives the value.
I am beginner for .net MVC. I guess my problem is related to route setting.
What I want to do is :I get data from database, in controller transfer data to json format and pass to view, use javascript decode json data and show on the html.
When I write methods under TechnologyController, type localhost:portnumber/Technology/Index, no decoded json data in html format, but if I type localhost:portnumber/Technology/GetJson
It show me a page with pure json data (which means if I call GetJson() method separately, it works)
I write the same code in HomeController, it runs correct, all the route setting is default:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
//This is my controller
public class TechnologyController : Controller
{
public ActionResult Index()
{
return View();
}
public JsonResult GetJson()
{
Technology myTech = new Technology(); //get data from database (Tested correct)
return Json(myTech.select(), JsonRequestBehavior.AllowGet);
}
}
//This is Javascript:
<script type="text/javascript">
$(document).ready(function() {
$.getJSON("Technology/GetJson/", null, function(data) {
sss.innerHTML+=data["title"];// this part is correct (I already tested,please ignore), the purpose is to parse json data to html.
.......
}
)};
)};
I understand if I call "localhost:portnumber/Technology/Index", it only execute index method, that is why GetJson method is not called, but what url should I call in order to call index() as well as GetJson.
something like:
$.getJSON("#Url.Action("GetJson","Technology"), null, function(data) {
edit 2-
Without Razor it would look like this:
$.getJSON("<%= Url.Action("GetJson","Technology") %>, null, function(data) {
Edit-
Wait you want to call Index AND GetJson? That should already be happening, just load the /index page which calls index controller action, then in the rendered script from there your invoking the GJson action. Why would you think you need to call Index again?
I imagine your method isnt getting hit because the url is incorrect. Grab fiddler*, and take a look at the acutal http traffic and see if it is 404'ing on the request.
*(once fiddler is running change your url to http://localhost:port/..... to http://localhost.:port/.....)
I guess you could modify the "index" method inorder to get the data from "GetJSon" method something like below.
public ActionResult Index()
{
return View("GetJson");
}
Hope this helps!!