passing in an additional parameter with the model to a View - c#

Still learning Mvc so sorry if this question is a bit weird.
I am passing the model in my Controller method and want to pass an additional parameter.
what I want to achieve is something like this but the parameter overload does not allow for the 'additional' parameter.
#using (Html.BeginForm("SubmitCall", "Home", new { Id = Model.ProductDetail.ProductId }))
and then in the controller
public ActionResult SubmitCall(ViewModel model, int Id)
{
return RedirectToAction("DetailViewById", model, new {productId = Id});//not allowed
}
Is there a better way of achieving this?
Kind regards

If your only intention is to redirect the client to another URL then the above scenario is not the right way to achieve this.
RedirectToAction will send a HTTP 302 with the Location information generated from your route information (again, in your case this would be the URL to DetailViewById with productId as a parameter or part of the URL - depends on your route configuration).
If you need to persist the ViewModel that is submitted by the client and operate on it once the user is requesting your redirected action, then i would suggest to use TempData which is designed for between-request persistence of such data.

Usually, the ViewModel is a combination of what you have coming back from database (DTO) + extra bits and pieces you need TO and FROM View.
So in my opinion, you should add this extra property to your Viewmodel.

Create an anonymous object for parameters:
return RedirectToAction("DetailViewById",
new {
productId = Id,
model.Property1,
model.Property2,
...
});

Related

Handling extra MVC parameter with different ActionResult

I'm working on a website that has 4 individual sections, each with their own controller. These controllers share a few models, however the model will do things slightly differently based on the controller calling it.
The route that I'd like to follow is {controller}/{model}/{id}/{action} so I could use controller1/cars/5/edit rather than controller1/editcar/5.
Is there any way to have my controller understand a model+action combination and handle them with different ActionResults, or am I forced to use an ActionResult on the model name and then use a conditional to figure out what action to take?
In Ruby I could use get "/controller1/cars/:id/edit" do. I'm just looking for something similar in MVC4.
Example routs:
/controller1/cars
(returns a view containing all cars from controller1)
/controller1/cars/5
(returns a view containing car with the ID 5 from controller1)
/controller1/cars/5/edit
(returns a view to edit car with ID 5 from controller1)
/controller2/cars
(returns a view containing all cars from controller2)
/controller2/boats
(returns a view containing all boats from controller2)
I think this route meets your needs. It requires some clever logic in your action methods but should give you the tools to handle it. Read my description of behavior.
routes.MapRoute(
"Default", // Route name
"{controller}/{model}/{id}/{action}", // URL with parameters
new { controller = "Home", action = "View", id = UrlParameter.Optional } // Parameter defaults
);
This route will Default to an action called View (that will presumably be used for Display) and has an option to direct to a different Action.
Model and id will be passed as arguments to you action method. Unfortunately, Model will not be sent as a type but a string (you may feed that into a Factory class).
if if is left out (eg /controller2/boats) it will be passed to your action as a null. This requires logic to handle but gives you the tools to handle it.
Thanks for the responses. The reason that I was having so much trouble with this was because I couldn't figure out how to separate controllers with a rout properly. This resulted in my idea breaking away from MVC standards and almost trying to implement a controller of controllers.
When I finally stumbled upon "Areas", I quickly realized that this is what I needed. I was able to add an Area for each section (or area) of my website, and within each area, I could define individual controllers and views, while my models remained in a shared directory outside of all areas. This now works perfectly.

Updating the model in the controller?

