How to bind nullable decimal values - asp.net-core

I'm having problems with ASP.NET Core MVC and decimal? value.
I have the following view model:
public class BlobViewModel
{
public int Id { get; set; }
public int? IntegerValue { get; set; }
public string StringValue { get; set; }
[DataType(DataType.Date)]
public DateTime? DateValue { get; set; }
public decimal? DecimalValue { get; set; }
}
And the following input element in my view
<input asp-for="DecimalValue" class="form-control" />
When I enter a decimal value, e.g. "68.5" or "68,5" and tab out of the input element, I get the following error:
The value '68.5' is not valid for DecimalValue.
I have tried with the [DataType(DataType.Currency)] attribute above the property, but I can't seem to get the binding to work. The other properties binds as expected.
Does anyone have an idea for how I accomplish this?

The error you get occurs if you local Windows settings isn't set to US localization and you are using the default asp.net template jquery validation to validate decimal values. The errors should occur irrespective if your decimals are nullable or not
In ASP.NET Core I don't think you can force the localization to US in the web.config as you get in this answer in the same way you can for ASP.NET MVC5 and earlier, so you will have to add javascript to override the jquery.validate.js as mentioned as an answer to the same question.
create a js file called validationlocalization and put it in your wwwroot\js folder with the following contents
$.validator.methods.range = function (value, element, param) {
var globalizedValue = value.replace(",", ".");
return this.optional(element) || (globalizedValue >= param[0] && globalizedValue <= param[1]);
}
$.validator.methods.number = function (value, element) {
return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:[\s\.,]\d{3})+)(?:[\.,]\d+)?$/.test(value);
}
In the cshtml pages that require decimal validation add a reference to the javascript file to your scripts section. Make sure it is added after an reference to the existing _ValidationScriptsPartial.
#section Scripts {
...
<script src="~/js/validationlocalization.js"></script>
More detail on this workaround

Related

Microsoft.AspNetCore.Components.Forms.InputRadioGroup` does not support the type xxx

I want to use radio group in blazor so after implementing edit form and select one of the radio button I got this error :
Microsoft.AspNetCore.Components.Forms.InputRadioGroup`1[EGameCafe.SPA.Models.GameModel] does not support the type 'EGameCafe.SPA.Models.GameModel'.
here is my edit form :
<EditForm Model="ViewModel" OnValidSubmit="HandleCreateGroup">
#if (ViewModel.Games.List.Any())
{
<InputRadioGroup Name="GameSelect" #bind-Value="Gamemodelsample">
#foreach (var game in ViewModel.Games.List)
{
<InputRadio Value="game" />
#game.GameName
<br />
}
</InputRadioGroup>
}
</EditForm>
#code{
public GameModel GameModelSample { get; set; } = new();
}
and GameModel is :
public class GameModel
{
public string GameId { get; set; }
public string GameName { get; set; }
}
The InputRadioGroup, like other Blazor components, supports only a limited amount of types like String or Int32. You had the right idea, but unfortunately, you run into a kind of limitation of Blazor.
You could try to create a wrapper field.
private String _selectedGameId = "<Your Default Id>";
public String SelectedGameId
{
get => _selectedGameId;
set
{
_selectedGameId = value;
// Set the property of the ViewModel used in your Model Property of the EditContext or any other property/field
ViewModel.SelectedGame = ViewModel.Games.List?.FirstOrDefault(x => x.GameId == value);
}
}
Use the property SelectedGameId as the bind value of the InputRadioGroup component.
<InputRadioGroup Name="GameSelect" #bind-Value="SelectedGameId" >
#foreach (var game in ViewModel.Games.List)
{
<InputRadio Value="game.GameId" />
#game.GameName
<br />
}
</InputRadioGroup>
As an alternative, you can create a custom component that inheriting from InputRadioGroup to create a kind of GameBasedInputRadioGroup. If you are interested I can post a sample.
Because in your code #bind-Value="Gamemodelsample",you are trying to bind GameName(string) to Gamemodelsaple(object), which will cause type mismatch problems.
You only need to modify your code to:
#bind-Value="GameModelSample.GameName"

DataAnnotation for float not working

In one of our ASP.NET Core 1.1 project, I'm getting the following error when rendering following View. I think I'm correctly following suggestions from SO users like #DarinDimitrov here
Error: Input string was not in correct format
ViewModel:
Public Class OrdersViewModel
{
....
[DisplayFormat(DataFormatString = "{(0:C)}")]
public float? price { get; set; }
}
View:
#model MyProj.Models.OrdersViewModel
#{
Layout = "";
}
....
<tr>
<td>Price:</td>
<td>#Html.DisplayFor(t => t.price)</td>
</tr>
UPDATE:
This #String.Format("{0:c}", Model.price) works as suggested here by #nemesv. But I don't want to use it in the view since ModelView is used at multiple places on various views. So I would like to keep using DisplayFor(...) at those places instead - as it's a bit simpler.
System.FormatException that you have means that your DataFormatString is wrong. In your case you need to remove () from format string (explicit call of String.Format works as uses the different template):
[DisplayFormat(DataFormatString = "{0:C}")]
public float? price { get; set; }
If you need the result string to be like (123.45), not 123.45 then do
[DisplayFormat(DataFormatString = "({0:C})")]

