ServiceStack rest with null? - rest

I'd like to make R a nullable int (and b a nullable bool). I can hit /api/test/1/2 no problem but /api/test/null/2 causes SerializationException
KeyValueDataContractDeserializer: Error converting to type: Input string was not in a correct format
I tried doing /api/test//2 but it ignored the double slash and thought it was {Ids}.
How do I make R nullable?
[Route("/Test")]
[Route("/Test/{Ids}")]
[Route("/Test/{R}/{E}")]
[Route("/Test/a/{Ids}/{R}/{E}/{b}/{f}")]
public class Test
{
public long[] Ids { get; set; }
public int? R{get;set;}
public int E{get;set;}
public bool? b { get; set; }
public float f { get; set; }
}
public class TestService : Service
{
public object Get(Test a)
{
return JsonSerializer.SerializeToString(a);
}
}

The null in your route is treated like a string literal which obviously is not a valid number. Basically you want to avoid passing in null in the first place (i.e. avoid specifying it), e.g instead of:
/api/test/null/2
You can do:
/api/test?E=2

Related

Deserialize the immutable class with the custom constructor

I have a public class with some public immutable properties (only get;). It also has a custom constructor, which takes one additional parameter, required not for the setting of a property, but only for the calculations. I think, because of that, this class cannot be deserialized properly via Newtonsoft Json.
Other classes with only corresponding input parameters to the properties work fine.
So, this class deserializes itself not properly, returning zeros. It has additional parameter 'value' which is not related to any property, and just used for a calcualtions and presenting the data.
public class DurationData
{
public DateTime Start { get; }
public int Index { get; }
public double ActivityDurationInHours { get; }
public string Activetime { get; }
public ShiftDurationData(DateTime start, int index, TimeSpan value )
{
Start = start;
Index = shiftIndex;
ActivityDurationInHours = Math.Round(value.TotalHours, 1);
Activetime = $"{(int)value.TotalHours:d2}:{value.Minutes:D2}:{value.Seconds:D2}";
}
}
if I set the mock of this like below or just with mutable properties (get;set) and without a constructor it deserializes itself properly.
public class DurationData
{
public DateTime Start { get; }
public int Index { get; }
public double ActivityDurationInHours { get; }
public string Activetime { get; }
public ShiftDurationData(DateTime start, int index, double activityDurationInHours, string activeTime)
{
Start = start;
Index = shiftIndex;
ActivityDurationInHours = activityDurationInHours
ActiveTime = activetime ?? throw new ArgumentNullException(nameof(activeTime))
}
}
But I don't wan't to create additional mock class and would like to work with original. How to do this properly

Web API Model binding - Complex Parameter

I have a string received in query string
f[0][p]=zap&f[0][v][] = 110&f[0][v][]=500&f[1][p] = prih&f[1][v][] = 10000000&f[1][v][] = 30000000000
I try to catch it with string[] but it is always null. How to represent this parameter to Web API so it can serialize it?
I have a workaround with reading it for Uri as a string and then parse it but it is not good for unit testing and would like to update it.
Is it even possible with structure like this?
Ok, I solved this, maybe it can help someone.
I needed a class to represent the received object :
public class Filter
{
private string p { get; set; }
private string[] v { get; set; }
private string cp { get; set; }
private string[] cv { get; set; }
}
And in method definition I needed:
public SubjectStats BusinessSubjects(string country, string start, string end, [FromUri] Filter[] f)
The key was to define object as Filter[] in method signature.

How to map a string property to a binary column in the database?

I have a class for a user entity. One of the properties is the user's password (a hash, actually). I made it a string (streamlined code):
public class User
{
public virtual int Id { get; set; }
public virtual string Password { get; set; }
}
There's also a Fluent NHibernate mapping (streamlined code):
public class UserMap : ClassMap<User>
{
public UserMap()
{
Table("users");
Id(x => x.Id).GeneratedBy.Sequence("users_id_seq");
Map(x => x.Password); // what do I put here???
}
}
The database column is of bytea data type on PostgreSQL. The above mapping doesn't work, because the property is string (text). What should I do?
you can Make Password a public property, which is only used to reference to the underlying private property HashedPassword.
something like so:
protected virtual byte[] /*or whatever the type is*/ HashedPassword {get; set;}
public virtual string Password
get
{
return (string)(HashedPassword); //or however you want to cast it to string...
}
set
//...
you can then tell fluent nHib to ignore your Password property.
Here is the final solution which works both ways (read & write), what I tried earlier didn't work properly. Hope this will help somebody.
public class User
{
private byte[] _password;
public virtual int Id { get; private set; }
public virtual string Password
{
get { return System.Text.Encoding.Unicode.GetString(_password); }
set { _password = System.Text.Encoding.Unicode.GetBytes(value); }
}
}
public class UserMap : ClassMap<User>
{
public UserMap()
{
Table("users");
Id(x => x.Id).GeneratedBy.Sequence("users_id_seq");
Map(x => x.Password)
.Access.LowerCaseField(Prefix.Underscore)
.CustomType<byte[]>();
}
}

conditional either or validation in asp.net mvc2

