Setting a boolean property from a 3rd party endpoint that returns a string - asp.net-core

I am attempting to deserialize a json object using JsonConvert - the data is coming from a 3rd party API
return JsonConvert.DeserializeObject<UserRegistration>(content,
JsonSnakeCaseNameStrategySettings.Settings());
The UserRegistration class:
public class UserRegistration
{
public UserRegistrationData UserRegistration { get; set; }
}
public class UserRegistrationData
{
public int UserId { get; set; }
public string Email { get; set; }
public UserRegistrationCustomFields CustomFields { get; set; }
}
public class UserRegistrationCustomFields
{
private bool emailDelivery;
public string DeliveryTime { get; set; }
public bool EmailDelivery {
get
{
return emailDelivery;
}
set
{
emailDelivery = value.ToString() == "1";
}
}
public bool SmsDelivery { get; set; }
public string PhoneNumber { get; set; }
}
I've tried several ways, this is my current iteration. The goal is to have "EmailDelivery" be a boolean, the value from the API will always be "1" or "0". This throws a JsonReaderException: Could not convert string to boolean: 0. Path 'user_registration.custom_fields.email_delivery', line 1, position 208.

You need custom JsonConverter to modify the deserialize principle.
Change your model like below:
public class UserRegistrationCustomFields
{
public string DeliveryTime { get; set; }
public bool EmailDelivery{get;set;}
public bool SmsDelivery { get; set; }
public string PhoneNumber { get; set; }
}
Custom a JsonConverter:
public class JsonBooleanConverter : JsonConverter
{
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var value = reader.Value.ToString().ToLower().Trim();
switch (value)
{
case "1": return true;
}
return false;
}
public override bool CanConvert(Type objectType)
{
if (objectType == typeof(Boolean))
{
return true;
}
return false;
}
}
How to use:
JsonConvert.DeserializeObject<UserRegistration>(json, new JsonBooleanConverter());

Related

How to update an existing entity that has a nested list of entities?

I'm trying to update an entity using entity framework but, everytime I try to do it, it raises an error saying that a nested entity the main class contains cannot be tracked.
These are my classes:
public abstract class BaseEntity
{
public int Id { get; set; }
}
public class Dashboard : BaseEntity
{
public int Order { get; set; }
public string Title { get; set; }
public bool Enabled { get; set; }
public virtual ICollection<Submenu> Submenu { get; set; }
}
public class Submenu : BaseEntity
{
public int Order { get; set; }
public bool Enabled { get; set; }
public string Title { get; set; }
public string Image { get; set; }
public string Descriptions { get; set; }
public virtual ICollection<Action> Actions { get; set; }
public int DashboardId { get; set; }
public virtual Dashboard Dashboard { get; set; }
}
public class Action : BaseEntity
{
public string Type { get; set; }
public string Label { get; set; }
public string Url { get; set; }
public string Extension { get; set; }
public virtual Submenu Submenu { get; set; }
public int SubmenuId { get; set; }
}
The one I am using to update is Dashboard, which contains the rest of the classes.
I'm trying to do it using a generic service layer and a generic repository that are defined this way:
public class GenericService<T> : IGenericService<T> where T : BaseEntity
{
private readonly IBaseRepository<T> baseRepository;
public GenericService(IBaseRepository<T> baseRepository)
{
this.baseRepository = baseRepository;
}
public async Task Update(T entity, T attachedEntity)
{
await baseRepository.Update(entity, attachedEntity);
}
}
public class BaseRepository<T> : IBaseRepository<T> where T : BaseEntity
{
private readonly PortalContext dataContext;
private DbSet<T> DbSet { get; set; }
public BaseRepository(PortalContext context)
{
dataContext = context;
DbSet = dataContext.Set<T>();
}
public async Task Update(T entity, T attachedEntity)
{
dataContext.Entry(attachedEntity).State = EntityState.Detached;
DbSet.Attach(entity);
dataContext.Entry(entity).State = EntityState.Modified;
await dataContext.SaveChangesAsync();
}
}
And, at last but no least, this is the way I am configuring everything at Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<PortalContext>(
options => options.UseSqlServer(Configuration.GetConnectionString("PortalContext"))
);
services.AddTransient(typeof(IGenericService<>), typeof(GenericService<>));
services.AddTransient(typeof(IBaseRepository<>), typeof(BaseRepository<>));
services.AddTransient<Func<string, ClaimsPrincipal, IRoleCheck>>((serviceProvider) =>
{
return (controllerName, claimsPrincipal) =>
new RoleCheck(serviceProvider.GetRequiredService<IGenericService<Dossier>>(),
serviceProvider.GetRequiredService<IGenericService<DossierTemplate>>(),
serviceProvider.GetRequiredService<IGenericService<Dashboard>>(),
controllerName, claimsPrincipal);
});
}
What the application first does is calling the RoleCheck class to retrieve and filter the required entities and, after that, the user can update them.
When I call the update function at the controller
public async Task<ActionResult<Dashboard>> Put(int id, [FromBody] Dashboard dashboard)
{
var currentDashboard = await service.Get(id);
if (currentDashboard == null)
{
return NotFound();
}
await service.Update(dashboard, currentDashboard);
return Ok();
}
I always receive the next error at the repository:
error
Is there something I am doing wrong? I have been stuck with this for a week now...
Thanks in advance and sorry for the long text, but I wanted it to be clear.
I could finally solve it by adding .AsNoTracking() at the Get() method of my repository:
public async Task<T> Get(int id, Func<IQueryable<T>, IIncludableQueryable<T, object>> includes)
{
IQueryable <T> query = DbSet.AsNoTracking();
if (includes != null)
{
query = includes(query);
}
return await query.FirstOrDefaultAsync(m => m.Id == id);
}

