In my application I am creating a record in one view & displaying it in other view.
bellow are controller actions
[HttpPost]
public ActionResult Create(Domain.Entities.Survey survey)
{
ISurveyRepository surveyRepository = new DbSurveyRepository();
surveyRepository.CreateSurvey(survey);
TempData.Add("surveyID",survey.ID);
return RedirectToAction("SingleSurvey");
}
public ActionResult SingleSurvey()
{
if (TempData["surveyID"] != null)
{
ISurveyRepository surveyRepository = new DbSurveyRepository();
Domain.Entities.Survey survey = surveyRepository.GetBySurveyID((int) TempData["surveyID"]);
return View(survey);
}
return View();
}
There are two views
1. Create
2. SingleSurvey
Now when I return view "SingleSurvey" from action "SingleSurvey" the URL displayed on browser is http://localhost:49611/SingleSurvey.
But I want to change this URL. What I want is http://localhost:49611/SingleSurvey/{my record id}/{my record title}
Is there any way to do this ?
In your route config file add the following route:
routes.MapRoute(
"SingleSurvey",
"{controller}/{action}/{id}/{title}",
new { controller = "Survey", action = "SingleSurvey", id = UrlParameter.Optional, title = UrlParameter.Optional }
);
Then update the create action to pass the ID and title as part of the route values:
[HttpPost]
public ActionResult Create(Domain.Entities.Survey survey)
{
ISurveyRepository surveyRepository = new DbSurveyRepository();
surveyRepository.CreateSurvey(survey);
TempData.Add("surveyID",survey.ID);
return RedirectToAction("SingleSurvey", new { id = survey.Id, title = survey.Title );
}
In additon, rather than using the TempData to pass the ID it is better to simply read the ID from the URL. To do this, update the SingleSurvey action to take in the ID as a parameter:
public ActionResult SingleSurvey(int? id)
{
if (id != null)
{
ISurveyRepository surveyRepository = new DbSurveyRepository();
Domain.Entities.Survey survey = surveyRepository.GetBySurveyID(id.Value);
return View(survey);
}
return View();
}
The MVC framework automatically binds the id parameter defined in the route to the id parameter on the action method. If you need to use the title in the SingleSurvey action you can also add it as an extra parameter.
Add 2 nullable parameters to the get method
public ActionResult SingleSurvey(int? id, string title)
{
// if id is not null, get the survey based on id
return View(survey);
}
then in the post method, redirect with the parameters
[HttpPost]
public ActionResult Create(Domain.Entities.Survey survey)
{
ISurveyRepository surveyRepository = new DbSurveyRepository();
surveyRepository.CreateSurvey(survey);
return RedirectToAction("SingleSurvey", new { id= survey.ID, title = survey.Title });
}
You might also want want to define a route so that the url is .../SingleSurvey/someID/someTitle rather than .../SingleSurvey?id=someID&title=someTitle
Side note: Its better performance to initialize a new instance of Survey and use return View(survey); rather than return View() in the case where you are creating a new survey
Related
I want to know, there is any technique so we can pass Model as a parameter in RedirectToAction
For Example:
public class Student{
public int Id{get;set;}
public string Name{get;set;}
}
Controller
public class StudentController : Controller
{
public ActionResult FillStudent()
{
return View();
}
[HttpPost]
public ActionResult FillStudent(Student student1)
{
return RedirectToAction("GetStudent","Student",new{student=student1});
}
public ActionResult GetStudent(Student student)
{
return View();
}
}
My Question - Can I pass student model in RedirectToAction?
Using TempData
Represents a set of data that persists only from one request to the
next
[HttpPost]
public ActionResult FillStudent(Student student1)
{
TempData["student"]= new Student();
return RedirectToAction("GetStudent","Student");
}
[HttpGet]
public ActionResult GetStudent(Student passedStd)
{
Student std=(Student)TempData["student"];
return View();
}
Alternative way
Pass the data using Query string
return RedirectToAction("GetStudent","Student", new {Name="John", Class="clsz"});
This will generate a GET Request like Student/GetStudent?Name=John & Class=clsz
Ensure the method you want to redirect to is decorated with [HttpGet] as
the above RedirectToAction will issue GET Request with http status
code 302 Found (common way of performing url redirect)
Just call the action no need for redirect to action or the new keyword for model.
[HttpPost]
public ActionResult FillStudent(Student student1)
{
return GetStudent(student1); //this will also work
}
public ActionResult GetStudent(Student student)
{
return View(student);
}
Yes you can pass the model that you have shown using
return RedirectToAction("GetStudent", "Student", student1 );
assuming student1 is an instance of Student
which will generate the following url (assuming your using the default routes and the value of student1 are ID=4 and Name="Amit")
.../Student/GetStudent/4?Name=Amit
Internally the RedirectToAction() method builds a RouteValueDictionary by using the .ToString() value of each property in the model. However, binding will only work if all the properties in the model are simple properties and it fails if any properties are complex objects or collections because the method does not use recursion. If for example, Student contained a property List<string> Subjects, then that property would result in a query string value of
....&Subjects=System.Collections.Generic.List'1[System.String]
and binding would fail and that property would be null
[HttpPost]
public async Task<ActionResult> Capture(string imageData)
{
if (imageData.Length > 0)
{
var imageBytes = Convert.FromBase64String(imageData);
using (var stream = new MemoryStream(imageBytes))
{
var result = (JsonResult)await IdentifyFace(stream);
var serializer = new JavaScriptSerializer();
var faceRecon = serializer.Deserialize<FaceIdentity>(serializer.Serialize(result.Data));
if (faceRecon.Success) return RedirectToAction("Index", "Auth", new { param = serializer.Serialize(result.Data) });
}
}
return Json(new { success = false, responseText = "Der opstod en fejl - Intet billede, manglede data." }, JsonRequestBehavior.AllowGet);
}
// GET: Auth
[HttpGet]
public ActionResult Index(string param)
{
var serializer = new JavaScriptSerializer();
var faceRecon = serializer.Deserialize<FaceIdentity>(param);
return View(faceRecon);
}
[NonAction]
private ActionResult CRUD(someModel entity)
{
try
{
//you business logic here
return View(entity);
}
catch (Exception exp)
{
ModelState.AddModelError("", exp.InnerException.Message);
Response.StatusCode = 350;
return someerrohandilingactionresult(entity, actionType);
}
//Retrun appropriate message or redirect to proper action
return RedirectToAction("Index");
}
i did find something like this, helps get rid of hardcoded tempdata tags
public class AccountController : Controller
{
[HttpGet]
public ActionResult Index(IndexPresentationModel model)
{
return View(model);
}
[HttpPost]
public ActionResult Save(SaveUpdateModel model)
{
// save the information
var presentationModel = new IndexPresentationModel();
presentationModel.Message = model.Message;
return this.RedirectToAction(c => c.Index(presentationModel));
}
}
this is the controller
public ActionResult Test() {
#ViewBag.TheMessageIs = "this is the message";
return RedirectToAction("Details", new { id = theId});
}
on the view of Action Named Details I will check if it has the ViewBag to show and show it:
#{
if(ViewBag.TheMessageIs != null){
#ViewBag.TheMessageIs
}
}
but here the redirection is working fine to the page, it's not show the message I have stored in ViewBag.TheMessageIs
thanks
Basically what you're doing is invoking the method Details from your Index method and since you're already overloading your Details action with an id, pass it the message as well:
public ActionResult Index()
{
//ViewBag.TheMessageIs = "this is the message";
return RedirectToAction("Details", new { id = 1, TheMessageIs = "this is the message" });
}
public ActionResult Details(int id, string TheMessageIs)
{
ViewBag.TheMessageIs = TheMessageIs;
return View();
}
Then in the Details view you can access the property like this:
#ViewBag.TheMessageIs
public ActionResult Test() {
TempData["shortMessage"] = "MyMessage";
return RedirectToAction("Details", new { id = theId});
}
public ActionResult Details {
//now I can populate my ViewBag (if I want to) with the TempData["shortMessage"] content
ViewBag.TheMessageIs = TempData["shortMessage"].ToString();
return View();
}
You have to do it like this since the viewbag looses its value when you redirect to another active / view
I have below controllers:
// GET: /MaterialPaymentRequestSbuItem/CreateChild
public ActionResult CreateChild(int? parentId)
{
if (parentId==null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var parenetRequest = (from request in db.MaterialPaymentRequests
where request.Id==(int)parentId
select request);
ViewBag.MaterialPaymentRequestId = new SelectList(parenetRequest, "Id", "Description", (int)parentId);
ViewBag.ParentID = parentId;
if (parenetRequest!=null && parenetRequest.First()!=null)
ViewBag.ParentTitle = parenetRequest.First().Description;
return View();
}
// POST: /MaterialPaymentRequestSbuItem/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateChild([Bind(Include = "Id,Name,Unit,UnitPrice,MaterialPaymentRequestId,Quantity")] MaterialPaymentRequestSubItem materialpaymentrequestsubitem)
{
if (ModelState.IsValid)
{
try
{
db.MaterialPaymentRequestSubItems.Add(materialpaymentrequestsubitem);
db.SaveChanges();
}
catch (Exception e)
{
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
}
updateTotalPriceOfParentPaymentRequest(db, db.MaterialPaymentRequests.Find(materialpaymentrequestsubitem.MaterialPaymentRequestId));
return RedirectToAction("List", new { id = materialpaymentrequestsubitem.MaterialPaymentRequestId });
}
ViewBag.MaterialPaymentRequestId = new SelectList(db.PaymentRequests, "Id", "Description", materialpaymentrequestsubitem.MaterialPaymentRequestId);
//need to becheked
ViewBag.ParentID = materialpaymentrequestsubitem.MaterialPaymentRequestId;
if (Request != null && Request["parentID"] != null)
{
try
{
int id = Int32.Parse(Request["parentID"]);
ViewBag.ParentTitle = db.MaterialPaymentRequests.Find(id).Description;
}
catch(Exception e)
{
}
}
return View(materialpaymentrequestsubitem);
}
My main problem is that user is allowed to select model.MaterialPaymentRequestId from drop-down and he/she may leave it with no value selected. MaterialPaymentRequestId is used in first controller (befor post) to find Parent title from db and pass it to view using ViewBag, however if user does not select MaterialPaymentRequestId dropdown items, after postback, I lost MaterialPaymentRequestId. Currently I read Request variable and look inside url to find parameters to lookup for parentID.
My url calls are like http://localhost:46813/Admin/MaterialPaymentRequestSbuItem/CreateChild?parentId=23.
However this practice seems like a bad practice than I cannot pass v variable between two controller methods a process like this:
Controller method(get) ---> View ---> Controller method(post)
Currently I feel a bit stuck in MVC!
i hope i got your point right, you can use an #Html.hiddenfor(model => model.ParentId) in your view it will store ParentId value from query string and when user submits form will be posted to POST method so you dont need to look into url to get it. use a viewmodel with ParentId property and do as below
public class MaterialPaymentsViewModel {
//other properties
public int ParentId {get;set;}
}
public ActionResult CreateChild(int? parentId)
{
var model = new MaterialPaymentsViewModel{ParentId = parentId};
//other stuff
return View(model);
}
//View
#using (Html.beginform()){
//
#html.hiddenfor(m => m.ParentId)
//submit
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateChild(MaterialPaymentsViewModel model)
{
if(model.ParentId != null)
{
//
}
//
}
When user click this element, I want catch id data in controller or in OnActionExecuting method in ActionFilter class.
How I can do this?
In view:
<a id="123" href="AreaName/ControllerName">TEST</a>
You could try this...
In Controller:
public ActionResult Index()
{
var model = new HomeViewModel { Id = 123 };
return View(model);
}
public void RecordClick(int id)
{
int incomingId = id;
}
In View:
#Html.ActionLink("Link Text", "RecordClick", "Home", new { id = #Model.Id }, null)
Generated HTML:
Link Text
Upon clicking link, id value will be sent to RecordClick action.
TEST
your controller
[HttpGet]
public ActionResult Index(int userid)
{
return View();
}
if you debug you should have that value
I'm trying to create a mvc application. I have a project controller, actions are below
[AllowAnonymous]
[HttpGet]
public ActionResult Index()
{
//TODO: Browse
return View();
}
[AllowAnonymous]
[HttpGet]
public ActionResult Index(long projectId)
{
using (var entity = new dixraContext())
{
var project = entity.Projects.FirstOrDefault(m => m.Id == projectId);
if (project == null)
return RedirectToAction("NotFound", "Error");
else
return RedirectToAction("Index", project.UrlName);
}
}
[AllowAnonymous]
[HttpGet]
public ActionResult Index(string projectName)
{
using (var entity = new dixraContext())
{
var project = entity.Projects.Where(m => m.Name == projectName);
return View(project);
}
}
I want to show URL's like
example.com/Project/ProjectName
But when i enter url as
example.com/Project/1
Got Error.
An error occurred while processing your request
. as response. When i enter example.com/Project/Index/1 i go into first action.
I also want to resolve project from id and redirect to usual Project/ProjectName url.
Looks like you've got conflicting routes. One way to solve this while leaving your three possible inputs would be checking your input parameter.
Also, your RedirectToAction has a string as its second parameter - that overload of RedirectToAction treats the second parameter as the controller name, not the route object:
Assuming your routes file looks ok:
routes.MapRoute(
name: "Project",
url: "Project/{projectName}",
defaults: new { controller = "Project", action = "Index" }
);
Your controller action might be:
[AllowAnonymous]
[HttpGet]
public ActionResult Index(string projectName)
{
if (string.IsNullOrWhiteSpace(projectName))
{
// return your empty view
}
int projectId;
if (int.TryParse(projectName, out projectId))
{
projectName = GetProjectNameFromDatabase(projectId);
return RedirectToAction("Index", new { projectName });
}
// return your view with your model
}
There may be a better way, but this will work.