I'm using ASP.NET MVC 3. I have a question if it's possible to update the model, even if it's not being sent to the controller? Perhaps the question is completle of, or I'm doing things in a wrong way?
I have an ajax-call to a controller method. I'm passing in an id. I would like the controller to find some stuff in the db, and then update the model, passing it back to the view.
I've got a pretty big model... I've found some solutions, where to convert the model to a javascript object, and send it to the controller. Is that the only/right way?
How to send a model in jQuery $.ajax() post request to MVC controller method
I thought that maybe the controller has the model, where I could update some fields in it?
The call to the controller:
function getBis(id) {
$.ajax({
type: "GET",
url: '#Url.Action("GetBis")',
data: { "id": id },
dataType: 'json',
cache: false,
success: function (data) {
// Do something here
},
error: function (jqXHR, textStatus, errorThrown) {
alert("Problem!");
}
});
}
The controller code:
public ActionResult GetBis(string id)
{
BeslutIStortDTO viewModel = new BeslutIStortDTO();
int theId;
if (!Int32.TryParse(id, out theId))
throw new Exception("Wrong id");
viewModel = _blLayer.GetBIS(theId);
// somehow update the model here!
return View("index", viewModel);
}
usually you "pass the model" between JQuery and your controller when you need to "reflect" what ever is changed on your UI without doing any mapping(MVC is smart enough to construct a new object from the parameters you give it). In your case you said you just need to pass an ID to do some stuff on your model. So all you need to do is pass the ID as parameter, get it within the controller action and then do your stuff.
have a look at the below link
Pass a parameter to a controller using jquery ajax
First by updating the model, do you mean you want to update the record in the DB? That is not a good practice to do in a get request. If not read on..
Once you got your object with GetBis method, you can change all properties of it.
If you want to send this object to Javascript, use JSON Result.
return JSON(viewModel);
and one more thing, don't initialize view model in the first line of code, unnecessary object allocation.
The short answer is Yes and No, depending upon exactly what you mean, however you may want to reconsider your design. I would guess you are actually trying to render a Domain Entity to your view, rather than a View Model. This is a common newbie mistake.
One thing I would like to clarify is the difference between domain entities, and view models.
Domain entities are generally pulled from your persistence layer, and that is where your state changes should take place.
View models are temporary constructs, created on the server, just before a view is output as HTML, to be used as the data storehouse for the View template. It does not exist on the client's web browser after the request, and it no longer lives on the server after a request.
If you are using Ajax to perform some type of data change, instead of reloading the page, then what you would generally do, is make changes to the Domain object (via Id), rather than the View Model you originally passed in (which doesn't exist anymore).
For example.
I have a domain entity which is tied to a database record.
Person {long id=1;string name=bob;bool enabled=true}
I have a view model (that i map to bob in the initial get controller function)
PersonData {long id=1;string name ="bob", enabled=true}
To do this, in my initial page GET controller function, i pull up the Domain entity bob from the database, copy his data over to an instance of the view model, then pass the view model to the View("EditPerson",pd) action result, which goes through the razor view page and view model, and substitutes values into the HTML it is writing to the response stream, where appropriate.
Now, you have HTML on a client's web browser, that is IT. No view model exists. Now you have some Ajax which is browser side scripting, that says when I click a "Toggle Status" link for instance, what would happen is the browser (without changing pages) will submit a request to the ajax url you provided, passing in an Id of bob. Your controller function should then load the Entity version of Bob, and toggle the Entity version of Bob's enabled to an appropriate value, then persist that change to the database.
Nowhere at all does the original VIEW Model come into play, as it has not existed since the initial page was rendered to the browser.
Is there something specific you want to accomplish that you cannot see a way to do with this pattern?

ASP.net MVC - Passing an Id into a Partial View

I have the following route in my MVC application:
/foobars/edit/{id}
The {id} in this case corresponds to the Id for my "Foobar" model.
In my Edit view I am doing the following:
#Html.Partial("~/Views/Notes/CreateNotePartial.cshtml", new CreateNoteViewModel())
The CreateNotePartial view uses a jQuery dialog and will POST to my NotesController using the following route:
/notes/create/{id}
The {id} in this case is NOT the same id as my Foobar id. My Foobar model has another property called UniqueId. I need to be able to pass this into my Partial view so that when I create the form to POST to the notes controller it passes in the right id. What is the best way to do this?
Right now I am doing the following:
// Foobar Edit View
#Html.Partial("~/Views/Notes/CreateNotePartial.cshtml", new CreateNoteViewModel(Model.UniqueId))
// Create Note Partial
#model CreateNoteModel
#using( Html.BeginForm("Create", "Notes", FormMethod.Post, new { id = Model.UniqueId }) ) {
}
Is there a better way to pass this to my partial view or is this the best way to do it?
Seems the best way to do it to me - I think your only other option is to pass it in ViewData, which everyone would tell you is not recommended for reasons of strong typing, magic strings, et al.
Certainly, it's the way that I do it (not that I'm the world's greatest authority of course).
From what it looks like, you're setting the form id to the model.UniqeId. That's just going to set the form's html element to whatever that model id is. I would not recommend doing that.
There's nothing wrong with using TempData (not the same as ViewData). TempData is made for passing a value from one view to another and then once it's accessed, it goes away. See this post for more.

Is using TempData to pass details between controller actions bad practice?

