asp.net core model binding for one property - asp.net

I have a complex type
public class Model
{
public double D2 { get; set; }
}
And I receive this type inside action
[HttpPost("{id}")]
public string Post(Model model)
{
return "";
}
Users want to have ability to type numbers with . (point) and , (comma) decimal separators, for example 234.245 and 234,245 are valid decimal types. But framework can't convert this numbers correctly. Is there a way to "catch" the binding for doubles to have ability to normalize symbols before converting to double?

Sure, there is a way. Grab d2 as string and then replace . to , and convert into double or whatever you want. For example:
public string Post(string d2)
{
var model = new Model(){ D2 = Convert.ToDouble(d2.Replace(".", ",")) }
return "";
}
If you don't like this way make custom setter in Model by almost the same way

Related

How to get string[] array from database with EF core [duplicate]

How can I store an array of doubles to database using Entity Framework Code-First with no impact on the existing code and architecture design?
I've looked at Data Annotation and Fluent API, I've also considered converting the double array to a string of bytes and store that byte to the database in it own column.
I cannot access the public double[] Data { get; set; } property with Fluent API, the error message I then get is:
The type double[] must be a non-nullable value type in order to use
it as parameter 'T'.
The class where Data is stored is successfully stored in the database, and the relationships to this class. I'm only missing the Data column.
You can do a thing like this :
[NotMapped]
public double[] Data
{
get
{
string[] tab = this.InternalData.Split(',');
return new double[] { double.Parse(tab[0]), double.Parse(tab[1]) };
}
set
{
this.InternalData = string.Format("{0},{1}", value[0], value[1]);
}
}
[EditorBrowsable(EditorBrowsableState.Never)]
public string InternalData { get; set; }
Thank you all for your inputs, due to your help I was able to track down the best way to solve this. Which is:
public string InternalData { get; set; }
public double[] Data
{
get
{
return Array.ConvertAll(InternalData.Split(';'), Double.Parse);
}
set
{
_data = value;
InternalData = String.Join(";", _data.Select(p => p.ToString()).ToArray());
}
}
Thanks to these stackoverflow posts:
String to Doubles array and
Array of Doubles to a String
I know it is a bit expensive, but you could do this
class Primitive
{
public int PrimitiveId { get; set; }
public double Data { get; set; }
[Required]
public Reference ReferenceClass { get; set; }
}
// This is the class that requires an array of doubles
class Reference
{
// Other EF stuff
// EF-acceptable reference to an 'array' of doubles
public virtual List<Primitive> Data { get; set; }
}
This will now map a single entity (here 'Reference') to a 'list' of your Primitive class. This is basically to allow the SQL database to be happy, and allow you to use your list of data appropriately.
This may not suit your needs, but will be a way to make EF happy.
It would be far easier if you use List<double> rather then double[]. You already have a table that stores your Data values. You probably have foreign key from some table to the table where your double values are stored. Create another model that reflects the table where doubles are stored and add foreign key mappings in the mappings class. That way you will not need to add some complex background logic which retrieves or stores values in a class property.
In my opinion almost all other answers work on the opposite of how it should be.
Entity EF should manage the string and the array must be generated from it. So the array must be whole read and written only when the string is accessed by EF.
A solution involving logic on Data[] is wrong because, as I wrote in a comment, you would run into paradoxical conditions. In all other conditions the variable must remain a pure array.
By putting the "get" and "set" logic in Data[], as I've seen so far, this happens:
1 - Every time an index access is made to the array, the array is automatically recreated from the string. This is a useless work, think of an iteration in a loop...
2 - when you go to set a single element it is not stored because it passes through "get" and not "set".
If you try to declare Data=new []{0,0,0} then set Data[1]=2 , going to re-read Data[1] the result is 0.
My solution is to completely turn the logic around.
public string Data_string
{
get => string.Join(';', Data??Array.Empty());
set => Data= value == null ? Array.Empty<double>() : Array.ConvertAll(value.Split(';',StringSplitOptions.RemoveEmptyEntries), double.Parse);
}
[NotMapped]
public double[] Data {get;set;}
Obviously this only applies to storing and retrieving data on databases, access to Data_string is exclusive to EF.
Once the string is read from the DB it is associated to Data_string which, through set, creates the Data array.
At this point you can work on Data without affecting the string in any way, like a normal array.
When you will ask EF to save in the DB, through the get in the Data_string property, the string will be completely reconstructed based on the Data elements and then stored as a string.
Practically the string is modified only twice, at the moment of reading from the DB and at the moment of saving.
In my opinion this solution is much more efficient than operating continuously on the string.
Nathan White has the best answer (got my vote).
Here is a small improvement over Joffrey Kern's answer to allow lists of any length (untested):
[NotMapped]
public IEnumerable<double> Data
{
get
{
var tab = InternalData.Split(',');
return tab.Select(double.Parse).AsEnumerable();
}
set { InternalData = string.Join(",", value); }
}
[EditorBrowsable(EditorBrowsableState.Never)]
public string InternalData { get; set; }
Don't use double[] use List insted.
Like this.
public class MyModel{
...
public List<MyClass> Data { get; set; }
...
}
public class MyClass{
public int Id { get; set; }
public double Value { get; set; }
}
All that solution that I see there are bad, because:
If you create table, you don't want to store data like this: "99.5,89.65,78.5,15.5" that's not valid! Firstly its a string that means if you can type letter into it and at the moment when your ASP.NET server call double.Parse it will result in FormatException and that you really don't want!
It's slower, because your server must parse the string. Why parse the string instead getting almost ready data from SQL Server to use?
i know this post is Ancient, but in case someone still needs to do something like this, PLEASE DO NOT USE THE ABOVE SOLUTIONS,
as the above solutions are EXTREMELY inefficient (Performance and Disk Space wise).., the best way is to store the array as a Byte array
public byte[] ArrayData;
[NotMapped]
public double[] Array {
get {
var OutputArray = new double[ArrayData.Length / 8];
for (int i = 0;i < ArrayData.Length / 8;i++)
OutputArray[i] = BitConverter.ToDouble(ArrayData, i * 8);
return OutputArray;
}
set {
var OutputData = new byte[value.Length * 8];
for (int i = 0;i < value.Length;i++) {
var BinaryValue = BitConverter.GetBytes(value[i]);
OutputData[(i*8)] = BinaryValue[0];
OutputData[(i*8)+1] = BinaryValue[1];
OutputData[(i*8)+2] = BinaryValue[2];
OutputData[(i*8)+3] = BinaryValue[3];
OutputData[(i*8)+4] = BinaryValue[4];
OutputData[(i*8)+5] = BinaryValue[5];
OutputData[(i*8)+6] = BinaryValue[6];
OutputData[(i*8)+7] = BinaryValue[7];
}
ArrayData = OutputData;
}
}
`
And if you need more performance, you can go for Unsafe code and use pointers .. instead of BitConverter ..
This is way better than saving double values (that can get huge) as string, then spliting the string array !! and then parsing the strings to double !!!
These getter/setters work on the whole array, but if you need to get just one item from the array, you can make a function that gets a single item from the array with a complexity of O(1) :
for Get :
public double Array_GetValue(int Index) {
return BitConverter.ToDouble(ArrayData, Index * 8);
}
for Set :
public void Array_SetValue(int Index, double Value) {
var BinaryValue = BitConverter.GetBytes(Value);
ArrayData[(Index*8)] = BinaryValue[0];
ArrayData[(Index*8)+1] = BinaryValue[1];
ArrayData[(Index*8)+2] = BinaryValue[2];
ArrayData[(Index*8)+3] = BinaryValue[3];
ArrayData[(Index*8)+4] = BinaryValue[4];
ArrayData[(Index*8)+5] = BinaryValue[5];
ArrayData[(Index*8)+6] = BinaryValue[6];
ArrayData[(Index*8)+7] = BinaryValue[7];
}
If your collection can be null or empty, and you want this to be preserved, do this:
[NotMapped]
public double[] Data
{
get => InternalData != null ? Array.ConvertAll(Data.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries), double.Parse) : null;
set => InternalData = value != null ? string.Join(";", value) : null;
}
Also, specify [Column(TypeName = "varchar")] on the string property for a more efficient storage data type.
A perfect enhancement to #Jonas's answer will be to add the necessary annotations. So, a cleaner version would be
[EditorBrowsable(EditorBrowsableState.Never)]
[JsonIgnore]
public string InternalData { get; set; }
[NotMapped]
public double[] Data
{
get => Array.ConvertAll(InternalData.Split(';'), double.Parse);
set
{
InternalData = string.Join(";", value.Select(p => p.ToString(CultureInfo.InvariantCulture)).ToArray());
}
}
The [JsonIgnore] Annotation will ignore the InternalData field from JSON serialization and Swagger UI.
[EditorBrowsable(EditorBrowsableState.Never)] will hide the public method from the IDE IntelliSense

How to use JsonConvert.SerializeObject with formatting to add brackets only around CSV values

I have an object that, when converted to a JSON string using the JsonConvert.SerializeObject method, will look like this:
{"01":{"CompanyName":"Hertz","Cars":"Ford, BMW, Fiat"},
"02":{"CompanyName":"Avis","Cars":"Dodge, Nash, Buick"}}
How can I use the Formatting parameter to make the result look like this:
{"01":{"CompanyName":"Hertz","Cars":["Ford", "BMW", "Fiat"]},
"02":{"CompanyName":"Avis","Cars":["Dodge", "Nash", "Buick"]}}
As #dbc mentioned in the comments, you cannot use the Formatting parameter of JsonConvert.SerializeObject to affect whether a particular value in the JSON is surrounded by square brackets or not. The Formatting parameter only controls whether or not Json.Net will add indenting and line breaks to the JSON output to make it easier to read by a human.
In JSON, square brackets are used to denote an array of values, as opposed to a single value. So, if you want to add square brackets for a particular property, the easiest way to do that is to change how that property is declared in your class such that it correspondingly represents an array (or list).
Based on your original JSON, I'm assuming you have a class which looks like this:
public class Company
{
public string CompanyName { get; set; }
public string Cars { get; set; }
}
...and you are creating your JSON something like this:
var results = new Dictionary<string, Company>();
results.Add("01", new Company
{
CompanyName = "Hertz",
Cars = "Ford, BMW, Fiat"
});
results.Add("02", new Company
{
CompanyName = "Avis",
Cars = "Dodge, Nash, Buick"
});
string json = JsonConvert.SerializeObject(results);
To get square brackets in the JSON, change the type of your Cars property from string to List<string>:
public class Company
{
public string CompanyName { get; set; }
public List<string> Cars { get; set; }
}
Of course, you will also need to make a corresponding change to the code which populates the results:
var results = new Dictionary<string, Company>();
results.Add("01", new Company
{
CompanyName = "Hertz",
Cars = new List<string> { "Ford", "BMW", "Fiat" }
});
results.Add("02", new Company
{
CompanyName = "Avis",
Cars = new List<string> { "Dodge", "Nash", "Buick" }
});
string json = JsonConvert.SerializeObject(results);
Here is a short demo: https://dotnetfiddle.net/lgg9jk

How to get value of a variable in a long delimited string

In a db table I have a string, such as...
Var1=0;CosType=1;DefaultType=US_Pass;DateYear=1;DateRange=1;ReportFormat=0
I want to create a VB.NET function that has 1 input var, the string (above) and the "token" to get the value for. (The return value is the value of the token.) For example, if I call it (LongString is the string above)....
txtValue.text = MyFunction(LongString,"DefaultType")
So, "US_Pass" would be returned.
What is the most efficient way to code MyFunction?
I've tried something like this...
return LongString.Substring(LongString.IndexOf(input_token) + 12)
I feel I'm close, but so far away.
Thanks!
This works as long as you know the key exists in your string:
public string MyFunction(string longString, string key)
{
return
longString
.Split(';')
.Select(x => x.Split('='))
.ToDictionary(x => x[0], x => x[1])[key];
}
With this code:
string longString = "Var1=0;CosType=1;DefaultType=US_Pass;DateYear=1;DateRange=1;ReportFormat=0";
Console.WriteLine(MyFunction(longString, "DefaultType"));
I get:
US_Pass
As VB.NET:
Public Function MyFunction(longString As String, key As String) As String
Return longString.Split(";"c).Select(Function(x) x.Split("="c)).ToDictionary(Function(x) x(0), Function(x) x(1))(key)
End Function
Split the string into parts at the semi-colons.
Dim parts As String() = LongString.Split(";")
Loop over the parts in a ForEach loop.
Find the part that StartsWith the the token value.
Find the equal sign (IndexOf) and take everything to the right of it (Substring).
That should give you enough to figure it out.
It's probably not a great idea to store data like this in your database. Hopefully you won't need to query these attributes from SQL.
In your case I would create a class to encapsulate the attributes. You pass in the string as a constructor parameter and let the class manage it.
Here's an example in C# that shouldn't be too hard to convert to VB:
public class AttributeCollection
{
private readonly Dictionary<string, string> _attrs;
public AttributeCollection(string values)
{
_attrs = (from v in values.Split(new[] {';'})
select v.Split(new[] {'='})).ToDictionary(i => i[0], i => i[1]);
}
public string this[string name]
{
get { return _attrs[name]; }
set { _attrs[name] = value; }
}
public override string ToString()
{
return string.Join(";", (from a in _attrs select a.Key + "=" + a.Value).ToArray());
}
}

Import two or multiple class models to a single controller on ASP.NET

I'm very new to ASP.NET, but I know a little programming in Java. I want to use a ZIP code to query a database which will return a string, then use that string to query another database. I wanted to do this on the same control model. I thought it would be easy, and it sounds pretty easy.
When I created the controller, I put the model class of the first database, and, so far, I've gotten as far as querying the first database, but now that I have the string I want to query a second database through the DBEntities.
This displays an error saying:
> The model item passed into the dictionary is of type
> 'System.Collections.Generic.List`1[FinalBallot.Models.AgainCandidate]',
> but this dictionary requires a model item of type
> 'System.Collections.Generic.IEnumerable`1[FinalBallot.Models.ZipTable]'.
Is there a way to solve this in an easy way?
public class Default1Controller : Controller
{
private CandidatesDBEntities db = new CandidatesDBEntities();
public string districString = "";
//
// GET: /Default1/
public ViewResult Index(string searchString)
{
var queryZip = from s in db.ZipTables select s;
var queryCandidates = from s1 in db.AgainCandidates select s1;
double sT = 0;
//method so it doesnt display the whole db
if (String.IsNullOrEmpty(searchString))
{
queryZip = queryZip.Where(s => s.ZipL.Equals(0));
}
if (!String.IsNullOrEmpty(searchString))
{
sT = double.Parse(searchString);
queryZip = queryZip.Where(s => s.ZipL.Equals(sT));
try
{
districString = queryZip.ToList().ElementAt(0).District;
}
catch
{
}
if (!String.IsNullOrEmpty(districString))
{
queryCandidates = queryCandidates.Where(s1 => s1.District.Equals(districString));
}
}
return View(queryCandidates.ToList());
}
In your view, did you specify the model to be IEnumerable<ZipTable>? The model that you're passing to your view is IEnumerable<AgainCandidate>, so you would get an error if you specified your model as something else. You'd need to change the model in your view to be IEnumerable<AgainCandidate>.
UPDATE:
Based on your revised explanation, you can do a couple things:
1) create a "ViewModel" that has two properties for each of your collections you want to display on the page like so:
public class MyViewModel
{
IEnumerable<ZipTable> Zips { get; set; }
IEnumerable<AgainCandidate> Candidates { get; set; }
}
Instantiate that in your action method and return that as your model. This would be my preferred approach.
2) Stash your two collections in the ViewData bag in your action method:
ViewData["Zips"] = queryZip.ToList();
ViewData["Candidates"] = queryCandidates.ToList();
return View(ViewData);
You can pull this data in your view like this:
#foreach (var zip in ViewData["Zips"] as IEnumerable<ZipTable>)
{
...
}

