How does MVC 5 generate url for GET redirect action result? - asp.net-mvc

So in my mvc 5 app, I got this default 'Index' action, which simply redirects to the search action, with the default model values:
[Route]
public ActionResult Index()
{
var model = new T();
return RedirectToAction("Search", model);
}
What i got puzzled about is how i end up with the url like '.../search?xxx=xxx...'? Is there anything i can do to customize or at least inject/replace the url generation, especially the query string part? e.g. i might want to display 1/0 for bool properties in the search model, and customize query string key names etc?
and why would someone vote down for my question? psst...

The query string generated depend on the model property name and type + value you passed in.
For example, say if your pass in model is like
public class MyModel
{
bool IsSort{get;set;}
}
If your model is like this and IsSort value is true, then you will get url like /search?IsSort=true
Say you want to change your query string to 1/0 instead of true or false, then create viewModel which has property string then assing it properly like:
public class MyModel
{
string IsSort{get;set;}
}
var model = new MyModel();
model.IsSort = true? "1":"0";
same apply to querystring key (which correspond to property name)

Related

Why use "new" for Route Values in "ActionLink" ---- for example

I have 2 examples below:
#Html.ActionLink("Create New", "Create", new { id = Model.Id })
and,
return RedirectToAction("Index", new { id = review.RestaurantId });
My question is regarding the new { id = xxx} part in object route values. Why do we use "new" in this case? What exactly does it do? Does it initialize "id" variable in this case?
Also, it is strange that these methods, create and index definition can only take arguments as defined in the route values...
That is,
public ActionResult create { int id)
{ ...}
is correct but following is wrong....
public ActionResult create { int somethingelse)
{ ...}
So please tell me what is the new {id = xx} in my first 2 examples is doing?
Thanks
new {} creates a new object of type Object. The type is anonymous. You see that syntax when writing linq queries that end in " select new {x = "foo". y="bar"}". It is often used when setting an object to type "var".
What you are doing in your ActionLink is providing Route Values. MVC takes the properties and values in the object and puts them in the QueryString of the request. It is what you might refer to as "magic". You can set a break point in your controller Action and check "HttpContext.Request.QueryString" to see it.
The input values for you Action methods have to match the properties that are being passed in via the QueryString.
That is actually creating an anonymously typed object and passing it into ActionLink(). ActionLink then uses that object, coupled with your routing rules to generate the link. MVC will look for properties on that object that match the routing names (usually of route parameters) and figure out how to build it. Since you likely have the default MVC route (/controller/action/{id}) that is what links everything together.
Further, that is why id "is correct", but somethingelse "is wrong".
If you change "id" to "somethingelse" in your routing rule, you could then see new { soemthingelse = ""} work in your ActionLink().
Does that help?
In both cases your creating a new anonymous object to pass into the query string as a route value. You create a new object because one does not already exist on the view.
The MVC source code:
if (additionalViewData != null) {
foreach (KeyValuePair<string, object> kvp in new RouteValueDictionary(additionalViewData)) {
viewData[kvp.Key] = kvp.Value;
}
}
They use it to create new RouteValueDictionary parameters.
You don't have to use it the this manor. You could create an object on the model and pass it in:
public class SomeModel
{
public SomeModel()
{
MyObject = new { id = 10 };
}
public int Id {get;set;}
public object MyObject {get;set;}
}
#Html.ActionLink("Create New", "Create", Model.MyObject)
This would also work though is probably not something you would attempt.
For the second part of your question. The RouteValueDictionary searches by key and assigns the value to the key that was given.
So whatever you call the key in the anonymous object, MVC will attempt to assign the value to it on the action. The name must match or they key cannot assign the value.

How to add a query string from surface controller in umbraco mvc in order to persist model values

