Action method expected parameter named Id and nothing otherwise - c#

The Error
The parameters dictionary contains a null entry for parameter 'UserId'
of non-nullable type 'System.Int64' for method
'System.Web.Mvc.ActionResult Predict(Int64)' in
'sportingbiz.Controllers.PredictionController'. An optional parameter
must be a reference type, a nullable type, or be declared as an
optional parameter. Parameter name: parameters
This does not work. Throws the error mentioned above
http://mysite/User/Profile/15
This works
http://mysite/User/Profile/?UserID=15
The Controller Action
public ActionResult Profile(long UserID)
{
}
When I changed the parameter name to Id it works. I think it's because Id was specified in the route collection (Global.asax). Is it possible to tell MVC that UserId should map to Id without changing it in the Global.asax

The only way to accomplish this (without getting into custom ModelBinders, which gets really hairy) is to:
make the parameter nullable
use the RouteData collection to set the property after-the-fact.
public ActionResult Profile(long? UserID)
{
UserID = UserID ?? long.Parse((string)RouteData.Values["id"]);
}

I would always make the id param on a controller something generic like Id, then you dont have to create lots of routes to match the different id types.
If you aren't using a string which is nullable for your id, you can provide a default value such as long id = 0 and handle the zero value as being the default starting sequence.
For example, in a paging method, you can set it to zero so you dont need any params on the first page, but passing it thereafter will request that page number etc etc
Si

I think the code already posted should work so I tested my version and it worked:
public ActionResult Profile(long? UserID)
{
if (UserID.HasValue)
{
}
else if (this.RouteData.Values["id"] != null)
{
long tempValue = 0;
if (long.TryParse(this.RouteData.Values["id"].ToString(), out tempValue))
{
UserID = tempValue;
}
}
return View();
}
Hope it helps.

Related

Use a custom name for a request parameter

