DataAnnotation for float not working - asp.net-core

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})")]

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"

How to bind nullable decimal values

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

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.

ASP.NET MVC 4 Display data From 2 Model using EF

I'm start learning ASP.NET MVC 4 and stuck displaying Data From 2 model in 1 File
Here's my Model
public class mst_item
{
[Key]
[DisplayName("Item Code")]
[Required]
public string item_code{get;set;}
[DisplayName("Item Name")]
[Required]
public string item_name{get;set;}
[DisplayName("Unit")]
[Required]
public mst_item_unit unit_id{ get; set; }
}
public class mst_item_unit
{
[Key]
public int unit_id { get; set; }
[DisplayName("Unit")]
public string unit_name { get; set; }
}
Then My Controller :
public ActionResult Item()
{
var list_item = db.mst_item.Include("mst_item_unit").ToList();
return View(list_item);
}
Then How to display the unit_name based on the mst_item.unit_id in View using INNER JOIN or Include? something like :
#foreach (var item in Model)
{
#Html.DisplayFor(modelItem => item.item_name)
#Html.DisplayFor(modelItem => item.unit_name)
}
I get stuck here, But I success while displaying the mst_item data without joining mst_item_unit (just display the ID based on mst_item.unit_id) before.
You just have a couple of issues:
The parameter to Include should be a navigation property on your entity, not the table name. In other words, change it to:
var list_item = db.mst_item.Include("unit_id").ToList();
You have to access the properties of this second entity through the navigation property. In other words, this is the view code you would need:
#foreach (var item in Model)
{
#Html.DisplayFor(modelItem => item.item_name)
#Html.DisplayFor(modelItem => item.unit_id.unit_name)
}
That said, you've also got some stylistic problems here, which since you're new, I'll point out.
Class and property names should be camel-cased, i.e. MstItem, rather than mst_item.
Navigation properties should be named after the objects they connect to, i.e. unit_id should be something like MstItemUnit, or just Unit, if you prefer. That removes the need to specify a display name for it, as well.
The use of the _id suffix on this navigation property is particularly troubling, because it implies that this property is an int or Guid - you know, something that could be used an id - whereas actually you're referencing a full-fledged object.
While not as important, it makes little sense to repeat the class name or a portion thereof in the property names of that class. For example, unit_name should just be Name. Obviously, it's the name of the unit, because that's the class.
With those in place, your code becomes much more readable and "human". For example:
#Html.DisplayFor(m => item.Name)
#Html.DisplayFor(m => item.Unit.Name)
You should be creating a ViewModel that will relate both your models, populate that ViewModel in your controller and use that in your View. The below link is very much your case.
Multiple Models in a Single View (C# MVC3)

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")]