Null Parameter Error - c#

I am having a problem calling an Edit method in an application I am creating. In the view an ActionLink is clicked that should be passing the order number to the Edit method as a parameter and opening an edit page with the info for the order populated in the fields. However upon clicking the link I receive the error:
The parameters dictionary contains a null entry for parameter 'orderNum' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ViewResult Edit(Int32)' in 'AddressUpdater.WebUI.Controllers.OrderController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
However the parameter is present in the URL. Here are the relevant method:
public ViewResult Edit(int orderNum)
{
Order order = repository.Orders.First(o => o.OrderNumber == orderNum);
return View(order);
}
If if change the parameter to int? orderNum the page will render without an error but none of the data is there.

Most probably there's something wrong with the sending of the data to the action method Edit, i.e. in your action link. Just open some devtool like Firebug or Chrome Dev tools to inspect what is being sent to the server.
When your url looks like
Edit?OrderNumber=1234
then you need to have a matching parameter on your Action method like
public ViewResult Edit(int orderNumber) {...}
Instead
Edit(int orderNum){...}
won't work. Basically url parameter name and action method parameter name have to match (not case sensitive, but the name has to match)

Related

HTTPGET Query String

An URL without a name but it has a value, is that still consider as a query string?
For example:
[HttpGet]
[Route("api/house/{Id}")]
public IActionResult GetHouseById(int Id)
link will be:
http://localhost:44565/api/house/1
Is this still consider a query string?
No, this is part of the path and in RESTful nomenclature is not a query string parameter.
Path variables are required components of the route and MUST be provided in order to identify the appropriate route. Omission of the id parameter when required by a path should cause a 404 (unless another route matches api/house).
Query string parameters however, are optional. They are the last part of the URI and occur after the ? character, such as api/house?id=1. In this style of URI, you might expect the endpoint to return the house that has an id of 1 if the query string parameter is provided, or all houses if it is omitted.
Finally, you would notate a querystring parameter via the FromUri attribute and omitting it from the path:
[HttpGet]
[Route("api/house")]
public IActionResult GetHouseById([FromUri]int id)

In ASP.NET MVC, why is the parameter bound as an array when binding to an object instead of a specific type

I have a bunch of controllers with a similar delete action, so I'm putting that into a base class. This is what it looked like before:
public async Task<ActionResult> Delete(int id)
{
await apiClient.Delete(id);
return new EmptyResult();
}
And in the view there's a raw link pointing to:
/Items/Delete?Id=" + item.Id
And that works fine, but then some of the models use a string as a key in place of int. Since the API client is backed by an Entity Framework repo which can delete by object, I just tried this:
public async Task<ActionResult> Delete(object id)
{
await apiClient.Delete(id);
return new EmptyResult();
}
Now I am getting a single-element array bound to id. The single element is the string representing the item.Id. Why's that? Why it's an array and not simply the element?
My guess is that's actually the default format for data passed to it, since all form values are passed to the server as string, and when there are name collisions, the values are accessible as an array under that name. So really, string[] is the default type of all submitted values, and anything else involves some kind of automatic conversion.
For example, if you had a form with three text inputs that all had the same name "text", the browser would send all three, and MVC would start out with a string array called "text". Since the controller parameter type is 'object', it really can't make any smart guesses about what to do with it, so it just gives you the original array.
On the other hand, if the field type is known to be string, then it combines them into a comma separated list; and you could probably avoid such an unwanted concatenation step by setting the type to 'string[]'. If the parameter type is 'int', it tries to convert the string value to an integer. If the parameter type is 'bool', it will try to interpret the string as a Boolean. So, the string array is actually the normal value, and it's everything else that's receiving special transforms.

What is wrong with my MVC4 Routes, Parameters, constructors?