After changing job I'm learning C# and Entity Framework; previously I worked with Java + Spring.
The question is: Is there an equivalent way to write this Java code into C# code?
public ModelAndView showUser(#RequestParam("k") String userName)
With Spring and the annotation RequestParam I could convert a request parameter named k into a more friendly and readable parameter named userName; so now, I expect a C# code like this:
public ActionResult showUser([RequestParam("k")] string userName)
Is this possible in some way?
I am not sure if you can do the same as in Java+spring but in C# MVC you can use Modal to transfer data from and to.
There you don't have to get the each and every request value separately you just have to mention your Modal Name in the parameter parentheses.
Answering your question, if tried to assign the value from the parameter it will throw
Default parameter for name must be a compile-time constant
public ActionResult Contact(string name = Request.Form["param1"])
{
return View();
}
Above code throws an error.
So to work with that used
public ActionResult Contact()
{
string name = Request.Form["param1"];
return View();
}
This will work.
I recommend you to use Modal and data annotations concept for the passing of data.
You can use that:
[HttpGet()]
public IActionResult showUser([FromQuery(Name = "k")] string userName)
{...}

How to get optional parameters in mvc action C#

There is an TestAction in HomeController as below:
public ActionResult TestAction(string a = "a", int b = 2, int c = 1)
{
var DATA = Request.Params;//Can't get param neither a nor b
return View();
}
If my visit link is "/Home/TestAction?c=23". Then DATA will be {c=23}, but not contain a and b.
Does there any way to get these two params to make DATA like {a="a", b=2, c=23} by visit link "/Home/TestAction?c=23". (These params are different in different page, so can't hard-code).
You can do it by passing the params in the url as following. The model binder will read the query string and pass these parameter values to the action method.
/Home/TestAction?a=valuea&b=valueb
You can also use the route data to pass the value. An appropriate route will need to be defined to do that.
Take all the paramters as nullable
int?,
string accepts null by default.
So after changes your method will look like
public ActionResult TestAction(string a, int? b, int? c)
{
//Check conditions for null here
return View();
}

When I assign a nullable integer to ViewBag, it un-nullables the value?

Consider this ASP.NET MVC 5 controller:
public class MyController : Controller {
public ActionResult Index(int? id) {
ViewBag.MyInt = id;
return View();
}
}
And this view:
<p>MyInt.HasValue: #MyInt.HasValue</p>
When I invoke the URL /my/ (with a null id), I get the following exception:
An exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Core.dll but was not handled in user code
Additional information: Cannot perform runtime binding on a null reference
Conversely, if I pass an ID in (eg, /my/1):
An exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Core.dll but was not handled in user code
Additional information: 'int' does not contain a definition for 'HasValue'
This suggests to me that ViewBag.MyInt is not of type Nullable<int>, but of either int or null.
Is this the ViewBag doing this? Or, is it something more fundamental about boxing Nullable types like this? Or, something else?
Is there another way to do this?
(I suppose that I could just change my check to ViewBag.MyInt == null, but let's pretend I really needed a Nullable type for some reason)
I would suggest that you create a view model which will give you full flexibility to make "MyInt" a null-able type for this.
Of course, the alternative would be to only set "MyInt" if it is not null...
public class MyController : Controller {
public ActionResult Index(int? id) {
if (id.HasValue)
{
ViewBag.MyInt = id;
}
return View();
}
}
View:
#if (ViewBag.MyInt != null)
{
<p>Has an Id</p>
}
else
{
<p>Has no Id.</p>
}
Personally, I would go with a viewmodel as it's best practice, I rarely use ViewBag unless its for a VERY simple scenario.
I'm not sure the reason, but you can always cast it as a nullable in the view.
<p>MyInt.HasValue: #(((int?)MyInt).HasValue)</p>
Although, that may seem like overkill.
ViewBag is an DynamicViewDataDictionary object (see answer by Robert Harvey and ASP.NET source code).
Nullable is a value type and gets boxed when you add it to ViewBag. See this article, and especially remarks, on MSDN. According to the same article, "when a nullable type is boxed, the CLR automatically boxes the underlying value of the Nullable object"...
It is safe to test a ViewBag property for null. If it is not null, the actual value is that of the underlying type of the original Nullable object. Therefore this code works:
#if (ViewBag.MyInt != null)
{
<p>#ViewBag.MyInt</p>
}
and even this:
<p>#ViewBag.MyInt</p>
If MyInt is not set in the ViewBag, the null value is rendered as blank. If it is set by assigning a Nullable value, then the actual value is an int.

Where do RouteValues go if the Controller's Action doesn't have matching parameters?

If I have the following code in one of my Views:
#Html.Action("Grid", "Product", new { section = SectionType.Product })
This will call the Grid action method of my ProductController, which is all well and good. If the Grid method is defined like this:
public ActionResult Grid(SectionType section) { ... }
Then the section parameter will get populated with SectionType.Product, as I had requested. However, if I don't put the parameter in the method declaration, like this:
public ActionResult Grid() { ... }
Then the section value that was set in the View seems to completely disapper. It's not in Request.Params, it's not in Request.QueryString, and in fact I can't seem to find it anywhere.
Can anyone tell me what happens to this value? Can I retrieve it from anywhere, or does MVC completely discard it if the method does not ask for it in the parameter list?
You can access any of the parameters extracted from the route via RouteValueDictionary Values collection of the RouteData in the RequestContext:
var section = Request.RequestContext.RouteData.Values["section"];
I am not sure, if it would be of the enumeration type required (i.e. SectionType) boxed into an object, or just a string (also boxed into an object) that you'll need to cast to the enumeration type appropriately yourself.
If there is no route with a segment which could obtain the value of the section parameter, it should be stored in the Request.QueryString and should be accessible through Request.QueryString["section"]. Also in this case the generated html should look like ...?section=SomeSection, while in the case if you had a suitable route, it had to look like .../SomeSection
I guess SectionType is an enum.
If yes, then an error will be happen if no matching parameters found in Action.
// throw exception if you don't pass section value
public ActionResult Grid(SectionType section) { ... }
The parameters dictionary contains a null entry for parameter
'section' of non-nullable type
'MvcApplication1.Controllers.SectionType' for method
'System.Web.Mvc.ActionResult
Index(MvcApplication1.Controllers.SectionType)' in
'MvcApplication1.Controllers.HomeController'. An optional parameter
must be a reference type, a nullable type, or be declared as an
optional parameter. Parameter name: parameters
From the message above, the exception is happen if no matching parameters found in the Action and the parameters is non-nullable type.
If you change your Action like this:
// nullable SectionType
public ActionResult Grid(SectionType? section) { ... }
or
// default value
public ActionResult Grid(SectionType section = SectionType.Area) { ... }
When section is nullable types, the Action will be called with section value is null.
When section have default value, the Action will be called with section value is null but in the action it will be use default value.

Question about use of new { }

I am currently working my way through the Apress ASP.NET MVC2 book, and I am a little bit confused as to the user of new { returnUrl } in the following code:
public RedirectToRouteResult RemoveFromCart(Cart cart, int productID, string returnUrl)
{
Product product = productsRepository.Products.FirstOrDefault(p => p.ProductID == productID);
cart.RemoveLine(product);
return RedirectToAction("Index", new { returnUrl });
}
Is it something to do with creating a new string, rather than simply passing a reference to the parameter passed in?
It's creating an anonymous type with a property returnUrl which also has the value of returnUrl. So it's like this:
var anon = new { returnUrl = returnUrl };
return RedirectToAction("Index", anon);
Using a name from the expression to determine the name of the property in an anonymous type is called a projection initializer.
Does that help to explain it to you at all? If not, you may want to revise anonymous types in general. They were introduced in C# 3, mostly for LINQ.
This is an anonymous type: http://msdn.microsoft.com/en-us/library/bb397696.aspx
That is an anonymous object. The property in the case above would create a new object with the string property 'returnUrl'.
In this context, it is specifying a url for the ActionResult to redirect the browser to.
That syntax creates an anonymous type. They're created on the fly as needed. In your example it creates a new object with one property and then passes it to the action as a parameter.

Categories

Resources