Pass Url Parameters to Action by Model in ASP.NET MVC 4

I want to assign my url parameters to Model properties, passed as a parameter to the associated Action. For example;
Say, my url is http://www.example.com/Item/Index?color=red&size=50
My action inside the controller is like below:
public class ItemController : Controller
{
public ActionResult Index(MyModel myModel)
{
//
return View(myModel);
}
}
I want to configure the model or whatever necessary so that my model takes the color and size as field values. The following didn't work:
public class MyModel
{
[Display(Name = "color")]
public string Color{ get; set; }
[Display(Name = "size")]
public string Size{ get; set; }
}
What would be the correct way to solve the problem?
Thanks for any suggestion.
Update
Well, yes! The code above would work correctly, because Url parameter names are the same as model property names. I should explain my problem exactly as I encounter for the next time, sorry.
I must correct a part of my question to make it clear. The url should have been: http://www.example.com/Item/Index?c=red&s=50 to detect the problem.
If the url is like that, the code would not work. Because Url parameters don't have the same name as Model properties.
Updated model is below:
public class MyModel
{
[Display(Name = "c")]
public string Color{ get; set; }
[Display(Name = "s")]
public string Size{ get; set; }
}
Try adding [FromUri] in front of the parameter.
public class ItemController : Controller
{
public ActionResult Index([FromUri] MyModel myModel)
{
// do something
return View();
}
}
debugging the issue
Here are some suggestions in debugging the issue, as it should work out of the box.
try binding to primitive types
public class ItemController : Controller
{
public ActionResult Index(string color, string size)
{
// do something
return View();
}
}
Try reading out of the request object directly
var size = this.Request["size"];
If either of those work there is an issue with your model binding.
Update
If you want to have the query string parameters different to the model in MVC you'll need to have a custom model binder. Take a look at Asp.Net MVC 2 - Bind a model's property to a different named value and http://ole.michelsen.dk/blog/bind-a-model-property-to-a-different-named-query-string-field.html which extends the answer a little.
https://github.com/yusufuzun/so-view-model-bind-20869735 has an example with some html helpers that could be useful.

mvc4 url validation

I'm writing this question here after trying to find an answer for two days.
basically here's what's going on.
I have a property in the viewmodel as follows
[Required(ErrorMessage = "Required Field")]
[Url(ErrorMessage="Please enter a valid url")]
[DisplayName("Website")]
public string web { get; set; }
in the view, I have this
#Html.EditorFor(model => model.web, new { AutoCompleteType = "Disabled", autocomplete = "off" })
now the problem lies in how the input text for this field is validated in the client side. the field must have the protocol prefix at all times, otherwise it becomes invalid.
what is the best way I can fix this issue?
Many Thanks
You can do this using the DataAnnotationsExtensions library. They have an UrlAttribute that you can configure to only validate when a protocol is specified. This attribute also supplies client-side validation. You can see an example of this behavior here: http://dataannotationsextensions.org/Url/Create
You can use this attribute as follows:
using System.ComponentModel.DataAnnotations;
namespace DataAnnotationsExtensions.Core
{
public class UrlEntity
{
[Url]
[Required]
public string Url { get; set; }
[Url(UrlOptions.OptionalProtocol)]
[Required]
public string UrlWithoutProtocolRequired { get; set; }
[Url(UrlOptions.DisallowProtocol)]
[Required]
public string UrlDisallowProtocol { get; set; }
}
}
For your purposes, the first option suffices.
The package of this library (with ASP.NET MVC support included) can be found on NuGet:
Install-Package DataAnnotationsExtensions.MVC3
Note: this also works fine with ASP.NET MVC 4
Not sure if I fully understand the question. Are you trying to validate for correctly formed URLs? If so you could implement a RegularExpression DataAnnotation as follows:
[RegularExpression(#"^http(s?)\:\/\/[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*(:(0-9)*)*(\/?)([a-zA-Z0-9\-\.\?\,\'\/\\\+&%\$#_]*)?$", ErrorMessage = "My Error Message")]

ASP.NET MVC Web Api Get Not Mapping QueryString To Strongly Typed Parameter

The parameter request is always null using Web API. Am I missing something with using a strongly typed object as a parameter instead of simple types as the parameters.
Url
http://localhost:2222/api/v1/divisions?EventId=30
Controller Action
public virtual ApiDivisionsResponse Get(ApiDivisionsRequest request)
{
return _apiDivisionsService.GetDivisions(request);
}
Object
public class ApiDivisionsRequest : ApiAuthorizedRequest
{
public ApiDivisionsRequest()
{
Page = 1;
PageSize = 10;
}
public int EventId { get; set; }
public int PageSize { get; set; }
public int Page { get; set; }
public string[] Includes { get; set; }
}
I very strongly invite you to read the following article to better understand how parameter binding works in the Web API. After reading it you will understand that by default the Web API binds query string parameters to primitive types and request body content to complex types.
So if you need to bind query string parameters to complex types you will need to override this default behavior by decorating your parameter with the [FromUri] parameter:
public virtual ApiDivisionsResponse Get([FromUri] ApiDivisionsRequest request)
{
...
}
And yeah, I agree with you - that's a hell of a mess - model binding was so easy in plain ASP.NET MVC and they created a nightmare in the Web API. But once you know how it works you will avoid the gotchas.