Entity Framework Core no duplicate entries with ErrorMessage

What is the best way to avoid duplicate entries with MVC-EFC and ErrorMessage return
Model Test.cs
public class Test
{
public int Id { get; set; }
[Required(ErrorMessage = "Select a Name")]
[StringLength(50, ErrorMessage = "Max 50 character")]
public string Name { get; set; }
[StringLength(100, ErrorMessage = "Max 100 character")]
public string Text { get; set; }
}
I use a ApiController with "ErrorMessage" return.
For column "Name" i do not want duplicates and a ErrorMessage return like "Entry already available!"
What is the best way?
Try to implement custom ValidationAttribute
Customer ValidationAttribute
public class UniqueValidation : ValidationAttribute
{
private readonly string _errorMessage;
public UniqueValidation(string ErrorMessage)
{
_errorMessage = ErrorMessage;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (validationContext != null && typeof(IName).IsAssignableFrom(validationContext.ObjectType))
{
ApplicationDbContext db = validationContext.GetService(typeof(ApplicationDbContext)) as ApplicationDbContext;
IQueryable<IName> result = db.GetType().GetMethod("Set").MakeGenericMethod(validationContext.ObjectType).Invoke(db, null) as IQueryable<IName>;
var v = result.FirstOrDefault(u => u.Name == ((IName)validationContext.ObjectInstance).Name);
if (v != null)
{
return new ValidationResult(_errorMessage);
}
}
return ValidationResult.Success;
}
}
Use
public class File: IName
{
public int Id { get; set; }
[UniqueValidation("FileName is exist")]
public string Name { get; set; }
[InverseProperty("Avatar")]
public ICollection<ApplicationUser> Users { get; set; }
}
public interface IName
{
string Name { get; set; }
}

ASP.Net core web API encode string to base64