I have certain situations where I need to pass a value between controller actions.
When passing a returnUrl from a view to all nested views. In the
view I have
#{
TempData["returnURL"] = Request.Url.AbsoluteUri;
}
and then access it in a similar way to this (in my real version I
check that the key is in TempData and that the returnURL is a real
URL):
return Redirect(TempData["returnURL"].ToString());
If it needs to continue on past the first page change (i.e. Search
page -> Edit page -> Edit Section page) I'm adding it again
TempData["returnURL"] = TempData["returnURL"];
When I need to pass a value from one controller action through a
view to another controller action that is called by ajax such as
here:
public ViewResult Index(FormCollection form)
{
var model = new GridColumnChooserViewModel();
//Select deleted/not deleted rows
if (form.HasKeys())
model.ShowRows = (form["deletedDropDown"] == null) ?
"Active" :
GetOptionByName(form["deletedDropDown"]);
TempData["ShowRows"] = model.ShowRows;
...
}
and then in my other ajax-called action controller I access it:
public JsonResult GetData()
{
//Select deleted/not deleted rows
var showRows = (TempData.ContainsKey("ShowRows") && TempData["ShowRows"] == null) ?
"Active" :
GetOptionByName(TempData["ShowRows"].ToString());
//refresh tempdata showrows so it is there for next call
TempData["ShowRows"] = model.ShowRows;
return this.GetDataSource(showRows);
}
My question is, is this really bad practice? From my understanding of it, I'm essentially using TempData like a session cookie. Is there a better way to do this, like using an actual cookie?
Yes, I would say that this in general is bad practice. While the ViewData dictionary approach is fast and fairly easy to implement it can leads to typo's and errors that are not caught at compile time. An alternative would be to use the ViewModel pattern which allows you to use strongly-typed classes for the specific view you need to expose values or content within. Ultimately giving you type safe and compile time checking along with intellisense.
My first choice would be to use a view model. If that doesn't fit then using session state may be just fine.
It seems like you are using TempData to flow state through the various pages of your site; in general, I'd say this is a bad practice.
Ideally, you would flow whatever upcoming state you would need to the client, and the client would store it (in some sort of JSON or whatever). Then, the client would return it to you as part of their action, and then you'd pass back the appropriate state, etc.; it speaks more to the stateless nature of HTTP applications.
I changed both situations to use Session so that I didn't have to keep pushing the TempData value on.
public ActionResult Create()
{
Session["returnURL"] = Request.UrlReferrer.AbsoluteUri;
...
}
Then I access it like this
var returnURL = (Session["returnURL"] != null) ? Session["returnURL"].ToString()
: Url.Action("Index", "Home");
Seems a bit better.

ASP.NET MVC - POST Action Method with Additional Parameters from URL

With ASP.net MVC is it possible to POST a form to a controller action which includes parameters not in the form, but from the URL?
For example
The Action method in GroupController:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(int idOne, int idTwo, Model model)
{ ... }
The route:
"{controller}/{action}/{idOne}/{idTwo}"
Posted URL:
/Employee/Show/1/42
In this example, the form is being posted to a different controller, the model has the correct value, however the other parameters have default values 0.
The behavior I was expecting is that the ModelBinder would see that I have two parameters that match the given route, and assign the current values of 1 and 42 to the parameters in the same same way a GET operation works.
Is this behavior not supported, or am I missing something?
EDIT:
To be clear, the form on the Show view for the controller Employee contains a form which is posting to a different controller. We can call it Group.
The form action URL looks like this
/Groups/Create/0/0
The form is declared as follows
Html.BeginForm("Create", "Groups")
After trying many different overloads for Html.BeginForm I have found that the parameters are only mapped when the form action URL matches the current URL in the browser address bar.
So if i navigate to the URL /Groups/Create/1/42 I will have a new form. If I then submit the form, the URL route values are passed to the POST action.
If I understand your question correctly, you want the action of the rendered <form> element pointing to URL containing route values. This should be possible with one of the overloads of the HtmlHelper.BeginForm() extension method:
Html.BeginForm("action","controller", new { idOne=1, idTwo=2 }, FormMethod.Post);
Let me know if I got your question all wrong :)
I'm pretty sure that you can only post form data from inputs inside the form. Have you considered rendering the view in such a way to create form input values off of the URL (perhaps with an HTML helper?).
UPDATE: If you don't want to use the form at all, use ControllerContext.RouteData.Values["idOne"] as opposed to passing it in through the method signature.
I had a similar problem, the configuration RouteConfig has solved this problem.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
...
routes.MapRoute(
"MyRoute",
"{controller}/{action}/{idOne}/{idTwo}",
new
{
controller = "Employee", // as an example
action = "Show",
idOne = UrlParameter.Optional,
idTwo= UrlParameter.Optional
}, new { idOne = #"\d{1,5}" });
}
}
...And...
Html.BeginRouteForm()
#using (Html.BeginRouteForm("MyRoute", new { idOne = 1, idTwo= 2 }, FormMethod.Post))
Writes an opening tag to the response. When the user submits
the form, the request will be processed by the route target.
This member is overloaded. For complete information about this member,
including syntax, usage, and examples, click a name in the overload
list.
And all works
I recently had this issue too, and because I had a different route, it was mapping to the default route, without taking into account the extra route params that I was passing in.
So to get it working quickly, I wrote the form using form tags instead, and used #Url.Action to create the required action.
Once you get to your Create view, your route values used to get there need to be re-posted to the post action.
So, one option is having a pair of hiddens, to hold the ids that came from the route. This way, once you post the formas, its values are posted along with the other inputs.

Categories

Resources