I have a problem with a small app i am writing. Now either my error is in my controller class or its in Routes. See images below.
Controller Class.
This is the default Route i have.
And this is the error i get when i run.
Image not very clear but it says:
The parameters dictionary contains a null entry for parameter 'playerId' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult Detail(Int32)' in 'GlobalUnited.WebUI.Controllers.PlayerController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
I read through some posts on here, one particularly:
Similar Link
What exactly does he mean when Daniel Renshaw says:
First, I would suggest you use MVC's automatic handling of parameters instead ofpulling them out of the Request yourself. Your controller action has an id parameter which seems to go ignored - use that and add others like it to get the input parameters.
Anyways, after reading that post, i changed my RouteConfig file to:
And Still i got this error. It says:
A route named 'DefaultApi' is already in the route collection. Route names must be unique.
Parameter name: name
I even tried to change my Detail action parameter to: Note the int? declaration
And i got this error after changing:
Is there something i could do to fix this, something less complicated??
All help will be appreciated, thanks.
Your parameter name playerID causes the problem here. ASP.NET MVC can only provide you a parameter named id using the default route. In your case, it cannot map the request to your action because playerID is not nullable or optional. Changing your parameter name to id will solve the problem.
public ActionResult Detail(int id)
You get the second error with route registration because you already have a route named "DefaultApi". You won't need this route if you change the parameter name(also it's registered elsewhere).
Third error is for trying to querying with the null value. ASP.NET MVC cannot map the value in URL to your parameter and you get the default value null. Since there isn't a row with a null value you get an empty sequence, then Single() method throws an exception.
As your parameter is called playerId you must pass it as a route value to the Detail action method and then check if it's null or not. This will take care of that last error you show in your question: Sequence contains no element.
Do this in the action method:
public ActionResult Detail(int? playerId)
{
if(playerId.HasValue)
{
var model = _dataSource.Players.Single(p => p.PlayerId == playerId);
return View(model);
}
// Handle the other possibility where playerId is NULL
}
For ASP.NET MVC to know how to do the correct parameter binding you must call the above action method this way, for example:
#Html.ActionLink("Player Details", "Detail", new { playerId = 1 });
Other than the duplicate route error, your errors have nothing to do with the DefaultApi route. You get a duplicate route because that route is configured in App_Start\WebApiConfig.cs
Your first problem is that you are telling MVC that you have a mandatory Route parameter called playerId, but you are not supplying this route parameter in the URL you're using. In order for this to work you would need to either alter your route to change id to playerId, or add a playerId querystring parameter to your url. If you alter the route, you would need a url like http://my.site/Player/Detail/1 (if you alter the route) or http://my.site/Player/Detail?playerId=1.
Another option is changing the parameter to public ActionResult Detail(int id) which would then use the existing default route that takes a single parameter called id and extracts it from the friendly url that ends in /1.
You could also make the method Detail(int? id), but then you would need to place a null guard around your linq query (because if you don't pass the ID on the URL it can't lookup a null record) so you would have to add this:
if (id.HasValue) {
// execute linq query
}
Alternatively, you could alter your query to return SingleOrDefault() rather than Single().

How to get Redirect() to work how I want

I've been having some problems getting redirects after login to work how I want. So I came up with the idea to store the current page in the viewbag and use that to redirect, so if the page is mydomain.com/debate/1 I end up with "/debate/1" stored in the viewbad but when I try to redirect its giving me this complaint
The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult DebateDetails(Int32)' in 'PoliticalDebate.Controllers.DebateController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
However If I manually type in mydomain.com/Debate/1 it works as expected.
Is there some way to get Redirect to work how I want ?
Since I don't see any code, I can't comment on the way you are trying to do it (which isn't working). On future posts, please post your code. This is one way how you can redirect if you are simply redirecting to the default action on the controller:
return this.RedirectToAction("Index", new { id = debateDetailsID } );
Although it's very hard to tell what you are truly trying to do because you mention debate/1 yet the method being called is DebateDetails which doesn't match (unless you've changed the default routes, again I don't know, there's no code).
Update
According to your comment, you have an error in your MapRoute. Your MapRoute should look like:
routes.MapRoute("Debate Details",
"debate/{id}",
new { controller = "Debate",
action = "DebateDetails",
// this id value is missing
// so it's not being passed to the controller
id = UrlParameter.Optional } );
the answer is there in the complaint, in this particular case you're sending a parameter so, checkout if this is specified
your code must look like redirectToAction("nameOfAction", new {id = yourIdOnViewBag}

MVC Action with Optional Parameters -- which is better?

Are there any pros/cons of using the following two alternatives in your action signature:
public ActionResult Action(int? x) // get MVC to bind null when no parameter is provided
{
if(x.HasValue)
{
// do something
}
}
OR
public ActionResult Action(int? x = null) // C# optional parameter (virtual overload)
{
if(x.HasValue)
{
// do something
}
}
I have never seen the second action signature in practice and can't see any usefulness of it.
The first one usually covers all the scenarios:
If no parameter is sent (GET /somecontroller/action), the value of the x argument will be null inside the action
If a x parameter is sent, but it is not a valid integer (GET /somecontroller/action?x=abc), the value of the x argument will be null inside the action and the modelstate will be invalid
If a x parameter is sent and the value represents a valid integer (GET /somecontroller/action?x=123), then x will be assigned to it.
In my examples I have used GET requests with query string parameters but obviously the same applies with other HTTP verbs and if x was a route parameter.
You only need to specify the optional parameter value if it is going to be anything else other than null.
MVC3 will automatically set null as the value of your parameter if nothing is specified in the overload, or in the call to the Action.
However, its worth noting that if there are any non-optional parameters after this parameter in the signature, then null would have to be specified in the call.
Therefore its best to put all optional params at the end of the signature.
Best Asp.net MVC solution - use action method selector
Why not simplify controller action methods by removing unnecessary code branch and have this kind of code as seen here:
public ActionResult Index()
{
// do something when there's no id
}
[RequiresRouteValues("id")]
public ActionResult Index(int id)
{
// do something when id is present
}
This is of course possible, as long as you provide the very simple code for RequiresRouteValuesAttribute action method selector. You can find code in this blog post that does exactly this.
By my opinion this is the best possible solution to this problem, because:
It simplifies code by removing unnecessary branch
Makes code easier to maintain (due to lower complexity)
Extends Asp.net MVC framework as it can and should
Keeps parameter types as they should be without the need to make them nullable
etc.
Anyway. All the details about this technique is explained in great detail in linked post.

Categories

Resources