I inherited a legacy webforms app that makes use of some nasty query string variables
I want to clean up the site using MVC routing, I can do this easy enough for some of the simple ones how
1 page alone call it Decision.aspx uses the following query strings.
City=Something
ShowMessages=true
CaseID = INT32
PersonID = INT32
SpectorKey = GUID
in some case the query string is a combination of many of these
like
enter code hereCity=Juno&ShowMessages=true&Personid=44
can anyone help me with this?
Just to cleat routes you can add something like this to your RouteConfig
routes.MapPageRoute(
"DecisionRoute",
"Decision/{City}/{ShowMessages}/{CaseID}/{PersonID}/{SpectorKey}", //Your URL
"~/Decision.aspx?City={City}&ShowMessages={ShowMessages}&CaseID={CaseID}&Personid={PersonID}&SpectorKey={SpectorKey}" //Actuall path
);
Note that in case that i posted all your parameters should always be. If it is not you must think how to order this paremeters.
Related
I am trying to implement POST-Redirect-GET in MVC using multiple named parameters.
I can do this with one parameter:
return RedirectToAction("MyGetView", new { bookId = id });
I could hardcode multiple parameters:
return RedirectToAction("MyGetView, new {bookId = id1, bookId=id2});
But how do I get from an IEnumerable< int> of Ids, which is of variable length, to a correct query string without constructing it by hand?
My current code looks like this:
var querystring= string.Join("", BookIds.Select(x => string.Format("bookId={0}&", x)));
querystring= querystring.Trim('&');
return Redirect("MyGetView?" + querystring);
It works fine, but it seems like there should be a better way.
(I want the parameters to be visible in the URL, so that users can bookmark the page. I believe this means I cannot use TempData.)
First, it's not wrong to use query parameters where the ASP.NET MVC Routes fail to work, and they do with arrays (basically). How is your "clean" URL route supposed to look like?
Example: /Books/View/6 (Works nice for one Book, 6 is the int ID)
But what do you want to have for multiple Books? /Books/View/6,5,134 maybe?
In this case you could just use your own convention of formatting the Url as a list of IDs.
Your redirect would look like: return RedirectToAction("View", "Book", new { Id = allIds.Join(",") });
And your View action can support this:
public ActionResult View(string id)
{
if (id == null)
throw new Exception... // Not expected
var ids = id.Split(new char[]{ ',' });
// Further processing...
}
If your're not satisfied with this approach (you might have issues when number of items is getting bigger) you can see what others tried, but it's basically what you already do, or I'm not sure if the other solutions are worth the effort.
Currently I am working with simple Forum module in ASP.NET MVC 3 which i will add later to my main application. The possibility to link to certain blocks like div used to present thread replies is very useful.
I figured out something which work and propably will be enough for my needs, I just wonder if there is something more elegant and simple aswell. I found a solution using ActionFilters, and since I'm quite begginner in MVC I would like to find some easier solution (if exists). Well i will propably learn ActionFilters soon aswell :)
So here is what I've done:
public ActionResult ShowThread(int id, int? postID)
{
var thread = db.ForumThreads.Find(id);
if (postID != null)
{
return Redirect(Url.Action("ShowThread",new {id=id})+"#post-"+postID.ToString());
}
return View(thread);
}
I know it is quite simple, but it is working. Also it doesn't check if the postID is valid yet, but it is not a part of question.
The solution is to use one of RedirectToAction overloads: http://msdn.microsoft.com/en-us/library/dd470154(v=vs.108).aspx.
Perhaps, in your case, the next one would do: http://msdn.microsoft.com/en-us/library/dd460291(v=vs.108).aspx
And the call would be:
return this.RedirectToAction("ShowThread", new { id = id, post = postID });
Another (simpler, but not safer!) solution is to format the URL you need to redirect to and to use the Redirect() method like this:
var redirectUrl = string.Format("/Home/ShowThread/{0}?post={1}", id, postID);
return this.Redirect(redirectUrl);
Pay attention to your URL mappings, though. The examples above assume the method
public ActionResult ShowThread(int id, int? post)
is in HomeController and the default route has not been changed. Otherwise you should
adjust the URL prepending the controller name (w/o Controller), or
change your default route to map to the controller's name.
I was getting the query string back using:
public ActionResult Index(int id)
{
var queryString = Request["myQueryString"];
}
Then I looked at:
help-testing-mvc3-controller-that-accesses-querystring
Which states:
It is against MVC's design pattern to use HttpRequest directly. You can access the query string variables on your action as parameters.
I don't really understand this. Is what I've done against the design pattern? If it is why is that and how could it be done?
It breaks the concept of model binding. It also gets complicated with unit testing and trying to new up a new HttpContext for a test. If it was just a parameter, you could just pass the value.
The preferred (and easier to read) method would be:
public ActionResult Index(int id, string myQueryString)
{
...
}
Your action method should take most of the data submitted from your form. One of the strengths of MVC is the model binding it has within it. Check out this page, as it has a good example of this:
http://www.codeproject.com/Articles/159749/ASP-NET-MVC-Model-Binding-Part1
You can accept literals (string, bool, etc.) but also strongly typed objects in your action methods.
Background:
In MVC3, I've used the following syntax to specify custom Action parameter names:
public ActionResult ActionName([Bind(Prefix = "principalID")] int userID,
[Bind(Prefix = "dependentID")] long applicationID)
The route for this action was defined as follows (ActionNameConstraint is a custom IRouteConstraint):
routes.MapHttpRoute(
"DependantAction",
"{controller}/{principalID}/{action}/{dependentID}",
new {controller = #"[^0-9]+", action = ActionNameConstraint.Instance, dependentID = RouteParameter.Optional}
);
Question:
The BindAttribute is a System.Web.Mvc class. Is there an equivalent of this (parameter binding) in Web Api?
Of course, if there are other solutions to achieve the same result, I'd love to hear them!
You can use the System.Web.Http.FromUriAttribute attribute to specify the parameter names used for model binding.
public ActionResult ActionName(
[FromUri(Name = "principalID.userID")] int userID,
[FromUri(Name= "dependentID.applicationID")] long applicationID
)
FromUri tells model binding to examine the query string and the RouteData for the request.
I understand that in WebAPI you just use special controller class base, and special Action names, but still after all they are controllers and actions.
Did you try it and it didn't work? A quick look at this article seems to suggest model binding in general (not the specific attribute though) should work normally:
http://blogs.msdn.com/b/jmstall/archive/2012/04/16/how-webapi-does-parameter-binding.aspx
Edit:
Some say this should work with MVC only and downvoted the answer. Here you go, more references:
MS Documentation:
http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
MSDN Blog Post
http://blogs.msdn.com/b/jmstall/archive/2012/04/16/how-webapi-does-parameter-binding.aspx
Accepted SO answer
Custom Parameter Names With Special Characters in ASP.NET Web API MVC 4
A post exploring several approaches (follow to the end)
http://blogs.msdn.com/b/jmstall/archive/2012/04/20/how-to-bind-to-custom-objects-in-action-signatures-in-mvc-webapi.aspx
Another MSDN blog post (see scenario 3)
http://blogs.msdn.com/b/hongmeig1/archive/2012/09/28/how-to-customize-parameter-binding.aspx
All the examples I've seen for overloading usually have only two methods of the same name with different parameters and one using the GET verb while the other uses POST. Is it possible to do two or more overloads on the same method, all with the same verb?
Here's an example of what I'm referring to: Can you overload controller methods in ASP.NET MVC?
I don't think you can overload the same action name with the one verb by default. As that other thread you point to says, you can overload the methods & then use an attribute to change the action that maps to the method, but I'm guessing that's not what you're looking for.
Another option that I've used before (depends on how complex/different your overloads are) is to simply use nullable values for the parameters & effectively merge your different signatures together. So instead of:
public ActionResult DoSomething(int id)...
public ActionResult DoSomething(string name)...
just have:
public ActionResult DoSomething(int? id, string? name)
Not the nicest solution, but if one overload just builds on another then its not too bad a compromise.
One final option that may be worth giving a go (I haven't tried it & don't even know if it'll work, but logically it should), is to write an implementation of the ActionMethodSelectorAttribute that compares the parameters passed in the ControllerContext to the method signature & tries to make a best match (i.e. try to resolve the ambiguity a bit more strictly than the default implementation).
I guess it is not. Since I found that the MVC framework didn't really care what you put in the parameter list, for example, my action is like:
public ActionResult Index(int id) {...}
It is ok to request like this: Domain.com/Index.aspx
or Domain.com/Index.aspx?id=012901
or even Domain.com/Index.aspx?login=938293
Since overloading in programming language means that you select different functions (with same name) using the input parameters, but MVC in this case didn't care about it! So other than ActionVerb overloading, I think it is not ok.