How to add a query string from surface controller in umbraco mvc . This is my current code.
Initially I wrote a code like
public ActionResult Registration(RegisterModel model)
{
//Code to insert register details
ViewBag.Success="Registered Successfully"
return CurrentUmbracoPage();
}
with this I could successful persist my ViewBag and model properties value but I could not add a query string with it.
For certain requirement I have to change the code that returns a url with querystring.
which I did as below
public ActionResult Registration(RegisterModel model)
{
//Code to insert register details
ViewBag.Success="Registered Successfully"
pageToRedirect = AppendQueryString("success");
return new RedirectResult(pageToRedirect);
}
public string AppendQueryString(string queryparam)
{
var pageToRedirect = new DynamicNode(Node.getCurrentNodeId()).Url;
pageToRedirect += "?reg=" + queryparam;
return pageToRedirect;
}
and with this my values of the properties in model could not persist and the ViewBag returned with null value.
Can any one suggest me how to add query string by persisting the values in the model and ViewBag.
Data in ViewBag will not be available on the View when it redirects. Hence you have to add message in TempData which will be available in the View after the redirect like TempData.Add("CustomMessage", "message");

Asp.net mvc sql query as parameter to controller action method

I am trying to send a query like below from UI to controller.
name='abc' and title='def'
I am trying to use lambda expression on controller to filter this query. But I am struggling hard to pass ui query to controller and make it as lambda expression.
Could you please throw some idea with example where i can pass sql query(string) as parameter and use it in controller action method as lambda expression. Any link or logic should be fine for me to try further.
[HttpGet]
public virtual ActionResult QueriedProjects(string builtQuery)
{
var Helpera = new Helpera(true);
var myProjectDetails = Helpera.myProjectDetails (null);
var myProjectDetails = new myProjectDetails ()
{ GetMyProjectDetails = myProjectDetails };
return View(myProjectDeails)
}
UI
on button click I am generating a query as string with entered values in query builder
Generated String: name='abc' and title= 'def'
If you pass values like this:
Contoller/QueriedProjects?name=abc&title=def
You need to have 2 parameters in your controller method like:
public virtual ActionResult QueriedProjects(string name, string title)

Entity ID as input model field vs action parameter?

Should an input model for creating or updating entities have an ID field to identify the entity, or should your edit action accept an ID parameter?
Compare
Input Model
[HttpPost]
public ActionResult(EntityInputModel input)
{
var entity = _unitOfWork.CurrenSession.Get<MyEntity>(input.Id);
// do editing
// ...
}
Action Parameter
[HttpPost]
public ActionResult(Guid id, EntityInputModel input)
{
var entity = _unitOfWork.CurrenSession.Get<MyEntity>(id);
// ...
}
Personally I prefer the first. I always define a specific view model for each POST action. So if this action requires an id I include it as part of this specific view model.

My action controller code looks amateurish

First post time,
I've been playing around with MVC abit... I have a view which has multiple input fields, some of these fields can be blank on post.
The action method inside the controller for the post looks something like this
public ActionResult Filter(int? id, string firstName, string lastName, bool? isMember)
I've been using the DynamicQuery extension which has been kicking around in order to perform dynamic Linq querys on my database and I've encapsulated this in a Search object which is passed to the data access layer for execusion.
However, I also have a customized ViewData object which is passed back to the view for displaying the input values and the results of the query.
It all looks a little nasty in code as I'm having to set both the Search object properties AND the ViewDatas.
public ActionResult Filter(int? id, string firstName, string lastName, bool? isMember) {
var search = new Search {
Id = id,
FirstName = firstName,
LastName = lastName,
Member = isMember
};
var memberViewData = new MemberViewData {
Id = id,
FirstName = firstName,
LastName = lastName,
Member = isMember
};
memberViewData.Results = _dataRepository.GetMember(search);
return View("Search", memberViewData);
}
Am I over thinking this and really should just pass the values to the data access layer and populate the ViewData in the controller, or is there a much more elegant pattern or practise I could use?
Sorry if this seems dump, not allot of people to bounce ideas off and time to dig into the framework.
Use modelbinder to bind data
According to your snippet MemberViewData class has the Results property in addition to properties of Search class. So first step would be to make MemberViewData derive from Search and define a constructor that accepts Search instance as parameter and assigns it's basic properties from it. Next I would change the action method like so:
public ActionResult Filter(Search search)
{
return View("Search", new MemberViewData(search)
{
Results = _dataRepository.GetMember(search)
});
}
Like Tadeusz mentioned, a ModelBinder can help build the MemberViewData for you, which would leave only the results to be fetched.
You could also decide on creating a presentation service that understands how to build this view data object and simply delegate to it. I'd prefer the model binder approach here though.

Resources