I am new to .Net Core development. I have a model:
public class CoreGoal
{
[Key]
public long CoreGoalId { get; set; }
public string Title { get; set; }
public string Effect { get; set; }
public string Target_Audience { get; set; }
public string Infrastructure { get; set; }
public virtual ICollection<Image> Images { get; set; }
public CoreGoal()
{
}
}
And Image model is as following:
public class Image
{
[Key]
public long ImagelId { get; set; }
public string Base64 { get; set; }
[ForeignKey("CoreGoalId")]
public long CoreGoalId { get; set; }
public Image()
{
}
}
I am using Repository pattern. My repository:
public interface ICoreGoalRepository
{
void CreateCoreGoal(CoreGoal coreGoal);
}
public class CoreGoalRepository : ICoreGoalRepository
{
private readonly WebAPIDataContext _db;
public CoreGoalRepository(WebAPIDataContext db)
{
_db = db;
}
//Find specific
public CoreGoal Find(long key)
{
return _db.CoreGoals.FirstOrDefault(t => t.CoreGoalId == key);
}
//Add new
public void CreateCoreGoal(CoreGoal coreGoal)
{
_db.CoreGoals.Add(coreGoal);
_db.SaveChanges();
}
}
And controller:
[Route("api/[controller]")]
public class CoreGoalController : Controller
{
private readonly ICoreGoalRepository _coreGoalRepository;
//Controller
public CoreGoalController(ICoreGoalRepository coreGoalRepository) {
_coreGoalRepository = coreGoalRepository;
}
[HttpGet("{id}", Name = "GetCoreGoal")]
public IActionResult GetById(long id)
{
var item = _coreGoalRepository.Find(id);
if (item == null)
{
return NotFound();
}
return new ObjectResult(item);
}
//Create
[HttpPost]
public IActionResult Create([FromBody] CoreGoal item)
{
if (item == null)
{
return BadRequest();
}
_coreGoalRepository.CreateCoreGoal(item);
return CreatedAtRoute("GetCoreGoal", new { id = item.CoreGoalId }, item);
}
}
On POST request for CoreGoal- While creating a new CoreGoal, I would like to convert Image model's Base64 attribute from string to byte[]. I found this (https://adrientorris.github.io/aspnet-core/manage-base64-encoding.html) blogpost, but I am not sure where Am I supposed to write this piece of code.
Can someone help me?
Initially you should chage you database model to save you binary image to db (also, it's still not good idea, but let leave it for a now):
public class Image
{
[Key]
public long ImagelId { get; set; }
[NotMapped]
public string Base64 { get; set; }
public byte[] Binary {get; set;}
[ForeignKey("CoreGoalId")]
public long CoreGoalId { get; set; }
public Image()
{
}
}
next you just should convert your image inside controller:
[HttpPost]
public IActionResult Create([FromBody] CoreGoal item)
{
if (item == null)
{
return BadRequest();
}
item.Binary = Convert.FromBase64String(item.Base64);
_coreGoalRepository.CreateCoreGoal(item);
return CreatedAtRoute("GetCoreGoal", new { id = item.CoreGoalId }, item);
}
BTW:you code still not good. It's not necessary to use Repository pattern with EF core (https://www.thereformedprogrammer.net/is-the-repository-pattern-useful-with-entity-framework-core/). And you should introduce two model layers: public layer and model layer. You shouldn't expose EF Core contract to outside.

JSON.Net - DeserializeObject Format

I'm using JSON.Net to try and deserialize some survey responses from SurveyGizmo.
Here's a snapshot of the data I'm reading in:
{"result_ok":true,
"total_count":"44",
"page":1,
"total_pages":1,
"results_per_page":50,
"data":[
{"id":"1",
"contact_id":"",
"status":"Complete",
"is_test_data":"0",
"datesubmitted":"2011-11-13 22:26:53",
"[question(59)]":"11\/12\/2011",
"[question(60)]":"06:15 pm",
"[question(62)]":"72",
"[question(63)]":"One",
"[question(69), option(10196)]":"10",
I've setup a class as far as datesubmitted but I'm not sure how to setup the class to deserialize the questions given that the amount of questions will change? I also need to capture the option if it's present.
I'm using this code to use the JSON.NET Deserialize function:
Dim responses As Responses = JsonConvert.DeserializeObject(Of Responses)(fcontents)
Classes:
Public Class Responses
Public Property result_OK As Boolean
Public Property total_count As Integer
Public Property page As Integer
Public Property total_pages As Integer
Public Property results_per_page As Integer
Public Overridable Property data As List(Of surveyresponse)
End Class
Public Class SurveyResponse
Public Property id As Integer
Public Property status As String
Public Property datesubmitted As Date
End Class
This trick to support totally crazy mappings is to use JsonConverter and completely replace the parsing for that object, (I apologize for the C#, but I'm no good at VB syntax):
class Program
{
static void Main(string[] args)
{
var result = JsonConvert.DeserializeObject<Responses>(TestData);
}
const string TestData = #"{""result_ok"":true,
""total_count"":""44"",
""page"":1,
""total_pages"":1,
""results_per_page"":50,
""data"":[
{""id"":""1"",
""contact_id"":"""",
""status"":""Complete"",
""is_test_data"":""0"",
""datesubmitted"":""2011-11-13 22:26:53"",
""[question(59)]"":""11\/12\/2011"",
""[question(60)]"":""06:15 pm"",
""[question(62)]"":""72"",
""[question(63)]"":""One"",
""[question(69), option(10196)]"":""10"",
}]}";
}
[JsonObject]
class Responses
{
public bool result_ok { get; set; }
public string total_count { get; set; }
public int page { get; set; }
public int total_pages { get; set; }
public int results_per_page { get; set; }
public SurveyResponse[] Data { get; set; }
}
[JsonObject]
// Here is the magic: When you see this type, use this class to read it.
// If you want, you can also define the JsonConverter by adding it to
// a JsonSerializer, and parsing with that.
[JsonConverter(typeof(DataItemConverter))]
class SurveyResponse
{
public string id { get; set; }
public string contact_id { get; set; }
public string status { get; set; }
public string is_test_data { get; set; }
public DateTime datesubmitted { get; set; }
public Dictionary<int, string> questions { get; set; }
}
class DataItemConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SurveyResponse);
}
public override bool CanRead
{
get { return true; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var value = (SurveyResponse)existingValue;
if (value == null)
{
value = new SurveyResponse();
value.questions = new Dictionary<int, string>()
}
// Skip opening {
reader.Read();
while (reader.TokenType == JsonToken.PropertyName)
{
var name = reader.Value.ToString();
reader.Read();
// Here is where you do your magic
if (name.StartsWith("[question("))
{
int index = int.Parse(name.Substring(10, name.IndexOf(')') - 10));
value.questions[index] = serializer.Deserialize<string>(reader);
}
else
{
var property = typeof(SurveyResponse).GetProperty(name);
property.SetValue(value, serializer.Deserialize(reader, property.PropertyType), null);
}
// Skip the , or } if we are at the end
reader.Read();
}
return value;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Now obviously there's a lot more you would want to do to get this really robust, but this gives you the basics of how to do it. There are more lightweight alternatives if you simply need to change property names (either JsonPropertyAttribute or overriding DefaultContractResolver.ResolvePropertyName(), but this gives you full control.

Can I use NHibernate to store an object in xml serialized form?

Say I have a class like this:
public class MyClass
{
public int Id { get; set; }
public DateTime Date { get; set; }
public string String1 { get; set; }
public string String2 { get; set; }
public string String3 { get; set; }
public string String4 { get; set; }
}
Is it possible to get NHibernate to store it in the following schema?
CREATE TABLE [dbo].[MyClass](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Xml] [varchar](max) NOT NULL,
)
Where the Id maps to Id, but then all other fields get serialized into XML (or otherwise)? I don't mind if these other fields have to go on a child object like the below, if that helps:
public class MyClass
{
public int Id { get; set; }
public AllOtherOptions Options { get; set; }
}
public class AllOtherOptions
{
public DateTime Date { get; set; }
public string String1 { get; set; }
public string String2 { get; set; }
public string String3 { get; set; }
public string String4 { get; set; }
}
I am thinking about doing something similar for an upcoming project. The project requires collecting a lot of data but only a few elements need to be stored in a relational database. I haven't started experimenting but these are my thoughts so far.
You can map an XML data type by creating a type that implements IUserType. If the child class (AllOtherOptions) is serializable, you should be able to map the XML field as a private member in MyClass and serialize/deserialize AllOtherOptions as needed. You could either dynamically maintain the XML field (sounds like a lot of work) or create an interceptor to do it. My thinking is that MyClass would implement an interface such as
public interface IXmlObjectContainer
{
void SerializeChildObjects();
void DeSerializeChildObjects();
}
and the interceptor would call those methods as needed. That's a proof of concept idea. I would probably refine that by exposing pairs of xml fields and serializable objects to remove the work of serializing from IXmlObjectContainer implementers. Or maybe handle serialization through the XML field's get/set accessors.
More info:
Working with XML Fields in NHibernate
Another XML implementation of IUserType
I had the same idea to save object in XML column. My idea was other. I took code from links and changed it to generic IUserType implementation. So any field/prop which is [Serializable] can be saved in XML column.
public class XmlUserType<T> : IUserType where T : class
{
public new bool Equals(object x, object y)
{
return x == y;
}
public int GetHashCode(object x)
{
return x.GetHashCode();
}
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
if (names.Length != 1)
throw new InvalidOperationException("names array has more than one element. can't handle this!");
var val = rs[names[0]] as string;
if (string.IsNullOrWhiteSpace(val) == false)
{
return KRD.Common.GenericXmlSerialization.Deserialize<T>(val);
}
return null;
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
var parameter = (DbParameter)cmd.Parameters[index];
T toSave = value as T;
if (toSave != null)
{
parameter.Value = KRD.Common.GenericXmlSerialization.Serialize(toSave);
}
else
{
parameter.Value = DBNull.Value;
}
}
public object DeepCopy(object value)
{
T toCopy = value as T;
if (toCopy == null)
return null;
string serialized = KRD.Common.GenericXmlSerialization.Serialize(toCopy);
return KRD.Common.GenericXmlSerialization.Deserialize<T>(serialized);
}
public object Replace(object original, object target, object owner)
{
throw new NotImplementedException();
}
public object Assemble(object cached, object owner)
{
var str = cached as string;
if (string.IsNullOrWhiteSpace(str) == false)
{
return null;
}
return KRD.Common.GenericXmlSerialization.Deserialize<T>(str);
}
public object Disassemble(object value)
{
var toCache = value as T;
if (toCache != null)
{
return KRD.Common.GenericXmlSerialization.Serialize(toCache);
}
return null;
}
public SqlType[] SqlTypes
{
get
{
return new SqlType[] { new SqlXmlType() };
}
}
public Type ReturnedType
{
get { return typeof(XmlDocument); }
}
public bool IsMutable
{
get { return true; }
}
}
public class SqlXmlType : SqlType
{
public SqlXmlType()
: base(DbType.Xml)
{
}
}
Usage with FluentNHibernate:
public class MainObject
{
public int Id { get; set; }
public ObjectAsXml Data { get; set; }
}
public class ObjectAsXml
{
public string Name { get; set; }
public int Date { get; set; }
public ObjectAsXml OtherObject { get; set; }
}
private class MainObjectMap : ClassMap<MainObject>
{
public MainObjectMap()
{
Id(id => id.Id);
Map(m => m.Data).CustomType<XmlUserType<ObjectAsXml>>().Nullable();
}
}
Maybe it will help somebody.