In my registration page I have land line phone number and mobile number fields.
I need to ensure that the user needs to add at least one phone number either the land line or mobile.
How do I do this?
Thanks
Arnab
You could write a custom validation attribute and decorate your model with it:
[AttributeUsage(AttributeTargets.Class)]
public class AtLeastOnePhoneAttribute: ValidationAttribute
{
public override bool IsValid(object value)
{
var model = value as SomeViewModel;
if (model != null)
{
return !string.IsNullOrEmpty(model.Phone1) ||
!string.IsNullOrEmpty(model.Phone2);
}
return false;
}
}
and then:
[AtLeastOnePhone(ErrorMessage = "Please enter at least one of the two phones")]
public class SomeViewModel
{
public string Phone1 { get; set; }
public string Phone2 { get; set; }
}
For more advanced validation scenarios you may take a look at FluentValidation.NET or Foolproof.
Adding a solution that can be applied to individual properties, rather than overriding the validation method at the class level...
Create the following custom attribute. Note the "otherPropertyName" parameter in the constructor. This will allow you to pass in the other property to use in validation.
public class OneOrOtherRequiredAttribute: ValidationAttribute
{
public string OtherPropertyName { get; set; }
public OneOrOtherRequiredAttribute(string otherPropertyName)
{
OtherPropertyName = otherPropertyName;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var otherPropertyInfo = validationContext.ObjectType.GetProperty(OtherPropertyName);
var otherValue = (string)otherPropertyInfo.GetValue(validationContext.ObjectInstance, null);
if (string.IsNullOrEmpty(otherValue) && string.IsNullOrEmpty((string)value))
{
return new ValidationResult(this.ErrorMessage); //The error message passed into the Attribute's constructor
}
return null;
}
}
You can then decorate your properties like so: (be sure to pass in the name of the other property to compare with)
[OneOrOtherRequired("GroupNumber", ErrorMessage = "Either Group Number or Customer Number is required")]
public string CustomerNumber { get; set; }
[OneOrOtherRequired("CustomerNumber", ErrorMessage="Either Group Number or Customer Number is required")]
public string GroupNumber { get; set; }

Entity Framework Complex Type Custom Validation, Stopping Validation Recursion

We are using complex types to manage our translatable fields like this:
[ComplexType]
public class Translated
{
[Required]
public string NL { get; set; }
[Required]
public string EN { get; set; }
[ScaffoldColumn(false)]
public string TranslatedText
{
get
{
return Util.Translate(NL, EN);
}
}
}
We require the fields to be present. But in some cases the whole Translated field is optional as in:
public class Question
{
...
[Optional(ErrorMessage="Foo")]
public Translated Description { get; set; }
...
}
However, it seems that the Optional attribute gets calculated, and when it returns false nothing is done with the result.
class OptionalAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
return false;
}
}
When I put the optional attribute on a non-complex type it works as expected, the error message will always be Foo.
The ultimate goal is to allow the Description to be empty in both cases, but when one of the fields is filled the errors should of course propagate.
Stopping the validation recursion would cause the field to be optional, but it would also prevent the validation of the fields in case they are filled in.
Any ideas on how to accomplish this?
Using the data annotation [Required] on your string properties will create non nullable fields in the database. From your description it seems that sometimes you'll want both of those values to be null.
I would suggest implementing your own validation defining what makes those fields optional.
[ComplexType]
public class Translated : IValidatableObject
{
public string NL { get; set; }
public string EN { get; set; }
[NotMapped]
public string TranslatedText
{
get
{
return Util.Translate(NL, EN);
}
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!string.IsNullOrEmpty(NL) && string.IsNullOrEmpty(EN))
yield return new ValidationResult("EN is required if NL is entered.");
if (!string.IsNullOrEmpty(EN) && string.IsNullOrEmpty(NL))
yield return new ValidationResult("NL is required if EN is entered.");
}
}
This is what I'm doing now. It has the disadvantage that for each kind of Translated (Translated, TranslatedOptional, TranslatedMultiline and TranslatedMultilineOptional) you have seperate classes.
Another disadvantage is that I don't know how to add the validation results to the NL en EN fields themselves instead of to the Translated.
[ComplexType]
public class TranslatedMultiline : IValidatableObject
{
[DataType(DataType.MultilineText)]
[Display(Name = "dutch", ResourceType = typeof(Caracal.Resources.GUI))]
public string NL { get; set; }
[DataType(DataType.MultilineText)]
[Display(Name = "english", ResourceType = typeof(Caracal.Resources.GUI))]
public string EN { get; set; }
[ScaffoldColumn(false)]
public string TranslatedText
{
get
{
return Util.Translate(NL, EN);
}
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (this is IOptional)
{
if (!string.IsNullOrEmpty(NL) && string.IsNullOrEmpty(EN))
yield return new ValidationResult("EN is required if NL is entered.");
// TODO: Translate
if (!string.IsNullOrEmpty(EN) && string.IsNullOrEmpty(NL))
yield return new ValidationResult("NL is required if EN is entered.");
// TODO: Translate
}
else
{
if (string.IsNullOrEmpty(NL))
yield return new ValidationResult("NL is required");
if (string.IsNullOrEmpty(EN))
yield return new ValidationResult("EN is required");
}
}
}
[ComplexType]
public class TranslatedMultilineOptional : TranslatedMultiline, IOptional { }
public interface IOptional {}