How to make BlazeDS name conversion to work for properties beginning with a lower-case letter followed by an upper-case one?

I have some trouble with the conversion applied by BlazeDS to the name of the properties when this name begins with a lower-case letter followed by a capital letter.
I have an ActionScript class similar to this:
package as.pkg {
[RemoteClass(alias="java.pkg.Example")]
public class Example {
private var mXRatio:Number;
public function get xRatio():Number {
return mXRatio;
}
public function set xRatio(r:Number):void {
mXRatio = r;
}
}
}
Then I have the equivalent Java class on the server:
package java.pkg;
public class Example {
private Double mXRatio;
public Double getXRatio() {
return mXRatio;
}
public void setXRatio( Double r ) {
mXRatio = r;
}
}
Sending instances from ActionScript to Java works perfectly fine. But when the instances are sent from Java to ActionScript, the following error is displayed:
ReferenceError: Error #1056: Cannot create property XRatio on as.pkg.Example.
Why BlazeDS does not convert the X of XRatio there? How can I avoid this?
BlazeDS uses reflection to inject values into your properties while serializing.
Therefore, your properties (public getter/setter pair or public variable) must have the exact same name or you will get serialization errors like the one you describe above.
Try this and it should be fine:
package as.pkg {
[RemoteClass(alias="java.pkg.Example")]
public class Example {
private var mXRatio:Number;
public function get XRatio():Number { //uppercase X i.s.o lowercase x
return mXRatio;
}
public function set XRatio(r:Number):void { //uppercase X i.s.o lowercase x
mXRatio = r;
}
}
}
Cheers

Resources