Equivalent of [Bind(Prefix = "principalId")] in MVC4 Web Api? - asp.net-mvc

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

Related

Is there simple way to use bookmarks in controller action's generated urls?

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.

How to access a query string in MVC

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.

Value cannot be null. Parameter name: String in asp.net mvc C#

I am pretty new to asp.net mvc. I want to get the parameter string in my url
http://localhost/Item/ItemSpec/3431?dep=62&cat=129&tab=2
How can I get the value=3431?
I tried to used HttpContext.Current.Request.QueryString["id"], but it's not work. 3431 is the id of the item that display in my page, that's why I used ["id"].
Thanks you so much.
The 3431 is part of the path of the request, not part of the query string. You could use HttpRequest.Path to get at the path, but MVC routing should allow you to simply write a controller method which accepts the ID as a parameter. I suggest you read up on how to configure routing. (Just searching for ASP.NET routing or MVC routing will give you lots of articles.)
Assuming the default route is configured in Global.asax ({controller}/{action}/{id}) you could have your controller action take an id parameter and the default model binder will automatically set its value:
public ActionResult Foo(string id)
{
...
}
If you want to fetch this id value from some other portion of your code that does have access to an HttpContext you need to fetch it from the RouteData:
var id = HttpContext.Request.RequestContext.RouteData["id"];
RouteData is available in all standard MVC locations. In your example you have used the static HttpContext.Current property which is something that you should never use. I suspect that you are trying to fetch this id from a portion of your code where you are not supposed to have access to the HttpContext. So you'd better fetch this id using standard techniques and then pass it as parameter to other parts of your code.
If Item is your controller, and ItemSpec is action, you can get the Id just by
public ActionResult ItemSpec(int id) { }
You routing have to be setup to:
context.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index" }
);
If you haven't changed your routing so it's still defined as it was when you created Asp.net MVC Web project then this should be one of your controllers:
public class ItemController : ControllerBase
{
...
public ActionResult ItemSpec(int id, int dep, int cat, int tab)
{
// implementation that uses all four values
}
...
}
This is of course just one of the actions in it. There may be others as well. Most likely the Index one that's generated by default and is also used by default routing...

Making mvccontrib testhelper work with actions that get route data automapped to objects

This is ASP.NET MVC v1 (not using the v2 yet)
I have a route entry like this:
routes.MapRoute(
"Srp",
"soeg-{searchQuery}/{listingType}",
new { controller = "Srp", action = "Search", listingType = string.Empty },
new { listingType = "privat|forhandler|"}
);
and an action to match it:
public ActionResult Search(QueryParameters queryParameters)
It works perfectly - the mvc framework knows to map the searchQuery and listingType onto the two properties of the QueryParameters object with the same names.
My problem is unit testing. I'm using Mvccontrib project and LOVING the ShouldMapTo method:
[Test]
public void RegisterSrpRoutes_SoegWithKeywordAndValidListingType_ShouldMapCorrectly()
{
var queryParameters = new QueryParameters {SearchQuery = "hest", ListingType = "privat"};
"~/soeg-hest/privat".ShouldMapTo<SrpController>(controller => controller.Search(queryParameters));
}
It doesn't work though! I used to have specific parameters on my action like this:
public ActionResult Search(string searchQuery, string listingType)
which worked (obviously the unittest would try and map to Search with two parameters (strings) instead of this one object.
Does anyone have an idea of how to solve the problem, short of going back to writing all properties as parameters. The mvc automapping of properties rocks, but i'm hoping there is some way i can have mvccontribs testhelper work with that as well.
It's been a while since I looked at this code, but I believe that it does a .Equals call on the parameter you send. For primitive types this is easy, but for you parameter object, try implementing the Equals override and have it test the equality of each of the properties.

Overloading asp.net MVC controller methods with same verb?

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.

Resources